merge the bouyer-socketcan branch to HEAD.
CAN stands for Controller Area Network, a broadcast network used in automation and automotive fields. For example, the NMEA2000 standard developped for marine devices uses a CAN network as the link layer. This is an implementation of the linux socketcan API: https://www.kernel.org/doc/Documentation/networking/can.txt you can also see can(4). This adds a new socket family (AF_CAN) and protocol (PF_CAN), as well as the canconfig(8) utility, used to set timing parameter of CAN hardware. Also inclued is a driver for the CAN controller found in the allwinner A20 SoC (I tested it with an Olimex lime2 board, connected with PIC18-based CAN devices). There is also the canloop(4) pseudo-device, which allows to use the socketcan API without CAN hardware. At this time the CANFD part of the linux socketcan API is not implemented. Error frames are not implemented either. But I could get the cansend and canreceive utilities from the canutils package to build and run with minimal changes. tcpudmp(8) can also be used to record frames, which can be decoded with etherreal.
This commit is contained in:
parent
99b53e88ef
commit
6e4cb2b9ab
@ -1,4 +1,4 @@
|
||||
# $NetBSD: mi,v 1.1157 2017/05/21 15:28:37 riastradh Exp $
|
||||
# $NetBSD: mi,v 1.1158 2017/05/27 21:02:54 bouyer Exp $
|
||||
#
|
||||
# Note: Don't delete entries from here - mark them as "obsolete" instead,
|
||||
# unless otherwise stated below.
|
||||
@ -456,6 +456,7 @@
|
||||
./sbin/blacklistctl base-sysutil-root
|
||||
./sbin/blacklistd base-sysutil-root
|
||||
./sbin/brconfig base-netutil-root
|
||||
./sbin/canconfig base-netutil-root
|
||||
./sbin/ccdconfig base-sysutil-root
|
||||
./sbin/cgdconfig base-sysutil-root
|
||||
./sbin/chown base-sysutil-root
|
||||
@ -1179,6 +1180,7 @@
|
||||
./usr/include/net80211 base-c-usr
|
||||
./usr/include/netatalk base-c-usr
|
||||
./usr/include/netbt base-c-usr
|
||||
./usr/include/netcan base-c-usr
|
||||
./usr/include/netccitt base-obsolete obsolete
|
||||
./usr/include/netinet base-c-usr
|
||||
./usr/include/netinet6 base-c-usr
|
||||
|
@ -1,4 +1,4 @@
|
||||
# $NetBSD: shl.mi,v 1.816 2017/05/21 15:28:37 riastradh Exp $
|
||||
# $NetBSD: shl.mi,v 1.817 2017/05/27 21:02:54 bouyer Exp $
|
||||
#
|
||||
# Note: Don't delete entries from here - mark them as "obsolete" instead,
|
||||
# unless otherwise stated below.
|
||||
@ -718,6 +718,9 @@
|
||||
./usr/lib/librumpnet_netbt.so base-rump-shlib rump
|
||||
./usr/lib/librumpnet_netbt.so.0 base-rump-shlib rump
|
||||
./usr/lib/librumpnet_netbt.so.0.0 base-rump-shlib rump
|
||||
./usr/lib/librumpnet_netcan.so base-rump-shlib rump
|
||||
./usr/lib/librumpnet_netcan.so.0 base-rump-shlib rump
|
||||
./usr/lib/librumpnet_netcan.so.0.0 base-rump-shlib rump
|
||||
./usr/lib/librumpnet_netinet.so base-rump-shlib rump
|
||||
./usr/lib/librumpnet_netinet.so.0 base-rump-shlib rump
|
||||
./usr/lib/librumpnet_netinet.so.0.0 base-rump-shlib rump
|
||||
|
@ -1,4 +1,4 @@
|
||||
# $NetBSD: mi,v 1.2137 2017/05/21 22:48:25 kamil Exp $
|
||||
# $NetBSD: mi,v 1.2138 2017/05/27 21:02:54 bouyer Exp $
|
||||
#
|
||||
# Note: don't delete entries from here - mark them as "obsolete" instead.
|
||||
./etc/mtree/set.comp comp-sys-root
|
||||
@ -2273,6 +2273,8 @@
|
||||
./usr/include/netbt/l2cap.h comp-c-include
|
||||
./usr/include/netbt/rfcomm.h comp-c-include
|
||||
./usr/include/netbt/sco.h comp-c-include
|
||||
./usr/include/netcan/can.h comp-c-include
|
||||
./usr/include/netcan/can_link.h comp-c-include
|
||||
./usr/include/netccitt/dll.h comp-obsolete obsolete
|
||||
./usr/include/netccitt/hd_var.h comp-obsolete obsolete
|
||||
./usr/include/netccitt/hdlc.h comp-obsolete obsolete
|
||||
@ -3565,6 +3567,8 @@
|
||||
./usr/lib/librumpnet_net_p.a comp-c-proflib rump,profile
|
||||
./usr/lib/librumpnet_netbt.a comp-c-lib rump
|
||||
./usr/lib/librumpnet_netbt_p.a comp-c-proflib rump,profile
|
||||
./usr/lib/librumpnet_netcan.a comp-c-lib rump
|
||||
./usr/lib/librumpnet_netcan_p.a comp-c-proflib rump,profile
|
||||
./usr/lib/librumpnet_netinet.a comp-c-lib rump
|
||||
./usr/lib/librumpnet_netinet6.a comp-c-lib rump
|
||||
./usr/lib/librumpnet_netinet6_p.a comp-c-proflib rump,profile
|
||||
|
@ -1,4 +1,4 @@
|
||||
# $NetBSD: shl.mi,v 1.305 2017/05/21 15:28:37 riastradh Exp $
|
||||
# $NetBSD: shl.mi,v 1.306 2017/05/27 21:02:54 bouyer Exp $
|
||||
#
|
||||
# Note: don't delete entries from here - mark them as "obsolete" instead.
|
||||
#
|
||||
@ -224,6 +224,7 @@
|
||||
./usr/lib/librumpnet_net80211_pic.a comp-c-piclib picinstall,rump
|
||||
./usr/lib/librumpnet_net_pic.a comp-c-piclib picinstall,rump
|
||||
./usr/lib/librumpnet_netbt_pic.a comp-c-piclib picinstall,rump
|
||||
./usr/lib/librumpnet_netcan_pic.a comp-c-piclib picinstall,rump
|
||||
./usr/lib/librumpnet_netinet6_pic.a comp-c-piclib picinstall,rump
|
||||
./usr/lib/librumpnet_netinet_pic.a comp-c-piclib picinstall,rump
|
||||
./usr/lib/librumpnet_netipsec_pic.a comp-c-piclib picinstall,rump
|
||||
|
@ -1,4 +1,4 @@
|
||||
# $NetBSD: mi,v 1.212 2017/05/26 11:16:18 martin Exp $
|
||||
# $NetBSD: mi,v 1.213 2017/05/27 21:02:55 bouyer Exp $
|
||||
./etc/mtree/set.debug comp-sys-root
|
||||
./usr/lib comp-sys-usr compatdir
|
||||
./usr/lib/i18n/libBIG5_g.a comp-c-debuglib debuglib,compatfile
|
||||
@ -216,6 +216,7 @@
|
||||
./usr/lib/librumpnet_net80211_g.a comp-c-debuglib debuglib,rump
|
||||
./usr/lib/librumpnet_net_g.a comp-c-debuglib debuglib,rump
|
||||
./usr/lib/librumpnet_netbt_g.a comp-c-debuglib debuglib,rump
|
||||
./usr/lib/librumpnet_netcan_g.a comp-c-debuglib debuglib,rump
|
||||
./usr/lib/librumpnet_netinet6_g.a comp-c-debuglib debuglib,rump
|
||||
./usr/lib/librumpnet_netinet_g.a comp-c-debuglib debuglib,rump
|
||||
./usr/lib/librumpnet_netipsec_g.a comp-c-debuglib debuglib,rump
|
||||
@ -308,6 +309,7 @@
|
||||
./usr/libdata/debug/sbin/blacklistctl.debug comp-sysutil-debug debug
|
||||
./usr/libdata/debug/sbin/blacklistd.debug comp-sysutil-debug debug
|
||||
./usr/libdata/debug/sbin/brconfig.debug comp-netutil-debug debug
|
||||
./usr/libdata/debug/sbin/canconfig.debug comp-netutil-debug debug
|
||||
./usr/libdata/debug/sbin/ccdconfig.debug comp-sysutil-debug debug
|
||||
./usr/libdata/debug/sbin/cgdconfig.debug comp-sysutil-debug debug
|
||||
./usr/libdata/debug/sbin/chown.debug comp-sysutil-debug debug
|
||||
@ -2254,6 +2256,8 @@
|
||||
./usr/libdata/debug/usr/tests/net/bpfjit/t_cop.debug tests-net-debug debug,atf,sljit,rump
|
||||
./usr/libdata/debug/usr/tests/net/bpfjit/t_extmem.debug tests-net-debug debug,atf,sljit,rump
|
||||
./usr/libdata/debug/usr/tests/net/bpfjit/t_mbuf.debug tests-net-debug debug,atf,sljit,rump
|
||||
./usr/libdata/debug/usr/tests/net/can/t_can.debug tests-net-debug debug,atf,rump
|
||||
./usr/libdata/debug/usr/tests/net/can/t_canfilter.debug tests-net-debug debug,atf,rump
|
||||
./usr/libdata/debug/usr/tests/net/carp/t_basic.debug tests-net-debug debug,atf,rump,obsolete
|
||||
./usr/libdata/debug/usr/tests/net/fdpass/fdpass32.debug tests-net-debug debug,atf,compattestfile
|
||||
./usr/libdata/debug/usr/tests/net/fdpass/fdpass64.debug tests-net-debug debug,atf,compattestfile
|
||||
|
@ -1,4 +1,4 @@
|
||||
# $NetBSD: shl.mi,v 1.175 2017/05/21 15:28:37 riastradh Exp $
|
||||
# $NetBSD: shl.mi,v 1.176 2017/05/27 21:02:55 bouyer Exp $
|
||||
./usr/lib/libbfd_g.a comp-c-debuglib debuglib,compatfile,binutils
|
||||
./usr/libdata/debug/lib base-sys-usr debug,dynamicroot,compatdir
|
||||
./usr/libdata/debug/lib/libblacklist.so.0.0.debug comp-sys-debug debug,dynamicroot
|
||||
@ -246,6 +246,7 @@
|
||||
./usr/libdata/debug/usr/lib/librumpnet_net.so.0.0.debug comp-rump-debug debug,rump
|
||||
./usr/libdata/debug/usr/lib/librumpnet_net80211.so.0.0.debug comp-rump-debug debug,rump
|
||||
./usr/libdata/debug/usr/lib/librumpnet_netbt.so.0.0.debug comp-rump-debug debug,rump
|
||||
./usr/libdata/debug/usr/lib/librumpnet_netcan.so.0.0.debug comp-rump-debug debug,rump
|
||||
./usr/libdata/debug/usr/lib/librumpnet_netinet.so.0.0.debug comp-rump-debug debug,rump
|
||||
./usr/libdata/debug/usr/lib/librumpnet_netinet6.so.0.0.debug comp-rump-debug debug,rump
|
||||
./usr/libdata/debug/usr/lib/librumpnet_netipsec.so.0.0.debug comp-rump-debug debug,rump
|
||||
|
@ -1,4 +1,4 @@
|
||||
# $NetBSD: mi,v 1.1556 2017/05/21 15:28:38 riastradh Exp $
|
||||
# $NetBSD: mi,v 1.1557 2017/05/27 21:02:55 bouyer Exp $
|
||||
#
|
||||
# Note: don't delete entries from here - mark them as "obsolete" instead.
|
||||
#
|
||||
@ -954,6 +954,8 @@
|
||||
./usr/share/man/cat4/bwi.0 man-sys-catman .cat
|
||||
./usr/share/man/cat4/ca.0 man-obsolete obsolete
|
||||
./usr/share/man/cat4/cac.0 man-sys-catman .cat
|
||||
./usr/share/man/cat4/can.0 man-sys-catman .cat
|
||||
./usr/share/man/cat4/canloop.0 man-sys-catman .cat
|
||||
./usr/share/man/cat4/cardbus.0 man-sys-catman .cat
|
||||
./usr/share/man/cat4/cardslot.0 man-sys-catman .cat
|
||||
./usr/share/man/cat4/carp.0 man-sys-catman .cat
|
||||
@ -2380,6 +2382,7 @@
|
||||
./usr/share/man/cat8/bthcid.0 man-sysutil-catman .cat
|
||||
./usr/share/man/cat8/btpand.0 man-sysutil-catman .cat
|
||||
./usr/share/man/cat8/btuartd.0 man-obsolete obsolete
|
||||
./usr/share/man/cat8/canconfig.0 man-netutil-catman .cat
|
||||
./usr/share/man/cat8/catman.0 man-man-catman .cat
|
||||
./usr/share/man/cat8/cats/MAKEDEV.0 man-obsolete obsolete
|
||||
./usr/share/man/cat8/cats/makedev.0 man-obsolete obsolete
|
||||
@ -4066,6 +4069,8 @@
|
||||
./usr/share/man/html4/btuart.html man-sys-htmlman html
|
||||
./usr/share/man/html4/bwi.html man-sys-htmlman html
|
||||
./usr/share/man/html4/cac.html man-sys-htmlman html
|
||||
./usr/share/man/html4/can.html man-sys-htmlman html
|
||||
./usr/share/man/html4/canloop.html man-sys-htmlman html
|
||||
./usr/share/man/html4/cardbus.html man-sys-htmlman html
|
||||
./usr/share/man/html4/cardslot.html man-sys-htmlman html
|
||||
./usr/share/man/html4/carp.html man-sys-htmlman html
|
||||
@ -5358,6 +5363,7 @@
|
||||
./usr/share/man/html8/btdevctl.html man-sysutil-htmlman html
|
||||
./usr/share/man/html8/bthcid.html man-sysutil-htmlman html
|
||||
./usr/share/man/html8/btpand.html man-sysutil-htmlman html
|
||||
./usr/share/man/html8/canconfig.html man-netutil-htmlman html
|
||||
./usr/share/man/html8/catman.html man-man-htmlman html
|
||||
./usr/share/man/html8/ccdconfig.html man-sysutil-htmlman html
|
||||
./usr/share/man/html8/cgdconfig.html man-sysutil-htmlman html
|
||||
@ -6950,6 +6956,8 @@
|
||||
./usr/share/man/man4/bwi.4 man-sys-man .man
|
||||
./usr/share/man/man4/ca.4 man-obsolete obsolete
|
||||
./usr/share/man/man4/cac.4 man-sys-man .man
|
||||
./usr/share/man/man4/can.4 man-sys-man .man
|
||||
./usr/share/man/man4/canloop.4 man-sys-man .man
|
||||
./usr/share/man/man4/cardbus.4 man-sys-man .man
|
||||
./usr/share/man/man4/cardslot.4 man-sys-man .man
|
||||
./usr/share/man/man4/carp.4 man-sys-man .man
|
||||
@ -8375,6 +8383,7 @@
|
||||
./usr/share/man/man8/bthcid.8 man-sysutil-man .man
|
||||
./usr/share/man/man8/btpand.8 man-sysutil-man .man
|
||||
./usr/share/man/man8/btuartd.8 man-obsolete obsolete
|
||||
./usr/share/man/man8/canconfig.8 man-netutil-man .man
|
||||
./usr/share/man/man8/catman.8 man-man-man .man
|
||||
./usr/share/man/man8/cats/MAKEDEV.8 man-obsolete obsolete
|
||||
./usr/share/man/man8/cats/makedev.8 man-obsolete obsolete
|
||||
|
@ -1,4 +1,4 @@
|
||||
# $NetBSD: mi,v 1.748 2017/05/26 09:02:33 martin Exp $
|
||||
# $NetBSD: mi,v 1.749 2017/05/27 21:02:55 bouyer Exp $
|
||||
#
|
||||
# Note: don't delete entries from here - mark them as "obsolete" instead.
|
||||
#
|
||||
@ -155,6 +155,7 @@
|
||||
./usr/libdata/debug/usr/tests/net/bpf tests-net-debug compattestfile,atf
|
||||
./usr/libdata/debug/usr/tests/net/bpfilter tests-net-debug compattestfile,atf
|
||||
./usr/libdata/debug/usr/tests/net/bpfjit tests-net-debug compattestfile,atf
|
||||
./usr/libdata/debug/usr/tests/net/can tests-net-debug compattestfile,atf
|
||||
./usr/libdata/debug/usr/tests/net/carp tests-net-debug compattestfile,atf
|
||||
./usr/libdata/debug/usr/tests/net/fdpass tests-net-debug compattestfile,atf
|
||||
./usr/libdata/debug/usr/tests/net/icmp tests-net-debug compattestfile,atf
|
||||
@ -3232,6 +3233,10 @@
|
||||
./usr/tests/net/bpfjit/t_cop tests-net-tests atf,rump,sljit
|
||||
./usr/tests/net/bpfjit/t_extmem tests-net-tests atf,rump,sljit
|
||||
./usr/tests/net/bpfjit/t_mbuf tests-net-tests atf,rump,sljit
|
||||
./usr/tests/net/can tests-net-tests compattestfile,atf
|
||||
./usr/tests/net/can/Atffile tests-net-tests atf,rump
|
||||
./usr/tests/net/can/t_can tests-net-tests atf,rump
|
||||
./usr/tests/net/can/t_canfilter tests-net-tests atf,rump
|
||||
./usr/tests/net/carp tests-net-tests compattestfile,atf
|
||||
./usr/tests/net/carp/Atffile tests-net-tests atf,rump
|
||||
./usr/tests/net/carp/Kyuafile tests-net-tests atf,rump,kyua
|
||||
|
@ -1,4 +1,4 @@
|
||||
# $NetBSD: NetBSD.dist.base,v 1.159 2017/04/10 16:38:40 christos Exp $
|
||||
# $NetBSD: NetBSD.dist.base,v 1.160 2017/05/27 21:02:55 bouyer Exp $
|
||||
# @(#)4.4BSD.dist 8.1 (Berkeley) 6/13/93
|
||||
|
||||
# Do not customize this file as it may be overwritten on upgrades.
|
||||
@ -209,6 +209,7 @@
|
||||
./usr/include/net/agr
|
||||
./usr/include/netatalk
|
||||
./usr/include/netbt
|
||||
./usr/include/netcan
|
||||
./usr/include/netinet
|
||||
./usr/include/net80211
|
||||
./usr/include/netinet6
|
||||
|
@ -1,4 +1,4 @@
|
||||
# $NetBSD: NetBSD.dist.tests,v 1.146 2017/05/14 00:07:07 kamil Exp $
|
||||
# $NetBSD: NetBSD.dist.tests,v 1.147 2017/05/27 21:02:55 bouyer Exp $
|
||||
|
||||
./usr/libdata/debug/usr/tests
|
||||
./usr/libdata/debug/usr/tests/atf
|
||||
@ -136,6 +136,7 @@
|
||||
./usr/libdata/debug/usr/tests/net/bpf
|
||||
./usr/libdata/debug/usr/tests/net/bpfilter
|
||||
./usr/libdata/debug/usr/tests/net/bpfjit
|
||||
./usr/libdata/debug/usr/tests/net/can
|
||||
./usr/libdata/debug/usr/tests/net/carp
|
||||
./usr/libdata/debug/usr/tests/net/fdpass
|
||||
./usr/libdata/debug/usr/tests/net/icmp
|
||||
@ -325,6 +326,7 @@
|
||||
./usr/tests/net/bpf
|
||||
./usr/tests/net/bpfilter
|
||||
./usr/tests/net/bpfjit
|
||||
./usr/tests/net/can
|
||||
./usr/tests/net/carp
|
||||
./usr/tests/net/fdpass
|
||||
./usr/tests/net/icmp
|
||||
|
@ -1,4 +1,4 @@
|
||||
.\" $NetBSD: socket.2,v 1.41 2013/03/01 18:25:16 joerg Exp $
|
||||
.\" $NetBSD: socket.2,v 1.42 2017/05/27 21:02:55 bouyer Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1983, 1991, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
@ -29,7 +29,7 @@
|
||||
.\"
|
||||
.\" @(#)socket.2 8.1 (Berkeley) 6/4/93
|
||||
.\"
|
||||
.Dd February 5, 2013
|
||||
.Dd April 27, 2017
|
||||
.Dt SOCKET 2
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -61,6 +61,7 @@ PF_INET6 IPv6 (Internet Protocol version 6) protocols
|
||||
PF_NS Xerox Network Systems protocols
|
||||
PF_APPLETALK AppleTalk protocols
|
||||
PF_BLUETOOTH Bluetooth protocols
|
||||
PF_CAN CAN bus protocols
|
||||
.Ed
|
||||
.Pp
|
||||
The socket has the indicated
|
||||
|
@ -1,4 +1,4 @@
|
||||
# $NetBSD: Makefile,v 1.129 2016/07/01 22:50:50 christos Exp $
|
||||
# $NetBSD: Makefile,v 1.130 2017/05/27 21:02:55 bouyer Exp $
|
||||
# @(#)Makefile 8.5 (Berkeley) 3/31/94
|
||||
|
||||
# Not ported: XNSrouted enpload scsiformat startslip
|
||||
@ -6,8 +6,9 @@
|
||||
|
||||
.include <bsd.own.mk>
|
||||
|
||||
SUBDIR= amrctl apmlabel atactl badsect bioctl brconfig ccdconfig cgdconfig \
|
||||
chown devpubd disklabel dkctl dkscan_bsdlabel dmesg dmctl \
|
||||
SUBDIR= amrctl apmlabel atactl badsect bioctl brconfig \
|
||||
canconfig ccdconfig cgdconfig chown \
|
||||
devpubd disklabel dkctl dkscan_bsdlabel dmesg dmctl \
|
||||
drvctl fastboot fdisk fsck fsirand gpt ifconfig init ldconfig luactl \
|
||||
mbrlabel mknod modload modstat modunload mount \
|
||||
newbtconf nologin nvmectl \
|
||||
|
6
sbin/canconfig/Makefile
Normal file
6
sbin/canconfig/Makefile
Normal file
@ -0,0 +1,6 @@
|
||||
# $NetBSD: Makefile,v 1.2 2017/05/27 21:02:55 bouyer Exp $
|
||||
|
||||
PROG= canconfig
|
||||
MAN= canconfig.8
|
||||
|
||||
.include <bsd.prog.mk>
|
128
sbin/canconfig/canconfig.8
Normal file
128
sbin/canconfig/canconfig.8
Normal file
@ -0,0 +1,128 @@
|
||||
.\" $NetBSD: canconfig.8,v 1.2 2017/05/27 21:02:55 bouyer Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2017 Manuel Bouyer.
|
||||
*
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd Apris 15, 2017
|
||||
.Dt CANCONFIG 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm canconfig
|
||||
.Nd configure CAN network interface parameters
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Fl a
|
||||
.Nm
|
||||
.Ar canif
|
||||
.Nm
|
||||
.Ar can
|
||||
.Ar command
|
||||
.Op Ar args ...
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
utility is used to configure CAN network interface parameters and retrieve
|
||||
CAN network interface parameters and status from the kernel.
|
||||
.Ss Timing
|
||||
.Pp
|
||||
The base time unit used to define the network bit rate is the time quanta (tq),
|
||||
its value is defined by the input clock freqency and the prescaler value
|
||||
as (1/ freq * prescaler).
|
||||
.Pp
|
||||
The network bit time is split in 4 segments:
|
||||
.Bl -tag -width "phase_seg1" -offset indent -compact
|
||||
.It sync_seg
|
||||
fixed to 1 tq
|
||||
.It prop_seg
|
||||
.It phase_seg1
|
||||
.It phase_seg2
|
||||
.El
|
||||
The network bit time is (1 + prop_seg + phase_seg1 + phase_seg2), in tq.
|
||||
The sample point is between phase_seg1 and phase_seg2.
|
||||
.Pp
|
||||
The receiver hardware is allowed to shorten prop_seg or phase_seg2 to
|
||||
resynchronise with the sender. The swj (Synchronisation Jump Width) parameter
|
||||
defines by how much the hardware can shorten these segments.
|
||||
.Pp
|
||||
Some hardware can use 3 sample points instead of one, and keep the majority as
|
||||
the final value.
|
||||
.Ss Options
|
||||
.Pp
|
||||
The options are as follows:
|
||||
.Bl -tag -width indent
|
||||
.It Fl a
|
||||
Display the status of all CAN devices present on the system.
|
||||
This flag is mutually exclusive with all other sub-commands.
|
||||
.El
|
||||
.Pp
|
||||
All other operations require that a CAN interface be specified.
|
||||
If a CAN interface is specified with no sub-commands,
|
||||
the status of that interface is displayed.
|
||||
.Pp
|
||||
The following sub-commands are available:
|
||||
.Pp
|
||||
.Bl -tag -width indent
|
||||
.It Cm up
|
||||
Start network operations on the interface. Requires that all timing parameters
|
||||
have been set.
|
||||
.It Cm down
|
||||
Stop network operations on the interface.
|
||||
.It Cm brp Ar value
|
||||
Set the value of the baud rate prescaler.
|
||||
.It Cm prop_seg Ar value
|
||||
set the number of tq for the propagation segment.
|
||||
.It Cm phase_seg1 Ar value
|
||||
set the number of tq for the phase segment 1.
|
||||
.It Cm phase_seg2 Ar value
|
||||
set the number of tq for the phase segment 2.
|
||||
.It Cm sjw Ar value
|
||||
set the number of tq for the Synchronisation Jump Width.
|
||||
.It Cm 3samples
|
||||
enables triple-sampling.
|
||||
.It Cm -3samples
|
||||
disables triple-sampling.
|
||||
.It Cm listenonly
|
||||
enables listenonly mode. In this mode the controller is passive, and
|
||||
doesn't send ACKs on the bus.
|
||||
.It Cm -listenonly
|
||||
disables listenonly mode.
|
||||
.It Cm loopback
|
||||
enables loopback mode. In this mode, the controller doens't expect ACK from
|
||||
the bus.
|
||||
.It Cm -loopback
|
||||
disables loopback mode.
|
||||
.El
|
||||
.Sh EXAMPLES
|
||||
TODO
|
||||
.Sh SEE ALSO
|
||||
.Xr ifconfig.if 5 ,
|
||||
.Xr ifconfig 8 ,
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
utility first appeared in
|
||||
.Nx 8.0 .
|
||||
.Sh AUTHORS
|
||||
This version of the
|
||||
.Nm
|
||||
utility was written by
|
||||
.An Manuel Bouyer .
|
583
sbin/canconfig/canconfig.c
Normal file
583
sbin/canconfig/canconfig.c
Normal file
@ -0,0 +1,583 @@
|
||||
/* $NetBSD: canconfig.c,v 1.2 2017/05/27 21:02:55 bouyer Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright 2001 Wasabi Systems, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Written by Jason R. Thorpe for Wasabi Systems, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed for the NetBSD Project by
|
||||
* Wasabi Systems, Inc.
|
||||
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
|
||||
* or promote products derived from this software without specific prior
|
||||
* written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: canconfig.c,v 1.2 2017/05/27 21:02:55 bouyer Exp $");
|
||||
#endif
|
||||
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <netcan/can.h>
|
||||
#include <netcan/can_link.h>
|
||||
#include <ifaddrs.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
struct command {
|
||||
const char *cmd_keyword;
|
||||
int cmd_argcnt;
|
||||
int cmd_flags;
|
||||
void (*cmd_func)(const struct command *, int, const char *,
|
||||
char **);
|
||||
};
|
||||
|
||||
#define CMD_INVERT 0x01 /* "invert" the sense of the command */
|
||||
|
||||
static void cmd_up(const struct command *, int, const char *, char **);
|
||||
static void cmd_down(const struct command *, int, const char *, char **);
|
||||
static void cmd_brp(const struct command *, int, const char *, char **);
|
||||
static void cmd_prop_seg(const struct command *, int, const char *, char **);
|
||||
static void cmd_phase_seg1(const struct command *, int, const char *, char **);
|
||||
static void cmd_phase_seg2(const struct command *, int, const char *, char **);
|
||||
static void cmd_sjw(const struct command *, int, const char *, char **);
|
||||
static void cmd_3samples(const struct command *, int, const char *, char **);
|
||||
static void cmd_listenonly(const struct command *, int, const char *, char **);
|
||||
static void cmd_loopback(const struct command *, int, const char *, char **);
|
||||
|
||||
static const struct command command_table[] = {
|
||||
{ "up", 0, 0, cmd_up },
|
||||
{ "down", 0, 0, cmd_down },
|
||||
|
||||
{ "brp", 1, 0, cmd_brp },
|
||||
{ "prop_seg", 1, 0, cmd_prop_seg },
|
||||
{ "phase_seg1", 1, 0, cmd_phase_seg1 },
|
||||
{ "phase_seg2", 1, 0, cmd_phase_seg2 },
|
||||
{ "sjw", 1, 0, cmd_sjw },
|
||||
|
||||
{ "3samples", 0, 0, cmd_3samples },
|
||||
{ "-3samples", 0, CMD_INVERT, cmd_3samples },
|
||||
|
||||
{ "listenonly", 0, 0, cmd_listenonly },
|
||||
{ "-listenonly", 0, CMD_INVERT, cmd_listenonly },
|
||||
|
||||
{ "loopback", 0, 0, cmd_loopback },
|
||||
{ "-loopback", 0, CMD_INVERT, cmd_loopback },
|
||||
|
||||
{ NULL, 0, 0, NULL },
|
||||
};
|
||||
|
||||
static void printall(int);
|
||||
static void status(int, const char *);
|
||||
static void show_timings(int, const char *, const char *);
|
||||
static int is_can(int s, const char *);
|
||||
static int get_val(const char *, u_long *);
|
||||
#define do_cmd(a,b,c,d,e,f) do_cmd2((a),(b),(c),(d),(e),NULL,(f))
|
||||
static int do_cmd2(int, const char *, u_long, void *, size_t, size_t *, int);
|
||||
__dead static void usage(void);
|
||||
|
||||
static int aflag;
|
||||
static struct ifreq g_ifr;
|
||||
static int g_ifr_updated = 0;
|
||||
|
||||
struct can_link_timecaps g_cltc;
|
||||
struct can_link_timings g_clt;
|
||||
static int g_clt_updated = 0;
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
const struct command *cmd;
|
||||
char *canifname;
|
||||
int sock, ch;
|
||||
|
||||
if (argc < 2)
|
||||
usage();
|
||||
|
||||
while ((ch = getopt(argc, argv, "a")) != -1) {
|
||||
switch (ch) {
|
||||
case 'a':
|
||||
aflag = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (aflag) {
|
||||
if (argc != 0)
|
||||
usage();
|
||||
sock = socket(AF_CAN, SOCK_RAW, CAN_RAW);
|
||||
if (sock < 0)
|
||||
err(1, "socket");
|
||||
|
||||
printall(sock);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (argc == 0)
|
||||
usage();
|
||||
|
||||
sock = socket(AF_CAN, SOCK_RAW, CAN_RAW);
|
||||
if (sock < 0)
|
||||
err(1, "socket");
|
||||
|
||||
canifname = argv[0];
|
||||
|
||||
if (is_can(sock, canifname) == 0)
|
||||
errx(1, "%s is not a can interface", canifname);
|
||||
|
||||
/* Get a copy of the interface flags. */
|
||||
strlcpy(g_ifr.ifr_name, canifname, sizeof(g_ifr.ifr_name));
|
||||
if (ioctl(sock, SIOCGIFFLAGS, &g_ifr) < 0)
|
||||
err(1, "unable to get interface flags");
|
||||
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
if (argc == 0) {
|
||||
status(sock, canifname);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (do_cmd(sock, canifname, CANGLINKTIMECAP, &g_cltc, sizeof(g_cltc), 0)
|
||||
< 0)
|
||||
err(1, "unable to get can link timecaps");
|
||||
|
||||
if (do_cmd(sock, canifname, CANGLINKTIMINGS, &g_clt, sizeof(g_clt), 0) < 0)
|
||||
err(1, "unable to get can link timings");
|
||||
|
||||
while (argc != 0) {
|
||||
for (cmd = command_table; cmd->cmd_keyword != NULL; cmd++) {
|
||||
if (strcmp(cmd->cmd_keyword, argv[0]) == 0)
|
||||
break;
|
||||
}
|
||||
if (cmd->cmd_keyword == NULL)
|
||||
errx(1, "unknown command: %s", argv[0]);
|
||||
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
if (argc < cmd->cmd_argcnt)
|
||||
errx(1, "command %s requires %d argument%s",
|
||||
cmd->cmd_keyword, cmd->cmd_argcnt,
|
||||
cmd->cmd_argcnt == 1 ? "" : "s");
|
||||
|
||||
(*cmd->cmd_func)(cmd, sock, canifname, argv);
|
||||
|
||||
argc -= cmd->cmd_argcnt;
|
||||
argv += cmd->cmd_argcnt;
|
||||
}
|
||||
|
||||
/* If the timings changed, update them. */
|
||||
if (g_clt_updated &&
|
||||
do_cmd(sock, canifname, CANSLINKTIMINGS, &g_clt, sizeof(g_clt), 1) < 0)
|
||||
err(1, "unable to set can link timings");
|
||||
|
||||
/* If the flags changed, update them. */
|
||||
if (g_ifr_updated && ioctl(sock, SIOCSIFFLAGS, &g_ifr) < 0)
|
||||
err(1, "unable to set interface flags");
|
||||
|
||||
exit (0);
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
static const char *usage_strings[] = {
|
||||
"-a",
|
||||
"<canif>",
|
||||
"<canif> up|down",
|
||||
"<canif> brp <value>",
|
||||
"<canif> prop_seg <value>",
|
||||
"<canif> phase_seg1 <value>",
|
||||
"<canif> phase_seg2 <value>",
|
||||
"<canif> sjw <value>",
|
||||
"<canif> 3samples | -3samples",
|
||||
"<canif> listenonly | -listenonly",
|
||||
"<canif> loopback | -loopback",
|
||||
NULL,
|
||||
};
|
||||
extern const char *__progname;
|
||||
int i;
|
||||
|
||||
for (i = 0; usage_strings[i] != NULL; i++)
|
||||
fprintf(stderr, "%s %s %s\n",
|
||||
i == 0 ? "usage:" : " ",
|
||||
__progname, usage_strings[i]);
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static int
|
||||
is_can(int s, const char *canif)
|
||||
{
|
||||
uint32_t linkmode;
|
||||
|
||||
if (do_cmd(s, canif, CANGLINKMODE, &linkmode, sizeof(linkmode), 0) < 0)
|
||||
return (0);
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
static void
|
||||
printb(const char *s, u_int v, const char *bits)
|
||||
{
|
||||
int i, any = 0;
|
||||
char c;
|
||||
|
||||
if (bits && *bits == 8)
|
||||
printf("%s=%o", s, v);
|
||||
else
|
||||
printf("%s=%x", s, v);
|
||||
if (bits) {
|
||||
bits++;
|
||||
putchar('<');
|
||||
while ((i = *bits++) != 0) {
|
||||
if (v & (1 << (i-1))) {
|
||||
if (any)
|
||||
putchar(',');
|
||||
any = 1;
|
||||
for (; (c = *bits) > 32; bits++)
|
||||
putchar(c);
|
||||
} else
|
||||
for (; *bits > 32; bits++)
|
||||
;
|
||||
}
|
||||
putchar('>');
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
printall(int sock)
|
||||
{
|
||||
struct ifaddrs *ifap, *ifa;
|
||||
char *p;
|
||||
|
||||
if (getifaddrs(&ifap) != 0)
|
||||
err(1, "getifaddrs");
|
||||
p = NULL;
|
||||
for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
|
||||
if (is_can(sock, ifa->ifa_name) == 0)
|
||||
continue;
|
||||
if (p != NULL && strcmp(p, ifa->ifa_name) == 0)
|
||||
continue;
|
||||
p = ifa->ifa_name;
|
||||
status(sock, ifa->ifa_name);
|
||||
}
|
||||
|
||||
freeifaddrs(ifap);
|
||||
}
|
||||
|
||||
static void
|
||||
status(int sock, const char *canifname)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
|
||||
strlcpy(ifr.ifr_name, canifname, sizeof(ifr.ifr_name));
|
||||
if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0)
|
||||
err(1, "unable to get flags");
|
||||
|
||||
printf("%s: ", canifname);
|
||||
printb("flags", ifr.ifr_flags, IFFBITS);
|
||||
printf("\n");
|
||||
|
||||
show_timings(sock, canifname, "\t");
|
||||
|
||||
}
|
||||
|
||||
static int
|
||||
valid_timings(struct can_link_timecaps *cltc, struct can_link_timings *clt)
|
||||
{
|
||||
if (clt->clt_brp < cltc->cltc_brp_min ||
|
||||
clt->clt_brp > cltc->cltc_brp_max)
|
||||
return 0;
|
||||
|
||||
if (clt->clt_prop < cltc->cltc_prop_min ||
|
||||
clt->clt_prop > cltc->cltc_prop_max)
|
||||
return 0;
|
||||
|
||||
if (clt->clt_ps1 < cltc->cltc_ps1_min ||
|
||||
clt->clt_ps1 > cltc->cltc_ps1_max)
|
||||
return 0;
|
||||
|
||||
if (clt->clt_ps2 < cltc->cltc_ps2_min ||
|
||||
clt->clt_ps2 > cltc->cltc_ps2_max)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
show_timings(int sock, const char *canifname, const char *prefix)
|
||||
{
|
||||
struct can_link_timecaps cltc;
|
||||
struct can_link_timings clt;
|
||||
u_int32_t linkmode;
|
||||
char hbuf[8];
|
||||
|
||||
if (do_cmd(sock, canifname, CANGLINKTIMECAP, &cltc, sizeof(cltc), 0)
|
||||
< 0)
|
||||
err(1, "unable to get can link timecaps");
|
||||
|
||||
if (do_cmd(sock, canifname, CANGLINKTIMINGS, &clt, sizeof(clt), 0) < 0)
|
||||
err(1, "unable to get can link timings");
|
||||
|
||||
if (do_cmd(sock, canifname, CANGLINKMODE, &linkmode, sizeof(linkmode),
|
||||
0) < 0)
|
||||
err(1, "unable to get can link mode");
|
||||
|
||||
humanize_number(hbuf, sizeof(hbuf), cltc.cltc_clock_freq, "Hz",
|
||||
HN_AUTOSCALE, HN_NOSPACE | HN_DIVISOR_1000);
|
||||
|
||||
printf("%stiming caps:\n", prefix);
|
||||
printf("%s clock %s, brp [%d..%d]/%d, prop_seg [%d..%d]\n",
|
||||
prefix, hbuf,
|
||||
cltc.cltc_brp_min, cltc.cltc_brp_max, cltc.cltc_brp_inc,
|
||||
cltc.cltc_prop_min, cltc.cltc_prop_max);
|
||||
printf("%s phase_seg1 [%d..%d], phase_seg2 [%d..%d], sjw [0..%d]\n",
|
||||
prefix,
|
||||
cltc.cltc_ps1_min, cltc.cltc_ps1_max,
|
||||
cltc.cltc_ps2_min, cltc.cltc_ps2_max,
|
||||
cltc.cltc_sjw_max);
|
||||
printf("%s ", prefix);
|
||||
printb("capabilities", cltc.cltc_linkmode_caps, CAN_IFFBITS);
|
||||
printf("\n");
|
||||
printf("%soperational timings:", prefix);
|
||||
if (valid_timings(&cltc, &clt)) {
|
||||
uint32_t tq, ntq, bps;
|
||||
tq = ((uint64_t)clt.clt_brp * (uint64_t)1000000000) /
|
||||
cltc.cltc_clock_freq;
|
||||
ntq = 1 + clt.clt_prop + clt.clt_ps1 + clt.clt_ps2;
|
||||
printf(" %d time quanta of %dns",
|
||||
1 + clt.clt_prop + clt.clt_ps1 + clt.clt_ps2, tq);
|
||||
bps = 1000000000 / (tq * ntq);
|
||||
humanize_number(hbuf, sizeof(hbuf), bps, "bps",
|
||||
HN_AUTOSCALE, HN_NOSPACE | HN_DIVISOR_1000);
|
||||
printf(", %s", hbuf);
|
||||
};
|
||||
printf("\n");
|
||||
|
||||
printf("%s brp %d, prop_seg %d, phase_seg1 %d, phase_seg2 %d, sjw %d\n",
|
||||
prefix,
|
||||
clt.clt_brp, clt.clt_prop, clt.clt_ps1, clt.clt_ps2, clt.clt_sjw);
|
||||
printf("%s ", prefix);
|
||||
printb("mode", linkmode, CAN_IFFBITS);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static int
|
||||
get_val(const char *cp, u_long *valp)
|
||||
{
|
||||
char *endptr;
|
||||
u_long val;
|
||||
|
||||
errno = 0;
|
||||
val = strtoul(cp, &endptr, 0);
|
||||
if (cp[0] == '\0' || endptr[0] != '\0' || errno == ERANGE)
|
||||
return (-1);
|
||||
|
||||
*valp = val;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
do_cmd2(int sock, const char *canifname, u_long op, void *arg, size_t argsize,
|
||||
size_t *outsizep, int set)
|
||||
{
|
||||
struct ifdrv ifd;
|
||||
int error;
|
||||
|
||||
memset(&ifd, 0, sizeof(ifd));
|
||||
|
||||
strlcpy(ifd.ifd_name, canifname, sizeof(ifd.ifd_name));
|
||||
ifd.ifd_cmd = op;
|
||||
ifd.ifd_len = argsize;
|
||||
ifd.ifd_data = arg;
|
||||
|
||||
error = ioctl(sock, set ? SIOCSDRVSPEC : SIOCGDRVSPEC, &ifd);
|
||||
|
||||
if (outsizep)
|
||||
*outsizep = ifd.ifd_len;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static void
|
||||
do_ifflag(int sock, const char *canifname, int flag, int set)
|
||||
{
|
||||
|
||||
if (set)
|
||||
g_ifr.ifr_flags |= flag;
|
||||
else
|
||||
g_ifr.ifr_flags &= ~flag;
|
||||
|
||||
g_ifr_updated = 1;
|
||||
}
|
||||
|
||||
static int
|
||||
do_canflag(int sock, const char *canifname, uint32_t flag, int set)
|
||||
{
|
||||
int cmd;
|
||||
if (set)
|
||||
cmd = CANSLINKMODE;
|
||||
else
|
||||
cmd = CANCLINKMODE;
|
||||
return do_cmd(sock, canifname, cmd, &flag, sizeof(flag), 1);
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_up(const struct command *cmd, int sock, const char *canifname,
|
||||
char **argv)
|
||||
{
|
||||
|
||||
do_ifflag(sock, canifname, IFF_UP, 1);
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_down(const struct command *cmd, int sock, const char *canifname,
|
||||
char **argv)
|
||||
{
|
||||
|
||||
do_ifflag(sock, canifname, IFF_UP, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_brp(const struct command *cmd, int sock, const char *bridge,
|
||||
char **argv)
|
||||
{
|
||||
u_long val;
|
||||
|
||||
if (get_val(argv[0], &val) < 0 || (val & ~0xffffffff) != 0)
|
||||
errx(1, "%s: invalid value: %s", cmd->cmd_keyword, argv[0]);
|
||||
if (val < g_cltc.cltc_brp_min || val > g_cltc.cltc_brp_max)
|
||||
errx(1, "%s: out of range value: %s", cmd->cmd_keyword, argv[0]);
|
||||
g_clt.clt_brp = val;
|
||||
g_clt_updated=1;
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_prop_seg(const struct command *cmd, int sock, const char *bridge,
|
||||
char **argv)
|
||||
{
|
||||
u_long val;
|
||||
|
||||
if (get_val(argv[0], &val) < 0 || (val & ~0xffffffff) != 0)
|
||||
errx(1, "%s: invalid value: %s", cmd->cmd_keyword, argv[0]);
|
||||
if (val < g_cltc.cltc_prop_min || val > g_cltc.cltc_prop_max)
|
||||
errx(1, "%s: out of range value: %s", cmd->cmd_keyword, argv[0]);
|
||||
g_clt.clt_prop = val;
|
||||
g_clt_updated=1;
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_phase_seg1(const struct command *cmd, int sock, const char *bridge,
|
||||
char **argv)
|
||||
{
|
||||
u_long val;
|
||||
|
||||
if (get_val(argv[0], &val) < 0 || (val & ~0xffffffff) != 0)
|
||||
errx(1, "%s: invalid value: %s", cmd->cmd_keyword, argv[0]);
|
||||
if (val < g_cltc.cltc_ps1_min || val > g_cltc.cltc_ps1_max)
|
||||
errx(1, "%s: out of range value: %s", cmd->cmd_keyword, argv[0]);
|
||||
g_clt.clt_ps1 = val;
|
||||
g_clt_updated=1;
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_phase_seg2(const struct command *cmd, int sock, const char *bridge,
|
||||
char **argv)
|
||||
{
|
||||
u_long val;
|
||||
|
||||
if (get_val(argv[0], &val) < 0 || (val & ~0xffffffff) != 0)
|
||||
errx(1, "%s: invalid value: %s", cmd->cmd_keyword, argv[0]);
|
||||
if (val < g_cltc.cltc_ps2_min || val > g_cltc.cltc_ps2_max)
|
||||
errx(1, "%s: out of range value: %s", cmd->cmd_keyword, argv[0]);
|
||||
g_clt.clt_ps2 = val;
|
||||
g_clt_updated=1;
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_sjw(const struct command *cmd, int sock, const char *bridge,
|
||||
char **argv)
|
||||
{
|
||||
u_long val;
|
||||
|
||||
if (get_val(argv[0], &val) < 0 || (val & ~0xffffffff) != 0)
|
||||
errx(1, "%s: invalid value: %s", cmd->cmd_keyword, argv[0]);
|
||||
if (val > g_cltc.cltc_sjw_max)
|
||||
errx(1, "%s: out of range value: %s", cmd->cmd_keyword, argv[0]);
|
||||
g_clt.clt_sjw = val;
|
||||
g_clt_updated=1;
|
||||
}
|
||||
static void
|
||||
cmd_3samples(const struct command *cmd, int sock, const char *canifname,
|
||||
char **argv)
|
||||
{
|
||||
if (do_canflag(sock, canifname, CAN_LINKMODE_3SAMPLES,
|
||||
(cmd->cmd_flags & CMD_INVERT) ? 0 : 1) < 0)
|
||||
err(1, "%s", cmd->cmd_keyword);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_listenonly(const struct command *cmd, int sock, const char *canifname,
|
||||
char **argv)
|
||||
{
|
||||
if (do_canflag(sock, canifname, CAN_LINKMODE_LISTENONLY,
|
||||
(cmd->cmd_flags & CMD_INVERT) ? 0 : 1) < 0)
|
||||
err(1, "%s", cmd->cmd_keyword);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_loopback(const struct command *cmd, int sock, const char *canifname,
|
||||
char **argv)
|
||||
{
|
||||
if (do_canflag(sock, canifname, CAN_LINKMODE_LOOPBACK,
|
||||
(cmd->cmd_flags & CMD_INVERT) ? 0 : 1) < 0)
|
||||
err(1, "%s", cmd->cmd_keyword);
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
# $NetBSD: Makefile,v 1.636 2017/05/16 23:21:53 jdolecek Exp $
|
||||
# $NetBSD: Makefile,v 1.637 2017/05/27 21:02:55 bouyer Exp $
|
||||
# @(#)Makefile 8.1 (Berkeley) 6/18/93
|
||||
|
||||
MAN= aac.4 ac97.4 acardide.4 aceride.4 acphy.4 \
|
||||
@ -16,7 +16,7 @@ MAN= aac.4 ac97.4 acardide.4 aceride.4 acphy.4 \
|
||||
brgphy.4 bridge.4 bthidev.4 bthub.4 btkbd.4 \
|
||||
btmagic.4 btms.4 btsco.4 btuart.4 \
|
||||
bwi.4 \
|
||||
cac.4 cardbus.4 carp.4 cas.4 ccd.4 cd.4 \
|
||||
cac.4 can.4 canloop.4 cardbus.4 carp.4 cas.4 ccd.4 cd.4 \
|
||||
cec.4 cgd.4 cfb.4 ch.4 chipsfb.4 ciphy.4 ciss.4 clcs.4 clct.4 \
|
||||
clockctl.4 cmdide.4 cmpci.4 cms.4 cnw.4 \
|
||||
com.4 coram.4 crypto.4 cs80bus.4 cuda.4 cypide.4 cxdtv.4 \
|
||||
|
96
share/man/man4/can.4
Normal file
96
share/man/man4/can.4
Normal file
@ -0,0 +1,96 @@
|
||||
.\" $NetBSD: can.4,v 1.2 2017/05/27 21:02:55 bouyer Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2017 Manuel Bouyer.
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd May 18, 2017
|
||||
.Dt CAN 4
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm CAN
|
||||
.Nd CAN Protocol
|
||||
.Sh SYNOPSIS
|
||||
.In sys/socket.h
|
||||
.In netcan/can.h
|
||||
.Ft int
|
||||
.Fn socket AF_CAN SOCK_RAW CAN_RAW
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
is the network layer protocol used on top of CAN bus networks. At this time
|
||||
only the SOCK_RAW socket type is supported.
|
||||
This protocol layer is intended to be compatible with the linux SocketCAN implementation.
|
||||
.Ss ADDRESSING
|
||||
A CAN frame consists of a 11 bits (standard frame format) or 29 bits
|
||||
(extended frame format) identifier, followed by up to 8 data bytes.
|
||||
The interpretation of the identifier is application-dependant, the CAN
|
||||
standard itself doesn't define an addressing.
|
||||
.Pp
|
||||
The
|
||||
.Nm
|
||||
layer uses a 32bits identifier. The 3 upper bits are used as control flags.
|
||||
The extended frame format is selected by setting the CAN_EFF_FLAG control bit.
|
||||
.Pp
|
||||
The socket address is defined as
|
||||
.Bd -literal
|
||||
struct sockaddr_can {
|
||||
u_int8_t can_len;
|
||||
sa_family_t can_family;
|
||||
int can_ifindex;
|
||||
union {
|
||||
/* transport protocol class address information */
|
||||
struct { canid_t rx_id, tx_id; } tp;
|
||||
/* reserved for future CAN protocols address information */
|
||||
} can_addr;
|
||||
};
|
||||
.Ed
|
||||
For CAN raw sockets, the 32bits identifier is part of the message data.
|
||||
The can_addr field of the sockaddr structure is not used.
|
||||
.Ss MESSAGE
|
||||
Raw CAN sockets use fixed-length messages defined as follow:
|
||||
.Bd -literal
|
||||
struct can_frame {
|
||||
canid_t can_id; /* ID + EFF/RTR/ERR flags */
|
||||
uint8_t can_dlc; /* frame payload length in byte (0 .. CAN_MAX_DLEN) */
|
||||
uint8_t __pad;
|
||||
uint8_t __res0;
|
||||
uint8_t __res1;
|
||||
uint8_t data[CAN_MAX_DLEN] __aligned(8);
|
||||
};
|
||||
.Ed
|
||||
The lower 11 bits (for standard frames) or 29 bits (for exended frames) are
|
||||
used as the on-wire identifier. The CAN_EFF_FLAG bit is set in can_id for
|
||||
extended frames. The CAN_RTR_FLAG bit is set in can_id for remote transmission
|
||||
request frames.
|
||||
.Sh SEE ALSO
|
||||
.Xr socket 2 ,
|
||||
.Xr netintro 4 ,
|
||||
.Xr canloop 4 ,
|
||||
.Xr canconfig 8 ,
|
||||
.Pa /usr/include/netcan/can.h
|
||||
.Pp
|
||||
.Lk https://en.wikipedia.org/wiki/SocketCAN "SocketCAN - Wikipedia"
|
||||
.Lk https://www.kernel.org/doc/Documentation/networking/can.txt "Readme file for the Controller Area Network Protocol Family"
|
||||
.Sh BUGS
|
||||
CANFD and error frames are not implemented.
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
protocol appeared in
|
||||
.Nx 8.0 .
|
53
share/man/man4/canloop.4
Normal file
53
share/man/man4/canloop.4
Normal file
@ -0,0 +1,53 @@
|
||||
.\" $NetBSD: canloop.4,v 1.2 2017/05/27 21:02:55 bouyer Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2017 Manuel Bouyer.
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd May 18, 2017
|
||||
.Dt CANLOOP 4
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm canloop
|
||||
.Nd software loopback CAN network interface
|
||||
.Sh SYNOPSIS
|
||||
.Cd "pseudo-device canloop"
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm canloop
|
||||
pseudo interface is a loopback interface for the CAN layer. It can be used
|
||||
as destination by a CAN application, when no CAN hardware is available.
|
||||
Other sockets bound to the same
|
||||
.Nm canloop
|
||||
interface (or not bound to any interface) will receive the frames.
|
||||
.Pp
|
||||
.Nm canloop
|
||||
interfaces can be created by using the
|
||||
.Xr ifconfig 8
|
||||
.Cm create
|
||||
command.
|
||||
.Sh SEE ALSO
|
||||
.Xr can 4 ,
|
||||
.Xr intro 4 ,
|
||||
.Xr ifconfig 8
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
device appeared in
|
||||
.Nx 8.0 .
|
@ -1,9 +1,9 @@
|
||||
# $NetBSD: Makefile,v 1.79 2013/03/01 18:25:27 joerg Exp $
|
||||
# $NetBSD: Makefile,v 1.80 2017/05/27 21:02:55 bouyer Exp $
|
||||
|
||||
.include <bsd.own.mk>
|
||||
|
||||
SUBDIR= altq arch compat dev fs miscfs \
|
||||
net net80211 netatalk netbt netipsec netinet netinet6 \
|
||||
net net80211 netatalk netbt netcan netipsec netinet netinet6 \
|
||||
netisdn netkey netmpls netnatm netsmb \
|
||||
nfs opencrypto sys ufs uvm
|
||||
|
||||
|
627
sys/arch/arm/allwinner/awin_can.c
Normal file
627
sys/arch/arm/allwinner/awin_can.c
Normal file
@ -0,0 +1,627 @@
|
||||
/* $NetBSD: awin_can.c,v 1.2 2017/05/27 21:02:55 bouyer Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2017 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Manuel Bouyer.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#include "locators.h"
|
||||
#include "opt_can.h"
|
||||
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
__KERNEL_RCSID(1, "$NetBSD: awin_can.c,v 1.2 2017/05/27 21:02:55 bouyer Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/device.h>
|
||||
#include <sys/intr.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/rndsource.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/systm.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/if_types.h>
|
||||
#include <net/bpf.h>
|
||||
|
||||
#ifdef CAN
|
||||
#include <netcan/can.h>
|
||||
#include <netcan/can_var.h>
|
||||
#endif
|
||||
|
||||
#include <arm/allwinner/awin_reg.h>
|
||||
#include <arm/allwinner/awin_var.h>
|
||||
|
||||
/* shortcut for all error interrupts */
|
||||
#define AWIN_CAN_INT_ALLERRS (\
|
||||
AWIN_CAN_INT_BERR | \
|
||||
AWIN_CAN_INT_ARB_LOST | \
|
||||
AWIN_CAN_INT_ERR_PASSIVE | \
|
||||
AWIN_CAN_INT_DATA_OR | \
|
||||
AWIN_CAN_INT_ERR \
|
||||
)
|
||||
|
||||
struct awin_can_softc {
|
||||
struct canif_softc sc_cansc;
|
||||
bus_space_tag_t sc_bst;
|
||||
bus_space_handle_t sc_bsh;
|
||||
kmutex_t sc_intr_lock;
|
||||
void *sc_ih;
|
||||
struct ifnet *sc_ifp;
|
||||
krndsource_t sc_rnd_source; /* random source */
|
||||
struct mbuf *sc_m_transmit; /* mbuf being transmitted */
|
||||
};
|
||||
#define sc_dev sc_cansc.csc_dev
|
||||
#define sc_timecaps sc_cansc.csc_timecaps
|
||||
#define sc_timings sc_cansc.csc_timings
|
||||
#define sc_linkmodes sc_cansc.csc_linkmodes
|
||||
|
||||
static int awin_can_match(device_t, cfdata_t, void *);
|
||||
static void awin_can_attach(device_t, device_t, void *);
|
||||
|
||||
static int awin_can_intr(void *);
|
||||
|
||||
static void awin_can_ifstart(struct ifnet *);
|
||||
static int awin_can_ifioctl(struct ifnet *, u_long, void *);
|
||||
static void awin_can_ifwatchdog(struct ifnet *);
|
||||
|
||||
static void awin_can_enter_reset(struct awin_can_softc *);
|
||||
static void awin_can_exit_reset(struct awin_can_softc *);
|
||||
|
||||
CFATTACH_DECL_NEW(awin_can, sizeof(struct awin_can_softc),
|
||||
awin_can_match, awin_can_attach, NULL, NULL);
|
||||
|
||||
static const struct awin_gpio_pinset awin_can_pinsets[2] = {
|
||||
[0] = { 'A', AWIN_PIO_PA_CAN_FUNC, AWIN_PIO_PA_CAN_PINS },
|
||||
[1] = { 'H', AWIN_PIO_PH_CAN_FUNC, AWIN_PIO_PH_CAN_PINS },
|
||||
};
|
||||
|
||||
static inline uint32_t
|
||||
awin_can_read(struct awin_can_softc *sc, bus_size_t o)
|
||||
{
|
||||
return bus_space_read_4(sc->sc_bst, sc->sc_bsh, o);
|
||||
}
|
||||
|
||||
static inline void
|
||||
awin_can_write(struct awin_can_softc *sc, bus_size_t o, uint32_t v)
|
||||
{
|
||||
return bus_space_write_4(sc->sc_bst, sc->sc_bsh, o, v);
|
||||
}
|
||||
|
||||
static int
|
||||
awin_can_match(device_t parent, cfdata_t cf, void *aux)
|
||||
{
|
||||
struct awinio_attach_args * const aio __diagused = aux;
|
||||
const struct awin_locators * const loc __diagused = &aio->aio_loc;
|
||||
const struct awin_gpio_pinset * const pinset =
|
||||
&awin_can_pinsets[cf->cf_flags & 1];
|
||||
|
||||
KASSERT(!strcmp(cf->cf_name, loc->loc_name));
|
||||
KASSERT(cf->cf_loc[AWINIOCF_PORT] == AWINIOCF_PORT_DEFAULT
|
||||
|| cf->cf_loc[AWINIOCF_PORT] == loc->loc_port);
|
||||
|
||||
if (!awin_gpio_pinset_available(pinset)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
awin_can_attach(device_t parent, device_t self, void *aux)
|
||||
{
|
||||
cfdata_t cf = device_cfdata(self);
|
||||
struct awin_can_softc * const sc = device_private(self);
|
||||
struct awinio_attach_args * const aio = aux;
|
||||
const struct awin_locators * const loc = &aio->aio_loc;
|
||||
const struct awin_gpio_pinset * const pinset =
|
||||
&awin_can_pinsets[cf->cf_flags & 1];
|
||||
struct ifnet *ifp;
|
||||
|
||||
sc->sc_dev = self;
|
||||
|
||||
awin_gpio_pinset_acquire(pinset);
|
||||
awin_reg_set_clear(aio->aio_core_bst, aio->aio_ccm_bsh,
|
||||
AWIN_APB1_GATING_REG, AWIN_APB_GATING1_CAN, 0);
|
||||
|
||||
mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_NET);
|
||||
|
||||
sc->sc_bst = aio->aio_core_bst;
|
||||
bus_space_subregion(sc->sc_bst, aio->aio_core_bsh,
|
||||
loc->loc_offset, loc->loc_size, &sc->sc_bsh);
|
||||
|
||||
sc->sc_timecaps.cltc_prop_min = 0;
|
||||
sc->sc_timecaps.cltc_prop_max = 0;
|
||||
sc->sc_timecaps.cltc_ps1_min = 1;
|
||||
sc->sc_timecaps.cltc_ps1_max = 16;
|
||||
sc->sc_timecaps.cltc_ps2_min = 1;
|
||||
sc->sc_timecaps.cltc_ps2_max = 8;
|
||||
sc->sc_timecaps.cltc_sjw_max = 4;
|
||||
sc->sc_timecaps.cltc_brp_min = 1;
|
||||
sc->sc_timecaps.cltc_brp_max = 64;
|
||||
sc->sc_timecaps.cltc_brp_inc = 1;
|
||||
sc->sc_timecaps.cltc_clock_freq = AWIN_REF_FREQ;
|
||||
sc->sc_timecaps.cltc_linkmode_caps =
|
||||
CAN_LINKMODE_3SAMPLES | CAN_LINKMODE_LISTENONLY |
|
||||
CAN_LINKMODE_LOOPBACK;
|
||||
can_ifinit_timings(&sc->sc_cansc);
|
||||
sc->sc_timings.clt_prop = 0;
|
||||
sc->sc_timings.clt_sjw = 1;
|
||||
|
||||
aprint_naive("\n");
|
||||
aprint_normal(": CAN bus controller\n");
|
||||
|
||||
awin_can_enter_reset(sc);
|
||||
/*
|
||||
* Disable and then clear all interrupts
|
||||
*/
|
||||
awin_can_write(sc, AWIN_CAN_INTE_REG, 0);
|
||||
awin_can_write(sc, AWIN_CAN_INT_REG,
|
||||
awin_can_read(sc, AWIN_CAN_INT_REG));
|
||||
|
||||
sc->sc_ih = intr_establish(loc->loc_intr, IPL_NET, IST_LEVEL,
|
||||
awin_can_intr, sc);
|
||||
if (sc->sc_ih == NULL) {
|
||||
aprint_error_dev(self, "failed to establish interrupt %d\n",
|
||||
loc->loc_intr);
|
||||
return;
|
||||
}
|
||||
aprint_normal_dev(self, "interrupting on irq %d\n", loc->loc_intr);
|
||||
|
||||
ifp = if_alloc(IFT_OTHER);
|
||||
sc->sc_ifp = ifp;
|
||||
strlcpy(ifp->if_xname, device_xname(self), IFNAMSIZ);
|
||||
ifp->if_softc = sc;
|
||||
ifp->if_capabilities = 0;
|
||||
ifp->if_flags = 0;
|
||||
ifp->if_start = awin_can_ifstart;
|
||||
ifp->if_ioctl = awin_can_ifioctl;
|
||||
ifp->if_watchdog = awin_can_ifwatchdog;
|
||||
|
||||
/*
|
||||
* Attach the interface.
|
||||
*/
|
||||
can_ifattach(ifp);
|
||||
if_deferred_start_init(ifp, NULL);
|
||||
bpf_mtap_softint_init(ifp);
|
||||
rnd_attach_source(&sc->sc_rnd_source, device_xname(self),
|
||||
RND_TYPE_NET, RND_FLAG_DEFAULT);
|
||||
#ifdef MBUFTRACE
|
||||
ifp->if_mowner = malloc(sizeof(struct mowner), M_DEVBUF,
|
||||
M_WAITOK | M_ZERO);
|
||||
strlcpy(ifp->if_mowner->mo_name, ifp->if_xname,
|
||||
sizeof(ifp->if_mowner->mo_name));
|
||||
MOWNER_ATTACH(ifp->if_mowner);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
awin_can_rx_intr(struct awin_can_softc *sc)
|
||||
{
|
||||
uint32_t reg0v;
|
||||
struct mbuf *m;
|
||||
struct ifnet *ifp = sc->sc_ifp;
|
||||
struct can_frame *cf;
|
||||
int dlc;
|
||||
int regd, i;
|
||||
|
||||
KASSERT(mutex_owned(&sc->sc_intr_lock));
|
||||
reg0v = awin_can_read(sc, AWIN_CAN_TXBUF0_REG);
|
||||
dlc = reg0v & AWIN_CAN_TXBUF0_DL;
|
||||
|
||||
if (dlc > CAN_MAX_DLC) {
|
||||
ifp->if_ierrors++;
|
||||
return;
|
||||
}
|
||||
|
||||
m = m_gethdr(M_NOWAIT, MT_HEADER);
|
||||
if (m == NULL) {
|
||||
ifp->if_ierrors++;
|
||||
return;
|
||||
}
|
||||
cf = mtod(m, struct can_frame *);
|
||||
memset(cf, 0, sizeof(struct can_frame));
|
||||
|
||||
cf->can_dlc = dlc;
|
||||
|
||||
if (reg0v & AWIN_CAN_TXBUF0_EFF) {
|
||||
cf->can_id =
|
||||
(awin_can_read(sc, AWIN_CAN_TXBUF1_REG) << 21) |
|
||||
(awin_can_read(sc, AWIN_CAN_TXBUF2_REG) << 13) |
|
||||
(awin_can_read(sc, AWIN_CAN_TXBUF3_REG) << 5) |
|
||||
((awin_can_read(sc, AWIN_CAN_TXBUF4_REG) >> 3) & 0x1f);
|
||||
cf->can_id |= CAN_EFF_FLAG;
|
||||
regd = AWIN_CAN_TXBUF5_REG;
|
||||
} else {
|
||||
cf->can_id =
|
||||
(awin_can_read(sc, AWIN_CAN_TXBUF1_REG) << 3) |
|
||||
((awin_can_read(sc, AWIN_CAN_TXBUF2_REG) << 5) & 0x7);
|
||||
regd = AWIN_CAN_TXBUF3_REG;
|
||||
}
|
||||
if (reg0v & AWIN_CAN_TXBUF0_RTR) {
|
||||
cf->can_id |= CAN_RTR_FLAG;
|
||||
} else {
|
||||
for (i = 0; i < cf->can_dlc; i++) {
|
||||
cf->data[i] = awin_can_read(sc, regd + i * 4);
|
||||
}
|
||||
}
|
||||
awin_can_write(sc, AWIN_CAN_CMD_REG, AWIN_CAN_CMD_REL_RX_BUF);
|
||||
m->m_len = m->m_pkthdr.len = CAN_MTU;
|
||||
ifp->if_ipackets++;
|
||||
ifp->if_ibytes += m->m_len;
|
||||
m_set_rcvif(m, ifp);
|
||||
can_bpf_mtap(ifp, m, 1);
|
||||
can_input(ifp, m);
|
||||
}
|
||||
|
||||
static void
|
||||
awin_can_tx_intr(struct awin_can_softc *sc)
|
||||
{
|
||||
struct ifnet * const ifp = sc->sc_ifp;
|
||||
struct mbuf *m;
|
||||
|
||||
KASSERT(mutex_owned(&sc->sc_intr_lock));
|
||||
if ((m = sc->sc_m_transmit) != NULL) {
|
||||
ifp->if_obytes += m->m_len;
|
||||
ifp->if_opackets++;
|
||||
can_mbuf_tag_clean(m);
|
||||
m_set_rcvif(m, ifp);
|
||||
can_input(ifp, m); /* loopback */
|
||||
sc->sc_m_transmit = NULL;
|
||||
ifp->if_timer = 0;
|
||||
}
|
||||
ifp->if_flags &= ~IFF_OACTIVE;
|
||||
if_schedule_deferred_start(ifp);
|
||||
}
|
||||
|
||||
static int
|
||||
awin_can_tx_abort(struct awin_can_softc *sc)
|
||||
{
|
||||
KASSERT(mutex_owned(&sc->sc_intr_lock));
|
||||
if (sc->sc_m_transmit) {
|
||||
m_freem(sc->sc_m_transmit);
|
||||
sc->sc_m_transmit = NULL;
|
||||
sc->sc_ifp->if_timer = 0;
|
||||
/*
|
||||
* the transmit abort will trigger a TX interrupt
|
||||
* which will restart the queue or cleae OACTIVE,
|
||||
* as appropriate
|
||||
*/
|
||||
awin_can_write(sc, AWIN_CAN_CMD_REG, AWIN_CAN_CMD_ABT_REQ);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
awin_can_err_intr(struct awin_can_softc *sc, uint32_t irq, uint32_t sts)
|
||||
{
|
||||
struct ifnet * const ifp = sc->sc_ifp;
|
||||
KASSERT(mutex_owned(&sc->sc_intr_lock));
|
||||
int txerr = 0;
|
||||
uint32_t reg;
|
||||
|
||||
if (irq & AWIN_CAN_INT_DATA_OR) {
|
||||
ifp->if_ierrors++;
|
||||
awin_can_write(sc, AWIN_CAN_CMD_REG, AWIN_CAN_CMD_CLR_OR);
|
||||
}
|
||||
if (irq & AWIN_CAN_INT_ERR) {
|
||||
reg = awin_can_read(sc, AWIN_CAN_REC_REG);
|
||||
printf("%s: ERR interrupt status 0x%x counters 0x%x\n",
|
||||
device_xname(sc->sc_dev), sts, reg);
|
||||
|
||||
}
|
||||
if (irq & AWIN_CAN_INT_BERR) {
|
||||
if (sts & AWIN_CAN_STA_TX)
|
||||
txerr++;
|
||||
if (sts & AWIN_CAN_STA_RX)
|
||||
ifp->if_ierrors++;
|
||||
}
|
||||
if (irq & AWIN_CAN_INT_ERR_PASSIVE) {
|
||||
printf("%s: PASSV interrupt status 0x%x\n",
|
||||
device_xname(sc->sc_dev), sts);
|
||||
}
|
||||
if (irq & AWIN_CAN_INT_ARB_LOST) {
|
||||
txerr++;
|
||||
}
|
||||
if (txerr) {
|
||||
ifp->if_oerrors += txerr;
|
||||
(void) awin_can_tx_abort(sc);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
awin_can_intr(void *arg)
|
||||
{
|
||||
struct awin_can_softc * const sc = arg;
|
||||
int rv = 0;
|
||||
int irq;
|
||||
|
||||
mutex_enter(&sc->sc_intr_lock);
|
||||
|
||||
while ((irq = awin_can_read(sc, AWIN_CAN_INT_REG)) != 0) {
|
||||
uint32_t sts = awin_can_read(sc, AWIN_CAN_STA_REG);
|
||||
rv = 1;
|
||||
|
||||
if (irq & AWIN_CAN_INT_TX_FLAG) {
|
||||
awin_can_tx_intr(sc);
|
||||
}
|
||||
if (irq & AWIN_CAN_INT_RX_FLAG) {
|
||||
while (sts & AWIN_CAN_STA_RX_RDY) {
|
||||
awin_can_rx_intr(sc);
|
||||
sts = awin_can_read(sc, AWIN_CAN_STA_REG);
|
||||
}
|
||||
}
|
||||
if (irq & AWIN_CAN_INT_ALLERRS) {
|
||||
awin_can_err_intr(sc, irq, sts);
|
||||
}
|
||||
awin_can_write(sc, AWIN_CAN_INT_REG, irq);
|
||||
rnd_add_uint32(&sc->sc_rnd_source, irq);
|
||||
|
||||
}
|
||||
mutex_exit(&sc->sc_intr_lock);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
awin_can_ifstart(struct ifnet *ifp)
|
||||
{
|
||||
struct awin_can_softc * const sc = ifp->if_softc;
|
||||
struct mbuf *m;
|
||||
struct can_frame *cf;
|
||||
int regd;
|
||||
uint32_t reg0val;
|
||||
int i;
|
||||
|
||||
mutex_enter(&sc->sc_intr_lock);
|
||||
if (ifp->if_flags & IFF_OACTIVE)
|
||||
goto out;
|
||||
|
||||
IF_DEQUEUE(&ifp->if_snd, m);
|
||||
|
||||
if (m == NULL)
|
||||
goto out;
|
||||
|
||||
MCLAIM(m, ifp->if_mowner);
|
||||
sc->sc_m_transmit = m;
|
||||
|
||||
KASSERT((m->m_flags & M_PKTHDR) != 0);
|
||||
KASSERT(m->m_len == m->m_pkthdr.len);
|
||||
|
||||
cf = mtod(m, struct can_frame *);
|
||||
reg0val = cf->can_dlc & AWIN_CAN_TXBUF0_DL;
|
||||
if (cf->can_id & CAN_RTR_FLAG)
|
||||
reg0val |= AWIN_CAN_TXBUF0_RTR;
|
||||
|
||||
if (cf->can_id & CAN_EFF_FLAG) {
|
||||
reg0val |= AWIN_CAN_TXBUF0_EFF;
|
||||
awin_can_write(sc, AWIN_CAN_TXBUF1_REG,
|
||||
(cf->can_id >> 21) & 0xff);
|
||||
awin_can_write(sc, AWIN_CAN_TXBUF2_REG,
|
||||
(cf->can_id >> 13) & 0xff);
|
||||
awin_can_write(sc, AWIN_CAN_TXBUF3_REG,
|
||||
(cf->can_id >> 5) & 0xff);
|
||||
awin_can_write(sc, AWIN_CAN_TXBUF4_REG,
|
||||
(cf->can_id << 3) & 0xf8);
|
||||
regd = AWIN_CAN_TXBUF5_REG;
|
||||
} else {
|
||||
awin_can_write(sc, AWIN_CAN_TXBUF1_REG,
|
||||
(cf->can_id >> 3) & 0xff);
|
||||
awin_can_write(sc, AWIN_CAN_TXBUF2_REG,
|
||||
(cf->can_id << 5) & 0xe0);
|
||||
regd = AWIN_CAN_TXBUF3_REG;
|
||||
}
|
||||
|
||||
for (i = 0; i < cf->can_dlc; i++) {
|
||||
awin_can_write(sc, regd + i * 4, cf->data[i]);
|
||||
}
|
||||
awin_can_write(sc, AWIN_CAN_TXBUF0_REG, reg0val);
|
||||
|
||||
if (sc->sc_linkmodes & CAN_LINKMODE_LOOPBACK) {
|
||||
awin_can_write(sc, AWIN_CAN_CMD_REG,
|
||||
AWIN_CAN_CMD_TANS_REQ | AWIN_CAN_CMD_SELF_REQ);
|
||||
} else {
|
||||
awin_can_write(sc, AWIN_CAN_CMD_REG, AWIN_CAN_CMD_TANS_REQ);
|
||||
}
|
||||
ifp->if_flags |= IFF_OACTIVE;
|
||||
ifp->if_timer = 5;
|
||||
can_bpf_mtap(ifp, m, 0);
|
||||
out:
|
||||
mutex_exit(&sc->sc_intr_lock);
|
||||
}
|
||||
|
||||
static int
|
||||
awin_can_ifup(struct awin_can_softc * const sc)
|
||||
{
|
||||
uint32_t reg;
|
||||
|
||||
/* setup timings and mode - has to be done in reset */
|
||||
reg = AWIN_CAN_MODSEL_RST;
|
||||
if (sc->sc_linkmodes & CAN_LINKMODE_LISTENONLY)
|
||||
reg |= AWIN_CAN_MODSEL_LST_ONLY;
|
||||
|
||||
if (sc->sc_linkmodes & CAN_LINKMODE_LOOPBACK)
|
||||
reg |= AWIN_CAN_MODSEL_LB_MOD;
|
||||
|
||||
awin_can_write(sc, AWIN_CAN_MODSEL_REG, reg);
|
||||
|
||||
reg = 0;
|
||||
if (sc->sc_timings.clt_prop != 0)
|
||||
return EINVAL;
|
||||
|
||||
if (sc->sc_timings.clt_brp > sc->sc_timecaps.cltc_brp_max ||
|
||||
sc->sc_timings.clt_brp < sc->sc_timecaps.cltc_brp_min)
|
||||
return EINVAL;
|
||||
reg |= (sc->sc_timings.clt_brp - 1) << 0;
|
||||
|
||||
if (sc->sc_timings.clt_ps1 > sc->sc_timecaps.cltc_ps1_max ||
|
||||
sc->sc_timings.clt_ps1 < sc->sc_timecaps.cltc_ps1_min)
|
||||
return EINVAL;
|
||||
reg |= (sc->sc_timings.clt_ps1 - 1) << 16;
|
||||
|
||||
if (sc->sc_timings.clt_ps2 > sc->sc_timecaps.cltc_ps2_max ||
|
||||
sc->sc_timings.clt_ps2 < sc->sc_timecaps.cltc_ps2_min)
|
||||
return EINVAL;
|
||||
reg |= (sc->sc_timings.clt_ps2 - 1) << 20;
|
||||
|
||||
if (sc->sc_timings.clt_sjw > sc->sc_timecaps.cltc_sjw_max ||
|
||||
sc->sc_timings.clt_sjw < 1)
|
||||
return EINVAL;
|
||||
reg |= (sc->sc_timings.clt_sjw - 1) << 14;
|
||||
|
||||
if (sc->sc_linkmodes & CAN_LINKMODE_3SAMPLES)
|
||||
reg |= AWIN_CAN_BUS_TIME_SAM;
|
||||
|
||||
awin_can_write(sc, AWIN_CAN_BUS_TIME_REG, reg);
|
||||
|
||||
/* set filters to accept all frames */
|
||||
awin_can_write(sc, AWIN_CAN_ACPC, 0x00000000);
|
||||
awin_can_write(sc, AWIN_CAN_ACPM, 0xffffffff);
|
||||
|
||||
/* clear errors counter */
|
||||
awin_can_write(sc, AWIN_CAN_REC_REG, 0);
|
||||
|
||||
/* leave reset mode and enable interrupts */
|
||||
awin_can_exit_reset(sc);
|
||||
awin_can_write(sc, AWIN_CAN_INTE_REG,
|
||||
AWIN_CAN_INT_TX_FLAG | AWIN_CAN_INT_RX_FLAG | AWIN_CAN_INT_ALLERRS);
|
||||
sc->sc_ifp->if_flags |= IFF_RUNNING;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
awin_can_ifdown(struct awin_can_softc * const sc)
|
||||
{
|
||||
sc->sc_ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
|
||||
sc->sc_ifp->if_timer = 0;
|
||||
awin_can_enter_reset(sc);
|
||||
awin_can_write(sc, AWIN_CAN_INTE_REG, 0);
|
||||
awin_can_write(sc, AWIN_CAN_INT_REG,
|
||||
awin_can_read(sc, AWIN_CAN_INT_REG));
|
||||
}
|
||||
|
||||
static int
|
||||
awin_can_ifioctl(struct ifnet *ifp, u_long cmd, void *data)
|
||||
{
|
||||
struct awin_can_softc * const sc = ifp->if_softc;
|
||||
struct ifreq *ifr = (struct ifreq *)data;
|
||||
int error = 0;
|
||||
|
||||
mutex_enter(&sc->sc_intr_lock);
|
||||
|
||||
switch (cmd) {
|
||||
case SIOCINITIFADDR:
|
||||
error = EAFNOSUPPORT;
|
||||
break;
|
||||
case SIOCSIFMTU:
|
||||
if ((unsigned)ifr->ifr_mtu != sizeof(struct can_frame))
|
||||
error = EINVAL;
|
||||
break;
|
||||
case SIOCADDMULTI:
|
||||
case SIOCDELMULTI:
|
||||
error = EAFNOSUPPORT;
|
||||
break;
|
||||
default:
|
||||
error = ifioctl_common(ifp, cmd, data);
|
||||
if (error == 0) {
|
||||
if ((ifp->if_flags & IFF_UP) != 0 &&
|
||||
(ifp->if_flags & IFF_RUNNING) == 0) {
|
||||
error = awin_can_ifup(sc);
|
||||
if (error) {
|
||||
ifp->if_flags &= ~IFF_UP;
|
||||
}
|
||||
} else if ((ifp->if_flags & IFF_UP) == 0 &&
|
||||
(ifp->if_flags & IFF_RUNNING) != 0) {
|
||||
awin_can_ifdown(sc);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_exit(&sc->sc_intr_lock);
|
||||
return error;
|
||||
}
|
||||
|
||||
void
|
||||
awin_can_ifwatchdog(struct ifnet *ifp)
|
||||
{
|
||||
struct awin_can_softc * const sc = ifp->if_softc;
|
||||
printf("%s: watchdog timeout\n", device_xname(sc->sc_dev));
|
||||
|
||||
mutex_enter(&sc->sc_intr_lock);
|
||||
printf("irq 0x%x en 0x%x mode 0x%x status 0x%x timings 0x%x err 0x%x\n",
|
||||
awin_can_read(sc, AWIN_CAN_INT_REG),
|
||||
awin_can_read(sc, AWIN_CAN_INTE_REG),
|
||||
awin_can_read(sc, AWIN_CAN_MODSEL_REG),
|
||||
awin_can_read(sc, AWIN_CAN_STA_REG),
|
||||
awin_can_read(sc, AWIN_CAN_BUS_TIME_REG),
|
||||
awin_can_read(sc, AWIN_CAN_REC_REG));
|
||||
/* if there is a transmit in progress abort */
|
||||
if (awin_can_tx_abort(sc)) {
|
||||
ifp->if_oerrors++;
|
||||
}
|
||||
mutex_exit(&sc->sc_intr_lock);
|
||||
}
|
||||
|
||||
static void
|
||||
awin_can_enter_reset(struct awin_can_softc *sc)
|
||||
{
|
||||
int i;
|
||||
uint32_t val;
|
||||
|
||||
for (i = 0; i < 1000; i++) {
|
||||
val = awin_can_read(sc, AWIN_CAN_MODSEL_REG);
|
||||
val |= AWIN_CAN_MODSEL_RST;
|
||||
awin_can_write(sc, AWIN_CAN_MODSEL_REG, val);
|
||||
val = awin_can_read(sc, AWIN_CAN_MODSEL_REG);
|
||||
if (val & AWIN_CAN_MODSEL_RST)
|
||||
return;
|
||||
}
|
||||
printf("%s: couldn't enter reset mode\n", device_xname(sc->sc_dev));
|
||||
}
|
||||
|
||||
static void
|
||||
awin_can_exit_reset(struct awin_can_softc *sc)
|
||||
{
|
||||
int i;
|
||||
uint32_t val;
|
||||
|
||||
for (i = 0; i < 1000; i++) {
|
||||
val = awin_can_read(sc, AWIN_CAN_MODSEL_REG);
|
||||
val &= ~AWIN_CAN_MODSEL_RST;
|
||||
awin_can_write(sc, AWIN_CAN_MODSEL_REG, val);
|
||||
val = awin_can_read(sc, AWIN_CAN_MODSEL_REG);
|
||||
if ((val & AWIN_CAN_MODSEL_RST) == 0)
|
||||
return;
|
||||
}
|
||||
printf("%s: couldn't leave reset mode\n", device_xname(sc->sc_dev));
|
||||
}
|
@ -31,7 +31,7 @@
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
__KERNEL_RCSID(1, "$NetBSD: awin_io.c,v 1.46 2016/05/11 18:33:40 bouyer Exp $");
|
||||
__KERNEL_RCSID(1, "$NetBSD: awin_io.c,v 1.47 2017/05/27 21:02:55 bouyer Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/bus.h>
|
||||
@ -192,6 +192,7 @@ static const struct awin_locators awin_locators[] = {
|
||||
{ "awinir", OFFANDSIZE(A31_CIR), NOPORT, AWIN_A31_IRQ_CIR, A31 },
|
||||
{ "awinir", OFFANDSIZE(A80_CIR), NOPORT, AWIN_A80_IRQ_R_CIR, A80 },
|
||||
{ "awinlradc", OFFANDSIZE(LRADC), NOPORT, AWIN_IRQ_LRADC, A20 },
|
||||
{ "awincan", OFFANDSIZE(CAN), NOPORT, AWIN_IRQ_CAN, A20 },
|
||||
};
|
||||
|
||||
static int
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: awin_reg.h,v 1.90 2016/12/26 16:20:17 rjs Exp $ */
|
||||
/* $NetBSD: awin_reg.h,v 1.91 2017/05/27 21:02:55 bouyer Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2013 The NetBSD Foundation, Inc.
|
||||
@ -3071,4 +3071,120 @@ struct awin_a31_dma_desc {
|
||||
#define AWIN_LRADC_DATA0_REG 0x0c
|
||||
#define AWIN_LRADC_DATA1_REG 0x10
|
||||
|
||||
/* CAN mode select register */
|
||||
#define AWIN_CAN_MODSEL_REG 0x00
|
||||
#define AWIN_CAN_MODSEL_SLEEP __BIT(4)
|
||||
#define AWIN_CAN_MODSEL_ACP_FLT_MOD __BIT(3)
|
||||
#define AWIN_CAN_MODSEL_LB_MOD __BIT(2)
|
||||
#define AWIN_CAN_MODSEL_LST_ONLY __BIT(1)
|
||||
#define AWIN_CAN_MODSEL_RST __BIT(0)
|
||||
|
||||
/* CAN command register */
|
||||
#define AWIN_CAN_CMD_REG 0x04
|
||||
#define AWIN_CAN_CMD_BUS_OFF __BIT(5)
|
||||
#define AWIN_CAN_CMD_SELF_REQ __BIT(4)
|
||||
#define AWIN_CAN_CMD_CLR_OR __BIT(3)
|
||||
#define AWIN_CAN_CMD_REL_RX_BUF __BIT(2)
|
||||
#define AWIN_CAN_CMD_ABT_REQ __BIT(1)
|
||||
#define AWIN_CAN_CMD_TANS_REQ __BIT(0)
|
||||
|
||||
/* CAN status register */
|
||||
#define AWIN_CAN_STA_REG 0x08
|
||||
#define AWIN_CAN_STA_ERR_CODE __BITS(23,22)
|
||||
#define AWIN_CAN_STA_ERR_CODE_BIT 0
|
||||
#define AWIN_CAN_STA_ERR_CODE_FORM 1
|
||||
#define AWIN_CAN_STA_ERR_CODE_STUFF 2
|
||||
#define AWIN_CAN_STA_ERR_CODE_OTHER 3
|
||||
#define AWIN_CAN_STA_ERR_DIR _BIT(21)
|
||||
#define AWIN_CAN_STA_ERR_SEG_CODE __BITS(20,16)
|
||||
#define AWIN_CAN_STA_ARB_LOST __BITS(12,8)
|
||||
#define AWIN_CAN_STA_BUS __BIT(7)
|
||||
#define AWIN_CAN_STA_ERR __BIT(6)
|
||||
#define AWIN_CAN_STA_TX __BIT(5)
|
||||
#define AWIN_CAN_STA_RX __BIT(4)
|
||||
#define AWIN_CAN_STA_TX_OVER __BIT(3)
|
||||
#define AWIN_CAN_STA_TX_RDY __BIT(2)
|
||||
#define AWIN_CAN_STA_DATA_OR __BIT(1)
|
||||
#define AWIN_CAN_STA_RX_RDY __BIT(0)
|
||||
|
||||
/* CAN interrupt register */
|
||||
#define AWIN_CAN_INT_REG 0x0c
|
||||
#define AWIN_CAN_INT_BERR __BIT(7)
|
||||
#define AWIN_CAN_INT_ARB_LOST __BIT(6)
|
||||
#define AWIN_CAN_INT_ERR_PASSIVE __BIT(5)
|
||||
#define AWIN_CAN_INT_WAKEUP __BIT(4)
|
||||
#define AWIN_CAN_INT_DATA_OR __BIT(3)
|
||||
#define AWIN_CAN_INT_ERR __BIT(2)
|
||||
#define AWIN_CAN_INT_TX_FLAG __BIT(1)
|
||||
#define AWIN_CAN_INT_RX_FLAG __BIT(0)
|
||||
|
||||
/* CAN interrupt enable register */
|
||||
#define AWIN_CAN_INTE_REG 0x10
|
||||
|
||||
/* CAN bus timing register */
|
||||
#define AWIN_CAN_BUS_TIME_REG 0x14
|
||||
#define AWIN_CAN_BUS_TIME_SAM __BIT(23)
|
||||
#define AWIN_CAN_BUS_TIME_PHSEG2 __BITS(22,20)
|
||||
#define AWIN_CAN_BUS_TIME_PHSEG1 __BITS(19,16)
|
||||
#define AWIN_CAN_BUS_TIME_SJW __BITS(15,14)
|
||||
#define AWIN_CAN_BUS_TIME_TQ_BRP __BITS(9,0)
|
||||
|
||||
/* CAN tx error warning limit register */
|
||||
#define AWIN_CAN_EWL_REG 0x18
|
||||
#define AWIN_CAN_EWL_ERR_WRN_LMT __BITS(7,0)
|
||||
|
||||
/* CAN error counter register */
|
||||
#define AWIN_CAN_REC_REG 0x1c
|
||||
#define AWIN_CAN_REC_RX_ERR_CNT __BITS(23,16)
|
||||
#define AWIN_CAN_REC_TX_ERR_CNT __BITS(7,0)
|
||||
|
||||
/* CAN receive message register */
|
||||
#define AWIN_CAN_RMSGC_REG 0x20
|
||||
#define AWIN_CAN_RMSGC_RX_MSG_CNT __BITS(7,0)
|
||||
|
||||
/* CAN receive buffer start address register */
|
||||
#define AWIN_CAN_RSADDR_REG 0x24
|
||||
#define AWIN_CAN_RSADDR_RX_BUF_SADDR __BITS(5,0)
|
||||
|
||||
/* CAN rx/tx message buffer 0 register */
|
||||
#define AWIN_CAN_TXBUF0_REG 0x40
|
||||
#define AWIN_CAN_TXBUF0_EFF __BIT(7)
|
||||
#define AWIN_CAN_TXBUF0_RTR __BIT(6)
|
||||
#define AWIN_CAN_TXBUF0_DL __BITS(3,0)
|
||||
|
||||
/* CAN rx/tx message buffer registers */
|
||||
#define AWIN_CAN_TXBUF1_REG 0x44
|
||||
#define AWIN_CAN_TXBUF2_REG 0x48
|
||||
#define AWIN_CAN_TXBUF3_REG 0x4c
|
||||
#define AWIN_CAN_TXBUF4_REG 0x50
|
||||
#define AWIN_CAN_TXBUF5_REG 0x54
|
||||
#define AWIN_CAN_TXBUF6_REG 0x58
|
||||
#define AWIN_CAN_TXBUF7_REG 0x5c
|
||||
#define AWIN_CAN_TXBUF8_REG 0x60
|
||||
#define AWIN_CAN_TXBUF9_REG 0x64
|
||||
#define AWIN_CAN_TXBUF10_REG 0x68
|
||||
#define AWIN_CAN_TXBUF11_REG 0x6c
|
||||
#define AWIN_CAN_TXBUF12_REG 0x70
|
||||
|
||||
/* CAN acceptance code 0 register */
|
||||
#define AWIN_CAN_ACPC 0x40
|
||||
|
||||
/* CAN acceptance mask 0 register */
|
||||
#define AWIN_CAN_ACPM 0x44
|
||||
|
||||
/* CAN transmit buffer for read back registers */
|
||||
#define AWIN_CAN_RBUF_RBACK0 0x180
|
||||
#define AWIN_CAN_RBUF_RBACK1 0x184
|
||||
#define AWIN_CAN_RBUF_RBACK2 0x188
|
||||
#define AWIN_CAN_RBUF_RBACK3 0x18c
|
||||
#define AWIN_CAN_RBUF_RBACK4 0x190
|
||||
#define AWIN_CAN_RBUF_RBACK5 0x194
|
||||
#define AWIN_CAN_RBUF_RBACK6 0x198
|
||||
#define AWIN_CAN_RBUF_RBACK7 0x19c
|
||||
#define AWIN_CAN_RBUF_RBACK8 0x1a0
|
||||
#define AWIN_CAN_RBUF_RBACK9 0x1a4
|
||||
#define AWIN_CAN_RBUF_RBACK10 0x1a8
|
||||
#define AWIN_CAN_RBUF_RBACK11 0x1ac
|
||||
#define AWIN_CAN_RBUF_RBACK12 0x1b0
|
||||
|
||||
#endif /* _ARM_ALLWINNER_AWIN_REG_H_ */
|
||||
|
@ -1,4 +1,4 @@
|
||||
# $NetBSD: files.awin,v 1.36 2016/05/27 20:01:49 bouyer Exp $
|
||||
# $NetBSD: files.awin,v 1.37 2017/05/27 21:02:55 bouyer Exp $
|
||||
#
|
||||
# Configuration info for Allwinner ARM Peripherals
|
||||
#
|
||||
@ -110,6 +110,11 @@ file arch/arm/allwinner/awin_eth.c awin_eth
|
||||
attach awge at awinio with awin_gige
|
||||
file arch/arm/allwinner/awin_gige.c awin_gige
|
||||
|
||||
# A20 CAN
|
||||
device awincan { } : ifnet
|
||||
attach awincan at awinio with awin_can
|
||||
file arch/arm/allwinner/awin_can.c awin_can
|
||||
|
||||
# USB2 OTG Controller
|
||||
attach motg at awinio with awin_otg
|
||||
file arch/arm/allwinner/awin_otg.c awin_otg
|
||||
|
@ -1,4 +1,4 @@
|
||||
# $NetBSD: files,v 1.1171 2017/02/26 11:56:49 rin Exp $
|
||||
# $NetBSD: files,v 1.1172 2017/05/27 21:02:56 bouyer Exp $
|
||||
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
|
||||
|
||||
version 20150846
|
||||
@ -232,6 +232,7 @@ file net/bpfjit.c sljit & bpfjit
|
||||
include "net80211/files.net80211"
|
||||
include "netatalk/files.netatalk"
|
||||
include "netbt/files.netbt"
|
||||
include "netcan/files.netcan"
|
||||
include "netinet/files.netinet"
|
||||
include "netinet6/files.netinet6"
|
||||
include "netipsec/files.netipsec"
|
||||
@ -1439,6 +1440,7 @@ defpseudodev tap: ifnet, ether, arp
|
||||
defpseudo carp: ifnet, ether, arp
|
||||
defpseudodev etherip: ifnet, ether, arp
|
||||
defpseudodev l2tp: ifnet, ether, arp
|
||||
defpseudo canloop: ifnet
|
||||
|
||||
defpseudo sequencer
|
||||
defpseudo clockctl
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: uipc_socket.c,v 1.254 2017/05/25 20:42:36 christos Exp $ */
|
||||
/* $NetBSD: uipc_socket.c,v 1.255 2017/05/27 21:02:56 bouyer Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2002, 2007, 2008, 2009 The NetBSD Foundation, Inc.
|
||||
@ -71,7 +71,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: uipc_socket.c,v 1.254 2017/05/25 20:42:36 christos Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: uipc_socket.c,v 1.255 2017/05/27 21:02:56 bouyer Exp $");
|
||||
|
||||
#ifdef _KERNEL_OPT
|
||||
#include "opt_compat_netbsd.h"
|
||||
@ -439,6 +439,7 @@ socket_listener_cb(kauth_cred_t cred, kauth_action_t action, void *cookie,
|
||||
case PF_ROUTE:
|
||||
case PF_OROUTE:
|
||||
case PF_BLUETOOTH:
|
||||
case PF_CAN:
|
||||
result = KAUTH_RESULT_ALLOW;
|
||||
break;
|
||||
default:
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: netisr.h,v 1.44 2015/05/25 08:29:01 ozaki-r Exp $ */
|
||||
/* $NetBSD: netisr.h,v 1.45 2017/05/27 21:02:56 bouyer Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1980, 1986, 1989, 1993
|
||||
@ -53,6 +53,7 @@
|
||||
#include "opt_atalk.h"
|
||||
#include "opt_mpls.h"
|
||||
#include "opt_natm.h"
|
||||
#include "opt_can.h"
|
||||
#include "arp.h"
|
||||
#endif /* defined(_KERNEL_OPT) */
|
||||
|
||||
@ -90,6 +91,10 @@
|
||||
#ifdef NETATALK
|
||||
#include <netatalk/at_extern.h>
|
||||
#endif
|
||||
#ifdef CAN
|
||||
#include <netcan/can.h>
|
||||
#include <netcan/can_var.h>
|
||||
#endif
|
||||
|
||||
#endif /* !defined(_LOCORE) */
|
||||
#endif /* defined(_KERNEL) */
|
||||
@ -109,6 +114,7 @@
|
||||
#define NETISR_NATM 27 /* same as AF_NATM */
|
||||
#define NETISR_ARP 28 /* same as AF_ARP */
|
||||
#define NETISR_MPLS 33 /* same as AF_MPLS */
|
||||
#define NETISR_CAN 35 /* same as AF_CAN */
|
||||
#define NETISR_MAX AF_MAX
|
||||
|
||||
#if !defined(_LOCORE) && defined(_KERNEL)
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: netisr_dispatch.h,v 1.18 2014/06/05 23:48:16 rmind Exp $ */
|
||||
/* $NetBSD: netisr_dispatch.h,v 1.19 2017/05/27 21:02:56 bouyer Exp $ */
|
||||
|
||||
#ifndef _NET_NETISR_DISPATCH_H_
|
||||
#define _NET_NETISR_DISPATCH_H_
|
||||
@ -41,5 +41,8 @@
|
||||
#ifdef NATM
|
||||
DONETISR(NETISR_NATM,natmintr);
|
||||
#endif
|
||||
#ifdef CAN
|
||||
DONETISR(NETISR_CAN,canintr);
|
||||
#endif
|
||||
|
||||
#endif /* !_NET_NETISR_DISPATCH_H_ */
|
||||
|
8
sys/netcan/Makefile
Normal file
8
sys/netcan/Makefile
Normal file
@ -0,0 +1,8 @@
|
||||
# $NetBSD: Makefile,v 1.2 2017/05/27 21:02:56 bouyer Exp $
|
||||
|
||||
KDIR= /sys/netcan
|
||||
INCSDIR= /usr/include/netcan
|
||||
|
||||
INCS= can.h can_link.h
|
||||
|
||||
.include <bsd.kinc.mk>
|
1013
sys/netcan/can.c
Normal file
1013
sys/netcan/can.c
Normal file
File diff suppressed because it is too large
Load Diff
128
sys/netcan/can.h
Normal file
128
sys/netcan/can.h
Normal file
@ -0,0 +1,128 @@
|
||||
/* $NetBSD: can.h,v 1.2 2017/05/27 21:02:56 bouyer Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2003, 2017 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Robert Swindells and Manuel Bouyer
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _NETCAN_CAN_H
|
||||
#define _NETCAN_CAN_H
|
||||
|
||||
#include <sys/featuretest.h>
|
||||
#include <machine/int_types.h>
|
||||
|
||||
|
||||
/* Definitions compatible (as much as possible) with socketCAN */
|
||||
|
||||
/*
|
||||
* CAN id structure
|
||||
* bits 0-28 : CAN identifier (11/29 bits, see bit 31)
|
||||
* bit2 29-31 : see below
|
||||
*/
|
||||
|
||||
typedef uint32_t canid_t;
|
||||
typedef uint32_t can_err_mask_t;
|
||||
|
||||
/* canid_t bits 29-31 descriptions */
|
||||
#define CAN_EFF_FLAG 0x80000000U /* extended frame format */
|
||||
#define CAN_RTR_FLAG 0x40000000U /* remote transmission request */
|
||||
#define CAN_ERR_FLAG 0x20000000U /* error message frame */
|
||||
|
||||
/* valid bits in CAN ID for frame formats */
|
||||
#define CAN_SFF_MASK 0x000007FFU /* standard frame format (SFF) */
|
||||
#define CAN_EFF_MASK 0x1FFFFFFFU /* extended frame format (EFF) */
|
||||
#define CAN_ERR_MASK 0x1FFFFFFFU /* error frame format */
|
||||
|
||||
/* CAN payload length and DLC definitions according to ISO 11898-1 */
|
||||
#define CAN_MAX_DLC 8
|
||||
#define CAN_MAX_DLEN 8
|
||||
|
||||
/* CAN frame */
|
||||
struct can_frame {
|
||||
canid_t can_id; /* ID + EFF/RTR/ERR flags */
|
||||
uint8_t can_dlc; /* frame payload length in byte (0 .. CAN_MAX_DLEN) */
|
||||
uint8_t __pad;
|
||||
uint8_t __res0;
|
||||
uint8_t __res1;
|
||||
uint8_t data[CAN_MAX_DLEN] __aligned(8);
|
||||
};
|
||||
|
||||
#define CAN_MTU (sizeof(struct can_frame))
|
||||
|
||||
/* protocols */
|
||||
#define CAN_RAW 1 /* RAW sockets */
|
||||
#define CAN_NPROTO 2
|
||||
|
||||
/*
|
||||
* Socket address, CAN style
|
||||
*/
|
||||
struct sockaddr_can {
|
||||
u_int8_t can_len;
|
||||
sa_family_t can_family;
|
||||
int can_ifindex;
|
||||
union {
|
||||
/* transport protocol class address information (e.g. ISOTP) */
|
||||
struct { canid_t rx_id, tx_id; } tp;
|
||||
/* reserved for future CAN protocols address information */
|
||||
} can_addr;
|
||||
};
|
||||
|
||||
/*
|
||||
* Options for use with [gs]etsockopt for raw sockets
|
||||
* First word of comment is data type; bool is stored in int.
|
||||
*/
|
||||
#define SOL_CAN_RAW CAN_RAW
|
||||
|
||||
#define CAN_RAW_FILTER 1 /* struct can_filter: set filter */
|
||||
#define CAN_RAW_LOOPBACK 4 /* bool: loopback to local sockets (default:on) */
|
||||
#define CAN_RAW_RECV_OWN_MSGS 5 /* bool: receive my own msgs (default:off) */
|
||||
|
||||
/*
|
||||
* CAN ID based filter
|
||||
* checks received can_id & can_filter.can_mask against
|
||||
* can_filter.can_id & can_filter.can_mask
|
||||
* valid flags for can_id:
|
||||
* CAN_INV_FILTER: invert filter
|
||||
* valid flags for can_mask:
|
||||
* CAN_ERR_FLAG: filter for error message frames
|
||||
*/
|
||||
struct can_filter {
|
||||
canid_t can_id;
|
||||
canid_t can_mask;
|
||||
};
|
||||
|
||||
#define CAN_INV_FILTER 0x20000000U
|
||||
|
||||
#ifdef _NETBSD_SOURCE
|
||||
#ifdef _KERNEL
|
||||
|
||||
#define satoscan(sa) ((struct sockaddr_can *)(sa))
|
||||
#define scantosa(scan) ((struct sockaddr *)(scan))
|
||||
|
||||
#endif /* _KERNEL */
|
||||
#endif /* _NETBSD_SOURCE */
|
||||
#endif /* _NETCAN_CAN_H */
|
80
sys/netcan/can_link.h
Normal file
80
sys/netcan/can_link.h
Normal file
@ -0,0 +1,80 @@
|
||||
/* $NetBSD: can_link.h,v 1.2 2017/05/27 21:02:56 bouyer Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2017 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Manuel Bouyer
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _NETCAN_CAN_LINK_H
|
||||
#define _NETCAN_CAN_LINK_H
|
||||
|
||||
/*
|
||||
* CAN bus link-layer related commands, from the SIOCSDRVSPEC
|
||||
*/
|
||||
|
||||
/* get timing capabilities from HW */
|
||||
struct can_link_timecaps {
|
||||
uint32_t cltc_prop_min; /* prop seg, in tq */
|
||||
uint32_t cltc_prop_max;
|
||||
uint32_t cltc_ps1_min; /* phase1 seg, in tq */
|
||||
uint32_t cltc_ps1_max;
|
||||
uint32_t cltc_ps2_min; /* phase 2 seg, in tq */
|
||||
uint32_t cltc_ps2_max;
|
||||
uint32_t cltc_sjw_max; /* Synchronisation Jump Width */
|
||||
uint32_t cltc_brp_min; /* bit-rate prescaler */
|
||||
uint32_t cltc_brp_max;
|
||||
uint32_t cltc_brp_inc;
|
||||
uint32_t cltc_clock_freq; /* prescaler input clock, in hz */
|
||||
uint32_t cltc_linkmode_caps; /* link mode, see below */
|
||||
};
|
||||
#define CANGLINKTIMECAP 0 /* get struct can_link_timecaps */
|
||||
|
||||
/* get/set timing parameters */
|
||||
struct can_link_timings {
|
||||
uint32_t clt_brp; /* prescaler value */
|
||||
uint32_t clt_prop; /* Propagation segment in tq */
|
||||
uint32_t clt_ps1; /* Phase segment 1 in tq */
|
||||
uint32_t clt_ps2; /* Phase segment 2 in tq */
|
||||
uint32_t clt_sjw; /* Synchronisation jump width in tq */
|
||||
};
|
||||
#define CANGLINKTIMINGS 1 /* get struct can_link_timings */
|
||||
#define CANSLINKTIMINGS 2 /* set struct can_link_timings */
|
||||
|
||||
/* link-level modes */
|
||||
#define CAN_LINKMODE_LOOPBACK 0x01 /* Loopback mode */
|
||||
#define CAN_LINKMODE_LISTENONLY 0x02 /* Listen-only mode */
|
||||
#define CAN_LINKMODE_3SAMPLES 0x04 /* Triple sampling mode */
|
||||
#define CAN_LINKMODE_PRESUME_ACK 0x08 /* Ignore missing CAN ACKs */
|
||||
#define CAN_IFFBITS \
|
||||
"\020\1LOOPBACK\2LISTENONLY\3TRIPLESAMPLE\4PRESUMEACK"
|
||||
|
||||
#define CANGLINKMODE 3 /* (uint32_t) get bits */
|
||||
#define CANSLINKMODE 4 /* (uint32_t) set bits */
|
||||
#define CANCLINKMODE 5 /* (uint32_t) clear bits */
|
||||
|
||||
#endif /* _NETCAN_CAN_LINK_H */
|
||||
|
380
sys/netcan/can_pcb.c
Normal file
380
sys/netcan/can_pcb.c
Normal file
@ -0,0 +1,380 @@
|
||||
/* $NetBSD: can_pcb.c,v 1.2 2017/05/27 21:02:56 bouyer Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2003, 2017 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Robert Swindells and Manuel Bouyer
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: can_pcb.c,v 1.2 2017/05/27 21:02:56 bouyer Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/kmem.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/protosw.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/socketvar.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/pool.h>
|
||||
#include <sys/proc.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/route.h>
|
||||
|
||||
#include <netcan/can.h>
|
||||
#include <netcan/can_var.h>
|
||||
#include <netcan/can_pcb.h>
|
||||
|
||||
#define CANPCBHASH_BIND(table, ifindex) \
|
||||
&(table)->canpt_bindhashtbl[ \
|
||||
(ifindex) & (table)->canpt_bindhash]
|
||||
#define CANPCBHASH_CONNECT(table, ifindex) \
|
||||
&(table)->canpt_connecthashtbl[ \
|
||||
(ifindex) & (table)->canpt_bindhash]
|
||||
|
||||
struct pool canpcb_pool;
|
||||
|
||||
void
|
||||
can_pcbinit(struct canpcbtable *table, int bindhashsize, int connecthashsize)
|
||||
{
|
||||
static int canpcb_pool_initialized;
|
||||
|
||||
if (canpcb_pool_initialized == 0) {
|
||||
pool_init(&canpcb_pool, sizeof(struct canpcb), 0, 0, 0,
|
||||
"canpcbpl", NULL, IPL_SOFTNET);
|
||||
canpcb_pool_initialized = 1;
|
||||
}
|
||||
|
||||
TAILQ_INIT(&table->canpt_queue);
|
||||
table->canpt_bindhashtbl = hashinit(bindhashsize, HASH_LIST, true,
|
||||
&table->canpt_bindhash);
|
||||
table->canpt_connecthashtbl = hashinit(connecthashsize, HASH_LIST,
|
||||
true, &table->canpt_connecthash);
|
||||
}
|
||||
|
||||
int
|
||||
can_pcballoc(struct socket *so, void *v)
|
||||
{
|
||||
struct canpcbtable *table = v;
|
||||
struct canpcb *canp;
|
||||
struct can_filter *can_init_filter;
|
||||
int s;
|
||||
|
||||
can_init_filter = kmem_alloc(sizeof(struct can_filter), KM_NOSLEEP);
|
||||
if (can_init_filter == NULL)
|
||||
return (ENOBUFS);
|
||||
can_init_filter->can_id = 0;
|
||||
can_init_filter->can_mask = 0; /* accept all by default */
|
||||
|
||||
s = splnet();
|
||||
canp = pool_get(&canpcb_pool, PR_NOWAIT);
|
||||
splx(s);
|
||||
if (canp == NULL) {
|
||||
kmem_free(can_init_filter, sizeof(struct can_filter));
|
||||
return (ENOBUFS);
|
||||
}
|
||||
memset(canp, 0, sizeof(*canp));
|
||||
canp->canp_table = table;
|
||||
canp->canp_socket = so;
|
||||
canp->canp_filters = can_init_filter;
|
||||
canp->canp_nfilters = 1;
|
||||
mutex_init(&canp->canp_mtx, MUTEX_DEFAULT, IPL_NET);
|
||||
canp->canp_refcount = 1;
|
||||
|
||||
so->so_pcb = canp;
|
||||
mutex_enter(&canp->canp_mtx);
|
||||
TAILQ_INSERT_HEAD(&table->canpt_queue, canp, canp_queue);
|
||||
can_pcbstate(canp, CANP_ATTACHED);
|
||||
mutex_exit(&canp->canp_mtx);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
can_pcbbind(void *v, struct sockaddr_can *scan, struct lwp *l)
|
||||
{
|
||||
struct canpcb *canp = v;
|
||||
|
||||
if (scan->can_family != AF_CAN)
|
||||
return (EAFNOSUPPORT);
|
||||
mutex_enter(&canp->canp_mtx);
|
||||
if (scan->can_ifindex != 0) {
|
||||
canp->canp_ifp = if_byindex(scan->can_ifindex);
|
||||
if (canp->canp_ifp == NULL)
|
||||
return (EADDRNOTAVAIL);
|
||||
soisconnected(canp->canp_socket);
|
||||
} else {
|
||||
canp->canp_ifp = NULL;
|
||||
canp->canp_socket->so_state &= ~SS_ISCONNECTED; /* XXX */
|
||||
}
|
||||
can_pcbstate(canp, CANP_BOUND);
|
||||
mutex_exit(&canp->canp_mtx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Connect from a socket to a specified address.
|
||||
*/
|
||||
int
|
||||
can_pcbconnect(void *v, struct sockaddr_can *scan)
|
||||
{
|
||||
#if 0
|
||||
struct canpcb *canp = v;
|
||||
struct sockaddr_can *ifaddr = NULL;
|
||||
int error;
|
||||
#endif
|
||||
|
||||
if (scan->can_family != AF_CAN)
|
||||
return (EAFNOSUPPORT);
|
||||
#if 0
|
||||
mutex_enter(&canp->canp_mtx);
|
||||
memcpy(&canp->canp_dst, scan, sizeof(struct sockaddr_can));
|
||||
can_pcbstate(canp, CANP_CONNECTED);
|
||||
mutex_exit(&canp->canp_mtx);
|
||||
return 0;
|
||||
#endif
|
||||
return EOPNOTSUPP;
|
||||
}
|
||||
|
||||
void
|
||||
can_pcbdisconnect(void *v)
|
||||
{
|
||||
struct canpcb *canp = v;
|
||||
|
||||
mutex_enter(&canp->canp_mtx);
|
||||
can_pcbstate(canp, CANP_DETACHED);
|
||||
mutex_exit(&canp->canp_mtx);
|
||||
if (canp->canp_socket->so_state & SS_NOFDREF)
|
||||
can_pcbdetach(canp);
|
||||
}
|
||||
|
||||
void
|
||||
can_pcbdetach(void *v)
|
||||
{
|
||||
struct canpcb *canp = v;
|
||||
struct socket *so = canp->canp_socket;
|
||||
|
||||
KASSERT(mutex_owned(softnet_lock));
|
||||
so->so_pcb = NULL;
|
||||
mutex_enter(&canp->canp_mtx);
|
||||
can_pcbstate(canp, CANP_DETACHED);
|
||||
can_pcbsetfilter(canp, NULL, 0);
|
||||
mutex_exit(&canp->canp_mtx);
|
||||
TAILQ_REMOVE(&canp->canp_table->canpt_queue, canp, canp_queue);
|
||||
sofree(so); /* sofree drops the softnet_lock */
|
||||
canp_unref(canp);
|
||||
mutex_enter(softnet_lock);
|
||||
}
|
||||
|
||||
void
|
||||
canp_ref(struct canpcb *canp)
|
||||
{
|
||||
KASSERT(mutex_owned(&canp->canp_mtx));
|
||||
canp->canp_refcount++;
|
||||
}
|
||||
|
||||
void
|
||||
canp_unref(struct canpcb *canp)
|
||||
{
|
||||
mutex_enter(&canp->canp_mtx);
|
||||
canp->canp_refcount--;
|
||||
KASSERT(canp->canp_refcount >= 0);
|
||||
if (canp->canp_refcount > 0) {
|
||||
mutex_exit(&canp->canp_mtx);
|
||||
return;
|
||||
}
|
||||
mutex_exit(&canp->canp_mtx);
|
||||
mutex_destroy(&canp->canp_mtx);
|
||||
pool_put(&canpcb_pool, canp);
|
||||
}
|
||||
|
||||
void
|
||||
can_setsockaddr(struct canpcb *canp, struct sockaddr_can *scan)
|
||||
{
|
||||
|
||||
mutex_enter(&canp->canp_mtx);
|
||||
memset(scan, 0, sizeof (*scan));
|
||||
scan->can_family = AF_CAN;
|
||||
scan->can_len = sizeof(*scan);
|
||||
scan->can_ifindex = canp->canp_ifp->if_index;
|
||||
mutex_exit(&canp->canp_mtx);
|
||||
}
|
||||
|
||||
int
|
||||
can_pcbsetfilter(struct canpcb *canp, struct can_filter *fp, int nfilters)
|
||||
{
|
||||
|
||||
struct can_filter *newf;
|
||||
KASSERT(mutex_owned(&canp->canp_mtx));
|
||||
|
||||
if (nfilters > 0) {
|
||||
newf =
|
||||
kmem_alloc(sizeof(struct can_filter) * nfilters, KM_SLEEP);
|
||||
if (newf == NULL)
|
||||
return ENOMEM;
|
||||
memcpy(newf, fp, sizeof(struct can_filter) * nfilters);
|
||||
} else {
|
||||
newf = NULL;
|
||||
}
|
||||
if (canp->canp_filters != NULL) {
|
||||
kmem_free(canp->canp_filters,
|
||||
sizeof(struct can_filter) * canp->canp_nfilters);
|
||||
}
|
||||
canp->canp_filters = newf;
|
||||
canp->canp_nfilters = nfilters;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Pass some notification to all connections of a protocol
|
||||
* associated with address dst. The local address and/or port numbers
|
||||
* may be specified to limit the search. The "usual action" will be
|
||||
* taken, depending on the ctlinput cmd. The caller must filter any
|
||||
* cmds that are uninteresting (e.g., no error in the map).
|
||||
* Call the protocol specific routine (if any) to report
|
||||
* any errors for each matching socket.
|
||||
*
|
||||
* Must be called at splsoftnet.
|
||||
*/
|
||||
int
|
||||
can_pcbnotify(struct canpcbtable *table, u_int32_t faddr, u_int32_t laddr,
|
||||
int errno, void (*notify)(struct canpcb *, int))
|
||||
{
|
||||
struct canpcbhead *head;
|
||||
struct canpcb *canp, *ncanp;
|
||||
int nmatch;
|
||||
|
||||
if (faddr == 0 || notify == 0)
|
||||
return (0);
|
||||
|
||||
nmatch = 0;
|
||||
head = CANPCBHASH_CONNECT(table, faddr, laddr);
|
||||
for (canp = LIST_FIRST(head); canp != NULL; canp = ncanp) {
|
||||
ncanp = LIST_NEXT(canp, canp_hash);
|
||||
if (canp->canp_faddr == faddr &&
|
||||
canp->canp_laddr == laddr) {
|
||||
(*notify)(canp, errno);
|
||||
nmatch++;
|
||||
}
|
||||
}
|
||||
return (nmatch);
|
||||
}
|
||||
|
||||
void
|
||||
can_pcbnotifyall(struct canpcbtable *table, u_int32_t faddr, int errno,
|
||||
void (*notify)(struct canpcb *, int))
|
||||
{
|
||||
struct canpcb *canp, *ncanp;
|
||||
|
||||
if (faddr == 0 || notify == 0)
|
||||
return;
|
||||
|
||||
TAILQ_FOREACH_SAFE(canp, &table->canpt_queue, canp_queue, ncanp) {
|
||||
if (canp->canp_faddr == faddr)
|
||||
(*notify)(canp, errno);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
void
|
||||
can_pcbpurgeif0(struct canpcbtable *table, struct ifnet *ifp)
|
||||
{
|
||||
struct canpcb *canp, *ncanp;
|
||||
struct ip_moptions *imo;
|
||||
int i, gap;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
can_pcbpurgeif(struct canpcbtable *table, struct ifnet *ifp)
|
||||
{
|
||||
struct canpcb *canp, *ncanp;
|
||||
|
||||
for (canp = CIRCLEQ_FIRST(&table->canpt_queue);
|
||||
canp != (void *)&table->canpt_queue;
|
||||
canp = ncanp) {
|
||||
ncanp = CIRCLEQ_NEXT(canp, canp_queue);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
void
|
||||
can_pcbstate(struct canpcb *canp, int state)
|
||||
{
|
||||
int ifindex = canp->canp_ifp ? canp->canp_ifp->if_index : 0;
|
||||
KASSERT(mutex_owned(&canp->canp_mtx));
|
||||
|
||||
if (canp->canp_state > CANP_ATTACHED)
|
||||
LIST_REMOVE(canp, canp_hash);
|
||||
|
||||
switch (state) {
|
||||
case CANP_BOUND:
|
||||
LIST_INSERT_HEAD(CANPCBHASH_BIND(canp->canp_table,
|
||||
ifindex), canp, canp_hash);
|
||||
break;
|
||||
case CANP_CONNECTED:
|
||||
LIST_INSERT_HEAD(CANPCBHASH_CONNECT(canp->canp_table,
|
||||
ifindex), canp, canp_hash);
|
||||
break;
|
||||
}
|
||||
|
||||
canp->canp_state = state;
|
||||
}
|
||||
|
||||
/*
|
||||
* check mbuf against socket accept filter.
|
||||
* returns true if mbuf is accepted, false otherwise
|
||||
*/
|
||||
bool
|
||||
can_pcbfilter(struct canpcb *canp, struct mbuf *m)
|
||||
{
|
||||
int i;
|
||||
struct can_frame *fmp;
|
||||
struct can_filter *fip;
|
||||
|
||||
KASSERT(mutex_owned(&canp->canp_mtx));
|
||||
KASSERT((m->m_flags & M_PKTHDR) != 0);
|
||||
KASSERT(m->m_len == m->m_pkthdr.len);
|
||||
|
||||
fmp = mtod(m, struct can_frame *);
|
||||
for (i = 0; i < canp->canp_nfilters; i++) {
|
||||
fip = &canp->canp_filters[i];
|
||||
if ((fmp->can_id & fip->can_mask) == fip->can_id)
|
||||
return true;
|
||||
}
|
||||
/* no match */
|
||||
return false;
|
||||
}
|
113
sys/netcan/can_pcb.h
Normal file
113
sys/netcan/can_pcb.h
Normal file
@ -0,0 +1,113 @@
|
||||
/* $NetBSD: can_pcb.h,v 1.2 2017/05/27 21:02:56 bouyer Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2003, 2017 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Robert Swindells and Manuel Bouyer
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _NETCAN_CAN_PCB_H_
|
||||
#define _NETCAN_CAN_PCB_H_
|
||||
|
||||
#include <sys/queue.h>
|
||||
|
||||
/*
|
||||
* Common structure pcb for can protocol implementation.
|
||||
* Here are stored pointers to local and foreign host table
|
||||
* entries, local and foreign socket numbers, and pointers
|
||||
* up (to a socket structure) and down (to a protocol-specific)
|
||||
* control block.
|
||||
*/
|
||||
struct canpcbpolicy;
|
||||
|
||||
|
||||
struct canpcb {
|
||||
LIST_ENTRY(canpcb) canp_hash;
|
||||
LIST_ENTRY(canpcb) canp_lhash;
|
||||
TAILQ_ENTRY(canpcb) canp_queue;
|
||||
kmutex_t canp_mtx; /* protect states and refcount */
|
||||
int canp_state;
|
||||
int canp_flags;
|
||||
struct socket *canp_socket; /* back pointer to socket */
|
||||
struct ifnet *canp_ifp; /* interface this socket is bound to */
|
||||
|
||||
struct canpcbtable *canp_table;
|
||||
struct can_filter *canp_filters; /* filter array */
|
||||
int canp_nfilters; /* size of canp_filters */
|
||||
|
||||
int canp_refcount;
|
||||
};
|
||||
|
||||
LIST_HEAD(canpcbhead, canpcb);
|
||||
|
||||
TAILQ_HEAD(canpcbqueue, canpcb);
|
||||
|
||||
struct canpcbtable {
|
||||
struct canpcbqueue canpt_queue;
|
||||
struct canpcbhead *canpt_bindhashtbl;
|
||||
struct canpcbhead *canpt_connecthashtbl;
|
||||
u_long canpt_bindhash;
|
||||
u_long canpt_connecthash;
|
||||
};
|
||||
|
||||
/* states in canp_state: */
|
||||
#define CANP_DETACHED 0
|
||||
#define CANP_ATTACHED 1
|
||||
#define CANP_BOUND 2
|
||||
#define CANP_CONNECTED 3
|
||||
|
||||
/* flags in canp_flags: */
|
||||
#define CANP_NO_LOOPBACK 0x0001 /* local loopback disabled */
|
||||
#define CANP_RECEIVE_OWN 0x0002 /* receive own message */
|
||||
|
||||
|
||||
#define sotocanpcb(so) ((struct canpcb *)(so)->so_pcb)
|
||||
|
||||
#ifdef _KERNEL
|
||||
void can_losing(struct canpcb *);
|
||||
int can_pcballoc (struct socket *, void *);
|
||||
int can_pcbbind(void *, struct sockaddr_can *, struct lwp *);
|
||||
int can_pcbconnect(void *, struct sockaddr_can *);
|
||||
void can_pcbdetach(void *);
|
||||
void can_pcbdisconnect(void *);
|
||||
void can_pcbinit(struct canpcbtable *, int, int);
|
||||
int can_pcbnotify(struct canpcbtable *, u_int32_t,
|
||||
u_int32_t, int, void (*)(struct canpcb *, int));
|
||||
void can_pcbnotifyall(struct canpcbtable *, u_int32_t, int,
|
||||
void (*)(struct canpcb *, int));
|
||||
void can_pcbpurgeif0(struct canpcbtable *, struct ifnet *);
|
||||
void can_pcbpurgeif(struct canpcbtable *, struct ifnet *);
|
||||
void can_pcbstate(struct canpcb *, int);
|
||||
void can_setsockaddr(struct canpcb *, struct sockaddr_can *);
|
||||
int can_pcbsetfilter(struct canpcb *, struct can_filter *, int);
|
||||
bool can_pcbfilter(struct canpcb *, struct mbuf *);
|
||||
|
||||
/* refcount management */
|
||||
void canp_ref(struct canpcb *);
|
||||
void canp_unref(struct canpcb *);
|
||||
#endif
|
||||
|
||||
#endif /* _NETCAN_CAN_PCB_H_ */
|
76
sys/netcan/can_proto.c
Normal file
76
sys/netcan/can_proto.c
Normal file
@ -0,0 +1,76 @@
|
||||
/* $NetBSD: can_proto.c,v 1.2 2017/05/27 21:02:56 bouyer Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2003, 2017 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Robert Swindells and Manuel Bouyer
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: can_proto.c,v 1.2 2017/05/27 21:02:56 bouyer Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/protosw.h>
|
||||
#include <sys/domain.h>
|
||||
#include <sys/mbuf.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/radix.h>
|
||||
#include <net/route.h>
|
||||
|
||||
/*
|
||||
* CAN protocol family
|
||||
*/
|
||||
#include <netcan/can.h>
|
||||
#include <netcan/can_var.h>
|
||||
|
||||
DOMAIN_DEFINE(candomain); /* forward declare and add to link set */
|
||||
|
||||
const struct protosw cansw[] = {
|
||||
{
|
||||
.pr_type = SOCK_RAW,
|
||||
.pr_domain = &candomain,
|
||||
.pr_init = can_init,
|
||||
.pr_flags = PR_ATOMIC|PR_ADDR,
|
||||
.pr_usrreqs = &can_usrreqs,
|
||||
.pr_ctloutput = &can_ctloutput,
|
||||
}
|
||||
};
|
||||
|
||||
struct domain candomain = {
|
||||
.dom_family = PF_CAN,
|
||||
.dom_name = "can",
|
||||
.dom_init = can_init,
|
||||
.dom_externalize = NULL, .dom_dispose = NULL,
|
||||
.dom_protosw = cansw,
|
||||
.dom_protoswNPROTOSW = &cansw[__arraycount(cansw)],
|
||||
.dom_ifqueues = { &canintrq, NULL },
|
||||
.dom_link = { NULL },
|
||||
.dom_mowner = MOWNER_INIT("",""),
|
||||
.dom_sa_cmpofs = offsetof(struct sockaddr_can, can_ifindex),
|
||||
.dom_sa_cmplen = sizeof(int)
|
||||
};
|
75
sys/netcan/can_var.h
Normal file
75
sys/netcan/can_var.h
Normal file
@ -0,0 +1,75 @@
|
||||
/* $NetBSD: can_var.h,v 1.2 2017/05/27 21:02:56 bouyer Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2003, 2017 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Robert Swindells and Manuel Bouyer
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _NETCAN_CAN_VAR_H_
|
||||
#define _NETCAN_CAN_VAR_H_
|
||||
|
||||
#include <sys/queue.h>
|
||||
#include <sys/device.h>
|
||||
#include <netcan/can_link.h>
|
||||
|
||||
struct can_ifreq {
|
||||
char cfr_name[IFNAMSIZ]; /* if name, e.g. "sja0" */
|
||||
};
|
||||
|
||||
#ifdef _KERNEL
|
||||
#include <sys/socketvar.h>
|
||||
|
||||
/*
|
||||
* common structure for CAN interface drivers. Should be at the start of
|
||||
* each driver's softc.
|
||||
*/
|
||||
struct canif_softc {
|
||||
device_t csc_dev;
|
||||
struct can_link_timecaps csc_timecaps; /* timing capabilities */
|
||||
struct can_link_timings csc_timings; /* operating timing values */
|
||||
uint32_t csc_linkmodes;
|
||||
};
|
||||
|
||||
extern struct ifqueue canintrq;
|
||||
extern struct domain candomain;
|
||||
|
||||
extern const struct pr_usrreqs can_usrreqs;
|
||||
|
||||
void can_ifattach(struct ifnet *);
|
||||
void can_ifdetach(struct ifnet *);
|
||||
void can_ifinit_timings(struct canif_softc *);
|
||||
void can_mbuf_tag_clean(struct mbuf *);
|
||||
void can_input(struct ifnet *, struct mbuf *);
|
||||
void *can_ctlinput(int, struct sockaddr *, void *);
|
||||
int can_ctloutput(int, struct socket *, struct sockopt *);
|
||||
void can_init(void);
|
||||
void canintr(void);
|
||||
void can_bpf_mtap(struct ifnet *, struct mbuf *, bool);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
8
sys/netcan/files.netcan
Normal file
8
sys/netcan/files.netcan
Normal file
@ -0,0 +1,8 @@
|
||||
# $NetBSD: files.netcan,v 1.2 2017/05/27 21:02:56 bouyer Exp $
|
||||
|
||||
defflag opt_can.h CAN # ISO-15765 CAN network stack
|
||||
|
||||
file netcan/can.c can
|
||||
file netcan/can_proto.c can
|
||||
file netcan/can_pcb.c can
|
||||
file netcan/if_canloop.c canloop
|
220
sys/netcan/if_canloop.c
Normal file
220
sys/netcan/if_canloop.c
Normal file
@ -0,0 +1,220 @@
|
||||
/* $NetBSD: if_canloop.c,v 1.2 2017/05/27 21:02:56 bouyer Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2017 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Manuel Bouyer.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Loopback interface driver for the CAN protocol
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: if_canloop.c,v 1.2 2017/05/27 21:02:56 bouyer Exp $");
|
||||
|
||||
#ifdef _KERNEL_OPT
|
||||
#include "opt_can.h"
|
||||
#include "opt_net_mpsafe.h"
|
||||
#endif
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/device.h>
|
||||
#include <sys/module.h>
|
||||
|
||||
#include <sys/cpu.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/if_types.h>
|
||||
#include <net/netisr.h>
|
||||
|
||||
#ifdef CAN
|
||||
#include <netcan/can.h>
|
||||
#endif
|
||||
|
||||
void canloopattach(int);
|
||||
void canloopinit(void);
|
||||
static int canloop_clone_create(struct if_clone *, int);
|
||||
static int canloop_clone_destroy(struct ifnet *);
|
||||
static int canloop_ioctl(struct ifnet *, u_long, void *);
|
||||
static void canloop_ifstart(struct ifnet *);
|
||||
|
||||
static int canloop_count;
|
||||
|
||||
static struct if_clone canloop_cloner =
|
||||
IF_CLONE_INITIALIZER("canlo", canloop_clone_create, canloop_clone_destroy);
|
||||
|
||||
void
|
||||
canloopattach(int n)
|
||||
{
|
||||
|
||||
/*
|
||||
* Nothing to do here, initialization is handled by the
|
||||
* module initialization code in canloopinit() below).
|
||||
*/
|
||||
}
|
||||
|
||||
void
|
||||
canloopinit(void)
|
||||
{
|
||||
|
||||
canloop_count = 0;
|
||||
if_clone_attach(&canloop_cloner);
|
||||
}
|
||||
|
||||
static int
|
||||
canloopdetach(void)
|
||||
{
|
||||
if (canloop_count > 0)
|
||||
return EBUSY;
|
||||
if_clone_detach(&canloop_cloner);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
canloop_clone_create(struct if_clone *ifc, int unit)
|
||||
{
|
||||
struct ifnet *ifp;
|
||||
|
||||
ifp = if_alloc(IFT_OTHER);
|
||||
|
||||
if_initname(ifp, ifc->ifc_name, unit);
|
||||
|
||||
ifp->if_flags = IFF_LOOPBACK | IFF_RUNNING;
|
||||
ifp->if_extflags = IFEF_OUTPUT_MPSAFE;
|
||||
ifp->if_ioctl = canloop_ioctl;
|
||||
ifp->if_start = canloop_ifstart;
|
||||
can_ifattach(ifp);
|
||||
#ifdef MBUFTRACE
|
||||
ifp->if_mowner = malloc(sizeof(struct mowner), M_DEVBUF,
|
||||
M_WAITOK | M_ZERO);
|
||||
strlcpy(ifp->if_mowner->mo_name, ifp->if_xname,
|
||||
sizeof(ifp->if_mowner->mo_name));
|
||||
MOWNER_ATTACH(ifp->if_mowner);
|
||||
#endif
|
||||
canloop_count++;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
canloop_clone_destroy(struct ifnet *ifp)
|
||||
{
|
||||
|
||||
#ifdef MBUFTRACE
|
||||
MOWNER_DETACH(ifp->if_mowner);
|
||||
free(ifp->if_mowner, M_DEVBUF);
|
||||
#endif
|
||||
|
||||
can_ifdetach(ifp);
|
||||
|
||||
if_free(ifp);
|
||||
canloop_count--;
|
||||
KASSERT(canloop_count >= 0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
canloop_ifstart(struct ifnet *ifp)
|
||||
{
|
||||
size_t pktlen;
|
||||
struct mbuf *m;
|
||||
|
||||
KERNEL_LOCK(1, NULL);
|
||||
while (true) {
|
||||
IF_DEQUEUE(&ifp->if_snd, m);
|
||||
if (m == NULL)
|
||||
break;
|
||||
MCLAIM(m, ifp->if_mowner);
|
||||
|
||||
if ((m->m_flags & M_PKTHDR) == 0)
|
||||
panic("canloop_output: no header mbuf");
|
||||
m_set_rcvif(m, ifp);
|
||||
if (ifp->if_flags & IFF_LOOPBACK)
|
||||
can_bpf_mtap(ifp, m, 0);
|
||||
|
||||
pktlen = m->m_pkthdr.len;
|
||||
ifp->if_opackets++;
|
||||
ifp->if_obytes += pktlen;
|
||||
|
||||
#ifdef CAN
|
||||
can_mbuf_tag_clean(m);
|
||||
can_input(ifp, m);
|
||||
#else
|
||||
printf("%s: can't handle CAN packet\n", ifp->if_xname);
|
||||
m_freem(m);
|
||||
#endif
|
||||
}
|
||||
|
||||
KERNEL_UNLOCK_ONE(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Process an ioctl request.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
canloop_ioctl(struct ifnet *ifp, u_long cmd, void *data)
|
||||
{
|
||||
struct ifreq *ifr = data;
|
||||
int error = 0;
|
||||
|
||||
switch (cmd) {
|
||||
|
||||
case SIOCINITIFADDR:
|
||||
error = EAFNOSUPPORT;
|
||||
break;
|
||||
|
||||
case SIOCSIFMTU:
|
||||
if ((unsigned)ifr->ifr_mtu != sizeof(struct can_frame))
|
||||
error = EINVAL;
|
||||
break;
|
||||
|
||||
case SIOCADDMULTI:
|
||||
case SIOCDELMULTI:
|
||||
error = EAFNOSUPPORT;
|
||||
break;
|
||||
|
||||
default:
|
||||
error = ifioctl_common(ifp, cmd, data);
|
||||
}
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Module infrastructure
|
||||
*/
|
||||
#include "../net/if_module.h"
|
||||
|
||||
IF_MODULE(MODULE_CLASS_DRIVER, canloop, "")
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: opt_rumpkernel.h,v 1.5 2016/04/15 01:35:26 ozaki-r Exp $ */
|
||||
/* $NetBSD: opt_rumpkernel.h,v 1.6 2017/05/27 21:02:56 bouyer Exp $ */
|
||||
|
||||
#ifndef __NetBSD__
|
||||
#define __NetBSD__
|
||||
@ -22,6 +22,8 @@
|
||||
|
||||
#define MPLS 1
|
||||
|
||||
#define CAN 1
|
||||
|
||||
#define SOSEND_NO_LOAN
|
||||
|
||||
#undef PIPE_SOCKETPAIR /* would need uipc_usrreq.c */
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: rumpdefs.h,v 1.36 2016/02/02 01:15:58 pooka Exp $ */
|
||||
/* $NetBSD: rumpdefs.h,v 1.37 2017/05/27 21:02:56 bouyer Exp $ */
|
||||
|
||||
/*
|
||||
* AUTOMATICALLY GENERATED. DO NOT EDIT.
|
||||
@ -240,7 +240,8 @@ enum rump_vtype { RUMP_VNON, RUMP_VREG, RUMP_VDIR, RUMP_VBLK, RUMP_VCHR, RUMP_VL
|
||||
#define RUMP_AF_IEEE80211 32
|
||||
#define RUMP_AF_MPLS 33
|
||||
#define RUMP_AF_ROUTE 34
|
||||
#define RUMP_AF_MAX 35
|
||||
#define RUMP_AF_CAN 35
|
||||
#define RUMP_AF_MAX 36
|
||||
#define RUMP_PF_UNSPEC RUMP_AF_UNSPEC
|
||||
#define RUMP_PF_LOCAL RUMP_AF_LOCAL
|
||||
#define RUMP_PF_UNIX RUMP_PF_LOCAL
|
||||
@ -277,6 +278,7 @@ enum rump_vtype { RUMP_VNON, RUMP_VREG, RUMP_VDIR, RUMP_VBLK, RUMP_VCHR, RUMP_VL
|
||||
#define RUMP_PF_BLUETOOTH RUMP_AF_BLUETOOTH
|
||||
#define RUMP_PF_MPLS RUMP_AF_MPLS
|
||||
#define RUMP_PF_ROUTE RUMP_AF_ROUTE
|
||||
#define RUMP_PF_CAN RUMP_AF_CAN
|
||||
#define RUMP_PF_MAX RUMP_AF_MAX
|
||||
#define RUMP_SO_DEBUG 0x0001
|
||||
#define RUMP_SO_ACCEPTCONN 0x0002
|
||||
|
@ -1,9 +1,9 @@
|
||||
# $NetBSD: Makefile.rumpnetcomp,v 1.18 2017/04/14 02:43:28 ozaki-r Exp $
|
||||
# $NetBSD: Makefile.rumpnetcomp,v 1.19 2017/05/27 21:02:56 bouyer Exp $
|
||||
#
|
||||
|
||||
.include <bsd.own.mk>
|
||||
|
||||
RUMPNETCOMP= agr bridge net net80211 netbt netinet netinet6 netipsec
|
||||
RUMPNETCOMP= agr bridge net net80211 netbt netcan netinet netinet6 netipsec
|
||||
RUMPNETCOMP+= gif netmpls npf l2tp local pppoe shmif tap tun vlan
|
||||
|
||||
.if ${MKSLJIT} != "no" || make(rumpdescribe)
|
||||
|
20
sys/rump/net/lib/libnetcan/Makefile
Normal file
20
sys/rump/net/lib/libnetcan/Makefile
Normal file
@ -0,0 +1,20 @@
|
||||
# $NetBSD: Makefile,v 1.2 2017/05/27 21:02:56 bouyer Exp $
|
||||
#
|
||||
|
||||
NOLINT= #defined
|
||||
|
||||
.include <bsd.own.mk>
|
||||
|
||||
.PATH: ${.CURDIR}/../../../../netcan
|
||||
|
||||
LIB= rumpnet_netcan
|
||||
COMMENT=CAN (PF_CAN)
|
||||
|
||||
IOCONF= NETCAN.ioconf
|
||||
|
||||
SRCS= can.c can_pcb.c can_proto.c if_canloop.c
|
||||
|
||||
SRCS+= netcan_component.c
|
||||
|
||||
.include <bsd.lib.mk>
|
||||
.include <bsd.klinks.mk>
|
7
sys/rump/net/lib/libnetcan/NETCAN.ioconf
Normal file
7
sys/rump/net/lib/libnetcan/NETCAN.ioconf
Normal file
@ -0,0 +1,7 @@
|
||||
# $NetBSD: NETCAN.ioconf,v 1.2 2017/05/27 21:02:56 bouyer Exp $
|
||||
|
||||
ioconf netcan
|
||||
|
||||
include "conf/files"
|
||||
|
||||
pseudo-device canloop
|
52
sys/rump/net/lib/libnetcan/netcan_component.c
Normal file
52
sys/rump/net/lib/libnetcan/netcan_component.c
Normal file
@ -0,0 +1,52 @@
|
||||
/* $NetBSD: netcan_component.c,v 1.2 2017/05/27 21:02:56 bouyer Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010 Antti Kantee. All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: netcan_component.c,v 1.2 2017/05/27 21:02:56 bouyer Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/domain.h>
|
||||
#include <sys/protosw.h>
|
||||
|
||||
#include <rump-sys/kern.h>
|
||||
#include <rump-sys/net.h>
|
||||
#include <net/netisr.h>
|
||||
#include <netcan/can_var.h>
|
||||
|
||||
RUMP_COMPONENT(RUMP_COMPONENT_NET)
|
||||
{
|
||||
extern struct domain candomain;
|
||||
|
||||
domain_attach(&candomain);
|
||||
rump_netisr_register(NETISR_CAN, canintr);
|
||||
}
|
||||
|
||||
void canloopinit(void);
|
||||
RUMP_COMPONENT(RUMP_COMPONENT_NET_IF)
|
||||
{
|
||||
canloopinit();
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: mbuf.h,v 1.169 2017/03/31 06:49:44 ozaki-r Exp $ */
|
||||
/* $NetBSD: mbuf.h,v 1.170 2017/05/27 21:02:56 bouyer Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1996, 1997, 1999, 2001, 2007 The NetBSD Foundation, Inc.
|
||||
@ -897,6 +897,7 @@ struct m_tag *m_tag_next(struct mbuf *, struct m_tag *);
|
||||
#define PACKET_TAG_VLAN 1 /* VLAN ID */
|
||||
#define PACKET_TAG_ENCAP 2 /* encapsulation data */
|
||||
#define PACKET_TAG_ESP 3 /* ESP information */
|
||||
#define PACKET_TAG_SO 4 /* sending socket pointer */
|
||||
#define PACKET_TAG_PF 11 /* packet filter */
|
||||
#define PACKET_TAG_ALTQ_QID 12 /* ALTQ queue id */
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: socket.h,v 1.121 2017/02/08 17:58:41 maya Exp $ */
|
||||
/* $NetBSD: socket.h,v 1.122 2017/05/27 21:02:56 bouyer Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
||||
@ -221,7 +221,8 @@ struct accept_filter_arg {
|
||||
#define AF_IEEE80211 32 /* IEEE80211 */
|
||||
#define AF_MPLS 33 /* MultiProtocol Label Switching */
|
||||
#define AF_ROUTE 34 /* Internal Routing Protocol */
|
||||
#define AF_MAX 35
|
||||
#define AF_CAN 35
|
||||
#define AF_MAX 36
|
||||
|
||||
/*
|
||||
* Structure used by kernel to store most
|
||||
@ -330,6 +331,7 @@ struct sockaddr_storage {
|
||||
#define PF_BLUETOOTH AF_BLUETOOTH
|
||||
#define PF_MPLS AF_MPLS
|
||||
#define PF_ROUTE AF_ROUTE
|
||||
#define PF_CAN AF_CAN
|
||||
|
||||
#define PF_MAX AF_MAX
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
# $NetBSD: Makefile,v 1.32 2017/04/14 02:56:48 ozaki-r Exp $
|
||||
# $NetBSD: Makefile,v 1.33 2017/05/27 21:02:56 bouyer Exp $
|
||||
|
||||
.include <bsd.own.mk>
|
||||
|
||||
@ -6,9 +6,9 @@ TESTSDIR= ${TESTSBASE}/net
|
||||
|
||||
TESTS_SUBDIRS= fdpass in_cksum net sys
|
||||
.if (${MKRUMP} != "no") && !defined(BSD_MK_COMPAT_FILE)
|
||||
TESTS_SUBDIRS+= arp bpf bpfilter carp icmp if if_bridge if_gif if_l2tp
|
||||
TESTS_SUBDIRS+= if_loop if_pppoe if_tap if_tun ipsec mcast mpls ndp npf
|
||||
TESTS_SUBDIRS+= route if_vlan
|
||||
TESTS_SUBDIRS+= arp bpf bpfilter can carp icmp if if_bridge if_gif
|
||||
TESTS_SUBDIRS+= if_l2tp if_loop if_pppoe if_tap if_tun ipsec
|
||||
TESTS_SUBDIRS+= mcast mpls ndp npf route if_vlan
|
||||
.if (${MKSLJIT} != "no")
|
||||
TESTS_SUBDIRS+= bpfjit
|
||||
.endif
|
||||
|
21
tests/net/can/Makefile
Normal file
21
tests/net/can/Makefile
Normal file
@ -0,0 +1,21 @@
|
||||
# $NetBSD: Makefile,v 1.2 2017/05/27 21:02:56 bouyer Exp $
|
||||
#
|
||||
|
||||
.include <bsd.own.mk>
|
||||
|
||||
TESTSDIR= ${TESTSBASE}/net/can
|
||||
|
||||
TESTS_C= t_can t_canfilter
|
||||
|
||||
SRCS.t_can= t_can.c h_canutils.c
|
||||
|
||||
SRCS.t_canfilter= t_canfilter.c h_canutils.c
|
||||
|
||||
# XXX we don't use INET here, but we need rumpnet_netinet anyway:
|
||||
# common code in if.c is compiled with -DINET and will dereference ip_pktq,
|
||||
# which is NULL if rumpnet_netinet is not inclued.
|
||||
#
|
||||
LDADD+= -lrumpnet_netcan -lrumpnet_netinet -lrumpnet_net -lrumpnet
|
||||
LDADD+= -lrump -lrumpuser -lrump -lpthread -lrumpdev -lrumpvfs
|
||||
|
||||
.include <bsd.test.mk>
|
200
tests/net/can/h_canutils.c
Normal file
200
tests/net/can/h_canutils.c
Normal file
@ -0,0 +1,200 @@
|
||||
/* $NetBSD: h_canutils.c,v 1.2 2017/05/27 21:02:56 bouyer Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2017 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Manuel Bouyer
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
* CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: h_canutils.c,v 1.2 2017/05/27 21:02:56 bouyer Exp $");
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/sockio.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#include <atf-c.h>
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <netcan/can.h>
|
||||
|
||||
#include <rump/rump.h>
|
||||
#include <rump/rump_syscalls.h>
|
||||
|
||||
#include "h_macros.h"
|
||||
#include "h_canutils.h"
|
||||
|
||||
void
|
||||
cancfg_rump_createif(const char *ifname)
|
||||
{
|
||||
int s, rv;
|
||||
struct ifreq ifr;
|
||||
|
||||
s = -1;
|
||||
if ((s = rump_sys_socket(AF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
|
||||
atf_tc_fail_errno("if config socket");
|
||||
}
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
|
||||
|
||||
if ((rv = rump_sys_ioctl(s, SIOCIFCREATE, &ifr)) < 0) {
|
||||
atf_tc_fail_errno("if config create");
|
||||
}
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
|
||||
|
||||
if ((rv = rump_sys_ioctl(s, SIOCGIFFLAGS, &ifr)) < 0) {
|
||||
atf_tc_fail_errno("if config get flags");
|
||||
}
|
||||
|
||||
ifr.ifr_flags |= IFF_UP;
|
||||
if ((rv = rump_sys_ioctl(s, SIOCSIFFLAGS, &ifr)) < 0) {
|
||||
atf_tc_fail_errno("if config set flags");
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
can_recvfrom(int s, struct can_frame *cf, int *len, struct sockaddr_can *sa)
|
||||
{
|
||||
socklen_t salen;
|
||||
fd_set rfds;
|
||||
struct timeval tmout;
|
||||
int rv;
|
||||
|
||||
memset(cf, 0, sizeof(struct can_frame));
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(s, &rfds);
|
||||
/* wait 1 second for the message (in some tests we expect no message) */
|
||||
tmout.tv_sec = 1;
|
||||
tmout.tv_usec = 0;
|
||||
rv = rump_sys_select(s + 1, &rfds, NULL, NULL, &tmout);
|
||||
switch(rv) {
|
||||
case -1:
|
||||
atf_tc_fail_errno("select");
|
||||
/* NOTREACHED */
|
||||
case 0:
|
||||
/* timeout */
|
||||
errno = EWOULDBLOCK;
|
||||
return -1;
|
||||
default: break;
|
||||
}
|
||||
ATF_CHECK_MSG(FD_ISSET(s, &rfds), "select returns but s not in set");
|
||||
salen = sizeof(struct sockaddr_can);
|
||||
if (( *len = rump_sys_recvfrom(s, cf, sizeof(struct can_frame),
|
||||
0, (struct sockaddr *)sa, &salen)) < 0) {
|
||||
atf_tc_fail_errno("recvfrom");
|
||||
}
|
||||
ATF_CHECK_MSG(rv > 0, "short read on socket");
|
||||
ATF_CHECK_MSG(sa->can_family == AF_CAN,
|
||||
"recvfrom provided wrong %d family", sa->can_family);
|
||||
ATF_CHECK_MSG(salen == sizeof(struct sockaddr_can),
|
||||
"recvfrom provided wrong size %d (!= %ld)", salen, sizeof(sa));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
can_read(int s, struct can_frame *cf, int *len)
|
||||
{
|
||||
fd_set rfds;
|
||||
struct timeval tmout;
|
||||
int rv;
|
||||
|
||||
memset(cf, 0, sizeof(struct can_frame));
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(s, &rfds);
|
||||
/* wait 1 second for the message (in some tests we expect no message) */
|
||||
tmout.tv_sec = 1;
|
||||
tmout.tv_usec = 0;
|
||||
rv = rump_sys_select(s + 1, &rfds, NULL, NULL, &tmout);
|
||||
switch(rv) {
|
||||
case -1:
|
||||
atf_tc_fail_errno("select");
|
||||
/* NOTREACHED */
|
||||
case 0:
|
||||
/* timeout */
|
||||
errno = EWOULDBLOCK;
|
||||
return -1;
|
||||
default: break;
|
||||
}
|
||||
ATF_CHECK_MSG(FD_ISSET(s, &rfds), "select returns but s not in set");
|
||||
if (( *len = rump_sys_read(s, cf, sizeof(struct can_frame))) < 0) {
|
||||
atf_tc_fail_errno("read");
|
||||
}
|
||||
ATF_CHECK_MSG(rv > 0, "short read on socket");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
can_bind(int s, const char *ifname)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
struct sockaddr_can sa;
|
||||
|
||||
strcpy(ifr.ifr_name, ifname );
|
||||
if (rump_sys_ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
|
||||
atf_tc_fail_errno("SIOCGIFINDEX");
|
||||
}
|
||||
ATF_CHECK_MSG(ifr.ifr_ifindex > 0, "%s index is %d (not > 0)",
|
||||
ifname, ifr.ifr_ifindex);
|
||||
|
||||
sa.can_family = AF_CAN;
|
||||
sa.can_ifindex = ifr.ifr_ifindex;
|
||||
|
||||
if (rump_sys_bind(s, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
|
||||
atf_tc_fail_errno("bind");
|
||||
}
|
||||
return ifr.ifr_ifindex;
|
||||
}
|
||||
|
||||
int
|
||||
can_socket_with_own(void)
|
||||
{
|
||||
int s;
|
||||
int v;
|
||||
|
||||
if ((s = rump_sys_socket(AF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
|
||||
atf_tc_fail_errno("CAN socket");
|
||||
}
|
||||
v = 1;
|
||||
if (rump_sys_setsockopt(s, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS,
|
||||
&v, sizeof(v)) < 0) {
|
||||
atf_tc_fail_errno("setsockopt(CAN_RAW_RECV_OWN_MSGS)");
|
||||
}
|
||||
return s;
|
||||
}
|
37
tests/net/can/h_canutils.h
Normal file
37
tests/net/can/h_canutils.h
Normal file
@ -0,0 +1,37 @@
|
||||
/* $NetBSD: h_canutils.h,v 1.2 2017/05/27 21:02:56 bouyer Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2017 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Manuel Bouyer
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
* CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
void cancfg_rump_createif(const char *);
|
||||
int can_recvfrom(int, struct can_frame *, int *, struct sockaddr_can *);
|
||||
int can_read(int, struct can_frame *, int *);
|
||||
int can_bind(int s, const char *);
|
||||
int can_socket_with_own(void);
|
734
tests/net/can/t_can.c
Normal file
734
tests/net/can/t_can.c
Normal file
@ -0,0 +1,734 @@
|
||||
/* $NetBSD: t_can.c,v 1.2 2017/05/27 21:02:56 bouyer Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2017 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Manuel Bouyer
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
* CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: t_can.c,v 1.2 2017/05/27 21:02:56 bouyer Exp $");
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/sockio.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#include <atf-c.h>
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <netcan/can.h>
|
||||
|
||||
#include <rump/rump.h>
|
||||
#include <rump/rump_syscalls.h>
|
||||
|
||||
#include "h_macros.h"
|
||||
#include "h_canutils.h"
|
||||
|
||||
ATF_TC(canlocreate);
|
||||
ATF_TC_HEAD(canlocreate, tc)
|
||||
{
|
||||
|
||||
atf_tc_set_md_var(tc, "descr", "check CAN loopback create/destroy");
|
||||
atf_tc_set_md_var(tc, "timeout", "5");
|
||||
}
|
||||
|
||||
ATF_TC_BODY(canlocreate, tc)
|
||||
{
|
||||
const char ifname[] = "canlo0";
|
||||
int s, rv;
|
||||
struct ifreq ifr;
|
||||
|
||||
rump_init();
|
||||
cancfg_rump_createif(ifname);
|
||||
|
||||
s = -1;
|
||||
if ((s = rump_sys_socket(AF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
|
||||
atf_tc_fail_errno("if config socket(2)");
|
||||
}
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
|
||||
|
||||
if ((rv = rump_sys_ioctl(s, SIOCIFDESTROY, &ifr)) < 0) {
|
||||
atf_tc_fail_errno("if config destroy");
|
||||
}
|
||||
}
|
||||
|
||||
ATF_TC(cannoown);
|
||||
ATF_TC_HEAD(cannoown, tc)
|
||||
{
|
||||
|
||||
atf_tc_set_md_var(tc, "descr", "check that CAN sockets don't gets its own message");
|
||||
atf_tc_set_md_var(tc, "timeout", "5");
|
||||
}
|
||||
|
||||
ATF_TC_BODY(cannoown, tc)
|
||||
{
|
||||
const char ifname[] = "canlo0";
|
||||
int s, rv, v;
|
||||
socklen_t vlen;
|
||||
struct sockaddr_can sa;
|
||||
int ifindex;
|
||||
struct can_frame cf_send, cf_receive;
|
||||
|
||||
rump_init();
|
||||
cancfg_rump_createif(ifname);
|
||||
|
||||
if ((s = rump_sys_socket(AF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
|
||||
atf_tc_fail_errno("CAN socket");
|
||||
}
|
||||
|
||||
ifindex = can_bind(s, ifname);
|
||||
|
||||
/* check sockopt CAN_RAW_LOOPBACK */
|
||||
vlen = sizeof(v);
|
||||
if (rump_sys_getsockopt(s, SOL_CAN_RAW, CAN_RAW_LOOPBACK,
|
||||
&v, &vlen) < 0) {
|
||||
atf_tc_fail_errno("getsockopt(CAN_RAW_LOOPBACK)");
|
||||
}
|
||||
ATF_CHECK_MSG(vlen == sizeof(v), "getsockopt(CAN_RAW_LOOPBACK) returns wrong len %d", vlen);
|
||||
ATF_CHECK_MSG(v == 1, "CAN_RAW_LOOPBACK is not on by default");
|
||||
|
||||
/* check sockopt CAN_RAW_RECV_OWN_MSGS, and set it */
|
||||
vlen = sizeof(v);
|
||||
if (rump_sys_getsockopt(s, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS,
|
||||
&v, &vlen) < 0) {
|
||||
atf_tc_fail_errno("getsockopt(CAN_RAW_RECV_OWN_MSGS)");
|
||||
}
|
||||
ATF_CHECK_MSG(vlen == sizeof(v), "getsockopt(CAN_RAW_RECV_OWN_MSGS) returns wrong len %d", vlen);
|
||||
ATF_CHECK_MSG(v == 0, "CAN_RAW_RECV_OWN_MSGS is not off by default");
|
||||
|
||||
/*
|
||||
* send a single byte message, but make sure remaining payload is
|
||||
* not 0.
|
||||
*/
|
||||
|
||||
memset(&cf_send, 0, sizeof(cf_send));
|
||||
cf_send.can_id = 1;
|
||||
cf_send.can_dlc = 1;
|
||||
cf_send.data[0] = 0xde;
|
||||
cf_send.data[1] = 0xad;
|
||||
cf_send.data[2] = 0xbe;
|
||||
cf_send.data[3] = 0xef;
|
||||
|
||||
if (rump_sys_write(s, &cf_send, sizeof(cf_send) - 7) < 0) {
|
||||
atf_tc_fail_errno("write");
|
||||
}
|
||||
|
||||
/* now try to read */
|
||||
if (can_recvfrom(s, &cf_receive, &rv, &sa) < 0) {
|
||||
if (errno == EWOULDBLOCK)
|
||||
return; /* expected timeout */
|
||||
atf_tc_fail_errno("can_recvfrom");
|
||||
}
|
||||
|
||||
ATF_CHECK_MSG(sa.can_ifindex == ifindex,
|
||||
"recvfrom provided wrong ifindex %d (!= %d)",
|
||||
sa.can_ifindex, ifindex);
|
||||
atf_tc_fail("we got our own message");
|
||||
}
|
||||
|
||||
ATF_TC(canwritelo);
|
||||
ATF_TC_HEAD(canwritelo, tc)
|
||||
{
|
||||
|
||||
atf_tc_set_md_var(tc, "descr", "check that CAN sockets gets its own message via write");
|
||||
atf_tc_set_md_var(tc, "timeout", "5");
|
||||
}
|
||||
|
||||
ATF_TC_BODY(canwritelo, tc)
|
||||
{
|
||||
const char ifname[] = "canlo0";
|
||||
int s, rv, v;
|
||||
socklen_t vlen;
|
||||
struct can_frame cf_send, cf_receive;
|
||||
|
||||
rump_init();
|
||||
cancfg_rump_createif(ifname);
|
||||
|
||||
s = can_socket_with_own();
|
||||
|
||||
can_bind(s, ifname);
|
||||
|
||||
/* check sockopt CAN_RAW_LOOPBACK */
|
||||
vlen = sizeof(v);
|
||||
if (rump_sys_getsockopt(s, SOL_CAN_RAW, CAN_RAW_LOOPBACK,
|
||||
&v, &vlen) < 0) {
|
||||
atf_tc_fail_errno("getsockopt(CAN_RAW_LOOPBACK)");
|
||||
}
|
||||
ATF_CHECK_MSG(vlen == sizeof(v), "getsockopt(CAN_RAW_LOOPBACK) returns wrong len %d", vlen);
|
||||
ATF_CHECK_MSG(v == 1, "CAN_RAW_LOOPBACK is not on by default");
|
||||
|
||||
/* check that sockopt CAN_RAW_RECV_OWN_MSGS is on */
|
||||
vlen = sizeof(v);
|
||||
if (rump_sys_getsockopt(s, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS,
|
||||
&v, &vlen) < 0) {
|
||||
atf_tc_fail_errno("getsockopt(CAN_RAW_RECV_OWN_MSGS)");
|
||||
}
|
||||
ATF_CHECK_MSG(v == 1, "CAN_RAW_RECV_OWN_MSGS is not on");
|
||||
|
||||
/*
|
||||
* send a single byte message, but make sure remaining payload is
|
||||
* not 0.
|
||||
*/
|
||||
|
||||
memset(&cf_send, 0, sizeof(cf_send));
|
||||
cf_send.can_id = 1;
|
||||
cf_send.can_dlc = 1;
|
||||
cf_send.data[0] = 0xde;
|
||||
cf_send.data[1] = 0xad;
|
||||
cf_send.data[2] = 0xbe;
|
||||
cf_send.data[3] = 0xef;
|
||||
|
||||
if (rump_sys_write(s, &cf_send, sizeof(cf_send) - 7) < 0) {
|
||||
atf_tc_fail_errno("write");
|
||||
}
|
||||
|
||||
if (can_read(s, &cf_receive, &rv) < 0) {
|
||||
atf_tc_fail_errno("can_read");
|
||||
}
|
||||
|
||||
memset(&cf_send, 0, sizeof(cf_send));
|
||||
cf_send.can_id = 1;
|
||||
cf_send.can_dlc = 1;
|
||||
cf_send.data[0] = 0xde;
|
||||
/* other data[] are expected to be 0 */
|
||||
|
||||
ATF_CHECK_MSG(memcmp(&cf_send, &cf_receive, sizeof(cf_send)) == 0,
|
||||
"received packet is not what we sent");
|
||||
}
|
||||
|
||||
ATF_TC(canwriteunbound);
|
||||
ATF_TC_HEAD(canwriteunbound, tc)
|
||||
{
|
||||
|
||||
atf_tc_set_md_var(tc, "descr", "check that write to unbound CAN sockets fails");
|
||||
atf_tc_set_md_var(tc, "timeout", "5");
|
||||
}
|
||||
|
||||
ATF_TC_BODY(canwriteunbound, tc)
|
||||
{
|
||||
const char ifname[] = "canlo0";
|
||||
int s, rv;
|
||||
struct can_frame cf_send;
|
||||
|
||||
rump_init();
|
||||
cancfg_rump_createif(ifname);
|
||||
|
||||
s = -1;
|
||||
if ((s = rump_sys_socket(AF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
|
||||
atf_tc_fail_errno("CAN socket");
|
||||
}
|
||||
|
||||
/*
|
||||
* send a single byte message.
|
||||
* not 0.
|
||||
*/
|
||||
|
||||
memset(&cf_send, 0, sizeof(cf_send));
|
||||
cf_send.can_id = 1;
|
||||
cf_send.can_dlc = 1;
|
||||
cf_send.data[0] = 0xde;
|
||||
|
||||
rv = rump_sys_write(s, &cf_send, sizeof(cf_send) - 7);
|
||||
ATF_CHECK_MSG(rv < 0 && errno == EDESTADDRREQ,
|
||||
"write to unbound socket didn't fail");
|
||||
}
|
||||
|
||||
ATF_TC(cansendtolo);
|
||||
ATF_TC_HEAD(cansendtolo, tc)
|
||||
{
|
||||
|
||||
atf_tc_set_md_var(tc, "descr", "check that CAN sockets gets its own message via sendto");
|
||||
atf_tc_set_md_var(tc, "timeout", "5");
|
||||
}
|
||||
|
||||
ATF_TC_BODY(cansendtolo, tc)
|
||||
{
|
||||
const char ifname[] = "canlo0";
|
||||
int s, rv;
|
||||
struct sockaddr_can sa;
|
||||
struct ifreq ifr;
|
||||
struct can_frame cf_send, cf_receive;
|
||||
|
||||
rump_init();
|
||||
cancfg_rump_createif(ifname);
|
||||
|
||||
s = can_socket_with_own();
|
||||
|
||||
strcpy(ifr.ifr_name, ifname );
|
||||
if ((rv = rump_sys_ioctl(s, SIOCGIFINDEX, &ifr)) < 0) {
|
||||
atf_tc_fail_errno("SIOCGIFINDEX");
|
||||
}
|
||||
ATF_CHECK_MSG(ifr.ifr_ifindex > 0, "%s index is %d (not > 0)",
|
||||
ifname, ifr.ifr_ifindex);
|
||||
|
||||
sa.can_family = AF_CAN;
|
||||
sa.can_ifindex = ifr.ifr_ifindex;
|
||||
|
||||
/*
|
||||
* send a single byte message, but make sure remaining payload is
|
||||
* not 0.
|
||||
*/
|
||||
|
||||
memset(&cf_send, 0, sizeof(cf_send));
|
||||
cf_send.can_id = 1;
|
||||
cf_send.can_dlc = 1;
|
||||
cf_send.data[0] = 0xde;
|
||||
cf_send.data[1] = 0xad;
|
||||
cf_send.data[2] = 0xbe;
|
||||
cf_send.data[3] = 0xef;
|
||||
|
||||
if (rump_sys_sendto(s, &cf_send, sizeof(cf_send) - 7,
|
||||
0, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
|
||||
atf_tc_fail_errno("sendto");
|
||||
}
|
||||
|
||||
if (can_read(s, &cf_receive, &rv) < 0) {
|
||||
atf_tc_fail_errno("read");
|
||||
}
|
||||
|
||||
memset(&cf_send, 0, sizeof(cf_send));
|
||||
cf_send.can_id = 1;
|
||||
cf_send.can_dlc = 1;
|
||||
cf_send.data[0] = 0xde;
|
||||
/* other data[] are expected to be 0 */
|
||||
|
||||
ATF_CHECK_MSG(memcmp(&cf_send, &cf_receive, sizeof(cf_send)) == 0,
|
||||
"received packet is not what we sent");
|
||||
}
|
||||
|
||||
ATF_TC(cansendtowrite);
|
||||
ATF_TC_HEAD(cansendtowrite, tc)
|
||||
{
|
||||
|
||||
atf_tc_set_md_var(tc, "descr", "check that write after sendto on unbound socket fails");
|
||||
atf_tc_set_md_var(tc, "timeout", "5");
|
||||
}
|
||||
|
||||
ATF_TC_BODY(cansendtowrite, tc)
|
||||
{
|
||||
const char ifname[] = "canlo0";
|
||||
int s, rv;
|
||||
struct sockaddr_can sa;
|
||||
struct ifreq ifr;
|
||||
struct can_frame cf_send, cf_receive;
|
||||
|
||||
rump_init();
|
||||
cancfg_rump_createif(ifname);
|
||||
|
||||
s = can_socket_with_own();
|
||||
|
||||
strcpy(ifr.ifr_name, ifname );
|
||||
if ((rv = rump_sys_ioctl(s, SIOCGIFINDEX, &ifr)) < 0) {
|
||||
atf_tc_fail_errno("SIOCGIFINDEX");
|
||||
}
|
||||
ATF_CHECK_MSG(ifr.ifr_ifindex > 0, "%s index is %d (not > 0)",
|
||||
ifname, ifr.ifr_ifindex);
|
||||
|
||||
sa.can_family = AF_CAN;
|
||||
sa.can_ifindex = ifr.ifr_ifindex;
|
||||
|
||||
/*
|
||||
* send a single byte message.
|
||||
* not 0.
|
||||
*/
|
||||
|
||||
memset(&cf_send, 0, sizeof(cf_send));
|
||||
cf_send.can_id = 1;
|
||||
cf_send.can_dlc = 1;
|
||||
cf_send.data[0] = 0xde;
|
||||
|
||||
if (rump_sys_sendto(s, &cf_send, sizeof(cf_send) - 7,
|
||||
0, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
|
||||
atf_tc_fail_errno("sendto");
|
||||
}
|
||||
|
||||
if (can_read(s, &cf_receive, &rv) < 0) {
|
||||
atf_tc_fail_errno("read");
|
||||
}
|
||||
|
||||
memset(&cf_send, 0, sizeof(cf_send));
|
||||
cf_send.can_id = 1;
|
||||
cf_send.can_dlc = 1;
|
||||
cf_send.data[0] = 0xde;
|
||||
/* other data[] are expected to be 0 */
|
||||
|
||||
ATF_CHECK_MSG(memcmp(&cf_send, &cf_receive, sizeof(cf_send)) == 0,
|
||||
"received packet is not what we sent");
|
||||
|
||||
rv = rump_sys_write(s, &cf_send, sizeof(cf_send) - 7);
|
||||
ATF_CHECK_MSG(rv < 0 && errno == EDESTADDRREQ,
|
||||
"write to unbound socket didn't fail");
|
||||
}
|
||||
|
||||
ATF_TC(canreadlocal);
|
||||
ATF_TC_HEAD(canreadlocal, tc)
|
||||
{
|
||||
|
||||
atf_tc_set_md_var(tc, "descr", "check all CAN sockets get messages");
|
||||
atf_tc_set_md_var(tc, "timeout", "5");
|
||||
}
|
||||
|
||||
ATF_TC_BODY(canreadlocal, tc)
|
||||
{
|
||||
const char ifname[] = "canlo0";
|
||||
int s1, rv1;
|
||||
int s2, rv2;
|
||||
struct can_frame cf_send, cf_receive1, cf_receive2;
|
||||
|
||||
rump_init();
|
||||
cancfg_rump_createif(ifname);
|
||||
|
||||
memset(&cf_send, 0, sizeof(cf_send));
|
||||
cf_send.can_id = 1;
|
||||
cf_send.can_dlc = 8;
|
||||
cf_send.data[0] = 0xde;
|
||||
cf_send.data[1] = 0xad;
|
||||
cf_send.data[2] = 0xbe;
|
||||
cf_send.data[3] = 0xef;
|
||||
|
||||
|
||||
if ((s1 = rump_sys_socket(AF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
|
||||
atf_tc_fail_errno("CAN socket");
|
||||
}
|
||||
|
||||
/* create a second socket */
|
||||
|
||||
s2 = can_socket_with_own();
|
||||
|
||||
can_bind(s2, ifname);
|
||||
|
||||
/*
|
||||
* send a single byte message, but make sure remaining payload is
|
||||
* not 0.
|
||||
*/
|
||||
|
||||
if (rump_sys_write(s2, &cf_send, sizeof(cf_send)) < 0) {
|
||||
atf_tc_fail_errno("write");
|
||||
}
|
||||
|
||||
if (can_read(s2, &cf_receive2, &rv2) < 0) {
|
||||
atf_tc_fail_errno("can_read");
|
||||
}
|
||||
|
||||
ATF_CHECK_MSG(memcmp(&cf_send, &cf_receive2, sizeof(cf_send)) == 0,
|
||||
"received (2) packet is not what we sent");
|
||||
|
||||
/* now check first socket */
|
||||
if (can_read(s1, &cf_receive1, &rv1) < 0) {
|
||||
atf_tc_fail_errno("can_read");
|
||||
}
|
||||
|
||||
ATF_CHECK_MSG(memcmp(&cf_send, &cf_receive1, sizeof(cf_send)) == 0,
|
||||
"received (1) packet is not what we sent");
|
||||
}
|
||||
|
||||
ATF_TC(canrecvfrom);
|
||||
ATF_TC_HEAD(canrecvfrom, tc)
|
||||
{
|
||||
|
||||
atf_tc_set_md_var(tc, "descr", "check that recvfrom gets the CAN interface");
|
||||
atf_tc_set_md_var(tc, "timeout", "5");
|
||||
}
|
||||
|
||||
ATF_TC_BODY(canrecvfrom, tc)
|
||||
{
|
||||
const char ifname[] = "canlo0";
|
||||
int s1, rv1;
|
||||
int s2, rv2;
|
||||
struct can_frame cf_send, cf_receive1, cf_receive2;
|
||||
int ifindex;
|
||||
struct sockaddr_can sa;
|
||||
|
||||
rump_init();
|
||||
cancfg_rump_createif(ifname);
|
||||
|
||||
memset(&cf_send, 0, sizeof(cf_send));
|
||||
cf_send.can_id = 1;
|
||||
cf_send.can_dlc = 8;
|
||||
cf_send.data[0] = 0xde;
|
||||
cf_send.data[1] = 0xad;
|
||||
cf_send.data[2] = 0xbe;
|
||||
cf_send.data[3] = 0xef;
|
||||
|
||||
|
||||
s1 = -1;
|
||||
if ((s1 = rump_sys_socket(AF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
|
||||
atf_tc_fail_errno("CAN socket");
|
||||
}
|
||||
|
||||
/* create a second socket */
|
||||
|
||||
s2 = can_socket_with_own();
|
||||
|
||||
ifindex = can_bind(s2, ifname);
|
||||
|
||||
if (rump_sys_write(s2, &cf_send, sizeof(cf_send)) < 0) {
|
||||
atf_tc_fail_errno("write");
|
||||
}
|
||||
|
||||
if (can_read(s2, &cf_receive2, &rv2) < 0) {
|
||||
atf_tc_fail_errno("can_read");
|
||||
}
|
||||
|
||||
ATF_CHECK_MSG(memcmp(&cf_send, &cf_receive2, sizeof(cf_send)) == 0,
|
||||
"received (2) packet is not what we sent");
|
||||
|
||||
/* now check first socket */
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
if (can_recvfrom(s1, &cf_receive1, &rv1, &sa) < 0) {
|
||||
atf_tc_fail_errno("can_recvfrom");
|
||||
}
|
||||
|
||||
ATF_CHECK_MSG(memcmp(&cf_send, &cf_receive1, sizeof(cf_send)) == 0,
|
||||
"recvfrom (1) packet is not what we sent");
|
||||
ATF_CHECK_MSG(sa.can_ifindex == ifindex,
|
||||
"recvfrom provided wrong ifindex %d (!= %d)",
|
||||
sa.can_ifindex, ifindex);
|
||||
}
|
||||
|
||||
ATF_TC(canbindfilter);
|
||||
ATF_TC_HEAD(canbindfilter, tc)
|
||||
{
|
||||
|
||||
atf_tc_set_md_var(tc, "descr", "check that socket bound to an interface doens't get other interface's messages");
|
||||
atf_tc_set_md_var(tc, "timeout", "5");
|
||||
}
|
||||
|
||||
ATF_TC_BODY(canbindfilter, tc)
|
||||
{
|
||||
const char ifname[] = "canlo0";
|
||||
const char ifname2[] = "canlo1";
|
||||
int s1, rv1;
|
||||
int s2, rv2;
|
||||
struct sockaddr_can sa;
|
||||
int ifindex2;
|
||||
struct can_frame cf_send, cf_receive1, cf_receive2;
|
||||
|
||||
rump_init();
|
||||
cancfg_rump_createif(ifname);
|
||||
cancfg_rump_createif(ifname2);
|
||||
|
||||
memset(&cf_send, 0, sizeof(cf_send));
|
||||
cf_send.can_id = 1;
|
||||
cf_send.can_dlc = 8;
|
||||
cf_send.data[0] = 0xde;
|
||||
cf_send.data[1] = 0xad;
|
||||
cf_send.data[2] = 0xbe;
|
||||
cf_send.data[3] = 0xef;
|
||||
|
||||
|
||||
s1 = can_socket_with_own();
|
||||
|
||||
can_bind(s1, ifname);
|
||||
|
||||
/* create a second socket */
|
||||
|
||||
s2 = can_socket_with_own();
|
||||
|
||||
ifindex2 = can_bind(s2, ifname2);
|
||||
|
||||
if (rump_sys_write(s2, &cf_send, sizeof(cf_send)) < 0) {
|
||||
atf_tc_fail_errno("write");
|
||||
}
|
||||
|
||||
if (can_read(s2, &cf_receive2, &rv2) < 0) {
|
||||
atf_tc_fail_errno("read");
|
||||
}
|
||||
|
||||
ATF_CHECK_MSG(memcmp(&cf_send, &cf_receive2, sizeof(cf_send)) == 0,
|
||||
"received (2) packet is not what we sent");
|
||||
|
||||
/* now check first socket */
|
||||
if (can_recvfrom(s1, &cf_receive1, &rv1, &sa) < 0) {
|
||||
if (errno == EWOULDBLOCK) {
|
||||
/* expected case */
|
||||
return;
|
||||
}
|
||||
atf_tc_fail_errno("can_recvfrom");
|
||||
}
|
||||
ATF_CHECK_MSG(memcmp(&cf_send, &cf_receive1, sizeof(cf_send)) == 0,
|
||||
"recvfrom (1) packet is not what we sent");
|
||||
ATF_CHECK_MSG(sa.can_ifindex == ifindex2,
|
||||
"recvfrom provided wrong ifindex %d (!= %d)",
|
||||
sa.can_ifindex, ifindex2);
|
||||
atf_tc_fail("we got message from other interface");
|
||||
}
|
||||
|
||||
ATF_TC(cannoloop);
|
||||
ATF_TC_HEAD(cannoloop, tc)
|
||||
{
|
||||
|
||||
atf_tc_set_md_var(tc, "descr", "check that disabling loopback works");
|
||||
atf_tc_set_md_var(tc, "timeout", "5");
|
||||
}
|
||||
|
||||
ATF_TC_BODY(cannoloop, tc)
|
||||
{
|
||||
const char ifname[] = "canlo0";
|
||||
int s1, rv1;
|
||||
int s2, rv2;
|
||||
int v;
|
||||
socklen_t vlen;
|
||||
struct sockaddr_can sa;
|
||||
struct can_frame cf_send, cf_receive1, cf_receive2;
|
||||
socklen_t salen;
|
||||
int ifindex;
|
||||
fd_set rfds;
|
||||
struct timeval tmout;
|
||||
|
||||
rump_init();
|
||||
cancfg_rump_createif(ifname);
|
||||
|
||||
memset(&cf_send, 0, sizeof(cf_send));
|
||||
cf_send.can_id = 1;
|
||||
cf_send.can_dlc = 8;
|
||||
cf_send.data[0] = 0xde;
|
||||
cf_send.data[1] = 0xad;
|
||||
cf_send.data[2] = 0xbe;
|
||||
cf_send.data[3] = 0xef;
|
||||
|
||||
|
||||
s1 = can_socket_with_own();
|
||||
v = 0;
|
||||
if (rump_sys_setsockopt(s1, SOL_CAN_RAW, CAN_RAW_LOOPBACK,
|
||||
&v, sizeof(v)) < 0) {
|
||||
atf_tc_fail_errno("setsockopt(LOOPBACK)");
|
||||
}
|
||||
v = -1;
|
||||
vlen = sizeof(v);
|
||||
if (rump_sys_getsockopt(s1, SOL_CAN_RAW, CAN_RAW_LOOPBACK,
|
||||
&v, &vlen) < 0) {
|
||||
atf_tc_fail_errno("getsockopt(CAN_RAW_LOOPBACK)");
|
||||
}
|
||||
ATF_CHECK_MSG(vlen == sizeof(v), "getsockopt(CAN_RAW_LOOPBACK) returns wrong len %d", vlen);
|
||||
ATF_CHECK_MSG(v == 0, "CAN_RAW_LOOPBACK is not off");
|
||||
|
||||
ifindex = can_bind(s1, ifname);
|
||||
|
||||
/* create a second socket */
|
||||
s2 = can_socket_with_own();
|
||||
|
||||
if (rump_sys_write(s1, &cf_send, sizeof(cf_send)) < 0) {
|
||||
atf_tc_fail_errno("write");
|
||||
}
|
||||
|
||||
|
||||
/* now check the sockets */
|
||||
memset(&cf_receive1, 0, sizeof(cf_receive1));
|
||||
memset(&cf_receive2, 0, sizeof(cf_receive2));
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(s1, &rfds);
|
||||
FD_SET(s2, &rfds);
|
||||
/* we should receive no message; wait for 1 seconds */
|
||||
tmout.tv_sec = 1;
|
||||
tmout.tv_usec = 0;
|
||||
rv1 = rump_sys_select(MAX(s1,s2) + 1, &rfds, NULL, NULL, &tmout);
|
||||
switch(rv1) {
|
||||
case -1:
|
||||
atf_tc_fail_errno("select");
|
||||
break;
|
||||
case 0:
|
||||
/* timeout: expected case */
|
||||
return;
|
||||
default: break;
|
||||
}
|
||||
salen = sizeof(sa);
|
||||
ATF_CHECK_MSG(FD_ISSET(s1, &rfds) || FD_ISSET(s2, &rfds),
|
||||
"select returns but s1 nor s2 is in set");
|
||||
if (FD_ISSET(s1, &rfds)) {
|
||||
if (( rv1 = rump_sys_recvfrom(s1, &cf_receive1,
|
||||
sizeof(cf_receive1), 0,
|
||||
(struct sockaddr *)&sa, &salen)) < 0) {
|
||||
atf_tc_fail_errno("recvfrom");
|
||||
}
|
||||
|
||||
ATF_CHECK_MSG(rv1 > 0, "short read on socket");
|
||||
|
||||
ATF_CHECK_MSG(memcmp(&cf_send, &cf_receive1,
|
||||
sizeof(cf_send)) == 0,
|
||||
"recvfrom (1) packet is not what we sent");
|
||||
ATF_CHECK_MSG(sa.can_family == AF_CAN,
|
||||
"recvfrom provided wrong %d family", sa.can_family);
|
||||
ATF_CHECK_MSG(salen == sizeof(sa),
|
||||
"recvfrom provided wrong size %d (!= %ld)",
|
||||
salen, sizeof(sa));
|
||||
ATF_CHECK_MSG(sa.can_ifindex == ifindex,
|
||||
"recvfrom provided wrong ifindex %d (!= %d)",
|
||||
sa.can_ifindex, ifindex);
|
||||
atf_tc_fail_nonfatal("we got message on s1");
|
||||
}
|
||||
if (FD_ISSET(s2, &rfds)) {
|
||||
if (( rv2 = rump_sys_recvfrom(s2, &cf_receive2,
|
||||
sizeof(cf_receive2), 0,
|
||||
(struct sockaddr *)&sa, &salen)) < 0) {
|
||||
atf_tc_fail_errno("recvfrom");
|
||||
}
|
||||
|
||||
ATF_CHECK_MSG(rv2 > 0, "short read on socket");
|
||||
|
||||
ATF_CHECK_MSG(memcmp(&cf_send, &cf_receive2,
|
||||
sizeof(cf_send)) == 0,
|
||||
"recvfrom (2) packet is not what we sent");
|
||||
ATF_CHECK_MSG(sa.can_family == AF_CAN,
|
||||
"recvfrom provided wrong %d family", sa.can_family);
|
||||
ATF_CHECK_MSG(salen == sizeof(sa),
|
||||
"recvfrom provided wrong size %d (!= %ld)",
|
||||
salen, sizeof(sa));
|
||||
ATF_CHECK_MSG(sa.can_ifindex == ifindex,
|
||||
"recvfrom provided wrong ifindex %d (!= %d)",
|
||||
sa.can_ifindex, ifindex);
|
||||
atf_tc_fail_nonfatal("we got message on s2");
|
||||
}
|
||||
}
|
||||
|
||||
ATF_TP_ADD_TCS(tp)
|
||||
{
|
||||
|
||||
ATF_TP_ADD_TC(tp, canlocreate);
|
||||
ATF_TP_ADD_TC(tp, cannoown);
|
||||
ATF_TP_ADD_TC(tp, canwritelo);
|
||||
ATF_TP_ADD_TC(tp, canwriteunbound);
|
||||
ATF_TP_ADD_TC(tp, cansendtolo);
|
||||
ATF_TP_ADD_TC(tp, cansendtowrite);
|
||||
ATF_TP_ADD_TC(tp, canreadlocal);
|
||||
ATF_TP_ADD_TC(tp, canrecvfrom);
|
||||
ATF_TP_ADD_TC(tp, canbindfilter);
|
||||
ATF_TP_ADD_TC(tp, cannoloop);
|
||||
return atf_no_error();
|
||||
}
|
464
tests/net/can/t_canfilter.c
Normal file
464
tests/net/can/t_canfilter.c
Normal file
@ -0,0 +1,464 @@
|
||||
/* $NetBSD: t_canfilter.c,v 1.2 2017/05/27 21:02:56 bouyer Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2017 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Manuel Bouyer
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
* CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: t_canfilter.c,v 1.2 2017/05/27 21:02:56 bouyer Exp $");
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/sockio.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#include <atf-c.h>
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <netcan/can.h>
|
||||
|
||||
#include <rump/rump.h>
|
||||
#include <rump/rump_syscalls.h>
|
||||
|
||||
#include "h_macros.h"
|
||||
#include "h_canutils.h"
|
||||
|
||||
ATF_TC(canfilter_basic);
|
||||
ATF_TC_HEAD(canfilter_basic, tc)
|
||||
{
|
||||
|
||||
atf_tc_set_md_var(tc, "descr", "check a simple CAN filter");
|
||||
atf_tc_set_md_var(tc, "timeout", "5");
|
||||
}
|
||||
|
||||
ATF_TC_BODY(canfilter_basic, tc)
|
||||
{
|
||||
const char ifname[] = "canlo0";
|
||||
int s, rv;
|
||||
struct can_frame cf_send, cf_receive;
|
||||
struct can_filter cfi;
|
||||
|
||||
rump_init();
|
||||
cancfg_rump_createif(ifname);
|
||||
|
||||
s = can_socket_with_own();
|
||||
|
||||
can_bind(s, ifname);
|
||||
|
||||
/* set filter */
|
||||
#define MY_ID 1
|
||||
cfi.can_id = MY_ID;
|
||||
cfi.can_mask = CAN_SFF_MASK | CAN_EFF_FLAG;
|
||||
if (rump_sys_setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER,
|
||||
&cfi, sizeof(cfi)) < 0) {
|
||||
atf_tc_fail_errno("setsockopt(CAN_RAW_FILTER)");
|
||||
}
|
||||
|
||||
/*
|
||||
* send a single byte message, but make sure remaining payload is
|
||||
* not 0.
|
||||
*/
|
||||
|
||||
memset(&cf_send, 0, sizeof(cf_send));
|
||||
cf_send.can_id = MY_ID;
|
||||
cf_send.can_dlc = 1;
|
||||
cf_send.data[0] = 0xde;
|
||||
cf_send.data[1] = 0xad;
|
||||
cf_send.data[2] = 0xbe;
|
||||
cf_send.data[3] = 0xef;
|
||||
|
||||
if (rump_sys_write(s, &cf_send, sizeof(cf_send) - 7) < 0) {
|
||||
atf_tc_fail_errno("write");
|
||||
}
|
||||
|
||||
if (can_read(s, &cf_receive, &rv) < 0) {
|
||||
atf_tc_fail_errno("read");
|
||||
}
|
||||
|
||||
ATF_CHECK_MSG(rv > 0, "short read on socket");
|
||||
|
||||
memset(&cf_send, 0, sizeof(cf_send));
|
||||
cf_send.can_id = MY_ID;
|
||||
cf_send.can_dlc = 1;
|
||||
cf_send.data[0] = 0xde;
|
||||
/* other data[] are expected to be 0 */
|
||||
|
||||
ATF_CHECK_MSG(memcmp(&cf_send, &cf_receive, sizeof(cf_send)) == 0,
|
||||
"received packet is not what we sent");
|
||||
|
||||
/* now send a packet with CAN_RTR_FLAG. Should pass too */
|
||||
|
||||
memset(&cf_send, 0, sizeof(cf_send));
|
||||
cf_send.can_id = MY_ID | CAN_RTR_FLAG;
|
||||
cf_send.can_dlc = 1;
|
||||
cf_send.data[0] = 0xde;
|
||||
cf_send.data[1] = 0xad;
|
||||
cf_send.data[2] = 0xbe;
|
||||
cf_send.data[3] = 0xef;
|
||||
|
||||
if (rump_sys_write(s, &cf_send, sizeof(cf_send) - 7) < 0) {
|
||||
atf_tc_fail_errno("write");
|
||||
}
|
||||
|
||||
if (can_read(s, &cf_receive, &rv) < 0) {
|
||||
atf_tc_fail_errno("read");
|
||||
}
|
||||
|
||||
ATF_CHECK_MSG(rv > 0, "short read on socket");
|
||||
|
||||
memset(&cf_send, 0, sizeof(cf_send));
|
||||
cf_send.can_id = MY_ID | CAN_RTR_FLAG;
|
||||
cf_send.can_dlc = 1;
|
||||
cf_send.data[0] = 0xde;
|
||||
/* other data[] are expected to be 0 */
|
||||
|
||||
ATF_CHECK_MSG(memcmp(&cf_send, &cf_receive, sizeof(cf_send)) == 0,
|
||||
"received packet is not what we sent");
|
||||
|
||||
/* now send a packet for a different id. Should not pass */
|
||||
|
||||
memset(&cf_send, 0, sizeof(cf_send));
|
||||
cf_send.can_id = MY_ID + 1;
|
||||
cf_send.can_dlc = 1;
|
||||
cf_send.data[0] = 0xde;
|
||||
cf_send.data[1] = 0xad;
|
||||
cf_send.data[2] = 0xbe;
|
||||
cf_send.data[3] = 0xef;
|
||||
|
||||
if (rump_sys_write(s, &cf_send, sizeof(cf_send) - 7) < 0) {
|
||||
atf_tc_fail_errno("write");
|
||||
}
|
||||
|
||||
if (can_read(s, &cf_receive, &rv) < 0) {
|
||||
if (errno == EWOULDBLOCK)
|
||||
return; /* expected timeout */
|
||||
atf_tc_fail_errno("read");
|
||||
}
|
||||
|
||||
ATF_CHECK_MSG(rv > 0, "short read on socket");
|
||||
|
||||
memset(&cf_send, 0, sizeof(cf_send));
|
||||
cf_send.can_id = MY_ID + 1;
|
||||
cf_send.can_dlc = 1;
|
||||
cf_send.data[0] = 0xde;
|
||||
/* other data[] are expected to be 0 */
|
||||
|
||||
ATF_CHECK_MSG(memcmp(&cf_send, &cf_receive, sizeof(cf_send)) == 0,
|
||||
"received packet is not what we sent");
|
||||
atf_tc_fail("we got our own message");
|
||||
#undef MY_ID
|
||||
}
|
||||
|
||||
ATF_TC(canfilter_null);
|
||||
ATF_TC_HEAD(canfilter_null, tc)
|
||||
{
|
||||
|
||||
atf_tc_set_md_var(tc, "descr", "check a NULL CAN filter");
|
||||
atf_tc_set_md_var(tc, "timeout", "5");
|
||||
}
|
||||
|
||||
ATF_TC_BODY(canfilter_null, tc)
|
||||
{
|
||||
const char ifname[] = "canlo0";
|
||||
int s, rv;
|
||||
struct can_frame cf_send, cf_receive;
|
||||
struct can_filter cfi[2];
|
||||
socklen_t cfilen;
|
||||
|
||||
rump_init();
|
||||
cancfg_rump_createif(ifname);
|
||||
|
||||
s = can_socket_with_own();
|
||||
can_bind(s, ifname);
|
||||
|
||||
if (rump_sys_setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER,
|
||||
NULL, 0) < 0) {
|
||||
atf_tc_fail_errno("setsockopt(CAN_RAW_FILTER)");
|
||||
}
|
||||
|
||||
/* get filter: should be NULL */
|
||||
cfilen = sizeof(cfi);
|
||||
if (rump_sys_getsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER,
|
||||
&cfi, &cfilen) < 0) {
|
||||
atf_tc_fail_errno("getsockopt(CAN_RAW_FILTER)");
|
||||
}
|
||||
ATF_CHECK_MSG(cfilen == 0,
|
||||
"CAN_RAW_FILTER returns wrong len (%d)", cfilen);
|
||||
/*
|
||||
* send a single byte message, but make sure remaining payload is
|
||||
* not 0.
|
||||
*/
|
||||
#define MY_ID 1
|
||||
|
||||
memset(&cf_send, 0, sizeof(cf_send));
|
||||
cf_send.can_id = MY_ID;
|
||||
cf_send.can_dlc = 1;
|
||||
cf_send.data[0] = 0xde;
|
||||
cf_send.data[1] = 0xad;
|
||||
cf_send.data[2] = 0xbe;
|
||||
cf_send.data[3] = 0xef;
|
||||
|
||||
if (rump_sys_write(s, &cf_send, sizeof(cf_send) - 7) < 0) {
|
||||
atf_tc_fail_errno("write");
|
||||
}
|
||||
|
||||
if (can_read(s, &cf_receive, &rv) < 0) {
|
||||
if (errno == EWOULDBLOCK)
|
||||
return; /* expected timeout */
|
||||
atf_tc_fail_errno("read");
|
||||
}
|
||||
|
||||
ATF_CHECK_MSG(rv > 0, "short read on socket");
|
||||
|
||||
memset(&cf_send, 0, sizeof(cf_send));
|
||||
cf_send.can_id = MY_ID;
|
||||
cf_send.can_dlc = 1;
|
||||
cf_send.data[0] = 0xde;
|
||||
/* other data[] are expected to be 0 */
|
||||
|
||||
ATF_CHECK_MSG(memcmp(&cf_send, &cf_receive, sizeof(cf_send)) == 0,
|
||||
"received packet is not what we sent");
|
||||
atf_tc_fail("we got our own message");
|
||||
#undef MY_ID
|
||||
}
|
||||
|
||||
ATF_TC(canfilter_multiple);
|
||||
ATF_TC_HEAD(canfilter_multiple, tc)
|
||||
{
|
||||
|
||||
atf_tc_set_md_var(tc, "descr", "check multiple CAN filters");
|
||||
atf_tc_set_md_var(tc, "timeout", "5");
|
||||
}
|
||||
|
||||
ATF_TC_BODY(canfilter_multiple, tc)
|
||||
{
|
||||
const char ifname[] = "canlo0";
|
||||
int s, rv;
|
||||
struct can_frame cf_send, cf_receive;
|
||||
struct can_filter cfi[2];
|
||||
|
||||
rump_init();
|
||||
cancfg_rump_createif(ifname);
|
||||
|
||||
s = can_socket_with_own();
|
||||
|
||||
can_bind(s, ifname);
|
||||
|
||||
/* set filter: accept MY_ID and MY_ID+1 */
|
||||
#define MY_ID 1
|
||||
cfi[0].can_id = MY_ID;
|
||||
cfi[0].can_mask = CAN_SFF_MASK | CAN_EFF_FLAG;
|
||||
cfi[1].can_id = MY_ID + 1;
|
||||
cfi[1].can_mask = CAN_SFF_MASK | CAN_EFF_FLAG;
|
||||
if (rump_sys_setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER,
|
||||
&cfi, sizeof(cfi)) < 0) {
|
||||
atf_tc_fail_errno("setsockopt(CAN_RAW_FILTER)");
|
||||
}
|
||||
|
||||
/*
|
||||
* send a single byte message, but make sure remaining payload is
|
||||
* not 0.
|
||||
*/
|
||||
|
||||
memset(&cf_send, 0, sizeof(cf_send));
|
||||
cf_send.can_id = MY_ID;
|
||||
cf_send.can_dlc = 1;
|
||||
cf_send.data[0] = 0xde;
|
||||
cf_send.data[1] = 0xad;
|
||||
cf_send.data[2] = 0xbe;
|
||||
cf_send.data[3] = 0xef;
|
||||
|
||||
if (rump_sys_write(s, &cf_send, sizeof(cf_send) - 7) < 0) {
|
||||
atf_tc_fail_errno("write");
|
||||
}
|
||||
|
||||
if (can_read(s, &cf_receive, &rv) < 0) {
|
||||
atf_tc_fail_errno("read");
|
||||
}
|
||||
|
||||
ATF_CHECK_MSG(rv > 0, "short read on socket");
|
||||
|
||||
memset(&cf_send, 0, sizeof(cf_send));
|
||||
cf_send.can_id = MY_ID;
|
||||
cf_send.can_dlc = 1;
|
||||
cf_send.data[0] = 0xde;
|
||||
/* other data[] are expected to be 0 */
|
||||
|
||||
ATF_CHECK_MSG(memcmp(&cf_send, &cf_receive, sizeof(cf_send)) == 0,
|
||||
"received packet is not what we sent");
|
||||
|
||||
/* now send a packet with MY_ID+1. Should pass too */
|
||||
|
||||
memset(&cf_send, 0, sizeof(cf_send));
|
||||
cf_send.can_id = MY_ID + 1;
|
||||
cf_send.can_dlc = 1;
|
||||
cf_send.data[0] = 0xde;
|
||||
cf_send.data[1] = 0xad;
|
||||
cf_send.data[2] = 0xbe;
|
||||
cf_send.data[3] = 0xef;
|
||||
|
||||
if (rump_sys_write(s, &cf_send, sizeof(cf_send) - 7) < 0) {
|
||||
atf_tc_fail_errno("write");
|
||||
}
|
||||
|
||||
if (can_read(s, &cf_receive, &rv) < 0) {
|
||||
atf_tc_fail_errno("read");
|
||||
}
|
||||
|
||||
ATF_CHECK_MSG(rv > 0, "short read on socket");
|
||||
|
||||
memset(&cf_send, 0, sizeof(cf_send));
|
||||
cf_send.can_id = MY_ID + 1;
|
||||
cf_send.can_dlc = 1;
|
||||
cf_send.data[0] = 0xde;
|
||||
/* other data[] are expected to be 0 */
|
||||
|
||||
ATF_CHECK_MSG(memcmp(&cf_send, &cf_receive, sizeof(cf_send)) == 0,
|
||||
"received packet is not what we sent");
|
||||
|
||||
/* now send a packet with MY_ID + 2. Should not pass */
|
||||
|
||||
memset(&cf_send, 0, sizeof(cf_send));
|
||||
cf_send.can_id = MY_ID + 2;
|
||||
cf_send.can_dlc = 1;
|
||||
cf_send.data[0] = 0xde;
|
||||
cf_send.data[1] = 0xad;
|
||||
cf_send.data[2] = 0xbe;
|
||||
cf_send.data[3] = 0xef;
|
||||
|
||||
if (rump_sys_write(s, &cf_send, sizeof(cf_send) - 7) < 0) {
|
||||
atf_tc_fail_errno("write");
|
||||
}
|
||||
|
||||
if (can_read(s, &cf_receive, &rv) < 0) {
|
||||
if (errno == EWOULDBLOCK)
|
||||
return; /* expected timeout */
|
||||
atf_tc_fail_errno("read");
|
||||
}
|
||||
|
||||
ATF_CHECK_MSG(rv > 0, "short read on socket");
|
||||
|
||||
memset(&cf_send, 0, sizeof(cf_send));
|
||||
cf_send.can_id = MY_ID + 2;
|
||||
cf_send.can_dlc = 1;
|
||||
cf_send.data[0] = 0xde;
|
||||
/* other data[] are expected to be 0 */
|
||||
|
||||
ATF_CHECK_MSG(memcmp(&cf_send, &cf_receive, sizeof(cf_send)) == 0,
|
||||
"received packet is not what we sent");
|
||||
atf_tc_fail("we got our own message");
|
||||
#undef MY_ID
|
||||
}
|
||||
|
||||
ATF_TC(canfilter_get);
|
||||
ATF_TC_HEAD(canfilter_get, tc)
|
||||
{
|
||||
|
||||
atf_tc_set_md_var(tc, "descr", "check reading CAN filters");
|
||||
atf_tc_set_md_var(tc, "timeout", "5");
|
||||
}
|
||||
|
||||
ATF_TC_BODY(canfilter_get, tc)
|
||||
{
|
||||
const char ifname[] = "canlo0";
|
||||
int s;
|
||||
struct can_filter cfi[2];
|
||||
socklen_t cfilen;
|
||||
|
||||
rump_init();
|
||||
cancfg_rump_createif(ifname);
|
||||
|
||||
s = -1;
|
||||
if ((s = rump_sys_socket(AF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
|
||||
atf_tc_fail_errno("CAN socket");
|
||||
}
|
||||
|
||||
cfilen = sizeof(cfi);
|
||||
/* get filter: should be default filter */
|
||||
if (rump_sys_getsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER,
|
||||
&cfi, &cfilen) < 0) {
|
||||
atf_tc_fail_errno("getsockopt(CAN_RAW_FILTER)");
|
||||
}
|
||||
ATF_CHECK_MSG(cfilen == sizeof(struct can_filter),
|
||||
"CAN_RAW_FILTER returns wrong len (%d)", cfilen);
|
||||
ATF_CHECK_MSG(cfi[0].can_id == 0 && cfi[0].can_mask == 0,
|
||||
"CAN_RAW_FILTER returns wrong filter (%d, %d)",
|
||||
cfi[0].can_id, cfi[0].can_mask);
|
||||
|
||||
/* set filter: accept MY_ID and MY_ID+1 */
|
||||
#define MY_ID 1
|
||||
cfi[0].can_id = MY_ID;
|
||||
cfi[0].can_mask = CAN_SFF_MASK | CAN_EFF_FLAG;
|
||||
cfi[1].can_id = MY_ID + 1;
|
||||
cfi[1].can_mask = CAN_SFF_MASK;
|
||||
if (rump_sys_setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER,
|
||||
&cfi, sizeof(cfi)) < 0) {
|
||||
atf_tc_fail_errno("setsockopt(CAN_RAW_FILTER)");
|
||||
}
|
||||
|
||||
/* and read back */
|
||||
cfilen = sizeof(cfi);
|
||||
memset(cfi, 0, cfilen);
|
||||
if (rump_sys_getsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER,
|
||||
&cfi, &cfilen) < 0) {
|
||||
atf_tc_fail_errno("getsockopt(CAN_RAW_FILTER)");
|
||||
}
|
||||
ATF_CHECK_MSG(cfilen == sizeof(struct can_filter) * 2,
|
||||
"CAN_RAW_FILTER returns wrong len (%d)", cfilen);
|
||||
ATF_CHECK_MSG(cfi[0].can_id == MY_ID &&
|
||||
cfi[0].can_mask == (CAN_SFF_MASK | CAN_EFF_FLAG),
|
||||
"CAN_RAW_FILTER returns wrong filter 0 (%d, %d)",
|
||||
cfi[0].can_id, cfi[0].can_mask);
|
||||
ATF_CHECK_MSG(cfi[1].can_id == MY_ID + 1 &&
|
||||
cfi[1].can_mask == CAN_SFF_MASK,
|
||||
"CAN_RAW_FILTER returns wrong filter 1 (%d, %d)",
|
||||
cfi[1].can_id, cfi[1].can_mask);
|
||||
|
||||
#undef MY_ID
|
||||
}
|
||||
|
||||
ATF_TP_ADD_TCS(tp)
|
||||
{
|
||||
|
||||
ATF_TP_ADD_TC(tp, canfilter_basic);
|
||||
ATF_TP_ADD_TC(tp, canfilter_null);
|
||||
ATF_TP_ADD_TC(tp, canfilter_multiple);
|
||||
ATF_TP_ADD_TC(tp, canfilter_get);
|
||||
return atf_no_error();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user