From 20c60154100742a87e9c5a45e05a6085976e8621 Mon Sep 17 00:00:00 2001 From: thuermann Date: Wed, 25 Apr 2007 08:38:52 +0000 Subject: [PATCH] Update patch files to current kernel versions. git-svn-id: svn://svn.berlios.de//socketcan/trunk@242 030b6a49-0b11-0410-94ab-b0dab22257f2 --- patches/{2.6.20.3.diff => 2.6.20.7.diff} | 0 patches/{2.6.21-rc4.diff => 2.6.21-rc7.diff} | 64 +- ...6.21-rc3_1_Includes_Makefiles_ipv6fix.diff | 160 - ...tworking-R180-2.6.21-rc3_2_New_Source.diff | 4874 ---------------- ...networking-R180-2.6.21-rc3_X_Complete.diff | 5034 ----------------- 5 files changed, 32 insertions(+), 10100 deletions(-) rename patches/{2.6.20.3.diff => 2.6.20.7.diff} (100%) rename patches/{2.6.21-rc4.diff => 2.6.21-rc7.diff} (67%) delete mode 100644 patches/linux-2.6.21-rc3/can-networking-R180-2.6.21-rc3_1_Includes_Makefiles_ipv6fix.diff delete mode 100644 patches/linux-2.6.21-rc3/can-networking-R180-2.6.21-rc3_2_New_Source.diff delete mode 100644 patches/linux-2.6.21-rc3/can-networking-R180-2.6.21-rc3_X_Complete.diff diff --git a/patches/2.6.20.3.diff b/patches/2.6.20.7.diff similarity index 100% rename from patches/2.6.20.3.diff rename to patches/2.6.20.7.diff diff --git a/patches/2.6.21-rc4.diff b/patches/2.6.21-rc7.diff similarity index 67% rename from patches/2.6.21-rc4.diff rename to patches/2.6.21-rc7.diff index 416afc3..e15e464 100644 --- a/patches/2.6.21-rc4.diff +++ b/patches/2.6.21-rc7.diff @@ -1,6 +1,6 @@ -diff -ruN linux-2.6.21-rc4/CREDITS linux/CREDITS ---- linux-2.6.21-rc4/CREDITS 2007-03-19 10:16:51.000000000 +0000 -+++ linux/CREDITS 2007-03-19 10:18:20.000000000 +0000 +diff -ruN linux-2.6.21-rc7/CREDITS linux/CREDITS +--- linux-2.6.21-rc7/CREDITS 2007-04-25 08:17:49.000000000 +0000 ++++ linux/CREDITS 2007-04-25 08:21:39.000000000 +0000 @@ -1324,6 +1324,14 @@ S: 5623 HZ Eindhoven S: The Netherlands @@ -31,10 +31,10 @@ diff -ruN linux-2.6.21-rc4/CREDITS linux/CREDITS N: Jon Tombs E: jon@gte.esi.us.es W: http://www.esi.us.es/~jon -diff -ruN linux-2.6.21-rc4/MAINTAINERS linux/MAINTAINERS ---- linux-2.6.21-rc4/MAINTAINERS 2007-03-19 10:16:52.000000000 +0000 -+++ linux/MAINTAINERS 2007-03-19 10:18:20.000000000 +0000 -@@ -856,6 +856,15 @@ +diff -ruN linux-2.6.21-rc7/MAINTAINERS linux/MAINTAINERS +--- linux-2.6.21-rc7/MAINTAINERS 2007-04-25 08:17:49.000000000 +0000 ++++ linux/MAINTAINERS 2007-04-25 08:21:39.000000000 +0000 +@@ -871,6 +871,15 @@ T: git kernel.org:/pub/scm/linux/kernel/git/mchehab/v4l-dvb.git S: Maintained @@ -50,9 +50,9 @@ diff -ruN linux-2.6.21-rc4/MAINTAINERS linux/MAINTAINERS CALGARY x86-64 IOMMU P: Muli Ben-Yehuda M: muli@il.ibm.com -diff -ruN linux-2.6.21-rc4/drivers/net/Makefile linux/drivers/net/Makefile ---- linux-2.6.21-rc4/drivers/net/Makefile 2007-03-19 10:17:08.000000000 +0000 -+++ linux/drivers/net/Makefile 2007-03-19 10:18:20.000000000 +0000 +diff -ruN linux-2.6.21-rc7/drivers/net/Makefile linux/drivers/net/Makefile +--- linux-2.6.21-rc7/drivers/net/Makefile 2007-04-25 08:17:52.000000000 +0000 ++++ linux/drivers/net/Makefile 2007-04-25 08:21:39.000000000 +0000 @@ -8,6 +8,7 @@ obj-$(CONFIG_CHELSIO_T1) += chelsio/ obj-$(CONFIG_CHELSIO_T3) += cxgb3/ @@ -61,9 +61,9 @@ diff -ruN linux-2.6.21-rc4/drivers/net/Makefile linux/drivers/net/Makefile obj-$(CONFIG_BONDING) += bonding/ obj-$(CONFIG_ATL1) += atl1/ obj-$(CONFIG_GIANFAR) += gianfar_driver.o -diff -ruN linux-2.6.21-rc4/include/linux/if_arp.h linux/include/linux/if_arp.h ---- linux-2.6.21-rc4/include/linux/if_arp.h 2007-03-19 10:11:25.000000000 +0000 -+++ linux/include/linux/if_arp.h 2007-03-19 10:18:20.000000000 +0000 +diff -ruN linux-2.6.21-rc7/include/linux/if_arp.h linux/include/linux/if_arp.h +--- linux-2.6.21-rc7/include/linux/if_arp.h 2007-04-13 20:48:14.000000000 +0000 ++++ linux/include/linux/if_arp.h 2007-04-25 08:21:39.000000000 +0000 @@ -52,6 +52,7 @@ #define ARPHRD_ROSE 270 #define ARPHRD_X25 271 /* CCITT X.25 */ @@ -72,9 +72,9 @@ diff -ruN linux-2.6.21-rc4/include/linux/if_arp.h linux/include/linux/if_arp.h #define ARPHRD_PPP 512 #define ARPHRD_CISCO 513 /* Cisco HDLC */ #define ARPHRD_HDLC ARPHRD_CISCO -diff -ruN linux-2.6.21-rc4/include/linux/if_ether.h linux/include/linux/if_ether.h ---- linux-2.6.21-rc4/include/linux/if_ether.h 2006-06-18 01:49:35.000000000 +0000 -+++ linux/include/linux/if_ether.h 2007-03-19 10:18:20.000000000 +0000 +diff -ruN linux-2.6.21-rc7/include/linux/if_ether.h linux/include/linux/if_ether.h +--- linux-2.6.21-rc7/include/linux/if_ether.h 2007-04-13 20:48:14.000000000 +0000 ++++ linux/include/linux/if_ether.h 2007-04-25 08:21:39.000000000 +0000 @@ -88,6 +88,7 @@ #define ETH_P_WAN_PPP 0x0007 /* Dummy type for WAN PPP frames*/ #define ETH_P_PPP_MP 0x0008 /* Dummy type for PPP MP frames */ @@ -83,9 +83,9 @@ diff -ruN linux-2.6.21-rc4/include/linux/if_ether.h linux/include/linux/if_ether #define ETH_P_PPPTALK 0x0010 /* Dummy type for Atalk over PPP*/ #define ETH_P_TR_802_2 0x0011 /* 802.2 frames */ #define ETH_P_MOBITEX 0x0015 /* Mobitex (kaz@cafe.net) */ -diff -ruN linux-2.6.21-rc4/include/linux/socket.h linux/include/linux/socket.h ---- linux-2.6.21-rc4/include/linux/socket.h 2007-03-19 10:17:19.000000000 +0000 -+++ linux/include/linux/socket.h 2007-03-19 10:18:20.000000000 +0000 +diff -ruN linux-2.6.21-rc7/include/linux/socket.h linux/include/linux/socket.h +--- linux-2.6.21-rc7/include/linux/socket.h 2007-04-25 08:17:54.000000000 +0000 ++++ linux/include/linux/socket.h 2007-04-25 08:21:39.000000000 +0000 @@ -185,6 +185,7 @@ #define AF_PPPOX 24 /* PPPoX sockets */ #define AF_WANPIPE 25 /* Wanpipe API Sockets */ @@ -102,9 +102,9 @@ diff -ruN linux-2.6.21-rc4/include/linux/socket.h linux/include/linux/socket.h #define PF_TIPC AF_TIPC #define PF_BLUETOOTH AF_BLUETOOTH #define PF_IUCV AF_IUCV -diff -ruN linux-2.6.21-rc4/include/linux/tty.h linux/include/linux/tty.h ---- linux-2.6.21-rc4/include/linux/tty.h 2007-03-19 10:17:19.000000000 +0000 -+++ linux/include/linux/tty.h 2007-03-19 10:18:20.000000000 +0000 +diff -ruN linux-2.6.21-rc7/include/linux/tty.h linux/include/linux/tty.h +--- linux-2.6.21-rc7/include/linux/tty.h 2007-04-25 08:17:54.000000000 +0000 ++++ linux/include/linux/tty.h 2007-04-25 08:21:39.000000000 +0000 @@ -24,7 +24,7 @@ #define NR_PTYS CONFIG_LEGACY_PTY_COUNT /* Number of legacy ptys */ #define NR_UNIX98_PTY_DEFAULT 4096 /* Default maximum for Unix98 ptys */ @@ -122,9 +122,9 @@ diff -ruN linux-2.6.21-rc4/include/linux/tty.h linux/include/linux/tty.h /* * This character is the same as _POSIX_VDISABLE: it cannot be used as -diff -ruN linux-2.6.21-rc4/net/Kconfig linux/net/Kconfig ---- linux-2.6.21-rc4/net/Kconfig 2007-03-19 10:17:19.000000000 +0000 -+++ linux/net/Kconfig 2007-03-19 10:18:20.000000000 +0000 +diff -ruN linux-2.6.21-rc7/net/Kconfig linux/net/Kconfig +--- linux-2.6.21-rc7/net/Kconfig 2007-04-25 08:17:54.000000000 +0000 ++++ linux/net/Kconfig 2007-04-25 08:21:39.000000000 +0000 @@ -217,6 +217,7 @@ endmenu @@ -133,9 +133,9 @@ diff -ruN linux-2.6.21-rc4/net/Kconfig linux/net/Kconfig source "net/irda/Kconfig" source "net/bluetooth/Kconfig" source "net/ieee80211/Kconfig" -diff -ruN linux-2.6.21-rc4/net/Makefile linux/net/Makefile ---- linux-2.6.21-rc4/net/Makefile 2007-03-19 10:17:19.000000000 +0000 -+++ linux/net/Makefile 2007-03-19 10:18:20.000000000 +0000 +diff -ruN linux-2.6.21-rc7/net/Makefile linux/net/Makefile +--- linux-2.6.21-rc7/net/Makefile 2007-04-25 08:17:54.000000000 +0000 ++++ linux/net/Makefile 2007-04-25 08:21:39.000000000 +0000 @@ -34,6 +34,7 @@ obj-$(CONFIG_NETROM) += netrom/ obj-$(CONFIG_ROSE) += rose/ @@ -144,10 +144,10 @@ diff -ruN linux-2.6.21-rc4/net/Makefile linux/net/Makefile obj-$(CONFIG_IRDA) += irda/ obj-$(CONFIG_BT) += bluetooth/ obj-$(CONFIG_SUNRPC) += sunrpc/ -diff -ruN linux-2.6.21-rc4/net/ipv6/addrconf.c linux/net/ipv6/addrconf.c ---- linux-2.6.21-rc4/net/ipv6/addrconf.c 2007-03-19 10:17:20.000000000 +0000 -+++ linux/net/ipv6/addrconf.c 2007-03-19 10:18:20.000000000 +0000 -@@ -2174,6 +2174,10 @@ +diff -ruN linux-2.6.21-rc7/net/ipv6/addrconf.c linux/net/ipv6/addrconf.c +--- linux-2.6.21-rc7/net/ipv6/addrconf.c 2007-04-25 08:17:54.000000000 +0000 ++++ linux/net/ipv6/addrconf.c 2007-04-25 08:21:39.000000000 +0000 +@@ -2177,6 +2177,10 @@ struct inet6_dev *idev = __in6_dev_get(dev); int run_pending = 0; diff --git a/patches/linux-2.6.21-rc3/can-networking-R180-2.6.21-rc3_1_Includes_Makefiles_ipv6fix.diff b/patches/linux-2.6.21-rc3/can-networking-R180-2.6.21-rc3_1_Includes_Makefiles_ipv6fix.diff deleted file mode 100644 index 9cf2468..0000000 --- a/patches/linux-2.6.21-rc3/can-networking-R180-2.6.21-rc3_1_Includes_Makefiles_ipv6fix.diff +++ /dev/null @@ -1,160 +0,0 @@ -diff -u -r a/CREDITS b/CREDITS ---- a/CREDITS 2007-03-09 09:51:49.000000000 +0100 -+++ b/CREDITS 2007-03-09 13:19:16.000000000 +0100 -@@ -1324,6 +1324,14 @@ - S: 5623 HZ Eindhoven - S: The Netherlands - -+N: Oliver Hartkopp -+E: oliver.hartkopp@volkswagen.de -+W: http://www.volkswagen.de -+D: Controller Area Network (network layer core) -+S: Brieffach 1776 -+S: 38436 Wolfsburg -+S: Germany -+ - N: Andrew Haylett - E: ajh@primag.co.uk - D: Selection mechanism -@@ -3277,6 +3285,14 @@ - S: F-35042 Rennes Cedex - S: France - -+N: Urs Thuermann -+E: urs.thuermann@volkswagen.de -+W: http://www.volkswagen.de -+D: Controller Area Network (network layer core) -+S: Brieffach 1776 -+S: 38436 Wolfsburg -+S: Germany -+ - N: Jon Tombs - E: jon@gte.esi.us.es - W: http://www.esi.us.es/~jon -diff -u -r a/drivers/net/Makefile b/drivers/net/Makefile ---- a/drivers/net/Makefile 2007-03-09 09:52:04.000000000 +0100 -+++ b/drivers/net/Makefile 2007-03-09 13:22:39.000000000 +0100 -@@ -8,6 +8,7 @@ - obj-$(CONFIG_CHELSIO_T1) += chelsio/ - obj-$(CONFIG_CHELSIO_T3) += cxgb3/ - obj-$(CONFIG_EHEA) += ehea/ -+obj-$(CONFIG_CAN) += can/ - obj-$(CONFIG_BONDING) += bonding/ - obj-$(CONFIG_ATL1) += atl1/ - obj-$(CONFIG_GIANFAR) += gianfar_driver.o -diff -u -r a/include/linux/if_arp.h b/include/linux/if_arp.h ---- a/include/linux/if_arp.h 2007-02-04 19:44:54.000000000 +0100 -+++ b/include/linux/if_arp.h 2007-03-09 13:25:02.000000000 +0100 -@@ -52,6 +52,7 @@ - #define ARPHRD_ROSE 270 - #define ARPHRD_X25 271 /* CCITT X.25 */ - #define ARPHRD_HWX25 272 /* Boards with X.25 in firmware */ -+#define ARPHRD_CAN 280 /* Controller Area Network */ - #define ARPHRD_PPP 512 - #define ARPHRD_CISCO 513 /* Cisco HDLC */ - #define ARPHRD_HDLC ARPHRD_CISCO -diff -u -r a/include/linux/if_ether.h b/include/linux/if_ether.h ---- a/include/linux/if_ether.h 2007-02-04 19:44:54.000000000 +0100 -+++ b/include/linux/if_ether.h 2007-03-09 13:25:46.000000000 +0100 -@@ -88,6 +88,7 @@ - #define ETH_P_WAN_PPP 0x0007 /* Dummy type for WAN PPP frames*/ - #define ETH_P_PPP_MP 0x0008 /* Dummy type for PPP MP frames */ - #define ETH_P_LOCALTALK 0x0009 /* Localtalk pseudo type */ -+#define ETH_P_CAN 0x000C /* Controller Area Network */ - #define ETH_P_PPPTALK 0x0010 /* Dummy type for Atalk over PPP*/ - #define ETH_P_TR_802_2 0x0011 /* 802.2 frames */ - #define ETH_P_MOBITEX 0x0015 /* Mobitex (kaz@cafe.net) */ -diff -u -r a/include/linux/socket.h b/include/linux/socket.h ---- a/include/linux/socket.h 2007-03-09 09:52:17.000000000 +0100 -+++ b/include/linux/socket.h 2007-03-09 13:26:58.000000000 +0100 -@@ -185,6 +185,7 @@ - #define AF_PPPOX 24 /* PPPoX sockets */ - #define AF_WANPIPE 25 /* Wanpipe API Sockets */ - #define AF_LLC 26 /* Linux LLC */ -+#define AF_CAN 29 /* Controller Area Network */ - #define AF_TIPC 30 /* TIPC sockets */ - #define AF_BLUETOOTH 31 /* Bluetooth sockets */ - #define AF_IUCV 32 /* IUCV sockets */ -@@ -219,6 +220,7 @@ - #define PF_PPPOX AF_PPPOX - #define PF_WANPIPE AF_WANPIPE - #define PF_LLC AF_LLC -+#define PF_CAN AF_CAN - #define PF_TIPC AF_TIPC - #define PF_BLUETOOTH AF_BLUETOOTH - #define PF_IUCV AF_IUCV -diff -u -r a/include/linux/tty.h b/include/linux/tty.h ---- a/include/linux/tty.h 2007-03-09 09:52:17.000000000 +0100 -+++ b/include/linux/tty.h 2007-03-09 13:28:33.000000000 +0100 -@@ -24,7 +24,7 @@ - #define NR_PTYS CONFIG_LEGACY_PTY_COUNT /* Number of legacy ptys */ - #define NR_UNIX98_PTY_DEFAULT 4096 /* Default maximum for Unix98 ptys */ - #define NR_UNIX98_PTY_MAX (1 << MINORBITS) /* Absolute limit */ --#define NR_LDISCS 17 -+#define NR_LDISCS 18 - - /* line disciplines */ - #define N_TTY 0 -@@ -45,6 +45,7 @@ - #define N_SYNC_PPP 14 /* synchronous PPP */ - #define N_HCI 15 /* Bluetooth HCI UART */ - #define N_GIGASET_M101 16 /* Siemens Gigaset M101 serial DECT adapter */ -+#define N_SLCAN 17 /* Serial / USB serial CAN Adaptors */ - - /* - * This character is the same as _POSIX_VDISABLE: it cannot be used as -diff -u -r a/MAINTAINERS b/MAINTAINERS ---- a/MAINTAINERS 2007-03-09 09:51:50.000000000 +0100 -+++ b/MAINTAINERS 2007-03-09 13:21:51.000000000 +0100 -@@ -856,6 +856,15 @@ - T: git kernel.org:/pub/scm/linux/kernel/git/mchehab/v4l-dvb.git - S: Maintained - -+CAN NETWORK LAYER -+P: Urs Thuermann -+M: urs.thuermann@volkswagen.de -+P: Oliver Hartkopp -+M: oliver.hartkopp@volkswagen.de -+L: socketcan-core@lists.berlios.de -+W: http://developer.berlios.de/projects/socketcan/ -+S: Maintained -+ - CALGARY x86-64 IOMMU - P: Muli Ben-Yehuda - M: muli@il.ibm.com -diff -u -r a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c ---- a/net/ipv6/addrconf.c 2007-03-09 09:52:20.000000000 +0100 -+++ b/net/ipv6/addrconf.c 2007-03-09 13:31:50.000000000 +0100 -@@ -2178,6 +2178,10 @@ - struct inet6_dev *idev = __in6_dev_get(dev); - int run_pending = 0; - -+ /* more non ipv6 compatible dev types to skip here? */ -+ if (dev->type == ARPHRD_CAN) -+ return NOTIFY_OK; -+ - switch(event) { - case NETDEV_REGISTER: - if (!idev) { -diff -u -r a/net/Kconfig b/net/Kconfig ---- a/net/Kconfig 2007-03-09 09:52:18.000000000 +0100 -+++ b/net/Kconfig 2007-03-09 13:29:23.000000000 +0100 -@@ -217,6 +217,7 @@ - endmenu - - source "net/ax25/Kconfig" -+source "net/can/Kconfig" - source "net/irda/Kconfig" - source "net/bluetooth/Kconfig" - source "net/ieee80211/Kconfig" -diff -u -r a/net/Makefile b/net/Makefile ---- a/net/Makefile 2007-03-09 09:52:18.000000000 +0100 -+++ b/net/Makefile 2007-03-09 13:29:55.000000000 +0100 -@@ -34,6 +34,7 @@ - obj-$(CONFIG_NETROM) += netrom/ - obj-$(CONFIG_ROSE) += rose/ - obj-$(CONFIG_AX25) += ax25/ -+obj-$(CONFIG_CAN) += can/ - obj-$(CONFIG_IRDA) += irda/ - obj-$(CONFIG_BT) += bluetooth/ - obj-$(CONFIG_SUNRPC) += sunrpc/ diff --git a/patches/linux-2.6.21-rc3/can-networking-R180-2.6.21-rc3_2_New_Source.diff b/patches/linux-2.6.21-rc3/can-networking-R180-2.6.21-rc3_2_New_Source.diff deleted file mode 100644 index c1d5bdc..0000000 --- a/patches/linux-2.6.21-rc3/can-networking-R180-2.6.21-rc3_2_New_Source.diff +++ /dev/null @@ -1,4874 +0,0 @@ -diff -N -u -r b/drivers/net/can/Kconfig c/drivers/net/can/Kconfig ---- b/drivers/net/can/Kconfig 1970-01-01 01:00:00.000000000 +0100 -+++ c/drivers/net/can/Kconfig 2007-03-09 13:45:53.000000000 +0100 -@@ -0,0 +1,26 @@ -+menu "CAN Device Drivers" -+ depends on CAN -+ -+config CAN_VCAN -+ tristate "Virtual Local CAN Interface (vcan)" -+ depends on CAN -+ default N -+ ---help--- -+ Similar to the network loopback devices, vcan offers a -+ virtual local CAN interface. -+ -+ This driver can also be built as a module. If so, the module -+ will be called vcan. -+ -+config CAN_DEBUG_DEVICES -+ bool "CAN devices debugging messages" -+ depends on CAN -+ default N -+ ---help--- -+ Say Y here if you want the CAN device drivers to produce a bunch of -+ debug messages to the system log. Select this if you are having -+ a problem with CAN support and want to see more of what is going -+ on. -+ -+endmenu -+ -diff -N -u -r b/drivers/net/can/Makefile c/drivers/net/can/Makefile ---- b/drivers/net/can/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ c/drivers/net/can/Makefile 2007-03-09 13:45:53.000000000 +0100 -@@ -0,0 +1,5 @@ -+# -+# Makefile for the Linux Controller Area Network drivers. -+# -+ -+obj-$(CONFIG_CAN_VCAN) += vcan.o -diff -N -u -r b/drivers/net/can/vcan.c c/drivers/net/can/vcan.c ---- b/drivers/net/can/vcan.c 1970-01-01 01:00:00.000000000 +0100 -+++ c/drivers/net/can/vcan.c 2007-03-09 13:45:53.000000000 +0100 -@@ -0,0 +1,301 @@ -+/* -+ * vcan.c - Virtual CAN interface -+ * -+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research -+ * 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, the following disclaimer and -+ * the referenced file 'COPYING'. -+ * 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. Neither the name of Volkswagen nor the names of its contributors -+ * may be used to endorse or promote products derived from this software -+ * without specific prior written permission. -+ * -+ * Alternatively, provided that this notice is retained in full, this -+ * software may be distributed under the terms of the GNU General -+ * Public License ("GPL") version 2 as distributed in the 'COPYING' -+ * file from the main directory of the linux kernel source. -+ * -+ * The provided data structures and external interfaces from this code -+ * are not restricted to be used by modules with a GPL compatible license. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT -+ * OWNER 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. -+ * -+ * Send feedback to -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+RCSID("$Id: vcan.c 168 2007-03-05 13:33:59Z hartkopp $"); -+ -+static __initdata const char banner[] = KERN_INFO "CAN: virtual CAN " -+ "interface " VERSION "\n"; -+ -+MODULE_DESCRIPTION("virtual CAN interface"); -+MODULE_LICENSE("Dual BSD/GPL"); -+MODULE_AUTHOR("Urs Thuermann "); -+ -+#ifdef CONFIG_CAN_DEBUG_DEVICES -+static int debug = 0; -+module_param(debug, int, S_IRUGO); -+#define DBG(args...) (debug & 1 ? \ -+ (printk(KERN_DEBUG "VCAN %s: ", __func__), \ -+ printk(args)) : 0) -+#define DBG_FRAME(args...) (debug & 2 ? can_debug_cframe(args) : 0) -+#define DBG_SKB(skb) (debug & 4 ? can_debug_skb(skb) : 0) -+#else -+#define DBG(args...) -+#define DBG_FRAME(args...) -+#define DBG_SKB(skb) -+#endif -+ -+/* Indicate if this VCAN driver should do a real loopback, or if this */ -+/* should be done in af_can.c */ -+#undef DO_LOOPBACK -+ -+#define STATSIZE sizeof(struct net_device_stats) -+ -+static int numdev = 4; /* default number of virtual CAN interfaces */ -+module_param(numdev, int, S_IRUGO); -+MODULE_PARM_DESC(numdev, "Number of virtual CAN devices"); -+ -+static struct net_device **vcan_devs; /* root pointer to netdevice structs */ -+ -+static int vcan_open(struct net_device *dev) -+{ -+ DBG("%s: interface up\n", dev->name); -+ -+ netif_start_queue(dev); -+ return 0; -+} -+ -+static int vcan_stop(struct net_device *dev) -+{ -+ DBG("%s: interface down\n", dev->name); -+ -+ netif_stop_queue(dev); -+ return 0; -+} -+ -+#ifdef DO_LOOPBACK -+ -+static void vcan_rx(struct sk_buff *skb, struct net_device *dev) -+{ -+ struct net_device_stats *stats = netdev_priv(dev); -+ stats->rx_packets++; -+ stats->rx_bytes += skb->len; -+ -+ skb->protocol = htons(ETH_P_CAN); -+ skb->dev = dev; -+ skb->ip_summed = CHECKSUM_UNNECESSARY; -+ -+ DBG("received skbuff on interface %d\n", dev->ifindex); -+ DBG_SKB(skb); -+ -+ netif_rx(skb); -+} -+ -+#endif -+ -+static int vcan_tx(struct sk_buff *skb, struct net_device *dev) -+{ -+ struct net_device_stats *stats = netdev_priv(dev); -+ int loop; -+ -+ DBG("sending skbuff on interface %s\n", dev->name); -+ DBG_SKB(skb); -+ DBG_FRAME("VCAN: transmit CAN frame", (struct can_frame *)skb->data); -+ -+ stats->tx_packets++; -+ stats->tx_bytes += skb->len; -+ -+ loop = *(struct sock **)skb->cb != NULL; /* loopback required */ -+ -+#ifdef DO_LOOPBACK -+ if (loop) { -+ if (atomic_read(&skb->users) != 1) { -+ struct sk_buff *old_skb = skb; -+ skb = skb_clone(old_skb, GFP_ATOMIC); -+ DBG(" freeing old skbuff %p, using new skbuff %p\n", -+ old_skb, skb); -+ kfree_skb(old_skb); -+ if (!skb) { -+ return 0; -+ } -+ } else -+ skb_orphan(skb); -+ -+ vcan_rx(skb, dev); /* with packet counting */ -+ } else { -+ /* no looped packets => no counting */ -+ kfree_skb(skb); -+ } -+#else -+ /* only count, when the CAN core did a loopback */ -+ if (loop) { -+ stats->rx_packets++; -+ stats->rx_bytes += skb->len; -+ } -+ kfree_skb(skb); -+#endif -+ return 0; -+} -+ -+static int vcan_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -+{ -+ return -EOPNOTSUPP; -+} -+ -+static int vcan_rebuild_header(struct sk_buff *skb) -+{ -+ DBG("skbuff %p\n", skb); -+ DBG_SKB(skb); -+ return 0; -+} -+ -+static int vcan_header(struct sk_buff *skb, struct net_device *dev, -+ unsigned short type, void *daddr, void *saddr, -+ unsigned int len) -+{ -+ DBG("skbuff %p, device %p\n", skb, dev); -+ DBG_SKB(skb); -+ return 0; -+} -+ -+ -+static struct net_device_stats *vcan_get_stats(struct net_device *dev) -+{ -+ struct net_device_stats *stats = netdev_priv(dev); -+ return stats; -+} -+ -+static void vcan_init(struct net_device *dev) -+{ -+ DBG("dev %s\n", dev->name); -+ -+ ether_setup(dev); -+ -+ memset(dev->priv, 0, STATSIZE); -+ -+ dev->type = ARPHRD_CAN; -+ dev->mtu = sizeof(struct can_frame); -+ dev->flags = IFF_NOARP; -+#ifdef DO_LOOPBACK -+ dev->flags |= IFF_LOOPBACK; -+#endif -+ -+ dev->open = vcan_open; -+ dev->stop = vcan_stop; -+ dev->set_config = NULL; -+ dev->hard_start_xmit = vcan_tx; -+ dev->do_ioctl = vcan_ioctl; -+ dev->get_stats = vcan_get_stats; -+ dev->hard_header = vcan_header; -+ dev->rebuild_header = vcan_rebuild_header; -+ dev->hard_header_cache = NULL; -+ -+ SET_MODULE_OWNER(dev); -+} -+ -+static __init int vcan_init_module(void) -+{ -+ int i, ndev = 0, result = 0; -+ -+ printk(banner); -+ -+ if (numdev < 1) -+ numdev = 1; /* register at least one interface */ -+ -+ printk(KERN_INFO "vcan: registering %d virtual CAN interfaces.\n", -+ numdev ); -+ -+ vcan_devs = kmalloc(numdev * sizeof(struct net_device *), GFP_KERNEL); -+ if (!vcan_devs) { -+ printk(KERN_ERR "vcan: Can't allocate vcan devices array!\n"); -+ return -ENOMEM; -+ } -+ -+ /* Clear the pointer array */ -+ memset(vcan_devs, 0, numdev * sizeof(struct net_device *)); -+ -+ for (i = 0; i < numdev; i++) { -+ if (!(vcan_devs[i] = alloc_netdev(STATSIZE, "vcan%d", -+ vcan_init))) { -+ printk(KERN_ERR "vcan: error allocating net_device\n"); -+ result = -ENOMEM; -+ goto out; -+ } else if ((result = register_netdev(vcan_devs[i])) < 0) { -+ printk(KERN_ERR "vcan: error %d registering " -+ "interface %s\n", -+ result, vcan_devs[i]->name); -+ free_netdev(vcan_devs[i]); -+ vcan_devs[i] = NULL; -+ goto out; -+ } else { -+ DBG("successfully registered interface %s\n", -+ vcan_devs[i]->name); -+ ndev++; -+ } -+ } -+ -+ if (ndev) -+ return 0; -+ -+ out: -+ for (i = 0; i < numdev; i++) { -+ if (vcan_devs[i]) { -+ unregister_netdev(vcan_devs[i]); -+ free_netdev(vcan_devs[i]); -+ } -+ } -+ -+ kfree(vcan_devs); -+ -+ return result; -+} -+ -+static __exit void vcan_cleanup_module(void) -+{ -+ int i; -+ -+ if (!vcan_devs) -+ return; -+ -+ for (i = 0; i < numdev; i++) { -+ if (vcan_devs[i]) { -+ unregister_netdev(vcan_devs[i]); -+ free_netdev(vcan_devs[i]); -+ } -+ } -+ -+ kfree(vcan_devs); -+} -+ -+module_init(vcan_init_module); -+module_exit(vcan_cleanup_module); -diff -N -u -r b/include/linux/can/bcm.h c/include/linux/can/bcm.h ---- b/include/linux/can/bcm.h 1970-01-01 01:00:00.000000000 +0100 -+++ c/include/linux/can/bcm.h 2007-03-07 17:13:13.000000000 +0100 -@@ -0,0 +1,56 @@ -+/* -+ * linux/can/bcm.h -+ * -+ * Definitions for CAN Broadcast Manager (BCM) -+ * -+ * $Id: bcm.h 176 2007-03-07 16:12:46Z hartkopp $ -+ * -+ * Author: Oliver Hartkopp -+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research -+ * All rights reserved. -+ * -+ * Send feedback to -+ * -+ */ -+ -+#ifndef CAN_BCM_H -+#define CAN_BCM_H -+ -+struct bcm_msg_head { -+ int opcode; /* command */ -+ int flags; /* special flags */ -+ int count; /* run 'count' times ival1 then ival2 */ -+ struct timeval ival1, ival2; /* intervals */ -+ canid_t can_id; /* 32 Bit SFF/EFF. MSB set at EFF */ -+ int nframes; /* number of following can_frame's */ -+ struct can_frame frames[0]; -+}; -+ -+enum { -+ TX_SETUP = 1, /* create (cyclic) transmission task */ -+ TX_DELETE, /* remove (cyclic) transmission task */ -+ TX_READ, /* read properties of (cyclic) transmission task */ -+ TX_SEND, /* send one CAN frame */ -+ RX_SETUP, /* create RX content filter subscription */ -+ RX_DELETE, /* remove RX content filter subscription */ -+ RX_READ, /* read properties of RX content filter subscription */ -+ TX_STATUS, /* reply to TX_READ request */ -+ TX_EXPIRED, /* notification on performed transmissions (count=0) */ -+ RX_STATUS, /* reply to RX_READ request */ -+ RX_TIMEOUT, /* cyclic message is absent */ -+ RX_CHANGED /* updated CAN frame (detected content change) */ -+}; -+ -+#define SETTIMER 0x0001 -+#define STARTTIMER 0x0002 -+#define TX_COUNTEVT 0x0004 -+#define TX_ANNOUNCE 0x0008 -+#define TX_CP_CAN_ID 0x0010 -+#define RX_FILTER_ID 0x0020 -+#define RX_CHECK_DLC 0x0040 -+#define RX_NO_AUTOTIMER 0x0080 -+#define RX_ANNOUNCE_RESUME 0x0100 -+#define TX_RESET_MULTI_IDX 0x0200 -+#define RX_RTR_FRAME 0x0400 -+ -+#endif /* CAN_BCM_H */ -diff -N -u -r b/include/linux/can/core.h c/include/linux/can/core.h ---- b/include/linux/can/core.h 1970-01-01 01:00:00.000000000 +0100 -+++ c/include/linux/can/core.h 2007-03-09 17:24:11.000000000 +0100 -@@ -0,0 +1,56 @@ -+/* -+ * linux/can/core.h -+ * -+ * Protoypes and definitions for CAN protocol modules using the PF_CAN core -+ * -+ * $Id: core.h 177 2007-03-08 11:02:43Z hartkopp $ -+ * -+ * Authors: Oliver Hartkopp -+ * Urs Thuermann -+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research -+ * All rights reserved. -+ * -+ * Send feedback to -+ * -+ */ -+ -+#ifndef CAN_CORE_H -+#define CAN_CORE_H -+ -+#include -+#include -+#include -+ -+#define DNAME(dev) ((dev) ? (dev)->name : "any") -+ -+#define CAN_PROC_DIR "net/can" /* /proc/... */ -+ -+struct can_proto { -+ int type; -+ int protocol; -+ int capability; -+ struct proto_ops *ops; -+ struct proto *prot; -+}; -+ -+/* function prototypes for the CAN networklayer core (af_can.c) */ -+ -+void can_debug_skb(struct sk_buff *skb); -+void can_debug_cframe(const char *msg, struct can_frame *cframe, ...); -+ -+void can_proto_register(struct can_proto *cp); -+void can_proto_unregister(struct can_proto *cp); -+int can_rx_register(struct net_device *dev, canid_t can_id, canid_t mask, -+ void (*func)(struct sk_buff *, void *), void *data, -+ char *ident); -+int can_rx_unregister(struct net_device *dev, canid_t can_id, canid_t mask, -+ void (*func)(struct sk_buff *, void *), void *data); -+void can_dev_register(struct net_device *dev, -+ void (*func)(unsigned long msg, void *), void *data); -+void can_dev_unregister(struct net_device *dev, -+ void (*func)(unsigned long msg, void *), void *data); -+int can_send(struct sk_buff *skb, int loop); -+ -+unsigned long timeval2jiffies(struct timeval *tv, int round_up); -+ -+#endif /* CAN_CORE_H */ -diff -N -u -r b/include/linux/can/error.h c/include/linux/can/error.h ---- b/include/linux/can/error.h 1970-01-01 01:00:00.000000000 +0100 -+++ c/include/linux/can/error.h 2007-03-05 09:25:43.000000000 +0100 -@@ -0,0 +1,95 @@ -+/* -+ * linux/can/error.h -+ * -+ * Definitions of the CAN error frame to be filtered and passed to the user. -+ * -+ * $Id: error.h 162 2007-03-05 08:25:02Z hartkopp $ -+ * -+ * Author: Oliver Hartkopp -+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research -+ * All rights reserved. -+ * -+ * Send feedback to -+ * -+ */ -+ -+#ifndef CAN_ERROR_H -+#define CAN_ERROR_H -+ -+#define CAN_ERR_DLC 8 /* dlc for error frames */ -+ -+/* error class (mask) in can_id */ -+#define CAN_ERR_TX_TIMEOUT 0x00000001U /* TX timeout (by netdevice driver) */ -+#define CAN_ERR_LOSTARB 0x00000002U /* lost arbitration / data[0] */ -+#define CAN_ERR_CRTL 0x00000004U /* controller problems / data[1] */ -+#define CAN_ERR_PROT 0x00000008U /* protocol violations / data[2..3] */ -+#define CAN_ERR_TRX 0x00000010U /* transceiver status / data[4] */ -+#define CAN_ERR_ACK 0x00000020U /* received no ACK on transmission */ -+#define CAN_ERR_BUSOFF 0x00000040U /* bus off */ -+#define CAN_ERR_BUSERROR 0x00000080U /* bus error (may flood!) */ -+#define CAN_ERR_RESTARTED 0x00000100U /* controller restarted */ -+ -+/* arbitration lost in bit ... / data[0] */ -+#define CAN_ERR_LOSTARB_UNSPEC 0x00 /* unspecified */ -+ /* else bit number in bitstream */ -+ -+/* error status of CAN-controller / data[1] */ -+#define CAN_ERR_CRTL_UNSPEC 0x00 /* unspecified */ -+#define CAN_ERR_CRTL_RX_OVERFLOW 0x01 /* RX buffer overflow */ -+#define CAN_ERR_CRTL_TX_OVERFLOW 0x02 /* TX buffer overflow */ -+#define CAN_ERR_CRTL_RX_WARNING 0x04 /* reached warning level for RX errors */ -+#define CAN_ERR_CRTL_TX_WARNING 0x08 /* reached warning level for TX errors */ -+#define CAN_ERR_CRTL_RX_PASSIVE 0x10 /* reached error passive status RX */ -+#define CAN_ERR_CRTL_TX_PASSIVE 0x20 /* reached error passive status TX */ -+ /* (at least one error counter exceeds */ -+ /* the protocol-defined level of 127) */ -+ -+/* error in CAN protocol (type) / data[2] */ -+#define CAN_ERR_PROT_UNSPEC 0x00 /* unspecified */ -+#define CAN_ERR_PROT_BIT 0x01 /* single bit error */ -+#define CAN_ERR_PROT_FORM 0x02 /* frame format error */ -+#define CAN_ERR_PROT_STUFF 0x04 /* bit stuffing error */ -+#define CAN_ERR_PROT_BIT0 0x08 /* unable to send dominant bit */ -+#define CAN_ERR_PROT_BIT1 0x10 /* unable to send recessive bit */ -+#define CAN_ERR_PROT_OVERLOAD 0x20 /* bus overload */ -+#define CAN_ERR_PROT_ACTIVE 0x40 /* active error announcement */ -+#define CAN_ERR_PROT_TX 0x80 /* error occured on transmission */ -+ -+/* error in CAN protocol (location) / data[3] */ -+#define CAN_ERR_PROT_LOC_UNSPEC 0x00 /* unspecified */ -+#define CAN_ERR_PROT_LOC_SOF 0x03 /* start of frame */ -+#define CAN_ERR_PROT_LOC_ID28_21 0x02 /* ID bits 28 - 21 (SFF: 10 - 3) */ -+#define CAN_ERR_PROT_LOC_ID20_18 0x06 /* ID bits 20 - 18 (SFF: 2 - 0 )*/ -+#define CAN_ERR_PROT_LOC_SRTR 0x04 /* substitute RTR (SFF: RTR) */ -+#define CAN_ERR_PROT_LOC_IDE 0x05 /* identifier extension */ -+#define CAN_ERR_PROT_LOC_ID17_13 0x07 /* ID bits 17-13 */ -+#define CAN_ERR_PROT_LOC_ID12_05 0x0F /* ID bits 12-5 */ -+#define CAN_ERR_PROT_LOC_ID04_00 0x0E /* ID bits 4-0 */ -+#define CAN_ERR_PROT_LOC_RTR 0x0C /* RTR */ -+#define CAN_ERR_PROT_LOC_RES1 0x0D /* reserved bit 1 */ -+#define CAN_ERR_PROT_LOC_RES0 0x09 /* reserved bit 0 */ -+#define CAN_ERR_PROT_LOC_DLC 0x0B /* data length code */ -+#define CAN_ERR_PROT_LOC_DATA 0x0A /* data section */ -+#define CAN_ERR_PROT_LOC_CRC_SEQ 0x08 /* CRC sequence */ -+#define CAN_ERR_PROT_LOC_CRC_DEL 0x18 /* CRC delimiter */ -+#define CAN_ERR_PROT_LOC_ACK 0x19 /* ACK slot */ -+#define CAN_ERR_PROT_LOC_ACK_DEL 0x1B /* ACK delimiter */ -+#define CAN_ERR_PROT_LOC_EOF 0x1A /* end of frame */ -+#define CAN_ERR_PROT_LOC_INTERM 0x12 /* intermission */ -+ -+/* error status of CAN-transceiver / data[4] */ -+/* CANH CANL */ -+#define CAN_ERR_TRX_UNSPEC 0x00 /* 0000 0000 */ -+#define CAN_ERR_TRX_CANH_NO_WIRE 0x04 /* 0000 0100 */ -+#define CAN_ERR_TRX_CANH_SHORT_TO_BAT 0x05 /* 0000 0101 */ -+#define CAN_ERR_TRX_CANH_SHORT_TO_VCC 0x06 /* 0000 0110 */ -+#define CAN_ERR_TRX_CANH_SHORT_TO_GND 0x07 /* 0000 0111 */ -+#define CAN_ERR_TRX_CANL_NO_WIRE 0x40 /* 0100 0000 */ -+#define CAN_ERR_TRX_CANL_SHORT_TO_BAT 0x50 /* 0101 0000 */ -+#define CAN_ERR_TRX_CANL_SHORT_TO_VCC 0x60 /* 0110 0000 */ -+#define CAN_ERR_TRX_CANL_SHORT_TO_GND 0x70 /* 0111 0000 */ -+#define CAN_ERR_TRX_CANL_SHORT_TO_CANH 0x80 /* 1000 0000 */ -+ -+/* controller specific additional information / data[5..7] */ -+ -+#endif /* CAN_ERROR_H */ -diff -N -u -r b/include/linux/can/raw.h c/include/linux/can/raw.h ---- b/include/linux/can/raw.h 1970-01-01 01:00:00.000000000 +0100 -+++ c/include/linux/can/raw.h 2007-03-07 17:13:13.000000000 +0100 -@@ -0,0 +1,31 @@ -+/* -+ * linux/can/raw.h -+ * -+ * Definitions for raw CAN sockets -+ * -+ * $Id: raw.h 176 2007-03-07 16:12:46Z hartkopp $ -+ * -+ * Authors: Oliver Hartkopp -+ * Urs Thuermann -+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research -+ * All rights reserved. -+ * -+ * Send feedback to -+ * -+ */ -+ -+#ifndef CAN_RAW_H -+#define CAN_RAW_H -+ -+#include -+ -+#define SOL_CAN_RAW (SOL_CAN_BASE + CAN_RAW) -+ -+/* for socket options affecting the socket (not the global system) */ -+ -+#define CAN_RAW_FILTER 1 /* set 0 .. n can_filter(s) */ -+#define CAN_RAW_ERR_FILTER 2 /* set filter for error frames */ -+#define CAN_RAW_LOOPBACK 3 /* local loopback (default:on) */ -+#define CAN_RAW_RECV_OWN_MSGS 4 /* receive my own msgs (default:off) */ -+ -+#endif -diff -N -u -r b/include/linux/can/version.h c/include/linux/can/version.h ---- b/include/linux/can/version.h 1970-01-01 01:00:00.000000000 +0100 -+++ c/include/linux/can/version.h 2007-03-05 14:59:06.000000000 +0100 -@@ -0,0 +1,40 @@ -+/* -+ * linux/can/version.h -+ * -+ * Version information for the CAN network layer implementation -+ -+ * Author: Urs Thuermann -+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research -+ * All rights reserved. -+ * -+ * Send feedback to -+ * -+ */ -+ -+#ifndef CAN_VERSION_H -+#define CAN_VERSION_H -+ -+#define RCSID(s) asm(".section .rodata.str1.1,\"aMS\",@progbits,1\n\t" \ -+ ".string \"" s "\"\n\t.previous\n") -+ -+RCSID("$Id: version.h 170 2007-03-05 13:58:26Z hartkopp $"); -+ -+#define MAJORVERSION 2 -+#define MINORVERSION 0 -+#define PATCHLEVEL 0 -+#define EXTRAVERSION "-pre6" -+ -+#define LLCF_VERSION_CODE (((MAJORVERSION) << 16) + ((MINORVERSION) << 8) \ -+ + (PATCHLEVEL)) -+ -+/* stringification: these are the usual macros to stringify with macro -+ expansion. The str() macro does the expansion, the xstr() macro is -+ for the actual stringification. -+*/ -+#define str(arg) xstr(arg) -+#define xstr(arg) #arg -+ -+#define VERSION str(MAJORVERSION) "." str(MINORVERSION) "." str(PATCHLEVEL) \ -+ EXTRAVERSION -+ -+#endif /* CAN_VERSION_H */ -diff -N -u -r b/include/linux/can.h c/include/linux/can.h ---- b/include/linux/can.h 1970-01-01 01:00:00.000000000 +0100 -+++ c/include/linux/can.h 2007-03-05 11:14:57.000000000 +0100 -@@ -0,0 +1,77 @@ -+/* -+ * linux/can.h -+ * -+ * Definitions for CAN networklayer (socket addr / CAN frame / CAN filter) -+ * -+ * $Id: can.h 165 2007-03-05 10:14:18Z hartkopp $ -+ * -+ * Authors: Oliver Hartkopp -+ * Urs Thuermann -+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research -+ * All rights reserved. -+ * -+ * Send feedback to -+ * -+ */ -+ -+#ifndef CAN_H -+#define CAN_H -+ -+#include -+#include -+#include -+ -+/* controller area network (CAN) kernel definitions */ -+ -+/* special address description flags for the CAN_ID */ -+#define CAN_EFF_FLAG 0x80000000U /* EFF/SFF is set in the MSB */ -+#define CAN_RTR_FLAG 0x40000000U /* remote transmission request */ -+#define CAN_ERR_FLAG 0x20000000U /* error 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 /* omit EFF, RTR, ERR flags */ -+ -+typedef __u32 canid_t; -+ -+struct can_frame { -+ canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */ -+ __u8 can_dlc; /* data length code: 0 .. 8 */ -+ __u8 data[8] __attribute__ ((aligned(8))); -+}; -+ -+/* particular protocols of the protocol family PF_CAN */ -+#define CAN_RAW 1 /* RAW sockets */ -+#define CAN_BCM 2 /* Broadcast Manager */ -+#define CAN_TP16 3 /* VAG Transport Protocol v1.6 */ -+#define CAN_TP20 4 /* VAG Transport Protocol v2.0 */ -+#define CAN_MCNET 5 /* Bosch MCNet */ -+#define CAN_ISOTP 6 /* ISO 15765-2 Transport Protocol */ -+#define CAN_BAP 7 /* VAG Bedien- und Anzeigeprotokoll */ -+#define CAN_NPROTO 8 -+ -+#define SOL_CAN_BASE 100 -+ -+struct sockaddr_can { -+ sa_family_t can_family; -+ int can_ifindex; -+ union { -+ struct { canid_t rx_id, tx_id; } tp16; -+ struct { canid_t rx_id, tx_id; } tp20; -+ struct { canid_t rx_id, tx_id; } mcnet; -+ struct { canid_t rx_id, tx_id; } isotp; -+ struct { int sg_id, sg_type; } bap; -+ } can_addr; -+}; -+ -+typedef canid_t can_err_mask_t; -+ -+struct can_filter { -+ canid_t can_id; -+ canid_t can_mask; -+}; -+ -+#define CAN_INV_FILTER 0x20000000U /* to be set in can_filter.can_id */ -+ -+#endif /* CAN_H */ -diff -N -u -r b/net/can/af_can.c c/net/can/af_can.c ---- b/net/can/af_can.c 1970-01-01 01:00:00.000000000 +0100 -+++ c/net/can/af_can.c 2007-03-09 17:25:16.000000000 +0100 -@@ -0,0 +1,934 @@ -+/* -+ * af_can.c - Protocol family CAN core module -+ * (used by different CAN protocol modules) -+ * -+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research -+ * 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, the following disclaimer and -+ * the referenced file 'COPYING'. -+ * 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. Neither the name of Volkswagen nor the names of its contributors -+ * may be used to endorse or promote products derived from this software -+ * without specific prior written permission. -+ * -+ * Alternatively, provided that this notice is retained in full, this -+ * software may be distributed under the terms of the GNU General -+ * Public License ("GPL") version 2 as distributed in the 'COPYING' -+ * file from the main directory of the linux kernel source. -+ * -+ * The provided data structures and external interfaces from this code -+ * are not restricted to be used by modules with a GPL compatible license. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT -+ * OWNER 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. -+ * -+ * Send feedback to -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include "af_can.h" -+ -+ -+RCSID("$Id: af_can.c 177 2007-03-08 11:02:43Z hartkopp $"); -+ -+#define IDENT "af_can" -+static __initdata const char banner[] = KERN_INFO "CAN: Controller Area " -+ "Network PF_CAN core " VERSION "\n"; -+ -+MODULE_DESCRIPTION("Controller Area Network PF_CAN core"); -+MODULE_LICENSE("Dual BSD/GPL"); -+MODULE_AUTHOR("Urs Thuermann , " -+ "Oliver Hartkopp "); -+ -+int stats_timer = 1; /* default: on */ -+module_param(stats_timer, int, S_IRUGO); -+ -+#ifdef CONFIG_CAN_DEBUG_CORE -+static int debug = 0; -+module_param(debug, int, S_IRUGO); -+#define DBG(args...) (debug & 1 ? \ -+ (printk(KERN_DEBUG "CAN %s: ", __func__), \ -+ printk(args)) : 0) -+#define DBG_FRAME(args...) (debug & 2 ? can_debug_cframe(args) : 0) -+#define DBG_SKB(skb) (debug & 4 ? can_debug_skb(skb) : 0) -+#else -+#define DBG(args...) -+#define DBG_FRAME(args...) -+#define DBG_SKB(skb) -+#endif -+ -+static __init int can_init(void); -+static __exit void can_exit(void); -+ -+static int can_create(struct socket *sock, int protocol); -+static int can_notifier(struct notifier_block *nb, -+ unsigned long msg, void *data); -+static int can_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg); -+static int can_rcv(struct sk_buff *skb, struct net_device *dev, -+ struct packet_type *pt, struct net_device *orig_dev); -+static int can_rcv_filter(struct dev_rcv_lists *d, struct sk_buff *skb); -+static struct dev_rcv_lists *find_dev_rcv_lists(struct net_device *dev); -+static struct hlist_head *find_rcv_list(canid_t *can_id, canid_t *mask, -+ struct dev_rcv_lists *d); -+static void can_rcv_lists_delete(struct rcu_head *rp); -+static void can_rx_delete(struct rcu_head *rp); -+static void can_rx_delete_all(struct hlist_head *rl); -+ -+ -+struct notifier { -+ struct list_head list; -+ struct net_device *dev; -+ void (*func)(unsigned long msg, void *data); -+ void *data; -+}; -+ -+static LIST_HEAD(notifier_list); -+static rwlock_t notifier_lock = RW_LOCK_UNLOCKED; -+ -+HLIST_HEAD(rx_dev_list); -+static struct dev_rcv_lists rx_alldev_list; -+static spinlock_t rcv_lists_lock = SPIN_LOCK_UNLOCKED; -+ -+static struct kmem_cache *rcv_cache __read_mostly; -+ -+static struct packet_type can_packet = { -+ .type = __constant_htons(ETH_P_CAN), -+ .dev = NULL, -+ .func = can_rcv, -+}; -+ -+static struct net_proto_family can_family_ops = { -+ .family = PF_CAN, -+ .create = can_create, -+ .owner = THIS_MODULE, -+}; -+ -+/* notifier block for netdevice event */ -+static struct notifier_block can_netdev_notifier = { -+ .notifier_call = can_notifier, -+}; -+ -+/* table of registered CAN protocols */ -+static struct can_proto *proto_tab[CAN_NPROTO]; -+ -+extern struct timer_list stattimer; /* timer for statistics update */ -+extern struct s_stats stats; /* packet statistics */ -+extern struct s_pstats pstats; /* receive list statistics */ -+ -+module_init(can_init); -+module_exit(can_exit); -+ -+/**************************************************/ -+/* af_can module init/exit functions */ -+/**************************************************/ -+ -+static __init int can_init(void) -+{ -+ printk(banner); -+ -+ rcv_cache = kmem_cache_create("can_receiver", sizeof(struct receiver), -+ 0, 0, NULL, NULL); -+ if (!rcv_cache) -+ return -ENOMEM; -+ -+ /* Insert struct dev_rcv_lists for reception on all devices. -+ This struct is zero initialized which is correct for the -+ embedded hlist heads, the dev pointer, and the entries counter. -+ */ -+ -+ spin_lock_bh(&rcv_lists_lock); -+ hlist_add_head_rcu(&rx_alldev_list.list, &rx_dev_list); -+ spin_unlock_bh(&rcv_lists_lock); -+ -+ if (stats_timer) { -+ /* statistics init */ -+ init_timer(&stattimer); -+ } -+ -+ /* procfs init */ -+ can_init_proc(); -+ -+ /* protocol register */ -+ sock_register(&can_family_ops); -+ register_netdevice_notifier(&can_netdev_notifier); -+ dev_add_pack(&can_packet); -+ -+ return 0; -+} -+ -+static __exit void can_exit(void) -+{ -+ struct dev_rcv_lists *d; -+ struct hlist_node *n, *next; -+ -+ if (stats_timer) { -+ /* stop statistics timer */ -+ del_timer(&stattimer); -+ } -+ -+ /* procfs remove */ -+ can_remove_proc(); -+ -+ /* protocol unregister */ -+ dev_remove_pack(&can_packet); -+ unregister_netdevice_notifier(&can_netdev_notifier); -+ sock_unregister(PF_CAN); -+ -+ /* remove rx_dev_list */ -+ spin_lock_bh(&rcv_lists_lock); -+ hlist_del(&rx_alldev_list.list); -+ hlist_for_each_entry_safe(d, n, next, &rx_dev_list, list) { -+ hlist_del(&d->list); -+ kfree(d); -+ } -+ spin_unlock_bh(&rcv_lists_lock); -+ -+ kmem_cache_destroy(rcv_cache); -+} -+ -+/**************************************************/ -+/* af_can protocol functions */ -+/**************************************************/ -+ -+void can_proto_register(struct can_proto *cp) -+{ -+ int proto = cp->protocol; -+ if (proto < 0 || proto >= CAN_NPROTO) { -+ printk(KERN_ERR "CAN: protocol number %d out " -+ "of range\n", proto); -+ return; -+ } -+ if (proto_tab[proto]) { -+ printk(KERN_ERR "CAN: protocol %d already " -+ "registered\n", proto); -+ return; -+ } -+ -+ if (proto_register(cp->prot, 0) != 0) { -+ return; -+ } -+ proto_tab[proto] = cp; -+ -+ /* use generic ioctl function if the module doesn't bring its own */ -+ if (!cp->ops->ioctl) -+ cp->ops->ioctl = can_ioctl; -+} -+ -+void can_proto_unregister(struct can_proto *cp) -+{ -+ int proto = cp->protocol; -+ if (!proto_tab[proto]) { -+ printk(KERN_ERR "CAN: protocol %d is not registered\n", proto); -+ return; -+ } -+ proto_unregister(cp->prot); -+ proto_tab[proto] = NULL; -+} -+ -+void can_dev_register(struct net_device *dev, -+ void (*func)(unsigned long msg, void *), void *data) -+{ -+ struct notifier *n; -+ -+ DBG("called for %s\n", dev->name); -+ -+ if (!(n = kmalloc(sizeof(*n), GFP_KERNEL))) -+ return; -+ -+ n->dev = dev; -+ n->func = func; -+ n->data = data; -+ -+ write_lock(¬ifier_lock); -+ list_add(&n->list, ¬ifier_list); -+ write_unlock(¬ifier_lock); -+} -+ -+void can_dev_unregister(struct net_device *dev, -+ void (*func)(unsigned long msg, void *), void *data) -+{ -+ struct notifier *n, *next; -+ -+ DBG("called for %s\n", dev->name); -+ -+ write_lock(¬ifier_lock); -+ list_for_each_entry_safe(n, next, ¬ifier_list, list) { -+ if (n->dev == dev && n->func == func && n->data == data) { -+ list_del(&n->list); -+ kfree(n); -+ break; -+ } -+ } -+ write_unlock(¬ifier_lock); -+} -+ -+/**************************************************/ -+/* af_can socket functions */ -+/**************************************************/ -+ -+static void can_sock_destruct(struct sock *sk) -+{ -+ DBG("called for sock %p\n", sk); -+ -+ skb_queue_purge(&sk->sk_receive_queue); -+ if (sk->sk_protinfo) -+ kfree(sk->sk_protinfo); -+} -+ -+static int can_create(struct socket *sock, int protocol) -+{ -+ struct sock *sk; -+ struct can_proto *cp; -+ int ret; -+ -+ DBG("socket %p, type %d, proto %d\n", sock, sock->type, protocol); -+ -+ sock->state = SS_UNCONNECTED; -+ -+ if (protocol < 0 || protocol >= CAN_NPROTO) -+ return -EINVAL; -+ -+ DBG("looking up proto %d in proto_tab[]\n", protocol); -+ -+ /* try to load protocol module, when CONFIG_KMOD is defined */ -+ if (!proto_tab[protocol]) { -+ char module_name[30]; -+ sprintf(module_name, "can-proto-%d", protocol); -+ if (request_module(module_name) == -ENOSYS) -+ printk(KERN_INFO "CAN: request_module(%s) not" -+ " implemented.\n", module_name); -+ } -+ -+ /* check for success and correct type */ -+ if (!(cp = proto_tab[protocol]) || cp->type != sock->type) -+ return -EPROTONOSUPPORT; -+ -+ if (cp->capability >= 0 && !capable(cp->capability)) -+ return -EPERM; -+ -+ sock->ops = cp->ops; -+ -+ sk = sk_alloc(PF_CAN, GFP_KERNEL, cp->prot, 1); -+ if (!sk) -+ goto oom; -+ sock_init_data(sock, sk); -+ sk->sk_destruct = can_sock_destruct; -+ -+ DBG("created sock: %p\n", sk); -+ -+ ret = 0; -+ if (sk->sk_prot->init) -+ ret = sk->sk_prot->init(sk); -+ if (ret) { -+ /* we must release sk */ -+ sock_orphan(sk); -+ sock_put(sk); -+ return ret; -+ } -+ -+ return 0; -+ -+ oom: -+ return -ENOMEM; -+} -+ -+static int can_notifier(struct notifier_block *nb, -+ unsigned long msg, void *data) -+{ -+ struct net_device *dev = (struct net_device *)data; -+ struct notifier *n; -+ -+ DBG("called for %s, msg = %lu\n", dev->name, msg); -+ -+ if (dev->type != ARPHRD_CAN) -+ return NOTIFY_DONE; -+ -+ switch (msg) { -+ struct dev_rcv_lists *d; -+ int i; -+ -+ case NETDEV_REGISTER: -+ -+ /* create new dev_rcv_lists for this device */ -+ -+ DBG("creating new dev_rcv_lists for %s\n", dev->name); -+ if (!(d = kmalloc(sizeof(*d), -+ in_interrupt() ? GFP_ATOMIC : GFP_KERNEL))) { -+ printk(KERN_ERR "CAN: allocation of receive " -+ "list failed\n"); -+ return NOTIFY_DONE; -+ } -+ /* N.B. zeroing the struct is the correct initialization -+ for the embedded hlist_head structs. -+ Another list type, e.g. list_head, would require -+ explicit initialization. */ -+ memset(d, 0, sizeof(*d)); -+ d->dev = dev; -+ -+ spin_lock_bh(&rcv_lists_lock); -+ hlist_add_head_rcu(&d->list, &rx_dev_list); -+ spin_unlock_bh(&rcv_lists_lock); -+ -+ break; -+ -+ case NETDEV_UNREGISTER: -+ spin_lock_bh(&rcv_lists_lock); -+ -+ if (!(d = find_dev_rcv_lists(dev))) { -+ printk(KERN_ERR "CAN: notifier: receive list not " -+ "found for dev %s\n", dev->name); -+ goto unreg_out; -+ } -+ -+ hlist_del_rcu(&d->list); -+ -+ /* remove all receivers hooked at this netdevice */ -+ can_rx_delete_all(&d->rx_err); -+ can_rx_delete_all(&d->rx_all); -+ can_rx_delete_all(&d->rx_fil); -+ can_rx_delete_all(&d->rx_inv); -+ can_rx_delete_all(&d->rx_eff); -+ for (i = 0; i < 2048; i++) -+ can_rx_delete_all(&d->rx_sff[i]); -+ -+ unreg_out: -+ spin_unlock_bh(&rcv_lists_lock); -+ -+ if (d) -+ call_rcu(&d->rcu, can_rcv_lists_delete); -+ -+ break; -+ } -+ -+ read_lock(¬ifier_lock); -+ list_for_each_entry(n, ¬ifier_list, list) { -+ if (n->dev == dev) -+ n->func(msg, n->data); -+ } -+ read_unlock(¬ifier_lock); -+ -+ return NOTIFY_DONE; -+} -+ -+static int can_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) -+{ -+ struct sock *sk = sock->sk; -+ -+ switch (cmd) { -+ case SIOCGSTAMP: -+ return sock_get_timestamp(sk, (struct timeval __user *)arg); -+ default: -+ return -ENOIOCTLCMD; -+ } -+ return 0; -+} -+ -+/**************************************************/ -+/* af_can tx path */ -+/**************************************************/ -+ -+int can_send(struct sk_buff *skb, int loop) -+{ -+ int err; -+ -+ if (loop) { /* local loopback (default) */ -+ *(struct sock **)skb->cb = skb->sk; /* tx sock reference */ -+ -+ /* interface not capabable to do the loopback itself? */ -+ if (!(skb->dev->flags & IFF_LOOPBACK)) { -+ struct sk_buff *newskb = skb_clone(skb, GFP_ATOMIC); -+ newskb->protocol = htons(ETH_P_CAN); -+ newskb->ip_summed = CHECKSUM_UNNECESSARY; -+ netif_rx(newskb); /* perform local loopback here */ -+ } -+ } else -+ *(struct sock **)skb->cb = NULL; /* no loopback required */ -+ -+ if (!(skb->dev->flags & IFF_UP)) -+ err = -ENETDOWN; -+ else if ((err = dev_queue_xmit(skb)) > 0) /* send to netdevice */ -+ err = net_xmit_errno(err); -+ -+ /* update statistics */ -+ stats.tx_frames++; -+ stats.tx_frames_delta++; -+ -+ return err; -+} -+ -+/**************************************************/ -+/* af_can rx path */ -+/**************************************************/ -+ -+int can_rx_register(struct net_device *dev, canid_t can_id, canid_t mask, -+ void (*func)(struct sk_buff *, void *), void *data, -+ char *ident) -+{ -+ struct receiver *r; -+ struct hlist_head *rl; -+ struct dev_rcv_lists *d; -+ int ret = 0; -+ -+ /* insert new receiver (dev,canid,mask) -> (func,data) */ -+ -+ DBG("dev %p, id %03X, mask %03X, callback %p, data %p, ident %s\n", -+ dev, can_id, mask, func, data, ident); -+ -+ if (!(r = kmem_cache_alloc(rcv_cache, GFP_KERNEL))) { -+ ret = -ENOMEM; -+ goto out; -+ } -+ -+ spin_lock_bh(&rcv_lists_lock); -+ -+ if (!(d = find_dev_rcv_lists(dev))) { -+ DBG("receive list not found for dev %s, id %03X, mask %03X\n", -+ DNAME(dev), can_id, mask); -+ kmem_cache_free(rcv_cache, r); -+ ret = -ENODEV; -+ goto out_unlock; -+ } -+ -+ rl = find_rcv_list(&can_id, &mask, d); -+ -+ r->can_id = can_id; -+ r->mask = mask; -+ r->matches = 0; -+ r->func = func; -+ r->data = data; -+ r->ident = ident; -+ -+ hlist_add_head_rcu(&r->list, rl); -+ d->entries++; -+ -+ pstats.rcv_entries++; -+ if (pstats.rcv_entries_max < pstats.rcv_entries) -+ pstats.rcv_entries_max = pstats.rcv_entries; -+ -+ out_unlock: -+ spin_unlock_bh(&rcv_lists_lock); -+ out: -+ return ret; -+} -+ -+static void can_rcv_lists_delete(struct rcu_head *rp) -+{ -+ struct dev_rcv_lists *d = container_of(rp, struct dev_rcv_lists, rcu); -+ kfree(d); -+} -+ -+static void can_rx_delete(struct rcu_head *rp) -+{ -+ struct receiver *r = container_of(rp, struct receiver, rcu); -+ kmem_cache_free(rcv_cache, r); -+} -+ -+static void can_rx_delete_all(struct hlist_head *rl) -+{ -+ struct receiver *r; -+ struct hlist_node *n; -+ -+ hlist_for_each_entry_rcu(r, n, rl, list) { -+ hlist_del_rcu(&r->list); -+ call_rcu(&r->rcu, can_rx_delete); -+ } -+} -+ -+int can_rx_unregister(struct net_device *dev, canid_t can_id, canid_t mask, -+ void (*func)(struct sk_buff *, void *), void *data) -+{ -+ struct receiver *r; -+ struct hlist_head *rl; -+ struct hlist_node *next; -+ struct dev_rcv_lists *d; -+ int ret = 0; -+ -+ DBG("dev %p, id %03X, mask %03X, callback %p, data %p\n", -+ dev, can_id, mask, func, data); -+ -+ r = NULL; -+ -+ spin_lock_bh(&rcv_lists_lock); -+ -+ if (!(d = find_dev_rcv_lists(dev))) { -+ DBG("receive list not found for dev %s, id %03X, mask %03X\n", -+ DNAME(dev), can_id, mask); -+ ret = -ENODEV; -+ goto out; -+ } -+ -+ rl = find_rcv_list(&can_id, &mask, d); -+ -+ /* Search the receiver list for the item to delete. This should -+ * exist, since no receiver may be unregistered that hasn't -+ * been registered before. -+ */ -+ -+ hlist_for_each_entry(r, next, rl, list) { -+ if (r->can_id == can_id && r->mask == mask -+ && r->func == func && r->data == data) -+ break; -+ } -+ -+ /* Check for bug in CAN protocol implementations: -+ * If no matching list item was found, the list cursor variable next -+ * will be NULL, while r will point to the last item of the list. -+ */ -+ -+ if (!next) { -+ DBG("receive list entry not found for " -+ "dev %s, id %03X, mask %03X\n", DNAME(dev), can_id, mask); -+ ret = -EINVAL; -+ r = NULL; -+ goto out; -+ } -+ -+ hlist_del_rcu(&r->list); -+ d->entries--; -+ -+ if (pstats.rcv_entries > 0) -+ pstats.rcv_entries--; -+ -+ out: -+ spin_unlock_bh(&rcv_lists_lock); -+ -+ /* schedule the receiver item for deletion */ -+ if (r) -+ call_rcu(&r->rcu, can_rx_delete); -+ -+ return ret; -+} -+ -+static int can_rcv(struct sk_buff *skb, struct net_device *dev, -+ struct packet_type *pt, struct net_device *orig_dev) -+{ -+ struct dev_rcv_lists *d; -+ int matches; -+ -+ DBG("received skbuff on device %s, ptype %04x\n", -+ dev->name, ntohs(pt->type)); -+ DBG_SKB(skb); -+ DBG_FRAME("af_can: can_rcv: received CAN frame", -+ (struct can_frame *)skb->data); -+ -+ /* update statistics */ -+ stats.rx_frames++; -+ stats.rx_frames_delta++; -+ -+ rcu_read_lock(); -+ -+ /* deliver the packet to sockets listening on all devices */ -+ matches = can_rcv_filter(&rx_alldev_list, skb); -+ -+ /* find receive list for this device */ -+ if ((d = find_dev_rcv_lists(dev))) -+ matches += can_rcv_filter(d, skb); -+ -+ rcu_read_unlock(); -+ -+ /* free the skbuff allocated by the netdevice driver */ -+ DBG("freeing skbuff %p\n", skb); -+ kfree_skb(skb); -+ -+ if (matches > 0) { -+ stats.matches++; -+ stats.matches_delta++; -+ } -+ -+ return 0; -+} -+ -+ -+static inline void deliver(struct sk_buff *skb, struct receiver *r) -+{ -+ struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC); -+ DBG("skbuff %p cloned to %p\n", skb, clone); -+ if (clone) { -+ r->func(clone, r->data); -+ r->matches++; /* update specific statistics */ -+ } -+} -+ -+static int can_rcv_filter(struct dev_rcv_lists *d, struct sk_buff *skb) -+{ -+ struct receiver *r; -+ struct hlist_node *n; -+ int matches = 0; -+ struct can_frame *cf = (struct can_frame*)skb->data; -+ canid_t can_id = cf->can_id; -+ -+ if (d->entries == 0) -+ return 0; -+ -+ if (can_id & CAN_ERR_FLAG) { -+ /* check for error frame entries only */ -+ hlist_for_each_entry_rcu(r, n, &d->rx_err, list) { -+ if (can_id & r->mask) { -+ DBG("match on rx_err skbuff %p\n", skb); -+ deliver(skb, r); -+ matches++; -+ } -+ } -+ goto out; -+ } -+ -+ /* check for unfiltered entries */ -+ hlist_for_each_entry_rcu(r, n, &d->rx_all, list) { -+ DBG("match on rx_all skbuff %p\n", skb); -+ deliver(skb, r); -+ matches++; -+ } -+ -+ /* check for can_id/mask entries */ -+ hlist_for_each_entry_rcu(r, n, &d->rx_fil, list) { -+ if ((can_id & r->mask) == r->can_id) { -+ DBG("match on rx_fil skbuff %p\n", skb); -+ deliver(skb, r); -+ matches++; -+ } -+ } -+ -+ /* check for inverted can_id/mask entries */ -+ hlist_for_each_entry_rcu(r, n, &d->rx_inv, list) { -+ if ((can_id & r->mask) != r->can_id) { -+ DBG("match on rx_inv skbuff %p\n", skb); -+ deliver(skb, r); -+ matches++; -+ } -+ } -+ -+ /* check CAN_ID specific entries */ -+ if (can_id & CAN_EFF_FLAG) { -+ hlist_for_each_entry_rcu(r, n, &d->rx_eff, list) { -+ if (r->can_id == can_id) { -+ DBG("match on rx_eff skbuff %p\n", skb); -+ deliver(skb, r); -+ matches++; -+ } -+ } -+ } else { -+ can_id &= CAN_SFF_MASK; -+ hlist_for_each_entry_rcu(r, n, &d->rx_sff[can_id], list) { -+ DBG("match on rx_sff skbuff %p\n", skb); -+ deliver(skb, r); -+ matches++; -+ } -+ } -+ -+ out: -+ return matches; -+} -+ -+static struct dev_rcv_lists *find_dev_rcv_lists(struct net_device *dev) -+{ -+ struct dev_rcv_lists *d; -+ struct hlist_node *n; -+ -+ /* find receive list for this device */ -+ -+ /* The hlist_for_each_entry*() macros curse through the list -+ * using the pointer variable n and set d to the containing -+ * struct in each list iteration. Therefore, after list -+ * iteration, d is unmodified when the list is empty, and it -+ * points to last list element, when the list is non-empty -+ * but no match in the loop body is found. I.e. d is *not* -+ * NULL when no match is found. We can, however, use the -+ * cursor variable n to decide if a match was found. -+ */ -+ -+ hlist_for_each_entry(d, n, &rx_dev_list, list) -+ if (d->dev == dev) -+ break; -+ -+ return n ? d : NULL; -+} -+ -+static struct hlist_head *find_rcv_list(canid_t *can_id, canid_t *mask, -+ struct dev_rcv_lists *d) -+{ -+ canid_t inv = *can_id & CAN_INV_FILTER; /* save flag before masking */ -+ -+ if (*mask & CAN_ERR_FLAG) { /* filter error frames */ -+ *mask &= CAN_ERR_MASK; /* clear CAN_ERR_FLAG in list entry */ -+ return &d->rx_err; -+ } -+ -+ /* ensure valid values in can_mask */ -+ if (*mask & CAN_EFF_FLAG) -+ *mask &= (CAN_EFF_MASK | CAN_EFF_FLAG | CAN_RTR_FLAG); -+ else -+ *mask &= (CAN_SFF_MASK | CAN_RTR_FLAG); -+ -+ *can_id &= *mask; /* reduce condition testing at receive time */ -+ -+ if (inv) /* inverse can_id/can_mask filter */ -+ return &d->rx_inv; -+ -+ if (!(*mask)) /* mask == 0 => no condition testing at receive time */ -+ return &d->rx_all; -+ -+ /* use extra filterset for the subscription of exactly *one* can_id */ -+ if (*can_id & CAN_EFF_FLAG) { -+ if (*mask == (CAN_EFF_MASK | CAN_EFF_FLAG)) -+ return &d->rx_eff; /* use-case for hash-table here? */ -+ } else { -+ if (*mask == CAN_SFF_MASK) -+ return &d->rx_sff[*can_id]; -+ } -+ -+ return &d->rx_fil; /* default: filter via can_id/can_mask */ -+} -+ -+/**************************************************/ -+/* af_can utility stuff */ -+/**************************************************/ -+ -+unsigned long timeval2jiffies(struct timeval *tv, int round_up) -+{ -+ unsigned long jif; -+ unsigned long sec = tv->tv_sec; -+ unsigned long usec = tv->tv_usec; -+ -+ if (sec > ULONG_MAX / HZ) /* check for overflow */ -+ return ULONG_MAX; -+ -+ if (round_up) /* any usec below one HZ? */ -+ usec += 1000000 / HZ - 1; /* pump it up */ -+ -+ jif = usec / (1000000 / HZ); -+ -+ if (sec * HZ > ULONG_MAX - jif) /* check for overflow */ -+ return ULONG_MAX; -+ else -+ return jif + sec * HZ; -+} -+ -+ -+/**************************************************/ -+/* af_can debugging stuff */ -+/**************************************************/ -+ -+#ifdef CONFIG_CAN_DEBUG_CORE -+ -+void can_debug_cframe(const char *msg, struct can_frame *cf, ...) -+{ -+ va_list ap; -+ int len; -+ int dlc, i; -+ char buf[1024]; -+ -+ len = sprintf(buf, KERN_DEBUG); -+ va_start(ap, cf); -+ len += snprintf(buf + len, sizeof(buf) - 64, msg, ap); -+ buf[len++] = ':'; -+ buf[len++] = ' '; -+ va_end(ap); -+ -+ if ((dlc = cf->can_dlc) > 8) -+ dlc = 8; -+ -+ if (cf->can_id & CAN_EFF_FLAG) -+ len += sprintf(buf + len, "<%08X> [%X] ", -+ cf->can_id & CAN_EFF_MASK, dlc); -+ else -+ len += sprintf(buf + len, "<%03X> [%X] ", -+ cf->can_id & CAN_SFF_MASK, dlc); -+ -+ for (i = 0; i < dlc; i++) -+ len += sprintf(buf + len, "%02X ", cf->data[i]); -+ -+ if (cf->can_id & CAN_RTR_FLAG) -+ len += sprintf(buf + len, "(RTR)"); -+ -+ buf[len++] = '\n'; -+ buf[len] = '\0'; -+ printk(buf); -+} -+ -+void can_debug_skb(struct sk_buff *skb) -+{ -+ int len, nbytes, i; -+ char buf[1024]; -+ -+ len = sprintf(buf, -+ KERN_DEBUG " skbuff at %p, dev: %d, proto: %04x\n" -+ KERN_DEBUG " users: %d, dataref: %d, nr_frags: %d, " -+ "h,d,t,e,l: %p %+d %+d %+d, %d", -+ skb, skb->dev ? skb->dev->ifindex : -1, -+ ntohs(skb->protocol), -+ atomic_read(&skb->users), -+ atomic_read(&(skb_shinfo(skb)->dataref)), -+ skb_shinfo(skb)->nr_frags, -+ skb->head, skb->data - skb->head, -+ skb->tail - skb->head, skb->end - skb->head, skb->len); -+ nbytes = skb->end - skb->head; -+ for (i = 0; i < nbytes; i++) { -+ if (i % 16 == 0) -+ len += sprintf(buf + len, "\n" KERN_DEBUG " "); -+ if (len < sizeof(buf) - 16) { -+ len += sprintf(buf + len, " %02x", skb->head[i]); -+ } else { -+ len += sprintf(buf + len, "..."); -+ break; -+ } -+ } -+ buf[len++] = '\n'; -+ buf[len] = '\0'; -+ printk(buf); -+} -+ -+EXPORT_SYMBOL(can_debug_cframe); -+EXPORT_SYMBOL(can_debug_skb); -+ -+#endif -+ -+/**************************************************/ -+/* Exported symbols */ -+/**************************************************/ -+EXPORT_SYMBOL(can_proto_register); -+EXPORT_SYMBOL(can_proto_unregister); -+EXPORT_SYMBOL(can_rx_register); -+EXPORT_SYMBOL(can_rx_unregister); -+EXPORT_SYMBOL(can_dev_register); -+EXPORT_SYMBOL(can_dev_unregister); -+EXPORT_SYMBOL(can_send); -+EXPORT_SYMBOL(timeval2jiffies); -diff -N -u -r b/net/can/af_can.h c/net/can/af_can.h ---- b/net/can/af_can.h 1970-01-01 01:00:00.000000000 +0100 -+++ c/net/can/af_can.h 2007-03-09 13:47:12.000000000 +0100 -@@ -0,0 +1,119 @@ -+/* -+ * $Id: af_can.h 177 2007-03-08 11:02:43Z hartkopp $ -+ * -+ * Copyright (c) 2002-2005 Volkswagen Group Electronic Research -+ * 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, the following disclaimer and -+ * the referenced file 'COPYING'. -+ * 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. Neither the name of Volkswagen nor the names of its contributors -+ * may be used to endorse or promote products derived from this software -+ * without specific prior written permission. -+ * -+ * Alternatively, provided that this notice is retained in full, this -+ * software may be distributed under the terms of the GNU General -+ * Public License ("GPL") version 2 as distributed in the 'COPYING' -+ * file from the main directory of the linux kernel source. -+ * -+ * The provided data structures and external interfaces from this code -+ * are not restricted to be used by modules with a GPL compatible license. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT -+ * OWNER 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. -+ * -+ * Send feedback to -+ * -+ */ -+ -+#ifndef AF_CAN_H -+#define AF_CAN_H -+ -+#include -+#include -+#include -+#include -+ -+#include -+ -+/* af_can rx dispatcher structures */ -+ -+struct receiver { -+ struct hlist_node list; -+ struct rcu_head rcu; -+ canid_t can_id; -+ canid_t mask; -+ unsigned long matches; -+ void (*func)(struct sk_buff *, void *); -+ void *data; -+ char *ident; -+}; -+ -+struct dev_rcv_lists { -+ struct hlist_node list; -+ struct rcu_head rcu; -+ struct net_device *dev; -+ struct hlist_head rx_err; -+ struct hlist_head rx_all; -+ struct hlist_head rx_fil; -+ struct hlist_head rx_inv; -+ struct hlist_head rx_sff[0x800]; -+ struct hlist_head rx_eff; -+ int entries; -+}; -+ -+/* statistic structures */ -+ -+struct s_stats { -+ unsigned long jiffies_init; -+ -+ unsigned long rx_frames; -+ unsigned long tx_frames; -+ unsigned long matches; -+ -+ unsigned long total_rx_rate; -+ unsigned long total_tx_rate; -+ unsigned long total_rx_match_ratio; -+ -+ unsigned long current_rx_rate; -+ unsigned long current_tx_rate; -+ unsigned long current_rx_match_ratio; -+ -+ unsigned long max_rx_rate; -+ unsigned long max_tx_rate; -+ unsigned long max_rx_match_ratio; -+ -+ unsigned long rx_frames_delta; -+ unsigned long tx_frames_delta; -+ unsigned long matches_delta; -+}; /* can be reset e.g. by can_init_stats() */ -+ -+struct s_pstats { -+ unsigned long stats_reset; -+ unsigned long rcv_entries; -+ unsigned long rcv_entries_max; -+}; /* persistent statistics */ -+ -+ -+/* function prototypes for the CAN networklayer procfs (proc.c) */ -+ -+void can_init_proc(void); -+void can_remove_proc(void); -+ -+#endif /* AF_CAN_H */ -diff -N -u -r b/net/can/bcm.c c/net/can/bcm.c ---- b/net/can/bcm.c 1970-01-01 01:00:00.000000000 +0100 -+++ c/net/can/bcm.c 2007-03-09 17:26:51.000000000 +0100 -@@ -0,0 +1,1600 @@ -+/* -+ * bcm.c - Broadcast Manager to filter/send (cyclic) CAN content -+ * -+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research -+ * 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, the following disclaimer and -+ * the referenced file 'COPYING'. -+ * 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. Neither the name of Volkswagen nor the names of its contributors -+ * may be used to endorse or promote products derived from this software -+ * without specific prior written permission. -+ * -+ * Alternatively, provided that this notice is retained in full, this -+ * software may be distributed under the terms of the GNU General -+ * Public License ("GPL") version 2 as distributed in the 'COPYING' -+ * file from the main directory of the linux kernel source. -+ * -+ * The provided data structures and external interfaces from this code -+ * are not restricted to be used by modules with a GPL compatible license. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT -+ * OWNER 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. -+ * -+ * Send feedback to -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+RCSID("$Id: bcm.c 179 2007-03-09 07:36:49Z hartkopp $"); -+ -+#ifdef CONFIG_CAN_DEBUG_CORE -+static int debug = 0; -+module_param(debug, int, S_IRUGO); -+#define DBG(args...) (debug & 1 ? \ -+ (printk(KERN_DEBUG "BCM %s: ", __func__), \ -+ printk(args)) : 0) -+#define DBG_FRAME(args...) (debug & 2 ? can_debug_cframe(args) : 0) -+#define DBG_SKB(skb) (debug & 4 ? can_debug_skb(skb) : 0) -+#else -+#define DBG(args...) -+#define DBG_FRAME(args...) -+#define DBG_SKB(skb) -+#endif -+ -+/* use of last_frames[index].can_dlc */ -+#define RX_RECV 0x40 /* received data for this element */ -+#define RX_THR 0x80 /* element not been sent due to throttle feature */ -+#define BCM_CAN_DLC_MASK 0x0F /* clean private flags in can_dlc by masking */ -+ -+/* get best masking value for can_rx_register() for a given single can_id */ -+#define REGMASK(id) ((id & CAN_RTR_FLAG) | ((id & CAN_EFF_FLAG) ? \ -+ (CAN_EFF_MASK | CAN_EFF_FLAG) : CAN_SFF_MASK)) -+ -+#define IDENT "bcm" -+static __initdata const char banner[] = KERN_INFO -+ "CAN: broadcast manager (bcm) socket protocol " VERSION "\n"; -+ -+MODULE_DESCRIPTION("PF_CAN bcm sockets"); -+MODULE_LICENSE("Dual BSD/GPL"); -+MODULE_AUTHOR("Oliver Hartkopp "); -+ -+#define GET_U64(p) (*(u64*)(p)->data) /* easy access */ -+ -+struct bcm_op { -+ struct list_head list; -+ int ifindex; -+ canid_t can_id; -+ int flags; -+ unsigned long j_ival1, j_ival2, j_lastmsg; -+ unsigned long frames_abs, frames_filtered; -+ struct timer_list timer, thrtimer; -+ struct timeval ival1, ival2; -+ struct timeval rx_stamp; -+ int rx_ifindex; -+ int count; -+ int nframes; -+ int currframe; -+ struct can_frame *frames; -+ struct can_frame *last_frames; -+ struct sock *sk; -+}; -+ -+struct bcm_opt { -+ int bound; -+ int ifindex; -+ struct list_head rx_ops; -+ struct list_head tx_ops; -+ unsigned long dropped_usr_msgs; -+ struct proc_dir_entry *bcm_proc_read; -+ char procname [9]; /* pointer printed in ASCII with \0 */ -+}; -+ -+static struct proc_dir_entry *proc_dir = NULL; -+ -+static int bcm_init(struct sock *sk); -+static void bcm_notifier(unsigned long msg, void *data); -+static int bcm_release(struct socket *sock); -+static int bcm_connect(struct socket *sock, struct sockaddr *uaddr, int len, -+ int flags); -+static int bcm_sendmsg(struct kiocb *iocb, struct socket *sock, -+ struct msghdr *msg, size_t size); -+static int bcm_recvmsg(struct kiocb *iocb, struct socket *sock, -+ struct msghdr *msg, size_t size, int flags); -+static unsigned int bcm_poll(struct file *file, struct socket *sock, -+ poll_table *wait); -+ -+static int bcm_read_proc(char *page, char **start, off_t off, -+ int count, int *eof, void *data); -+ -+static void bcm_tx_timeout_handler(unsigned long data); -+static int bcm_tx_send(struct msghdr *msg, int ifindex, struct sock *sk); -+static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg, -+ int ifindex, struct sock *sk); -+static void bcm_can_tx(struct bcm_op *op); -+ -+static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg, -+ int ifindex, struct sock *sk); -+static void bcm_rx_handler(struct sk_buff *skb, void *op); -+static void bcm_rx_timeout_handler(unsigned long data); -+static void bcm_rx_thr_handler(unsigned long data); -+static void bcm_rx_cmp_to_index(struct bcm_op *op, int index, -+ struct can_frame *rxdata); -+static void bcm_rx_changed(struct bcm_op *op, struct can_frame *data); -+static void bcm_rx_starttimer(struct bcm_op *op); -+static void bcm_rx_update_and_send(struct bcm_op *op, -+ struct can_frame *lastdata, -+ struct can_frame *rxdata); -+static void bcm_send_to_user(struct bcm_op *op, struct bcm_msg_head *head, -+ struct can_frame *frames, struct timeval *tv); -+ -+static int bcm_delete_tx_op(struct list_head *ops, canid_t can_id, -+ int ifindex); -+static int bcm_delete_rx_op(struct list_head *ops, canid_t can_id, -+ int ifindex); -+static void bcm_remove_op(struct bcm_op *op); -+static int bcm_read_op(struct list_head *ops, struct bcm_msg_head *msg_head, -+ int ifindex); -+static struct bcm_op *bcm_find_op(struct list_head *ops, canid_t can_id, -+ int ifindex); -+ -+static struct proto_ops bcm_ops = { -+ .family = PF_CAN, -+ .release = bcm_release, -+ .bind = sock_no_bind, -+ .connect = bcm_connect, -+ .socketpair = sock_no_socketpair, -+ .accept = sock_no_accept, -+ .getname = sock_no_getname, -+ .poll = bcm_poll, -+ .ioctl = NULL, /* use can_ioctl() from af_can.c */ -+ .listen = sock_no_listen, -+ .shutdown = sock_no_shutdown, -+ .setsockopt = sock_no_setsockopt, -+ .getsockopt = sock_no_getsockopt, -+ .sendmsg = bcm_sendmsg, -+ .recvmsg = bcm_recvmsg, -+ .mmap = sock_no_mmap, -+ .sendpage = sock_no_sendpage, -+}; -+ -+#ifdef CONFIG_CAN_BCM_USER -+#define BCM_CAP (-1) -+#else -+#define BCM_CAP CAP_NET_RAW -+#endif -+ -+struct bcm_sock { -+ struct sock sk; -+ struct bcm_opt opt; -+}; -+ -+#define bcm_sk(sk) (&((struct bcm_sock *)(sk))->opt) -+ -+static struct proto bcm_proto = { -+ .name = "CAN_BCM", -+ .owner = THIS_MODULE, -+ .obj_size = sizeof(struct bcm_sock), -+ .init = bcm_init, -+}; -+ -+static struct can_proto bcm_can_proto = { -+ .type = SOCK_DGRAM, -+ .protocol = CAN_BCM, -+ .capability = BCM_CAP, -+ .ops = &bcm_ops, -+ .prot = &bcm_proto, -+}; -+ -+#define CFSIZ sizeof(struct can_frame) -+#define OPSIZ sizeof(struct bcm_op) -+#define MHSIZ sizeof(struct bcm_msg_head) -+ -+static int __init bcm_module_init(void) -+{ -+ printk(banner); -+ -+ can_proto_register(&bcm_can_proto); -+ -+ /* create /proc/net/can/bcm directory */ -+ proc_dir = proc_mkdir(CAN_PROC_DIR"/"IDENT, NULL); -+ -+ if (proc_dir) -+ proc_dir->owner = THIS_MODULE; -+ -+ return 0; -+} -+ -+static void __exit bcm_module_exit(void) -+{ -+ can_proto_unregister(&bcm_can_proto); -+ -+ if (proc_dir) -+ remove_proc_entry(CAN_PROC_DIR"/"IDENT, NULL); -+ -+} -+ -+/**************************************************/ -+/* initial settings at socket creation time */ -+/**************************************************/ -+ -+static int bcm_init(struct sock *sk) -+{ -+ struct bcm_opt *bo = bcm_sk(sk); -+ -+ bo->bound = 0; -+ bo->ifindex = 0; -+ bo->dropped_usr_msgs = 0; -+ bo->bcm_proc_read = NULL; -+ -+ INIT_LIST_HEAD(&bo->tx_ops); -+ INIT_LIST_HEAD(&bo->rx_ops); -+ -+ return 0; -+} -+ -+/**************************************************/ -+/* handling of netdevice problems */ -+/**************************************************/ -+ -+static void bcm_notifier(unsigned long msg, void *data) -+{ -+ struct sock *sk = (struct sock *)data; -+ struct bcm_opt *bo = bcm_sk(sk); -+ -+ DBG("called for sock %p\n", sk); -+ -+ switch (msg) { -+ case NETDEV_UNREGISTER: -+ bo->bound = 0; -+ bo->ifindex = 0; -+ /* fallthrough */ -+ case NETDEV_DOWN: -+ sk->sk_err = ENETDOWN; -+ if (!sock_flag(sk, SOCK_DEAD)) -+ sk->sk_error_report(sk); -+ } -+} -+ -+/**************************************************/ -+/* standard socket functions */ -+/**************************************************/ -+ -+static int bcm_release(struct socket *sock) -+{ -+ struct sock *sk = sock->sk; -+ struct bcm_opt *bo = bcm_sk(sk); -+ struct bcm_op *op, *next; -+ -+ DBG("socket %p, sk %p\n", sock, sk); -+ -+ /* remove bcm_ops, timer, rx_unregister(), etc. */ -+ -+ list_for_each_entry_safe(op, next, &bo->tx_ops, list) { -+ DBG("removing tx_op %p for can_id %03X\n", op, op->can_id); -+ bcm_remove_op(op); -+ } -+ -+ list_for_each_entry_safe(op, next, &bo->rx_ops, list) { -+ DBG("removing rx_op %p for can_id %03X\n", op, op->can_id); -+ -+ /* Don't care if we're bound or not (due to netdev problems) */ -+ /* can_rx_unregister() is always a save thing to do here */ -+ if (op->ifindex) { -+ struct net_device *dev = dev_get_by_index(op->ifindex); -+ if (dev) { -+ can_rx_unregister(dev, op->can_id, -+ REGMASK(op->can_id), -+ bcm_rx_handler, op); -+ dev_put(dev); -+ } -+ } else -+ can_rx_unregister(NULL, op->can_id, -+ REGMASK(op->can_id), -+ bcm_rx_handler, op); -+ -+ bcm_remove_op(op); -+ } -+ -+ /* remove procfs entry */ -+ if ((proc_dir) && (bo->bcm_proc_read)) { -+ remove_proc_entry(bo->procname, proc_dir); -+ } -+ -+ /* remove device notifier */ -+ if (bo->ifindex) { -+ struct net_device *dev = dev_get_by_index(bo->ifindex); -+ if (dev) { -+ can_dev_unregister(dev, bcm_notifier, sk); -+ dev_put(dev); -+ } -+ } -+ -+ sock_put(sk); -+ -+ return 0; -+} -+ -+static int bcm_connect(struct socket *sock, struct sockaddr *uaddr, int len, -+ int flags) -+{ -+ struct sockaddr_can *addr = (struct sockaddr_can *)uaddr; -+ struct sock *sk = sock->sk; -+ struct bcm_opt *bo = bcm_sk(sk); -+ -+ if (bo->bound) -+ return -EISCONN; -+ -+ /* bind a device to this socket */ -+ if (addr->can_ifindex) { -+ struct net_device *dev = dev_get_by_index(addr->can_ifindex); -+ if (!dev) { -+ DBG("could not find device index %d\n", -+ addr->can_ifindex); -+ return -ENODEV; -+ } -+ bo->ifindex = dev->ifindex; -+ can_dev_register(dev, bcm_notifier, sk); /* register notif. */ -+ dev_put(dev); -+ -+ DBG("socket %p bound to device %s (idx %d)\n", -+ sock, dev->name, dev->ifindex); -+ } else { -+ /* no notifier for ifindex = 0 ('any' CAN device) */ -+ bo->ifindex = 0; -+ } -+ -+ bo->bound = 1; -+ -+ if (proc_dir) { -+ /* unique socket address as filename */ -+ sprintf(bo->procname, "%p", sock); -+ bo->bcm_proc_read = create_proc_read_entry(bo->procname, 0644, -+ proc_dir, -+ bcm_read_proc, sk); -+ } -+ -+ return 0; -+} -+ -+static int bcm_sendmsg(struct kiocb *iocb, struct socket *sock, -+ struct msghdr *msg, size_t size) -+{ -+ struct sock *sk = sock->sk; -+ struct bcm_opt *bo = bcm_sk(sk); -+ int ifindex = bo->ifindex; /* default ifindex for this bcm_op */ -+ struct bcm_msg_head msg_head; -+ int ret; /* read bytes or error codes as return value */ -+ -+ if (!bo->bound) { -+ DBG("sock %p not bound\n", sk); -+ return -ENOTCONN; -+ } -+ -+ /* check for alternative ifindex for this bcm_op */ -+ -+ if (!ifindex && msg->msg_name) { /* no bound device as default */ -+ struct sockaddr_can *addr = -+ (struct sockaddr_can *)msg->msg_name; -+ if (addr->can_family != AF_CAN) -+ return -EINVAL; -+ ifindex = addr->can_ifindex; /* ifindex from sendto() */ -+ -+ if (ifindex && !dev_get_by_index(ifindex)) { -+ DBG("device %d not found\n", ifindex); -+ return -ENODEV; -+ } -+ } -+ -+ /* read message head information */ -+ -+ if ((ret = memcpy_fromiovec((u8*)&msg_head, msg->msg_iov, -+ MHSIZ)) < 0) -+ return ret; -+ -+ DBG("opcode %d for can_id %03X\n", msg_head.opcode, msg_head.can_id); -+ -+ switch (msg_head.opcode) { -+ -+ case TX_SETUP: -+ -+ ret = bcm_tx_setup(&msg_head, msg, ifindex, sk); -+ break; -+ -+ case RX_SETUP: -+ -+ ret = bcm_rx_setup(&msg_head, msg, ifindex, sk); -+ break; -+ -+ case TX_DELETE: -+ -+ if (bcm_delete_tx_op(&bo->tx_ops, msg_head.can_id, ifindex)) -+ ret = MHSIZ; -+ else -+ ret = -EINVAL; -+ break; -+ -+ case RX_DELETE: -+ -+ if (bcm_delete_rx_op(&bo->rx_ops, msg_head.can_id, ifindex)) -+ ret = MHSIZ; -+ else -+ ret = -EINVAL; -+ break; -+ -+ case TX_READ: -+ -+ /* reuse msg_head for the reply */ -+ msg_head.opcode = TX_STATUS; /* reply to TX_READ */ -+ ret = bcm_read_op(&bo->tx_ops, &msg_head, ifindex); -+ break; -+ -+ case RX_READ: -+ -+ /* reuse msg_head for the reply */ -+ msg_head.opcode = RX_STATUS; /* reply to RX_READ */ -+ ret = bcm_read_op(&bo->rx_ops, &msg_head, ifindex); -+ break; -+ -+ case TX_SEND: -+ -+ if (msg_head.nframes < 1) /* we need at least one can_frame */ -+ return -EINVAL; -+ -+ ret = bcm_tx_send(msg, ifindex, sk); -+ break; -+ -+ default: -+ -+ DBG("Unknown opcode %d\n", msg_head.opcode); -+ ret = -EINVAL; -+ break; -+ } -+ -+ return ret; -+} -+ -+static int bcm_recvmsg(struct kiocb *iocb, struct socket *sock, -+ struct msghdr *msg, size_t size, int flags) -+{ -+ struct sock *sk = sock->sk; -+ struct sk_buff *skb; -+ int error = 0; -+ int noblock; -+ int err; -+ -+ DBG("socket %p, sk %p\n", sock, sk); -+ -+ noblock = flags & MSG_DONTWAIT; -+ flags &= ~MSG_DONTWAIT; -+ if (!(skb = skb_recv_datagram(sk, flags, noblock, &error))) { -+ return error; -+ } -+ -+ DBG("delivering skbuff %p\n", skb); -+ DBG_SKB(skb); -+ -+ if (skb->len < size) -+ size = skb->len; -+ if ((err = memcpy_toiovec(msg->msg_iov, skb->data, size)) < 0) { -+ skb_free_datagram(sk, skb); -+ return err; -+ } -+ -+ sock_recv_timestamp(msg, sk, skb); -+ -+ if (msg->msg_name) { -+ msg->msg_namelen = sizeof(struct sockaddr_can); -+ memcpy(msg->msg_name, skb->cb, msg->msg_namelen); -+ } -+ -+ DBG("freeing sock %p, skbuff %p\n", sk, skb); -+ skb_free_datagram(sk, skb); -+ -+ return size; -+} -+ -+static unsigned int bcm_poll(struct file *file, struct socket *sock, -+ poll_table *wait) -+{ -+ unsigned int mask = 0; -+ -+ DBG("socket %p\n", sock); -+ -+ mask = datagram_poll(file, sock, wait); -+ return mask; -+} -+ -+/**************************************************/ -+/* helper functions for bcm_sendmsg() */ -+/**************************************************/ -+ -+static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg, -+ int ifindex, struct sock *sk) -+{ -+ struct bcm_opt *bo = bcm_sk(sk); -+ struct bcm_op *op; -+ int i, err; -+ -+ if (!ifindex) /* we need a real device to send frames */ -+ return -ENODEV; -+ -+ if (msg_head->nframes < 1) /* we need at least one can_frame */ -+ return -EINVAL; -+ -+ /* check the given can_id */ -+ -+ if ((op = bcm_find_op(&bo->tx_ops, msg_head->can_id, ifindex))) { -+ -+ /* update existing BCM operation */ -+ -+ DBG("TX_SETUP: modifying existing tx_op %p for can_id %03X\n", -+ op, msg_head->can_id); -+ -+ /* Do we need more space for the can_frames than currently */ -+ /* allocated? -> This is a _really_ unusual use-case and */ -+ /* therefore (complexity / locking) it is not supported. */ -+ if (msg_head->nframes > op->nframes) -+ return -E2BIG; -+ -+ /* update can_frames content */ -+ for (i = 0; i < msg_head->nframes; i++) { -+ if ((err = memcpy_fromiovec((u8*)&op->frames[i], -+ msg->msg_iov, CFSIZ)) < 0) -+ return err; -+ -+ if (msg_head->flags & TX_CP_CAN_ID) { -+ /* copy can_id into frame */ -+ op->frames[i].can_id = msg_head->can_id; -+ } -+ } -+ -+ } else { -+ /* insert new BCM operation for the given can_id */ -+ -+ if (!(op = kmalloc(OPSIZ, GFP_KERNEL))) -+ return -ENOMEM; -+ -+ memset(op, 0, OPSIZ); /* init to zero, e.g. for timers */ -+ -+ DBG("TX_SETUP: creating new tx_op %p for can_id %03X\n", -+ op, msg_head->can_id); -+ -+ op->can_id = msg_head->can_id; -+ -+ /* create array for can_frames and copy the data */ -+ if (!(op->frames = kmalloc(msg_head->nframes * CFSIZ, -+ GFP_KERNEL))) { -+ kfree(op); -+ return -ENOMEM; -+ } -+ -+ for (i = 0; i < msg_head->nframes; i++) { -+ if ((err = memcpy_fromiovec((u8*)&op->frames[i], -+ msg->msg_iov, -+ CFSIZ)) < 0) { -+ kfree(op->frames); -+ kfree(op); -+ return err; -+ } -+ -+ if (msg_head->flags & TX_CP_CAN_ID) { -+ /* copy can_id into frame */ -+ op->frames[i].can_id = msg_head->can_id; -+ } -+ } -+ -+ /* tx_ops never compare with previous received messages */ -+ op->last_frames = NULL; -+ -+ /* bcm_can_tx / bcm_tx_timeout_handler needs this */ -+ op->sk = sk; -+ -+ op->ifindex = ifindex; -+ -+ /* initialize uninitialized (kmalloc) structure */ -+ init_timer(&op->timer); -+ -+ /* currently unused in tx_ops */ -+ init_timer(&op->thrtimer); -+ -+ /* handler for tx_ops */ -+ op->timer.function = bcm_tx_timeout_handler; -+ -+ /* timer.data points to this op-structure */ -+ op->timer.data = (unsigned long)op; -+ -+ /* add this bcm_op to the list of the tx_ops */ -+ list_add(&op->list, &bo->tx_ops); -+ -+ } /* if ((op = bcm_find_op(&bo->tx_ops, msg_head->can_id, ifindex))) */ -+ -+ if (op->nframes != msg_head->nframes) { -+ op->nframes = msg_head->nframes; -+ /* start multiple frame transmission with index 0 */ -+ op->currframe = 0; -+ } -+ -+ /* check flags */ -+ -+ op->flags = msg_head->flags; -+ -+ if (op->flags & TX_RESET_MULTI_IDX) { -+ /* start multiple frame transmission with index 0 */ -+ op->currframe = 0; -+ } -+ -+ if (op->flags & SETTIMER) { -+ -+ /* set timer values */ -+ -+ op->count = msg_head->count; -+ op->ival1 = msg_head->ival1; -+ op->ival2 = msg_head->ival2; -+ op->j_ival1 = timeval2jiffies(&msg_head->ival1, 1); -+ op->j_ival2 = timeval2jiffies(&msg_head->ival2, 1); -+ -+ DBG("TX_SETUP: SETTIMER count=%d j_ival1=%ld j_ival2=%ld\n", -+ op->count, op->j_ival1, op->j_ival2); -+ -+ /* disable an active timer due to zero values? */ -+ if (!op->j_ival1 && !op->j_ival2) { -+ del_timer(&op->timer); -+ DBG("TX_SETUP: SETTIMER disabled timer.\n"); -+ } -+ } -+ -+ if ((op->flags & STARTTIMER) && -+ ((op->j_ival1 && op->count) || op->j_ival2)) { -+ -+ del_timer(&op->timer); -+ -+ /* spec: send can_frame when starting timer */ -+ op->flags |= TX_ANNOUNCE; -+ -+ if (op->j_ival1 && (op->count > 0)){ -+ op->timer.expires = jiffies + op->j_ival1; -+ /* op->count-- is done in bcm_tx_timeout_handler */ -+ DBG("TX_SETUP: adding timer ival1. func=%p data=%p " -+ "exp=0x%08X\n", -+ op->timer.function, -+ (char*) op->timer.data, -+ (unsigned int) op->timer.expires); -+ } else{ -+ op->timer.expires = jiffies + op->j_ival2; -+ DBG("TX_SETUP: adding timer ival2. func=%p data=%p " -+ "exp=0x%08X\n", -+ op->timer.function, -+ (char*) op->timer.data, -+ (unsigned int) op->timer.expires); -+ } -+ -+ add_timer(&op->timer); -+ } -+ -+ if (op->flags & TX_ANNOUNCE) -+ bcm_can_tx(op); -+ -+ return msg_head->nframes * CFSIZ + MHSIZ; -+} -+ -+static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg, -+ int ifindex, struct sock *sk) -+{ -+ struct bcm_opt *bo = bcm_sk(sk); -+ struct bcm_op *op; -+ int do_rx_register; -+ int err; -+ -+ if ((msg_head->flags & RX_FILTER_ID) || (!(msg_head->nframes))) { -+ /* be robust against wrong usage ... */ -+ msg_head->flags |= RX_FILTER_ID; -+ msg_head->nframes = 0; /* ignore trailing garbage */ -+ } -+ -+ if ((msg_head->flags & RX_RTR_FRAME) && -+ ((msg_head->nframes != 1) || -+ (!(msg_head->can_id & CAN_RTR_FLAG)))) { -+ -+ DBG("RX_SETUP: bad RX_RTR_FRAME setup!\n"); -+ return -EINVAL; -+ } -+ -+ /* check the given can_id */ -+ -+ if ((op = bcm_find_op(&bo->rx_ops, msg_head->can_id, ifindex))) { -+ -+ /* update existing BCM operation */ -+ -+ DBG("RX_SETUP: modifying existing rx_op %p for can_id %03X\n", -+ op, msg_head->can_id); -+ -+ /* Do we need more space for the can_frames than currently */ -+ /* allocated? -> This is a _really_ unusual use-case and */ -+ /* therefore (complexity / locking) it is not supported. */ -+ if (msg_head->nframes > op->nframes) -+ return -E2BIG; -+ -+ if (msg_head->nframes) { -+ /* update can_frames content */ -+ if ((err = memcpy_fromiovec((u8*)op->frames, -+ msg->msg_iov, -+ msg_head->nframes -+ * CFSIZ) < 0)) -+ return err; -+ -+ /* clear last_frames to indicate 'nothing received' */ -+ memset(op->last_frames, 0, msg_head->nframes * CFSIZ); -+ } -+ -+ op->nframes = msg_head->nframes; -+ /* Only an update -> do not call can_rx_register() */ -+ do_rx_register = 0; -+ -+ } else { -+ /* insert new BCM operation for the given can_id */ -+ -+ if (!(op = kmalloc(OPSIZ, GFP_KERNEL))) -+ return -ENOMEM; -+ -+ memset(op, 0, OPSIZ); /* init to zero, e.g. for timers */ -+ -+ DBG("RX_SETUP: creating new rx_op %p for can_id %03X\n", -+ op, msg_head->can_id); -+ -+ op->can_id = msg_head->can_id; -+ op->nframes = msg_head->nframes; -+ -+ if (msg_head->nframes) { -+ -+ /* create array for can_frames and copy the data */ -+ if (!(op->frames = kmalloc(msg_head->nframes * CFSIZ, -+ GFP_KERNEL))) { -+ kfree(op); -+ return -ENOMEM; -+ } -+ -+ if ((err = memcpy_fromiovec((u8*)op->frames, -+ msg->msg_iov, -+ msg_head->nframes -+ * CFSIZ)) < 0) { -+ kfree(op->frames); -+ kfree(op); -+ return err; -+ } -+ -+ /* create array for received can_frames */ -+ if (!(op->last_frames = kmalloc(msg_head->nframes -+ * CFSIZ, -+ GFP_KERNEL))) { -+ kfree(op->frames); -+ kfree(op); -+ return -ENOMEM; -+ } -+ -+ /* clear last_frames to indicate 'nothing received' */ -+ memset(op->last_frames, 0, msg_head->nframes * CFSIZ); -+ } else { -+ /* op->frames = NULL due to memset */ -+ -+ /* even when we have the RX_FILTER_ID case, we need */ -+ /* to store the last frame for the throttle feature */ -+ -+ /* create array for received can_frames */ -+ if (!(op->last_frames = kmalloc(CFSIZ, GFP_KERNEL))) { -+ kfree(op); -+ return -ENOMEM; -+ } -+ -+ /* clear last_frames to indicate 'nothing received' */ -+ memset(op->last_frames, 0, CFSIZ); -+ } -+ -+ op->sk = sk; /* bcm_delete_rx_op() needs this */ -+ op->ifindex = ifindex; -+ -+ /* initialize uninitialized (kmalloc) structure */ -+ init_timer(&op->timer); -+ -+ /* init throttle timer for RX_CHANGED */ -+ init_timer(&op->thrtimer); -+ -+ /* handler for rx timeouts */ -+ op->timer.function = bcm_rx_timeout_handler; -+ -+ /* timer.data points to this op-structure */ -+ op->timer.data = (unsigned long)op; -+ -+ /* handler for RX_CHANGED throttle timeouts */ -+ op->thrtimer.function = bcm_rx_thr_handler; -+ -+ /* timer.data points to this op-structure */ -+ op->thrtimer.data = (unsigned long)op; -+ -+ op->thrtimer.expires = 0; /* mark disabled timer */ -+ -+ /* add this bcm_op to the list of the tx_ops */ -+ list_add(&op->list, &bo->rx_ops); -+ -+ do_rx_register = 1; /* call can_rx_register() */ -+ -+ } /* if ((op = bcm_find_op(&bo->rx_ops, msg_head->can_id, ifindex))) */ -+ -+ -+ /* check flags */ -+ -+ op->flags = msg_head->flags; -+ -+ if (op->flags & RX_RTR_FRAME) { -+ -+ /* no timers in RTR-mode */ -+ del_timer(&op->thrtimer); -+ del_timer(&op->timer); -+ -+ /* funny feature in RX(!)_SETUP only for RTR-mode: */ -+ /* copy can_id into frame BUT without RTR-flag to */ -+ /* prevent a full-load-loopback-test ... ;-] */ -+ if ((op->flags & TX_CP_CAN_ID) || -+ (op->frames[0].can_id == op->can_id)) -+ op->frames[0].can_id = op->can_id & ~CAN_RTR_FLAG; -+ -+ } else { -+ if (op->flags & SETTIMER) { -+ -+ /* set timer value */ -+ -+ op->ival1 = msg_head->ival1; -+ op->j_ival1 = timeval2jiffies(&msg_head->ival1, 1); -+ op->ival2 = msg_head->ival2; -+ op->j_ival2 = timeval2jiffies(&msg_head->ival2, 1); -+ -+ DBG("RX_SETUP: SETTIMER j_ival1=%ld j_ival2=%ld\n", -+ op->j_ival1, op->j_ival2); -+ -+ /* disable an active timer due to zero value? */ -+ if (!op->j_ival1) { -+ del_timer(&op->timer); -+ DBG("RX_SETUP: disabled timer rx timeouts.\n"); -+ } -+ -+ /* free currently blocked msgs ? */ -+ if (op->thrtimer.expires) { /* blocked by timer? */ -+ DBG("RX_SETUP: unblocking throttled msgs.\n"); -+ del_timer(&op->thrtimer); -+ /* send blocked msgs hereafter */ -+ op->thrtimer.expires = jiffies + 2; -+ add_timer(&op->thrtimer); -+ } -+ /* if (op->j_ival2) is zero, no (new) throttling */ -+ /* will happen. For details see functions */ -+ /* bcm_rx_update_and_send() and bcm_rx_thr_handler() */ -+ } -+ -+ if ((op->flags & STARTTIMER) && op->j_ival1) { -+ -+ del_timer(&op->timer); -+ -+ op->timer.expires = jiffies + op->j_ival1; -+ -+ DBG("RX_SETUP: adding timer ival1. func=%p data=%p" -+ " exp=0x%08X\n", -+ (char *) op->timer.function, -+ (char *) op->timer.data, -+ (unsigned int) op->timer.expires); -+ -+ add_timer(&op->timer); -+ } -+ } -+ -+ /* now we can register for can_ids, if we added a new bcm_op */ -+ if (do_rx_register) { -+ DBG("RX_SETUP: can_rx_register() for can_id %03X. " -+ "rx_op is %p\n", op->can_id, op); -+ -+ if (ifindex) { -+ struct net_device *dev = dev_get_by_index(ifindex); -+ -+ if (dev) { -+ can_rx_register(dev, op->can_id, -+ REGMASK(op->can_id), -+ bcm_rx_handler, op, IDENT); -+ dev_put(dev); -+ } -+ } else -+ can_rx_register(NULL, op->can_id, REGMASK(op->can_id), -+ bcm_rx_handler, op, IDENT); -+ } -+ -+ return msg_head->nframes * CFSIZ + MHSIZ; -+} -+ -+static int bcm_tx_send(struct msghdr *msg, int ifindex, struct sock *sk) -+{ -+ struct sk_buff *skb; -+ struct net_device *dev; -+ int err; -+ -+ /* just copy and send one can_frame */ -+ -+ if (!ifindex) /* we need a real device to send frames */ -+ return -ENODEV; -+ -+ skb = alloc_skb(CFSIZ, GFP_KERNEL); -+ -+ if (!skb) -+ return -ENOMEM; -+ -+ if ((err = memcpy_fromiovec(skb_put(skb, CFSIZ), msg->msg_iov, -+ CFSIZ)) < 0) { -+ kfree_skb(skb); -+ return err; -+ } -+ -+ DBG_FRAME("BCM: TX_SEND: sending frame", -+ (struct can_frame *)skb->data); -+ dev = dev_get_by_index(ifindex); -+ -+ if (!dev) { -+ kfree_skb(skb); -+ return -ENODEV; -+ } -+ -+ skb->dev = dev; -+ skb->sk = sk; -+ can_send(skb, 1); /* send with loopback */ -+ dev_put(dev); -+ -+ return CFSIZ + MHSIZ; -+} -+ -+static int bcm_read_op(struct list_head *ops, struct bcm_msg_head *msg_head, -+ int ifindex) -+{ -+ struct bcm_op *op; -+ int ret; -+ -+ if ((op = bcm_find_op(ops, msg_head->can_id, ifindex))) { -+ -+ DBG("TRX_READ: sending status for can_id %03X\n", -+ msg_head->can_id); -+ /* put current values into msg_head */ -+ msg_head->flags = op->flags; -+ msg_head->count = op->count; -+ msg_head->ival1 = op->ival1; -+ msg_head->ival2 = op->ival2; -+ msg_head->nframes = op->nframes; -+ -+ bcm_send_to_user(op, msg_head, op->frames, NULL); -+ -+ ret = MHSIZ; -+ -+ } else { -+ -+ DBG("TRX_READ: did not find op for can_id %03X\n", -+ msg_head->can_id); -+ ret = -EINVAL; -+ } -+ -+ return ret; -+} -+ -+/**************************************************/ -+/* procfs functions */ -+/**************************************************/ -+ -+static char *bcm_proc_getifname(int ifindex) -+{ -+ struct net_device *dev; -+ -+ if (!ifindex) -+ return "any"; -+ -+ dev = __dev_get_by_index(ifindex); /* no usage counting */ -+ if (dev) -+ return dev->name; -+ -+ return "???"; -+} -+ -+static int bcm_read_proc(char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int len = 0; -+ struct sock *sk = (struct sock *)data; -+ struct bcm_opt *bo = bcm_sk(sk); -+ struct bcm_op *op; -+ -+ len += snprintf(page + len, PAGE_SIZE - len, ">>> socket %p", -+ sk->sk_socket); -+ len += snprintf(page + len, PAGE_SIZE - len, " / sk %p", sk); -+ len += snprintf(page + len, PAGE_SIZE - len, " / bo %p", bo); -+ len += snprintf(page + len, PAGE_SIZE - len, " / dropped %lu", -+ bo->dropped_usr_msgs); -+ len += snprintf(page + len, PAGE_SIZE - len, " / bound %s", -+ bcm_proc_getifname(bo->ifindex)); -+ len += snprintf(page + len, PAGE_SIZE - len, " <<<\n"); -+ -+ list_for_each_entry(op, &bo->rx_ops, list) { -+ -+ unsigned long reduction; -+ -+ /* print only active entries & prevent division by zero */ -+ if (!op->frames_abs) -+ continue; -+ -+ len += snprintf(page + len, PAGE_SIZE - len, -+ "rx_op: %03X %-5s ", -+ op->can_id, bcm_proc_getifname(op->ifindex)); -+ len += snprintf(page + len, PAGE_SIZE - len, "[%d]%c ", -+ op->nframes, -+ (op->flags & RX_CHECK_DLC)?'d':' '); -+ if (op->j_ival1) -+ len += snprintf(page + len, PAGE_SIZE - len, -+ "timeo=%ld ", op->j_ival1); -+ -+ if (op->j_ival2) -+ len += snprintf(page + len, PAGE_SIZE - len, -+ "thr=%ld ", op->j_ival2); -+ -+ len += snprintf(page + len, PAGE_SIZE - len, -+ "# recv %ld (%ld) => reduction: ", -+ op->frames_filtered, op->frames_abs); -+ -+ reduction = 100 - (op->frames_filtered * 100) / op->frames_abs; -+ -+ len += snprintf(page + len, PAGE_SIZE - len, "%s%ld%%\n", -+ (reduction == 100)?"near ":"", reduction); -+ -+ if (len > PAGE_SIZE - 200) { -+ /* mark output cut off */ -+ len += snprintf(page + len, PAGE_SIZE - len, "(..)\n"); -+ break; -+ } -+ } -+ -+ list_for_each_entry(op, &bo->tx_ops, list) { -+ -+ len += snprintf(page + len, PAGE_SIZE - len, -+ "tx_op: %03X %s [%d] ", -+ op->can_id, bcm_proc_getifname(op->ifindex), -+ op->nframes); -+ if (op->j_ival1) -+ len += snprintf(page + len, PAGE_SIZE - len, "t1=%ld ", -+ op->j_ival1); -+ -+ if (op->j_ival2) -+ len += snprintf(page + len, PAGE_SIZE - len, "t2=%ld ", -+ op->j_ival2); -+ -+ len += snprintf(page + len, PAGE_SIZE - len, "# sent %ld\n", -+ op->frames_abs); -+ -+ if (len > PAGE_SIZE - 100) { -+ /* mark output cut off */ -+ len += snprintf(page + len, PAGE_SIZE - len, "(..)\n"); -+ break; -+ } -+ } -+ -+ len += snprintf(page + len, PAGE_SIZE - len, "\n"); -+ -+ *eof = 1; -+ return len; -+} -+ -+/**************************************************/ -+/* bcm_op handling tx path */ -+/**************************************************/ -+ -+static void bcm_can_tx(struct bcm_op *op) -+{ -+ struct sk_buff *skb; -+ struct net_device *dev; -+ struct can_frame *cf = &op->frames[op->currframe]; -+ -+ DBG_FRAME("BCM: bcm_can_tx: sending frame", cf); -+ -+ if (!op->ifindex) -+ return; /* no target device -> exit */ -+ -+ dev = dev_get_by_index(op->ifindex); -+ -+ if (!dev) -+ return; /* should this bcm_op remove itself here? */ -+ -+ skb = alloc_skb(CFSIZ, -+ in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); -+ -+ if (!skb) -+ goto out; /* no memory */ -+ -+ memcpy(skb_put(skb, CFSIZ), cf, CFSIZ); -+ -+ skb->dev = dev; -+ skb->sk = op->sk; -+ can_send(skb, 1); /* send with loopback */ -+ -+ op->currframe++; -+ op->frames_abs++; /* statistics */ -+ -+ /* reached last frame? */ -+ if (op->currframe >= op->nframes) -+ op->currframe = 0; -+ out: -+ dev_put(dev); -+} -+ -+static void bcm_tx_timeout_handler(unsigned long data) -+{ -+ struct bcm_op *op = (struct bcm_op*)data; -+ -+ DBG("Called with bcm_op %p\n", op); -+ -+ if (op->j_ival1 && (op->count > 0)) { -+ -+ op->count--; -+ -+ if (!op->count && (op->flags & TX_COUNTEVT)) { -+ /* create notification to user */ -+ -+ struct bcm_msg_head msg_head; -+ -+ DBG("sending TX_EXPIRED for can_id %03X\n", -+ op->can_id); -+ -+ msg_head.opcode = TX_EXPIRED; -+ msg_head.flags = op->flags; -+ msg_head.count = op->count; -+ msg_head.ival1 = op->ival1; -+ msg_head.ival2 = op->ival2; -+ msg_head.can_id = op->can_id; -+ msg_head.nframes = 0; -+ -+ bcm_send_to_user(op, &msg_head, NULL, NULL); -+ } -+ } -+ -+ DBG("count=%d j_ival1=%ld j_ival2=%ld\n", -+ op->count, op->j_ival1, op->j_ival2); -+ -+ if (op->j_ival1 && (op->count > 0)) { -+ -+ op->timer.expires = jiffies + op->j_ival1; -+ add_timer(&op->timer); -+ -+ DBG("adding timer ival1. func=%p data=%p exp=0x%08X\n", -+ op->timer.function, -+ (char*) op->timer.data, -+ (unsigned int) op->timer.expires); -+ -+ bcm_can_tx(op); /* send (next) frame */ -+ } else { -+ if (op->j_ival2) { -+ op->timer.expires = jiffies + op->j_ival2; -+ add_timer(&op->timer); -+ -+ DBG("adding timer ival2. func=%p data=%p exp=0x%08X\n", -+ op->timer.function, -+ (char*) op->timer.data, -+ (unsigned int) op->timer.expires); -+ -+ bcm_can_tx(op); /* send (next) frame */ -+ } else -+ DBG("no timer restart\n"); -+ } -+ -+ return; -+ -+} -+ -+/**************************************************/ -+/* bcm_op handling rx path */ -+/**************************************************/ -+ -+static void bcm_rx_handler(struct sk_buff *skb, void *data) -+{ -+ struct bcm_op *op = (struct bcm_op*)data; -+ struct can_frame rxframe; -+ int i; -+ -+ del_timer(&op->timer); /* disable timeout */ -+ -+ DBG("Called with bcm_op %p\n", op); -+ -+ if (skb->len == sizeof(rxframe)) { -+ memcpy(&rxframe, skb->data, sizeof(rxframe)); -+ skb_get_timestamp(skb, &op->rx_stamp); /* save rx timestamp */ -+ /* save originator for recvfrom() */ -+ op->rx_ifindex = skb->dev->ifindex; -+ op->frames_abs++; /* statistics */ -+ kfree_skb(skb); -+ DBG("got can_frame with can_id %03X\n", rxframe.can_id); -+ } else { -+ DBG("Wrong skb->len = %d\n", skb->len); -+ kfree_skb(skb); -+ return; -+ } -+ -+ DBG_FRAME("BCM: bcm_rx_handler: CAN frame", &rxframe); -+ -+ if (op->can_id != rxframe.can_id) { -+ DBG("ERROR! Got wrong can_id %03X! Expected %03X.\n", -+ rxframe.can_id, op->can_id); -+ return; -+ } -+ -+ if (op->flags & RX_RTR_FRAME) { /* send reply for RTR-request */ -+ DBG("RTR-request\n"); -+ bcm_can_tx(op); /* send op->frames[0] to CAN device */ -+ return; -+ } -+ -+ if (op->flags & RX_FILTER_ID) { /* the easiest case */ -+ DBG("Easy does it with RX_FILTER_ID\n"); -+ bcm_rx_update_and_send(op, &op->last_frames[0], &rxframe); -+ bcm_rx_starttimer(op); -+ return; -+ } -+ -+ if (op->nframes == 1) { /* simple compare with index 0 */ -+ DBG("Simple compare\n"); -+ bcm_rx_cmp_to_index(op, 0, &rxframe); -+ bcm_rx_starttimer(op); -+ return; -+ } -+ -+ if (op->nframes > 1) { /* multiplex compare */ -+ -+ DBG("Multiplex compare\n"); -+ /* find the first multiplex mask that fits */ -+ /* MUX-mask is in index 0 */ -+ -+ for (i=1; i < op->nframes; i++) { -+ -+ if ((GET_U64(&op->frames[0]) & GET_U64(&rxframe)) == -+ (GET_U64(&op->frames[0]) & -+ GET_U64(&op->frames[i]))) { -+ DBG("found MUX index %d\n", i); -+ bcm_rx_cmp_to_index(op, i, &rxframe); -+ break; -+ } -+ } -+ bcm_rx_starttimer(op); -+ } -+} -+ -+static void bcm_rx_cmp_to_index(struct bcm_op *op, int index, -+ struct can_frame *rxdata) -+{ -+ /* no one uses the MSBs of can_dlc for comparation, */ -+ /* so we use it here to detect the first time of reception */ -+ -+ if (!(op->last_frames[index].can_dlc & RX_RECV)) { /* first time? */ -+ DBG("first time :)\n"); -+ bcm_rx_update_and_send(op, &op->last_frames[index], rxdata); -+ return; -+ } -+ -+ /* do a real check in can_data */ -+ -+ DBG("op->frames[index].data = 0x%016llx\n", -+ GET_U64(&op->frames[index])); -+ DBG("op->last_frames[index].data = 0x%016llx\n", -+ GET_U64(&op->last_frames[index])); -+ DBG("rxdata->data = 0x%016llx\n", GET_U64(rxdata)); -+ -+ if ((GET_U64(&op->frames[index]) & GET_U64(rxdata)) != -+ (GET_U64(&op->frames[index]) & GET_U64(&op->last_frames[index]))) { -+ DBG("relevant data change :)\n"); -+ bcm_rx_update_and_send(op, &op->last_frames[index], rxdata); -+ return; -+ } -+ -+ -+ if (op->flags & RX_CHECK_DLC) { -+ -+ /* do a real check in dlc */ -+ -+ if (rxdata->can_dlc != (op->last_frames[index].can_dlc & -+ BCM_CAN_DLC_MASK)) { -+ DBG("dlc change :)\n"); -+ bcm_rx_update_and_send(op, &op->last_frames[index], -+ rxdata); -+ return; -+ } -+ } -+ DBG("no relevant change :(\n"); -+} -+ -+static void bcm_rx_update_and_send(struct bcm_op *op, -+ struct can_frame *lastdata, -+ struct can_frame *rxdata) -+{ -+ unsigned long nexttx = op->j_lastmsg + op->j_ival2; -+ -+ memcpy(lastdata, rxdata, CFSIZ); -+ lastdata->can_dlc |= RX_RECV; /* mark as used */ -+ -+ /* throttle bcm_rx_changed ? */ -+ if ((op->thrtimer.expires) || /* somebody else is already waiting OR */ -+ ((op->j_ival2) && (nexttx > jiffies))) { /* we have to wait */ -+ -+ lastdata->can_dlc |= RX_THR; /* mark as 'throttled' */ -+ -+ if (!(op->thrtimer.expires)) { /* start only the first time */ -+ op->thrtimer.expires = nexttx; -+ add_timer(&op->thrtimer); -+ -+ DBG("adding thrtimer. func=%p data=%p exp=0x%08X\n", -+ op->thrtimer.function, -+ (char*) op->thrtimer.data, -+ (unsigned int) op->thrtimer.expires); -+ } -+ } else -+ bcm_rx_changed(op, rxdata); /* send RX_CHANGED to the user */ -+} -+ -+static void bcm_rx_starttimer(struct bcm_op *op) -+{ -+ if (op->flags & RX_NO_AUTOTIMER) -+ return; -+ -+ if (op->j_ival1) { -+ -+ op->timer.expires = jiffies + op->j_ival1; -+ -+ DBG("adding rx timeout timer ival1. func=%p data=%p " -+ "exp=0x%08X\n", -+ op->timer.function, -+ (char*) op->timer.data, -+ (unsigned int) op->timer.expires); -+ -+ add_timer(&op->timer); -+ } -+} -+ -+ -+static void bcm_rx_changed(struct bcm_op *op, struct can_frame *data) -+{ -+ struct bcm_msg_head head; -+ -+ op->j_lastmsg = jiffies; -+ op->frames_filtered++; /* statistics */ -+ -+ if (op->frames_filtered > ULONG_MAX/100) -+ op->frames_filtered = op->frames_abs = 0; /* restart */ -+ -+ DBG("setting j_lastmsg to 0x%08X for rx_op %p\n", -+ (unsigned int) op->j_lastmsg, op); -+ DBG("sending notification\n"); -+ -+ head.opcode = RX_CHANGED; -+ head.flags = op->flags; -+ head.count = op->count; -+ head.ival1 = op->ival1; -+ head.ival2 = op->ival2; -+ head.can_id = op->can_id; -+ head.nframes = 1; -+ -+ bcm_send_to_user(op, &head, data, &op->rx_stamp); -+} -+ -+ -+static void bcm_rx_timeout_handler(unsigned long data) -+{ -+ struct bcm_op *op = (struct bcm_op*)data; -+ struct bcm_msg_head msg_head; -+ -+ DBG("sending RX_TIMEOUT for can_id %03X. op is %p\n", op->can_id, op); -+ -+ msg_head.opcode = RX_TIMEOUT; -+ msg_head.flags = op->flags; -+ msg_head.count = op->count; -+ msg_head.ival1 = op->ival1; -+ msg_head.ival2 = op->ival2; -+ msg_head.can_id = op->can_id; -+ msg_head.nframes = 0; -+ -+ bcm_send_to_user(op, &msg_head, NULL, NULL); -+ -+ /* no restart of the timer is done here! */ -+ -+ /* if user wants to be informed, when cyclic CAN-Messages come back */ -+ if ((op->flags & RX_ANNOUNCE_RESUME) && op->last_frames) { -+ /* clear received can_frames to indicate 'nothing received' */ -+ memset(op->last_frames, 0, op->nframes * CFSIZ); -+ DBG("RX_ANNOUNCE_RESTART\n"); -+ } -+ -+} -+ -+static void bcm_rx_thr_handler(unsigned long data) -+{ -+ struct bcm_op *op = (struct bcm_op*)data; -+ int i = 0; -+ -+ op->thrtimer.expires = 0; /* mark disabled / consumed timer */ -+ -+ if (op->nframes > 1){ -+ -+ DBG("sending MUX RX_CHANGED for can_id %03X. op is %p\n", -+ op->can_id, op); -+ /* for MUX filter we start at index 1 */ -+ for (i=1; inframes; i++){ -+ if ((op->last_frames) && -+ (op->last_frames[i].can_dlc & RX_THR)){ -+ op->last_frames[i].can_dlc &= ~RX_THR; -+ bcm_rx_changed(op, &op->last_frames[i]); -+ } -+ } -+ } else { -+ -+ DBG("sending simple RX_CHANGED for can_id %03X. op is %p\n", -+ op->can_id, op); -+ /* for RX_FILTER_ID and simple filter */ -+ if (op->last_frames && (op->last_frames[0].can_dlc & RX_THR)){ -+ op->last_frames[0].can_dlc &= ~RX_THR; -+ bcm_rx_changed(op, &op->last_frames[0]); -+ } -+ } -+} -+ -+static void bcm_send_to_user(struct bcm_op *op, struct bcm_msg_head *head, -+ struct can_frame *frames, struct timeval *tv) -+{ -+ struct sk_buff *skb; -+ struct can_frame *firstframe; -+ struct sock *sk = op->sk; -+ int datalen = head->nframes * CFSIZ; -+ struct sockaddr_can *addr; -+ int err; -+ -+ skb = alloc_skb(sizeof(*head) + datalen, -+ in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); -+ if (!skb) -+ return; -+ -+ memcpy(skb_put(skb, sizeof(*head)), head, sizeof(*head)); -+ /* can_frames starting here */ -+ firstframe = (struct can_frame *) skb->tail; -+ -+ if (tv) -+ skb_set_timestamp(skb, tv); /* restore timestamp */ -+ -+ addr = (struct sockaddr_can *)skb->cb; -+ memset(addr, 0, sizeof(*addr)); -+ addr->can_family = AF_CAN; -+ /* restore originator for recvfrom() */ -+ addr->can_ifindex = op->rx_ifindex; -+ -+ if (head->nframes){ -+ memcpy(skb_put(skb, datalen), frames, datalen); -+ -+ /* the BCM uses the can_dlc-element of the can_frame */ -+ /* structure for internal purposes. This is only */ -+ /* relevant for updates that are generated by the */ -+ /* BCM, where nframes is 1 */ -+ if (head->nframes == 1) -+ firstframe->can_dlc &= BCM_CAN_DLC_MASK; -+ } -+ if ((err = sock_queue_rcv_skb(sk, skb)) < 0) { -+ struct bcm_opt *bo = bcm_sk(sk); -+ DBG("sock_queue_rcv_skb failed: %d\n", err); -+ kfree_skb(skb); -+ bo->dropped_usr_msgs++; /* don't care about overflows */ -+ } -+} -+ -+/**************************************************/ -+/* bcm_op handling: find & delete bcm_op elements */ -+/**************************************************/ -+ -+static struct bcm_op *bcm_find_op(struct list_head *ops, canid_t can_id, -+ int ifindex) -+{ -+ struct bcm_op *op; -+ -+ list_for_each_entry(op, ops, list) -+ if ((op->can_id == can_id) && (op->ifindex == ifindex)) -+ return op; -+ -+ return NULL; -+} -+ -+static int bcm_delete_rx_op(struct list_head *ops, canid_t can_id, int ifindex) -+{ -+ struct bcm_op *op, *n; -+ -+ list_for_each_entry_safe(op, n, ops, list) { -+ if ((op->can_id == can_id) && (op->ifindex == ifindex)) { -+ DBG("removing rx_op %p for can_id %03X\n", -+ op, op->can_id); -+ -+ /* Don't care if we're bound or not (due to netdev */ -+ /* problems) can_rx_unregister() is always a save */ -+ /* thing to do here. */ -+ if (op->ifindex) { -+ struct net_device *dev = -+ dev_get_by_index(op->ifindex); -+ if (dev) { -+ can_rx_unregister(dev, op->can_id, -+ REGMASK(op->can_id), -+ bcm_rx_handler, op); -+ dev_put(dev); -+ } -+ } else -+ can_rx_unregister(NULL, op->can_id, -+ REGMASK(op->can_id), -+ bcm_rx_handler, op); -+ -+ list_del(&op->list); -+ bcm_remove_op(op); -+ return 1; /* done */ -+ } -+ } -+ -+ return 0; /* not found */ -+} -+ -+static int bcm_delete_tx_op(struct list_head *ops, canid_t can_id, int ifindex) -+{ -+ struct bcm_op *op, *n; -+ -+ list_for_each_entry_safe(op, n, ops, list) { -+ if ((op->can_id == can_id) && (op->ifindex == ifindex)) { -+ DBG("removing rx_op %p for can_id %03X\n", -+ op, op->can_id); -+ list_del(&op->list); -+ bcm_remove_op(op); -+ return 1; /* done */ -+ } -+ } -+ -+ return 0; /* not found */ -+} -+ -+static void bcm_remove_op(struct bcm_op *op) -+{ -+ del_timer(&op->timer); -+ del_timer(&op->thrtimer); -+ if (op->frames) -+ kfree(op->frames); -+ if (op->last_frames) -+ kfree(op->last_frames); -+ kfree(op); -+ -+ return; -+} -+ -+module_init(bcm_module_init); -+module_exit(bcm_module_exit); -diff -N -u -r b/net/can/Kconfig c/net/can/Kconfig ---- b/net/can/Kconfig 1970-01-01 01:00:00.000000000 +0100 -+++ c/net/can/Kconfig 2007-03-09 13:47:12.000000000 +0100 -@@ -0,0 +1,71 @@ -+# -+# Controller Area Network (CAN) network layer core configuration -+# -+ -+menuconfig CAN -+ depends on NET -+ tristate "CAN bus subsystem support" -+ ---help--- -+ Controller Area Network (CAN) is a slow (up to 1Mbit/s) serial -+ communications protocol was developed by Bosch at 1991 mainly for -+ automotive, but now widely used in marine (NMEA2000), industrial and -+ medical applications. -+ More information is contained in the directory . -+ -+ If you want CAN support, you should say Y here and also to the -+ specific driver for your controller(s) below. -+ -+ This CAN support can also be built as a module. If so, the module -+ will be called can.ko. -+ -+config CAN_RAW -+ tristate "Raw CAN Protocol (raw access with CAN-ID filtering)" -+ depends on CAN -+ default N -+ ---help--- -+ The Raw CAN protocol option offers access to the CAN bus via -+ the BSD socket API. You probably want to use the raw socket in -+ most cases where no higher level protocol is being used. The raw -+ socket has several filter options e.g. ID-Masking / Errorframes. -+ To receive/send raw CAN messages, use AF_CAN with protocol CAN_RAW. -+ -+config CAN_RAW_USER -+ bool "Allow non-root users to access Raw CAN Protocol sockets" -+ depends on CAN_RAW -+ default N -+ ---help--- -+ Say Y here if you want non-root users to be able to access CAN_RAW- -+ sockets. This may lead to a security hole. -+ -+config CAN_BCM -+ tristate "Broadcast Manager CAN Protocol (with content filtering)" -+ depends on CAN -+ default N -+ ---help--- -+ The Broadcast Manager offers content filtering, timeout monitoring, -+ sending of RTR-frames and cyclic CAN messages without permanent user -+ interaction. The BCM can be 'programmed' via the BSD socket API and -+ informs you on demand e.g. only on content updates / timeouts. -+ You probably want to use the bcm socket in most cases where cyclic -+ CAN messages are used on the bus (e.g. in automotive environments). -+ To use the Broadcast Manager, use AF_CAN with protocol CAN_BCM. -+ -+config CAN_BCM_USER -+ bool "Allow non-root users to access CAN broadcast manager sockets" -+ depends on CAN_BCM -+ default N -+ ---help--- -+ Say Y here if you want non-root users to be able to access CAN_BCM- -+ sockets. This may lead to a security hole. -+ -+config CAN_DEBUG_CORE -+ bool "CAN Core debugging messages" -+ depends on CAN -+ ---help--- -+ Say Y here if you want the CAN core to produce a bunch of debug -+ messages to the system log. Select this if you are having a -+ problem with CAN support and want to see more of what is going on. -+ -+ -+source "drivers/net/can/Kconfig" -+ -diff -N -u -r b/net/can/Makefile c/net/can/Makefile ---- b/net/can/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ c/net/can/Makefile 2007-03-09 13:47:12.000000000 +0100 -@@ -0,0 +1,12 @@ -+# -+# Makefile for the Linux Controller Area Network core. -+# -+ -+obj-$(CONFIG_CAN) += can.o -+can-objs := af_can.o proc.o -+ -+obj-$(CONFIG_CAN_RAW) += can-raw.o -+can-raw-objs := raw.o -+ -+obj-$(CONFIG_CAN_BCM) += can-bcm.o -+can-bcm-objs := bcm.o -diff -N -u -r b/net/can/proc.c c/net/can/proc.c ---- b/net/can/proc.c 1970-01-01 01:00:00.000000000 +0100 -+++ c/net/can/proc.c 2007-03-09 13:47:12.000000000 +0100 -@@ -0,0 +1,663 @@ -+/* -+ * proc.c - procfs support for Protocol family CAN core module -+ * -+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research -+ * 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, the following disclaimer and -+ * the referenced file 'COPYING'. -+ * 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. Neither the name of Volkswagen nor the names of its contributors -+ * may be used to endorse or promote products derived from this software -+ * without specific prior written permission. -+ * -+ * Alternatively, provided that this notice is retained in full, this -+ * software may be distributed under the terms of the GNU General -+ * Public License ("GPL") version 2 as distributed in the 'COPYING' -+ * file from the main directory of the linux kernel source. -+ * -+ * The provided data structures and external interfaces from this code -+ * are not restricted to be used by modules with a GPL compatible license. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT -+ * OWNER 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. -+ * -+ * Send feedback to -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include "af_can.h" -+ -+RCSID("$Id: proc.c 177 2007-03-08 11:02:43Z hartkopp $"); -+ -+/* proc filenames */ -+ -+#define CAN_PROC_VERSION "version" -+#define CAN_PROC_STATS "stats" -+#define CAN_PROC_RESET_STATS "reset_stats" -+#define CAN_PROC_RCVLIST_ALL "rcvlist_all" -+#define CAN_PROC_RCVLIST_FIL "rcvlist_fil" -+#define CAN_PROC_RCVLIST_INV "rcvlist_inv" -+#define CAN_PROC_RCVLIST_SFF "rcvlist_sff" -+#define CAN_PROC_RCVLIST_EFF "rcvlist_eff" -+#define CAN_PROC_RCVLIST_ERR "rcvlist_err" -+ -+static void can_init_stats(int caller); -+static void can_stat_update(unsigned long data); -+ -+static struct proc_dir_entry *can_create_proc_readentry(const char *name, -+ mode_t mode, read_proc_t* read_proc, void *data); -+static void can_remove_proc_readentry(const char *name); -+static unsigned long calc_rate(unsigned long oldjif, unsigned long newjif, -+ unsigned long count); -+ -+static int can_proc_read_version(char *page, char **start, off_t off, -+ int count, int *eof, void *data); -+static int can_proc_read_stats(char *page, char **start, off_t off, -+ int count, int *eof, void *data); -+static int can_proc_read_reset_stats(char *page, char **start, off_t off, -+ int count, int *eof, void *data); -+static int can_proc_read_rcvlist_all(char *page, char **start, off_t off, -+ int count, int *eof, void *data); -+static int can_proc_read_rcvlist_fil(char *page, char **start, off_t off, -+ int count, int *eof, void *data); -+static int can_proc_read_rcvlist_inv(char *page, char **start, off_t off, -+ int count, int *eof, void *data); -+static int can_proc_read_rcvlist_sff(char *page, char **start, off_t off, -+ int count, int *eof, void *data); -+static int can_proc_read_rcvlist_eff(char *page, char **start, off_t off, -+ int count, int *eof, void *data); -+static int can_proc_read_rcvlist_err(char *page, char **start, off_t off, -+ int count, int *eof, void *data); -+ -+static struct proc_dir_entry *can_dir = NULL; -+static struct proc_dir_entry *pde_version = NULL; -+static struct proc_dir_entry *pde_stats = NULL; -+static struct proc_dir_entry *pde_reset_stats = NULL; -+static struct proc_dir_entry *pde_rcvlist_all = NULL; -+static struct proc_dir_entry *pde_rcvlist_fil = NULL; -+static struct proc_dir_entry *pde_rcvlist_inv = NULL; -+static struct proc_dir_entry *pde_rcvlist_sff = NULL; -+static struct proc_dir_entry *pde_rcvlist_eff = NULL; -+static struct proc_dir_entry *pde_rcvlist_err = NULL; -+ -+struct timer_list stattimer; /* timer for statistics update */ -+ -+struct s_stats stats; /* statistics */ -+struct s_pstats pstats; -+ -+extern struct hlist_head rx_dev_list; /* rx dispatcher structures */ -+extern int stats_timer; /* module parameter. default: on */ -+ -+/**************************************************/ -+/* procfs init / remove */ -+/**************************************************/ -+ -+void can_init_proc(void) -+{ -+ -+ /* procfs init */ -+ -+ /* create /proc/can directory */ -+ can_dir = proc_mkdir(CAN_PROC_DIR, NULL); -+ -+ if (!can_dir) { -+ printk(KERN_INFO "CAN: failed to create CAN_PROC_DIR. " -+ "CONFIG_PROC_FS missing?\n"); -+ return; -+ } -+ -+ can_dir->owner = THIS_MODULE; -+ -+ /* own procfs entries from the AF_CAN core */ -+ pde_version = can_create_proc_readentry( -+ CAN_PROC_VERSION, 0644, can_proc_read_version, NULL); -+ pde_stats = can_create_proc_readentry( -+ CAN_PROC_STATS, 0644, can_proc_read_stats, NULL); -+ pde_reset_stats = can_create_proc_readentry( -+ CAN_PROC_RESET_STATS, 0644, can_proc_read_reset_stats, NULL); -+ pde_rcvlist_all = can_create_proc_readentry( -+ CAN_PROC_RCVLIST_ALL, 0644, can_proc_read_rcvlist_all, NULL); -+ pde_rcvlist_fil = can_create_proc_readentry( -+ CAN_PROC_RCVLIST_FIL, 0644, can_proc_read_rcvlist_fil, NULL); -+ pde_rcvlist_inv = can_create_proc_readentry( -+ CAN_PROC_RCVLIST_INV, 0644, can_proc_read_rcvlist_inv, NULL); -+ pde_rcvlist_sff = can_create_proc_readentry( -+ CAN_PROC_RCVLIST_SFF, 0644, can_proc_read_rcvlist_sff, NULL); -+ pde_rcvlist_eff = can_create_proc_readentry( -+ CAN_PROC_RCVLIST_EFF, 0644, can_proc_read_rcvlist_eff, NULL); -+ pde_rcvlist_err = can_create_proc_readentry( -+ CAN_PROC_RCVLIST_ERR, 0644, can_proc_read_rcvlist_err, NULL); -+ -+ if (stats_timer) { -+ /* the statistics are updated every second (timer triggered) */ -+ stattimer.function = can_stat_update; -+ stattimer.data = 0; -+ stattimer.expires = jiffies + HZ; /* every second */ -+ add_timer(&stattimer); /* start statistics timer */ -+ } -+} -+ -+void can_remove_proc(void) -+{ -+ /* procfs remove */ -+ if (pde_version) -+ can_remove_proc_readentry(CAN_PROC_VERSION); -+ -+ if (pde_stats) -+ can_remove_proc_readentry(CAN_PROC_STATS); -+ -+ if (pde_reset_stats) -+ can_remove_proc_readentry(CAN_PROC_RESET_STATS); -+ -+ if (pde_rcvlist_all) -+ can_remove_proc_readentry(CAN_PROC_RCVLIST_ALL); -+ -+ if (pde_rcvlist_fil) -+ can_remove_proc_readentry(CAN_PROC_RCVLIST_FIL); -+ -+ if (pde_rcvlist_inv) -+ can_remove_proc_readentry(CAN_PROC_RCVLIST_INV); -+ -+ if (pde_rcvlist_sff) -+ can_remove_proc_readentry(CAN_PROC_RCVLIST_SFF); -+ -+ if (pde_rcvlist_eff) -+ can_remove_proc_readentry(CAN_PROC_RCVLIST_EFF); -+ -+ if (pde_rcvlist_err) -+ can_remove_proc_readentry(CAN_PROC_RCVLIST_ERR); -+ -+ if (can_dir) -+ remove_proc_entry(CAN_PROC_DIR, NULL); -+} -+ -+/**************************************************/ -+/* proc read functions */ -+/**************************************************/ -+ -+static int can_print_rcvlist(char *page, int len, struct hlist_head *rx_list, -+ struct net_device *dev) -+{ -+ struct receiver *r; -+ struct hlist_node *n; -+ -+ rcu_read_lock(); -+ hlist_for_each_entry_rcu(r, n, rx_list, list) { -+ char *fmt = r->can_id & CAN_EFF_FLAG ? /* EFF & CAN_ID_ALL */ -+ " %-5s %08X %08x %08x %08x %8ld %s\n" : -+ " %-5s %03X %08x %08x %08x %8ld %s\n"; -+ -+ len += snprintf(page + len, PAGE_SIZE - len, fmt, -+ DNAME(dev), r->can_id, r->mask, -+ (unsigned int)r->func, (unsigned int)r->data, -+ r->matches, r->ident); -+ -+ /* does a typical line fit into the current buffer? */ -+ /* 100 Bytes before end of buffer */ -+ if (len > PAGE_SIZE - 100) { -+ /* mark output cut off */ -+ len += snprintf(page + len, PAGE_SIZE - len, -+ " (..)\n"); -+ break; -+ } -+ } -+ rcu_read_unlock(); -+ -+ return len; -+} -+ -+static int can_print_recv_banner(char *page, int len) -+{ -+ /* can1. 00000000 00000000 00000000 -+ ....... 0 tp20 */ -+ len += snprintf(page + len, PAGE_SIZE - len, -+ " device can_id can_mask function" -+ " userdata matches ident\n"); -+ -+ return len; -+} -+ -+static int can_proc_read_stats(char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int len = 0; -+ -+ len += snprintf(page + len, PAGE_SIZE - len, "\n"); -+ len += snprintf(page + len, PAGE_SIZE - len, -+ " %8ld transmitted frames (TXF)\n", stats.tx_frames); -+ len += snprintf(page + len, PAGE_SIZE - len, -+ " %8ld received frames (RXF)\n", stats.rx_frames); -+ len += snprintf(page + len, PAGE_SIZE - len, -+ " %8ld matched frames (RXMF)\n", stats.matches); -+ -+ len += snprintf(page + len, PAGE_SIZE - len, "\n"); -+ -+ len += snprintf(page + len, PAGE_SIZE - len, -+ " %8ld %% total match ratio (RXMR)\n", -+ stats.total_rx_match_ratio); -+ -+ len += snprintf(page + len, PAGE_SIZE - len, -+ " %8ld frames/s total tx rate (TXR)\n", -+ stats.total_tx_rate); -+ len += snprintf(page + len, PAGE_SIZE - len, -+ " %8ld frames/s total rx rate (RXR)\n", -+ stats.total_rx_rate); -+ -+ len += snprintf(page + len, PAGE_SIZE - len, "\n"); -+ -+ len += snprintf(page + len, PAGE_SIZE - len, -+ " %8ld %% current match ratio (CRXMR)\n", -+ stats.current_rx_match_ratio); -+ -+ len += snprintf(page + len, PAGE_SIZE - len, -+ " %8ld frames/s current tx rate (CTXR)\n", -+ stats.current_tx_rate); -+ len += snprintf(page + len, PAGE_SIZE - len, -+ " %8ld frames/s current rx rate (CRXR)\n", -+ stats.current_rx_rate); -+ -+ len += snprintf(page + len, PAGE_SIZE - len, "\n"); -+ -+ len += snprintf(page + len, PAGE_SIZE - len, -+ " %8ld %% max match ratio (MRXMR)\n", -+ stats.max_rx_match_ratio); -+ -+ len += snprintf(page + len, PAGE_SIZE - len, -+ " %8ld frames/s max tx rate (MTXR)\n", -+ stats.max_tx_rate); -+ len += snprintf(page + len, PAGE_SIZE - len, -+ " %8ld frames/s max rx rate (MRXR)\n", -+ stats.max_rx_rate); -+ -+ len += snprintf(page + len, PAGE_SIZE - len, "\n"); -+ -+ len += snprintf(page + len, PAGE_SIZE - len, -+ " %8ld current receive list entries (CRCV)\n", -+ pstats.rcv_entries); -+ len += snprintf(page + len, PAGE_SIZE - len, -+ " %8ld maximum receive list entries (MRCV)\n", -+ pstats.rcv_entries_max); -+ -+ if (pstats.stats_reset) -+ len += snprintf(page + len, PAGE_SIZE - len, -+ "\n %8ld statistic resets (STR)\n", -+ pstats.stats_reset); -+ -+ len += snprintf(page + len, PAGE_SIZE - len, "\n"); -+ -+ *eof = 1; -+ return len; -+} -+ -+static int can_proc_read_reset_stats(char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int len = 0; -+ -+ can_init_stats(1); -+ -+ len += snprintf(page + len, PAGE_SIZE - len, -+ "CAN statistic reset #%ld done.\n", -+ pstats.stats_reset); -+ -+ *eof = 1; -+ return len; -+} -+ -+static int can_proc_read_version(char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int len = 0; -+ -+ len += snprintf(page + len, PAGE_SIZE - len, -+ "%06X [ Volkswagen Group - Low Level CAN Framework" -+ " (LLCF) v%s ]\n", LLCF_VERSION_CODE, VERSION); -+ *eof = 1; -+ return len; -+} -+ -+static int can_proc_read_rcvlist_all(char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int len = 0; -+ struct dev_rcv_lists *d; -+ struct hlist_node *n; -+ -+ /* RX_ALL */ -+ len += snprintf(page + len, PAGE_SIZE - len, -+ "\nreceive list 'rx_all':\n"); -+ -+ /* find receive list for this device */ -+ rcu_read_lock(); -+ hlist_for_each_entry_rcu(d, n, &rx_dev_list, list) { -+ -+ if (!hlist_empty(&d->rx_all)) { -+ len = can_print_recv_banner(page, len); -+ len = can_print_rcvlist(page, len, &d->rx_all, d->dev); -+ } else -+ len += snprintf(page + len, PAGE_SIZE - len, -+ " (%s: no entry)\n", DNAME(d->dev)); -+ -+ if (len > PAGE_SIZE - 100) -+ break; /* exit on end of buffer */ -+ } -+ rcu_read_unlock(); -+ -+ len += snprintf(page + len, PAGE_SIZE - len, "\n"); -+ -+ *eof = 1; -+ return len; -+} -+ -+static int can_proc_read_rcvlist_fil(char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int len = 0; -+ struct dev_rcv_lists *d; -+ struct hlist_node *n; -+ -+ /* RX_FIL */ -+ len += snprintf(page + len, PAGE_SIZE - len, -+ "\nreceive list 'rx_fil':\n"); -+ -+ /* find receive list for this device */ -+ rcu_read_lock(); -+ hlist_for_each_entry_rcu(d, n, &rx_dev_list, list) { -+ -+ if (!hlist_empty(&d->rx_fil)) { -+ len = can_print_recv_banner(page, len); -+ len = can_print_rcvlist(page, len, &d->rx_fil, d->dev); -+ } else -+ len += snprintf(page + len, PAGE_SIZE - len, -+ " (%s: no entry)\n", DNAME(d->dev)); -+ -+ if (len > PAGE_SIZE - 100) -+ break; /* exit on end of buffer */ -+ } -+ rcu_read_unlock(); -+ -+ len += snprintf(page + len, PAGE_SIZE - len, "\n"); -+ -+ *eof = 1; -+ return len; -+} -+ -+static int can_proc_read_rcvlist_inv(char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int len = 0; -+ struct dev_rcv_lists *d; -+ struct hlist_node *n; -+ -+ /* RX_INV */ -+ len += snprintf(page + len, PAGE_SIZE - len, -+ "\nreceive list 'rx_inv':\n"); -+ -+ /* find receive list for this device */ -+ rcu_read_lock(); -+ hlist_for_each_entry_rcu(d, n, &rx_dev_list, list) { -+ -+ if (!hlist_empty(&d->rx_inv)) { -+ len = can_print_recv_banner(page, len); -+ len = can_print_rcvlist(page, len, &d->rx_inv, d->dev); -+ } else -+ len += snprintf(page + len, PAGE_SIZE - len, -+ " (%s: no entry)\n", DNAME(d->dev)); -+ -+ if (len > PAGE_SIZE - 100) -+ break; /* exit on end of buffer */ -+ } -+ rcu_read_unlock(); -+ -+ len += snprintf(page + len, PAGE_SIZE - len, "\n"); -+ -+ *eof = 1; -+ return len; -+} -+ -+static int can_proc_read_rcvlist_sff(char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int len = 0; -+ struct dev_rcv_lists *d; -+ struct hlist_node *n; -+ -+ /* RX_SFF */ -+ len += snprintf(page + len, PAGE_SIZE - len, -+ "\nreceive list 'rx_sff':\n"); -+ -+ /* find receive list for this device */ -+ rcu_read_lock(); -+ hlist_for_each_entry_rcu(d, n, &rx_dev_list, list) { -+ int i, all_empty = 1; -+ /* check wether at least one list is non-empty */ -+ for (i = 0; i < 0x800; i++) -+ if (!hlist_empty(&d->rx_sff[i])) { -+ all_empty = 0; -+ break; -+ } -+ -+ if (!all_empty) { -+ len = can_print_recv_banner(page, len); -+ for (i = 0; i < 0x800; i++) { -+ if (!hlist_empty(&d->rx_sff[i]) && -+ len < PAGE_SIZE - 100) -+ len = can_print_rcvlist(page, len, -+ &d->rx_sff[i], -+ d->dev); -+ } -+ } else -+ len += snprintf(page + len, PAGE_SIZE - len, -+ " (%s: no entry)\n", DNAME(d->dev)); -+ -+ if (len > PAGE_SIZE - 100) -+ break; /* exit on end of buffer */ -+ } -+ rcu_read_unlock(); -+ -+ len += snprintf(page + len, PAGE_SIZE - len, "\n"); -+ -+ *eof = 1; -+ return len; -+} -+ -+static int can_proc_read_rcvlist_eff(char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int len = 0; -+ struct dev_rcv_lists *d; -+ struct hlist_node *n; -+ -+ /* RX_EFF */ -+ len += snprintf(page + len, PAGE_SIZE - len, -+ "\nreceive list 'rx_eff':\n"); -+ -+ /* find receive list for this device */ -+ rcu_read_lock(); -+ hlist_for_each_entry_rcu(d, n, &rx_dev_list, list) { -+ -+ if (!hlist_empty(&d->rx_eff)) { -+ len = can_print_recv_banner(page, len); -+ len = can_print_rcvlist(page, len, &d->rx_eff, d->dev); -+ } else -+ len += snprintf(page + len, PAGE_SIZE - len, -+ " (%s: no entry)\n", DNAME(d->dev)); -+ -+ if (len > PAGE_SIZE - 100) -+ break; /* exit on end of buffer */ -+ } -+ rcu_read_unlock(); -+ -+ len += snprintf(page + len, PAGE_SIZE - len, "\n"); -+ -+ *eof = 1; -+ return len; -+} -+ -+static int can_proc_read_rcvlist_err(char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int len = 0; -+ struct dev_rcv_lists *d; -+ struct hlist_node *n; -+ -+ /* RX_ERR */ -+ len += snprintf(page + len, PAGE_SIZE - len, -+ "\nreceive list 'rx_err':\n"); -+ -+ /* find receive list for this device */ -+ rcu_read_lock(); -+ hlist_for_each_entry_rcu(d, n, &rx_dev_list, list) { -+ -+ if (!hlist_empty(&d->rx_err)) { -+ len = can_print_recv_banner(page, len); -+ len = can_print_rcvlist(page, len, &d->rx_err, d->dev); -+ } else -+ len += snprintf(page + len, PAGE_SIZE - len, -+ " (%s: no entry)\n", DNAME(d->dev)); -+ -+ if (len > PAGE_SIZE - 100) -+ break; /* exit on end of buffer */ -+ } -+ rcu_read_unlock(); -+ -+ len += snprintf(page + len, PAGE_SIZE - len, "\n"); -+ -+ *eof = 1; -+ return len; -+} -+ -+/**************************************************/ -+/* proc utility functions */ -+/**************************************************/ -+ -+static struct proc_dir_entry *can_create_proc_readentry(const char *name, -+ mode_t mode, -+ read_proc_t* read_proc, -+ void *data) -+{ -+ if (can_dir) -+ return create_proc_read_entry(name, mode, can_dir, read_proc, -+ data); -+ else -+ return NULL; -+} -+ -+static void can_remove_proc_readentry(const char *name) -+{ -+ if (can_dir) -+ remove_proc_entry(name, can_dir); -+} -+ -+static unsigned long calc_rate(unsigned long oldjif, unsigned long newjif, -+ unsigned long count) -+{ -+ unsigned long ret = 0; -+ -+ if (oldjif == newjif) -+ return 0; -+ -+ /* see can_rcv() - this should NEVER happen! */ -+ if (count > (ULONG_MAX / HZ)) { -+ printk(KERN_ERR "CAN: calc_rate: count exceeded! %ld\n", -+ count); -+ return 99999999; -+ } -+ -+ ret = (count * HZ) / (newjif - oldjif); -+ -+ return ret; -+} -+ -+/**************************************************/ -+/* af_can statistics stuff */ -+/**************************************************/ -+ -+static void can_init_stats(int caller) -+{ -+ memset(&stats, 0, sizeof(stats)); -+ stats.jiffies_init = jiffies; -+ pstats.stats_reset++; -+} -+ -+static void can_stat_update(unsigned long data) -+{ -+ unsigned long j = jiffies; /* snapshot */ -+ -+ //DBG("CAN: can_stat_update() jiffies = %ld\n", j); -+ -+ if (j < stats.jiffies_init) /* jiffies overflow */ -+ can_init_stats(2); -+ -+ /* stats.rx_frames is the definitively max. statistic value */ -+ -+ /* prevent overflow in calc_rate() */ -+ if (stats.rx_frames > (ULONG_MAX / HZ)) -+ can_init_stats(3); /* restart */ -+ -+ /* matches overflow - very improbable */ -+ if (stats.matches > (ULONG_MAX / 100)) -+ can_init_stats(4); -+ -+ /* calc total values */ -+ if (stats.rx_frames) -+ stats.total_rx_match_ratio = (stats.matches * 100) / -+ stats.rx_frames; -+ -+ stats.total_tx_rate = calc_rate(stats.jiffies_init, j, -+ stats.tx_frames); -+ stats.total_rx_rate = calc_rate(stats.jiffies_init, j, -+ stats.rx_frames); -+ -+ /* calc current values */ -+ if (stats.rx_frames_delta) -+ stats.current_rx_match_ratio = -+ (stats.matches_delta * 100) / stats.rx_frames_delta; -+ -+ stats.current_tx_rate = calc_rate(0, HZ, stats.tx_frames_delta); -+ stats.current_rx_rate = calc_rate(0, HZ, stats.rx_frames_delta); -+ -+ /* check / update maximum values */ -+ if (stats.max_tx_rate < stats.current_tx_rate) -+ stats.max_tx_rate = stats.current_tx_rate; -+ -+ if (stats.max_rx_rate < stats.current_rx_rate) -+ stats.max_rx_rate = stats.current_rx_rate; -+ -+ if (stats.max_rx_match_ratio < stats.current_rx_match_ratio) -+ stats.max_rx_match_ratio = stats.current_rx_match_ratio; -+ -+ /* clear values for 'current rate' calculation */ -+ stats.tx_frames_delta = 0; -+ stats.rx_frames_delta = 0; -+ stats.matches_delta = 0; -+ -+ /* restart timer */ -+ stattimer.expires = jiffies + HZ; /* every second */ -+ add_timer(&stattimer); -+} -diff -N -u -r b/net/can/raw.c c/net/can/raw.c ---- b/net/can/raw.c 1970-01-01 01:00:00.000000000 +0100 -+++ c/net/can/raw.c 2007-03-09 17:27:37.000000000 +0100 -@@ -0,0 +1,724 @@ -+/* -+ * raw.c - Raw sockets for protocol family CAN -+ * -+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research -+ * 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, the following disclaimer and -+ * the referenced file 'COPYING'. -+ * 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. Neither the name of Volkswagen nor the names of its contributors -+ * may be used to endorse or promote products derived from this software -+ * without specific prior written permission. -+ * -+ * Alternatively, provided that this notice is retained in full, this -+ * software may be distributed under the terms of the GNU General -+ * Public License ("GPL") version 2 as distributed in the 'COPYING' -+ * file from the main directory of the linux kernel source. -+ * -+ * The provided data structures and external interfaces from this code -+ * are not restricted to be used by modules with a GPL compatible license. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT -+ * OWNER 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. -+ * -+ * Send feedback to -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+RCSID("$Id: raw.c 177 2007-03-08 11:02:43Z hartkopp $"); -+ -+#define IDENT "raw" -+static __initdata const char banner[] = KERN_INFO "CAN: raw socket protocol" -+ " " VERSION "\n"; -+ -+MODULE_DESCRIPTION("PF_CAN raw sockets"); -+MODULE_LICENSE("Dual BSD/GPL"); -+MODULE_AUTHOR("Urs Thuermann "); -+ -+#ifdef CONFIG_CAN_DEBUG_CORE -+static int debug = 0; -+module_param(debug, int, S_IRUGO); -+#define DBG(args...) (debug & 1 ? \ -+ (printk(KERN_DEBUG "RAW %s: ", __func__), \ -+ printk(args)) : 0) -+#define DBG_SKB(skb) (debug & 4 ? can_debug_skb(skb) : 0) -+#else -+#define DBG(args...) -+#define DBG_SKB(skb) -+#endif -+ -+static int raw_init(struct sock *sk); -+static int raw_release(struct socket *sock); -+static int raw_bind (struct socket *sock, struct sockaddr *uaddr, int len); -+static int raw_getname(struct socket *sock, struct sockaddr *uaddr, -+ int *len, int peer); -+static unsigned int raw_poll(struct file *file, struct socket *sock, -+ poll_table *wait); -+static int raw_setsockopt(struct socket *sock, int level, int optname, -+ char __user *optval, int optlen); -+static int raw_getsockopt(struct socket *sock, int level, int optname, -+ char __user *optval, int __user *optlen); -+static int raw_sendmsg(struct kiocb *iocb, struct socket *sock, -+ struct msghdr *msg, size_t size); -+static int raw_recvmsg(struct kiocb *iocb, struct socket *sock, -+ struct msghdr *msg, size_t size, int flags); -+static void raw_rcv(struct sk_buff *skb, void *data); -+static void raw_notifier(unsigned long msg, void *data); -+ -+static void raw_add_filters(struct net_device *dev, struct sock *sk); -+static void raw_remove_filters(struct net_device *dev, struct sock *sk); -+ -+ -+static struct proto_ops raw_ops = { -+ .family = PF_CAN, -+ .release = raw_release, -+ .bind = raw_bind, -+ .connect = sock_no_connect, -+ .socketpair = sock_no_socketpair, -+ .accept = sock_no_accept, -+ .getname = raw_getname, -+ .poll = raw_poll, -+ .ioctl = NULL, /* use can_ioctl() from af_can.c */ -+ .listen = sock_no_listen, -+ .shutdown = sock_no_shutdown, -+ .setsockopt = raw_setsockopt, -+ .getsockopt = raw_getsockopt, -+ .sendmsg = raw_sendmsg, -+ .recvmsg = raw_recvmsg, -+ .mmap = sock_no_mmap, -+ .sendpage = sock_no_sendpage, -+}; -+ -+ -+/* A raw socket has a list of can_filters attached to it, each receiving -+ the CAN frames matching that filter. If the filter list is empty, -+ no CAN frames will be received by the socket. The default after -+ opening the socket, is to have one filter which receives all frames. -+ The filter list is allocated dynamically with the exception of the -+ list containing only one item. This common case is optimized by -+ storing the single filter in dfilter, to avoid using dynamic memory. -+*/ -+ -+struct raw_opt { -+ int bound; -+ int ifindex; -+ int loopback; -+ int recv_own_msgs; -+ int count; /* number of active filters */ -+ struct can_filter dfilter; /* default/single filter */ -+ struct can_filter *filter; /* pointer to filter(s) */ -+ can_err_mask_t err_mask; -+}; -+ -+#ifdef CONFIG_CAN_RAW_USER -+#define RAW_CAP (-1) -+#else -+#define RAW_CAP CAP_NET_RAW -+#endif -+ -+#undef CAN_RAW_SUPPORT_REBIND /* use bind on already bound socket */ -+ -+struct raw_sock { -+ struct sock sk; -+ struct raw_opt opt; -+}; -+ -+#define raw_sk(sk) (&((struct raw_sock *)(sk))->opt) -+ -+static struct proto raw_proto = { -+ .name = "CAN_RAW", -+ .owner = THIS_MODULE, -+ .obj_size = sizeof(struct raw_sock), -+ .init = raw_init, -+}; -+ -+static struct can_proto raw_can_proto = { -+ .type = SOCK_RAW, -+ .protocol = CAN_RAW, -+ .capability = RAW_CAP, -+ .ops = &raw_ops, -+ .prot = &raw_proto, -+}; -+ -+#define MASK_ALL 0 -+ -+static __init int raw_module_init(void) -+{ -+ printk(banner); -+ -+ can_proto_register(&raw_can_proto); -+ return 0; -+} -+ -+static __exit void raw_module_exit(void) -+{ -+ can_proto_unregister(&raw_can_proto); -+} -+ -+static int raw_init(struct sock *sk) -+{ -+ struct raw_opt *ro = raw_sk(sk); -+ -+ ro->bound = 0; -+ -+ /* set default filter to single entry dfilter */ -+ ro->dfilter.can_id = 0; -+ ro->dfilter.can_mask = MASK_ALL; -+ ro->filter = &ro->dfilter; -+ ro->count = 1; -+ -+ /* set default loopback behaviour */ -+ ro->loopback = 1; -+ ro->recv_own_msgs = 0; -+ -+ return 0; -+} -+ -+static int raw_release(struct socket *sock) -+{ -+ struct sock *sk = sock->sk; -+ struct raw_opt *ro = raw_sk(sk); -+ struct net_device *dev = NULL; -+ -+ DBG("socket %p, sk %p, refcnt %d\n", sock, sk, -+ atomic_read(&sk->sk_refcnt)); -+ -+ if (ro->bound && ro->ifindex) -+ dev = dev_get_by_index(ro->ifindex); -+ -+ /* remove current filters & unregister */ -+ if (ro->bound) -+ raw_remove_filters(dev, sk); -+ if (ro->count > 1) -+ kfree(ro->filter); -+ -+ /* remove current error mask */ -+ if (ro->err_mask && ro->bound) -+ can_rx_unregister(dev, 0, ro->err_mask | CAN_ERR_FLAG, -+ raw_rcv, sk); -+ -+ if (dev) { -+ can_dev_unregister(dev, raw_notifier, sk); -+ dev_put(dev); -+ } -+ -+ sock_put(sk); -+ -+ return 0; -+} -+ -+static int raw_bind(struct socket *sock, struct sockaddr *uaddr, int len) -+{ -+ struct sockaddr_can *addr = (struct sockaddr_can *)uaddr; -+ struct sock *sk = sock->sk; -+ struct raw_opt *ro = raw_sk(sk); -+ struct net_device *dev; -+ -+ DBG("socket %p to device %d\n", sock, addr->can_ifindex); -+ -+ if (len < sizeof(*addr)) -+ return -EINVAL; -+ -+ if (ro->bound) { -+#ifdef CAN_RAW_SUPPORT_REBIND -+ /* remove current bindings / notifier */ -+ if (ro->ifindex) { -+ dev = dev_get_by_index(ro->ifindex); -+ if (!dev) { -+ DBG("could not find device %d\n", -+ addr->can_ifindex); -+ return -ENODEV; -+ } -+ if (!(dev->flags & IFF_UP)) { -+ sk->sk_err = ENETDOWN; -+ if (!sock_flag(sk, SOCK_DEAD)) -+ sk->sk_error_report(sk); -+ goto out; -+ } -+ can_dev_unregister(dev, raw_notifier, sk); -+ } else -+ dev = NULL; -+ -+ /* unregister current filters for this device */ -+ raw_remove_filters(dev, sk); -+ -+ if (dev) -+ dev_put(dev); -+ -+ ro->bound = 0; -+#else -+ return -EINVAL; -+#endif -+ } -+ -+ if (addr->can_ifindex) { -+ dev = dev_get_by_index(addr->can_ifindex); -+ if (!dev) { -+ DBG("could not find device %d\n", addr->can_ifindex); -+ return -ENODEV; -+ } -+ if (!(dev->flags & IFF_UP)) { -+ sk->sk_err = ENETDOWN; -+ if (!sock_flag(sk, SOCK_DEAD)) -+ sk->sk_error_report(sk); -+ goto out; -+ } -+ can_dev_register(dev, raw_notifier, sk); -+ } else -+ dev = NULL; -+ -+ ro->ifindex = addr->can_ifindex; -+ -+ raw_add_filters(dev, sk); /* filters set by default/setsockopt */ -+ -+ if (ro->err_mask) /* error frame filter set by setsockopt */ -+ can_rx_register(dev, 0, ro->err_mask | CAN_ERR_FLAG, -+ raw_rcv, sk, IDENT); -+ -+ ro->bound = 1; -+ -+ out: -+ if (dev) -+ dev_put(dev); -+ -+ return 0; -+} -+ -+static int raw_getname(struct socket *sock, struct sockaddr *uaddr, -+ int *len, int peer) -+{ -+ struct sockaddr_can *addr = (struct sockaddr_can *)uaddr; -+ struct sock *sk = sock->sk; -+ struct raw_opt *ro = raw_sk(sk); -+ -+ if (peer) -+ return -EOPNOTSUPP; -+ -+ addr->can_family = AF_CAN; -+ addr->can_ifindex = ro->ifindex; -+ *len = sizeof(*addr); -+ -+ return 0; -+} -+ -+static unsigned int raw_poll(struct file *file, struct socket *sock, -+ poll_table *wait) -+{ -+ unsigned int mask = 0; -+ -+ DBG("socket %p\n", sock); -+ -+ mask = datagram_poll(file, sock, wait); -+ return mask; -+} -+ -+static int raw_setsockopt(struct socket *sock, int level, int optname, -+ char __user *optval, int optlen) -+{ -+ struct sock *sk = sock->sk; -+ struct raw_opt *ro = raw_sk(sk); -+ struct can_filter *filter = NULL; /* dyn. alloc'ed filters */ -+ struct can_filter sfilter; /* single filter */ -+ struct net_device *dev = NULL; -+ can_err_mask_t err_mask = 0; -+ int count = 0; -+ int err; -+ -+ if (level != SOL_CAN_RAW) -+ return -EINVAL; -+ -+ switch (optname) { -+ case CAN_RAW_FILTER: -+ if (optlen % sizeof(struct can_filter) != 0) -+ return -EINVAL; -+ -+ count = optlen / sizeof(struct can_filter); -+ -+ if (count > 1) { /* does not fit into dfilter */ -+ if (!(filter = kmalloc(optlen, GFP_KERNEL))) -+ return -ENOMEM; -+ if ((err = copy_from_user(filter, optval, optlen))) { -+ kfree(filter); -+ return err; -+ } -+ } else if (count == 1) { -+ if ((err = copy_from_user(&sfilter, optval, optlen))) -+ return err; -+ } -+ -+ if (ro->bound && ro->ifindex) -+ dev = dev_get_by_index(ro->ifindex); -+ -+ /* remove current filters & unregister */ -+ if (ro->bound) -+ raw_remove_filters(dev, sk); -+ if (ro->count > 1) -+ kfree(ro->filter); -+ -+ if (count == 1) { /* copy data for single filter */ -+ ro->dfilter = sfilter; -+ filter = &ro->dfilter; -+ } -+ -+ /* add new filters & register */ -+ ro->filter = filter; -+ ro->count = count; -+ if (ro->bound) -+ raw_add_filters(dev, sk); -+ -+ if (dev) -+ dev_put(dev); -+ -+ break; -+ -+ case CAN_RAW_ERR_FILTER: -+ if (optlen != sizeof(err_mask)) -+ return -EINVAL; -+ if ((err = copy_from_user(&err_mask, optval, optlen))) -+ return err; -+ -+ err_mask &= CAN_ERR_MASK; -+ -+ if (ro->bound && ro->ifindex) -+ dev = dev_get_by_index(ro->ifindex); -+ -+ /* remove current error mask */ -+ if (ro->err_mask && ro->bound) -+ can_rx_unregister(dev, 0, ro->err_mask | CAN_ERR_FLAG, -+ raw_rcv, sk); -+ -+ /* add new error mask */ -+ ro->err_mask = err_mask; -+ if (ro->err_mask && ro->bound) -+ can_rx_register(dev, 0, ro->err_mask | CAN_ERR_FLAG, -+ raw_rcv, sk, IDENT); -+ -+ if (dev) -+ dev_put(dev); -+ -+ break; -+ -+ case CAN_RAW_LOOPBACK: -+ if (optlen != sizeof(ro->loopback)) -+ return -EINVAL; -+ if ((err = copy_from_user(&ro->loopback, optval, optlen))) -+ return err; -+ break; -+ -+ case CAN_RAW_RECV_OWN_MSGS: -+ if (optlen != sizeof(ro->recv_own_msgs)) -+ return -EINVAL; -+ if ((err = copy_from_user(&ro->recv_own_msgs, optval, optlen))) -+ return err; -+ break; -+ -+ default: -+ return -ENOPROTOOPT; -+ } -+ return 0; -+} -+ -+static int raw_getsockopt(struct socket *sock, int level, int optname, -+ char __user *optval, int __user *optlen) -+{ -+ struct sock *sk = sock->sk; -+ struct raw_opt *ro = raw_sk(sk); -+ struct can_filter *filter = ro->filter; -+ int count = ro->count; -+ int len; -+ -+ if (level != SOL_CAN_RAW) -+ return -EINVAL; -+ -+ switch (optname) { -+ case CAN_RAW_FILTER: -+ if (get_user(len, optlen)) -+ return -EFAULT; -+ -+ if (count && filter) { -+ int filter_size = count * sizeof(struct can_filter); -+ if (len < filter_size) -+ return -EINVAL; -+ if (len > filter_size) -+ len = filter_size; -+ if (copy_to_user(optval, filter, len)) -+ return -EFAULT; -+ } else -+ len = 0; -+ -+ if (put_user(len, optlen)) -+ return -EFAULT; -+ -+ break; -+ -+ case CAN_RAW_ERR_FILTER: -+ if (get_user(len, optlen)) -+ return -EFAULT; -+ -+ if (len < sizeof(can_err_mask_t)) -+ return -EINVAL; -+ -+ if (len > sizeof(can_err_mask_t)) -+ len = sizeof(can_err_mask_t); -+ -+ if (copy_to_user(optval, &ro->err_mask, len)) -+ return -EFAULT; -+ -+ if (put_user(len, optlen)) -+ return -EFAULT; -+ -+ break; -+ -+ case CAN_RAW_LOOPBACK: -+ if (get_user(len, optlen)) -+ return -EFAULT; -+ -+ if (len < sizeof(int)) -+ return -EINVAL; -+ -+ if (len > sizeof(int)) -+ len = sizeof(int); -+ -+ if (copy_to_user(optval, &ro->loopback, len)) -+ return -EFAULT; -+ -+ if (put_user(len, optlen)) -+ return -EFAULT; -+ -+ break; -+ -+ case CAN_RAW_RECV_OWN_MSGS: -+ if (get_user(len, optlen)) -+ return -EFAULT; -+ -+ if (len < sizeof(int)) -+ return -EINVAL; -+ -+ if (len > sizeof(int)) -+ len = sizeof(int); -+ -+ if (copy_to_user(optval, &ro->recv_own_msgs, len)) -+ return -EFAULT; -+ -+ if (put_user(len, optlen)) -+ return -EFAULT; -+ -+ break; -+ -+ default: -+ return -ENOPROTOOPT; -+ } -+ return 0; -+} -+ -+static void raw_add_filters(struct net_device *dev, struct sock *sk) -+{ -+ struct raw_opt *ro = raw_sk(sk); -+ struct can_filter *filter = ro->filter; -+ int i; -+ -+ for (i = 0; i < ro->count; i++) { -+ can_rx_register(dev, filter[i].can_id, filter[i].can_mask, -+ raw_rcv, sk, IDENT); -+ DBG("filter can_id %08X, can_mask %08X%s, sk %p\n", -+ filter[i].can_id, filter[i].can_mask, -+ filter[i].can_id & CAN_INV_FILTER ? " (inv)" : "", sk); -+ } -+} -+ -+static void raw_remove_filters(struct net_device *dev, struct sock *sk) -+{ -+ struct raw_opt *ro = raw_sk(sk); -+ struct can_filter *filter = ro->filter; -+ int i; -+ -+ for (i = 0; i < ro->count; i++) { -+ can_rx_unregister(dev, filter[i].can_id, filter[i].can_mask, -+ raw_rcv, sk); -+ DBG("filter can_id %08X, can_mask %08X%s, sk %p\n", -+ filter[i].can_id, filter[i].can_mask, -+ filter[i].can_id & CAN_INV_FILTER ? " (inv)" : "", sk); -+ } -+} -+ -+static int raw_sendmsg(struct kiocb *iocb, struct socket *sock, -+ struct msghdr *msg, size_t size) -+{ -+ struct sock *sk = sock->sk; -+ struct raw_opt *ro = raw_sk(sk); -+ struct sk_buff *skb; -+ struct net_device *dev; -+ int ifindex; -+ int err; -+ -+ DBG("socket %p, sk %p\n", sock, sk); -+ -+ if (msg->msg_name) { -+ struct sockaddr_can *addr = -+ (struct sockaddr_can *)msg->msg_name; -+ if (addr->can_family != AF_CAN) -+ return -EINVAL; -+ ifindex = addr->can_ifindex; -+ } else -+ ifindex = ro->ifindex; -+ -+ if (!(dev = dev_get_by_index(ifindex))) { -+ DBG("device %d not found\n", ifindex); -+ return -ENXIO; -+ } -+ -+ if (!(skb = alloc_skb(size, GFP_KERNEL))) { -+ dev_put(dev); -+ return -ENOMEM; -+ } -+ -+ if ((err = memcpy_fromiovec(skb_put(skb, size), -+ msg->msg_iov, size)) < 0) { -+ kfree_skb(skb); -+ dev_put(dev); -+ return err; -+ } -+ skb->dev = dev; -+ skb->sk = sk; -+ -+ DBG("sending skbuff to interface %d\n", ifindex); -+ DBG_SKB(skb); -+ -+ err = can_send(skb, ro->loopback); -+ -+ dev_put(dev); -+ -+ if (err) -+ return err; -+ -+ return size; -+} -+ -+static int raw_recvmsg(struct kiocb *iocb, struct socket *sock, -+ struct msghdr *msg, size_t size, int flags) -+{ -+ struct sock *sk = sock->sk; -+ struct sk_buff *skb; -+ int error = 0; -+ int noblock; -+ -+ DBG("socket %p, sk %p\n", sock, sk); -+ -+ noblock = flags & MSG_DONTWAIT; -+ flags &= ~MSG_DONTWAIT; -+ -+ if (!(skb = skb_recv_datagram(sk, flags, noblock, &error))) -+ return error; -+ -+ DBG("delivering skbuff %p\n", skb); -+ DBG_SKB(skb); -+ -+ if (size < skb->len) -+ msg->msg_flags |= MSG_TRUNC; -+ else -+ size = skb->len; -+ -+ if ((error = memcpy_toiovec(msg->msg_iov, skb->data, size)) < 0) { -+ skb_free_datagram(sk, skb); -+ return error; -+ } -+ -+ sock_recv_timestamp(msg, sk, skb); -+ -+ if (msg->msg_name) { -+ msg->msg_namelen = sizeof(struct sockaddr_can); -+ memcpy(msg->msg_name, skb->cb, msg->msg_namelen); -+ } -+ -+ DBG("freeing sock %p, skbuff %p\n", sk, skb); -+ skb_free_datagram(sk, skb); -+ -+ return size; -+} -+ -+static void raw_rcv(struct sk_buff *skb, void *data) -+{ -+ struct sock *sk = (struct sock*)data; -+ struct raw_opt *ro = raw_sk(sk); -+ struct sockaddr_can *addr; -+ int error; -+ -+ DBG("received skbuff %p, sk %p\n", skb, sk); -+ DBG_SKB(skb); -+ -+ if (!ro->recv_own_msgs) { -+ if (*(struct sock **)skb->cb == sk) { /* tx sock reference */ -+ DBG("trashed own tx msg\n"); -+ kfree_skb(skb); -+ return; -+ } -+ } -+ -+ addr = (struct sockaddr_can *)skb->cb; -+ memset(addr, 0, sizeof(*addr)); -+ addr->can_family = AF_CAN; -+ addr->can_ifindex = skb->dev->ifindex; -+ -+ if ((error = sock_queue_rcv_skb(sk, skb)) < 0) { -+ DBG("sock_queue_rcv_skb failed: %d\n", error); -+ DBG("freeing skbuff %p\n", skb); -+ kfree_skb(skb); -+ } -+} -+ -+static void raw_notifier(unsigned long msg, void *data) -+{ -+ struct sock *sk = (struct sock *)data; -+ struct raw_opt *ro = raw_sk(sk); -+ -+ DBG("called for sock %p\n", sk); -+ -+ switch (msg) { -+ case NETDEV_UNREGISTER: -+ ro->ifindex = 0; -+ ro->bound = 0; -+ /* fallthrough */ -+ case NETDEV_DOWN: -+ sk->sk_err = ENETDOWN; -+ if (!sock_flag(sk, SOCK_DEAD)) -+ sk->sk_error_report(sk); -+ break; -+ } -+} -+ -+ -+module_init(raw_module_init); -+module_exit(raw_module_exit); diff --git a/patches/linux-2.6.21-rc3/can-networking-R180-2.6.21-rc3_X_Complete.diff b/patches/linux-2.6.21-rc3/can-networking-R180-2.6.21-rc3_X_Complete.diff deleted file mode 100644 index c2adc25..0000000 --- a/patches/linux-2.6.21-rc3/can-networking-R180-2.6.21-rc3_X_Complete.diff +++ /dev/null @@ -1,5034 +0,0 @@ -diff -N -u -r a/CREDITS c/CREDITS ---- a/CREDITS 2007-03-09 09:51:49.000000000 +0100 -+++ c/CREDITS 2007-03-09 13:39:10.000000000 +0100 -@@ -1324,6 +1324,14 @@ - S: 5623 HZ Eindhoven - S: The Netherlands - -+N: Oliver Hartkopp -+E: oliver.hartkopp@volkswagen.de -+W: http://www.volkswagen.de -+D: Controller Area Network (network layer core) -+S: Brieffach 1776 -+S: 38436 Wolfsburg -+S: Germany -+ - N: Andrew Haylett - E: ajh@primag.co.uk - D: Selection mechanism -@@ -3277,6 +3285,14 @@ - S: F-35042 Rennes Cedex - S: France - -+N: Urs Thuermann -+E: urs.thuermann@volkswagen.de -+W: http://www.volkswagen.de -+D: Controller Area Network (network layer core) -+S: Brieffach 1776 -+S: 38436 Wolfsburg -+S: Germany -+ - N: Jon Tombs - E: jon@gte.esi.us.es - W: http://www.esi.us.es/~jon -diff -N -u -r a/drivers/net/can/Kconfig c/drivers/net/can/Kconfig ---- a/drivers/net/can/Kconfig 1970-01-01 01:00:00.000000000 +0100 -+++ c/drivers/net/can/Kconfig 2007-03-09 13:45:53.000000000 +0100 -@@ -0,0 +1,26 @@ -+menu "CAN Device Drivers" -+ depends on CAN -+ -+config CAN_VCAN -+ tristate "Virtual Local CAN Interface (vcan)" -+ depends on CAN -+ default N -+ ---help--- -+ Similar to the network loopback devices, vcan offers a -+ virtual local CAN interface. -+ -+ This driver can also be built as a module. If so, the module -+ will be called vcan. -+ -+config CAN_DEBUG_DEVICES -+ bool "CAN devices debugging messages" -+ depends on CAN -+ default N -+ ---help--- -+ Say Y here if you want the CAN device drivers to produce a bunch of -+ debug messages to the system log. Select this if you are having -+ a problem with CAN support and want to see more of what is going -+ on. -+ -+endmenu -+ -diff -N -u -r a/drivers/net/can/Makefile c/drivers/net/can/Makefile ---- a/drivers/net/can/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ c/drivers/net/can/Makefile 2007-03-09 13:45:53.000000000 +0100 -@@ -0,0 +1,5 @@ -+# -+# Makefile for the Linux Controller Area Network drivers. -+# -+ -+obj-$(CONFIG_CAN_VCAN) += vcan.o -diff -N -u -r a/drivers/net/can/vcan.c c/drivers/net/can/vcan.c ---- a/drivers/net/can/vcan.c 1970-01-01 01:00:00.000000000 +0100 -+++ c/drivers/net/can/vcan.c 2007-03-09 13:45:53.000000000 +0100 -@@ -0,0 +1,301 @@ -+/* -+ * vcan.c - Virtual CAN interface -+ * -+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research -+ * 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, the following disclaimer and -+ * the referenced file 'COPYING'. -+ * 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. Neither the name of Volkswagen nor the names of its contributors -+ * may be used to endorse or promote products derived from this software -+ * without specific prior written permission. -+ * -+ * Alternatively, provided that this notice is retained in full, this -+ * software may be distributed under the terms of the GNU General -+ * Public License ("GPL") version 2 as distributed in the 'COPYING' -+ * file from the main directory of the linux kernel source. -+ * -+ * The provided data structures and external interfaces from this code -+ * are not restricted to be used by modules with a GPL compatible license. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT -+ * OWNER 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. -+ * -+ * Send feedback to -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+RCSID("$Id: vcan.c 168 2007-03-05 13:33:59Z hartkopp $"); -+ -+static __initdata const char banner[] = KERN_INFO "CAN: virtual CAN " -+ "interface " VERSION "\n"; -+ -+MODULE_DESCRIPTION("virtual CAN interface"); -+MODULE_LICENSE("Dual BSD/GPL"); -+MODULE_AUTHOR("Urs Thuermann "); -+ -+#ifdef CONFIG_CAN_DEBUG_DEVICES -+static int debug = 0; -+module_param(debug, int, S_IRUGO); -+#define DBG(args...) (debug & 1 ? \ -+ (printk(KERN_DEBUG "VCAN %s: ", __func__), \ -+ printk(args)) : 0) -+#define DBG_FRAME(args...) (debug & 2 ? can_debug_cframe(args) : 0) -+#define DBG_SKB(skb) (debug & 4 ? can_debug_skb(skb) : 0) -+#else -+#define DBG(args...) -+#define DBG_FRAME(args...) -+#define DBG_SKB(skb) -+#endif -+ -+/* Indicate if this VCAN driver should do a real loopback, or if this */ -+/* should be done in af_can.c */ -+#undef DO_LOOPBACK -+ -+#define STATSIZE sizeof(struct net_device_stats) -+ -+static int numdev = 4; /* default number of virtual CAN interfaces */ -+module_param(numdev, int, S_IRUGO); -+MODULE_PARM_DESC(numdev, "Number of virtual CAN devices"); -+ -+static struct net_device **vcan_devs; /* root pointer to netdevice structs */ -+ -+static int vcan_open(struct net_device *dev) -+{ -+ DBG("%s: interface up\n", dev->name); -+ -+ netif_start_queue(dev); -+ return 0; -+} -+ -+static int vcan_stop(struct net_device *dev) -+{ -+ DBG("%s: interface down\n", dev->name); -+ -+ netif_stop_queue(dev); -+ return 0; -+} -+ -+#ifdef DO_LOOPBACK -+ -+static void vcan_rx(struct sk_buff *skb, struct net_device *dev) -+{ -+ struct net_device_stats *stats = netdev_priv(dev); -+ stats->rx_packets++; -+ stats->rx_bytes += skb->len; -+ -+ skb->protocol = htons(ETH_P_CAN); -+ skb->dev = dev; -+ skb->ip_summed = CHECKSUM_UNNECESSARY; -+ -+ DBG("received skbuff on interface %d\n", dev->ifindex); -+ DBG_SKB(skb); -+ -+ netif_rx(skb); -+} -+ -+#endif -+ -+static int vcan_tx(struct sk_buff *skb, struct net_device *dev) -+{ -+ struct net_device_stats *stats = netdev_priv(dev); -+ int loop; -+ -+ DBG("sending skbuff on interface %s\n", dev->name); -+ DBG_SKB(skb); -+ DBG_FRAME("VCAN: transmit CAN frame", (struct can_frame *)skb->data); -+ -+ stats->tx_packets++; -+ stats->tx_bytes += skb->len; -+ -+ loop = *(struct sock **)skb->cb != NULL; /* loopback required */ -+ -+#ifdef DO_LOOPBACK -+ if (loop) { -+ if (atomic_read(&skb->users) != 1) { -+ struct sk_buff *old_skb = skb; -+ skb = skb_clone(old_skb, GFP_ATOMIC); -+ DBG(" freeing old skbuff %p, using new skbuff %p\n", -+ old_skb, skb); -+ kfree_skb(old_skb); -+ if (!skb) { -+ return 0; -+ } -+ } else -+ skb_orphan(skb); -+ -+ vcan_rx(skb, dev); /* with packet counting */ -+ } else { -+ /* no looped packets => no counting */ -+ kfree_skb(skb); -+ } -+#else -+ /* only count, when the CAN core did a loopback */ -+ if (loop) { -+ stats->rx_packets++; -+ stats->rx_bytes += skb->len; -+ } -+ kfree_skb(skb); -+#endif -+ return 0; -+} -+ -+static int vcan_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -+{ -+ return -EOPNOTSUPP; -+} -+ -+static int vcan_rebuild_header(struct sk_buff *skb) -+{ -+ DBG("skbuff %p\n", skb); -+ DBG_SKB(skb); -+ return 0; -+} -+ -+static int vcan_header(struct sk_buff *skb, struct net_device *dev, -+ unsigned short type, void *daddr, void *saddr, -+ unsigned int len) -+{ -+ DBG("skbuff %p, device %p\n", skb, dev); -+ DBG_SKB(skb); -+ return 0; -+} -+ -+ -+static struct net_device_stats *vcan_get_stats(struct net_device *dev) -+{ -+ struct net_device_stats *stats = netdev_priv(dev); -+ return stats; -+} -+ -+static void vcan_init(struct net_device *dev) -+{ -+ DBG("dev %s\n", dev->name); -+ -+ ether_setup(dev); -+ -+ memset(dev->priv, 0, STATSIZE); -+ -+ dev->type = ARPHRD_CAN; -+ dev->mtu = sizeof(struct can_frame); -+ dev->flags = IFF_NOARP; -+#ifdef DO_LOOPBACK -+ dev->flags |= IFF_LOOPBACK; -+#endif -+ -+ dev->open = vcan_open; -+ dev->stop = vcan_stop; -+ dev->set_config = NULL; -+ dev->hard_start_xmit = vcan_tx; -+ dev->do_ioctl = vcan_ioctl; -+ dev->get_stats = vcan_get_stats; -+ dev->hard_header = vcan_header; -+ dev->rebuild_header = vcan_rebuild_header; -+ dev->hard_header_cache = NULL; -+ -+ SET_MODULE_OWNER(dev); -+} -+ -+static __init int vcan_init_module(void) -+{ -+ int i, ndev = 0, result = 0; -+ -+ printk(banner); -+ -+ if (numdev < 1) -+ numdev = 1; /* register at least one interface */ -+ -+ printk(KERN_INFO "vcan: registering %d virtual CAN interfaces.\n", -+ numdev ); -+ -+ vcan_devs = kmalloc(numdev * sizeof(struct net_device *), GFP_KERNEL); -+ if (!vcan_devs) { -+ printk(KERN_ERR "vcan: Can't allocate vcan devices array!\n"); -+ return -ENOMEM; -+ } -+ -+ /* Clear the pointer array */ -+ memset(vcan_devs, 0, numdev * sizeof(struct net_device *)); -+ -+ for (i = 0; i < numdev; i++) { -+ if (!(vcan_devs[i] = alloc_netdev(STATSIZE, "vcan%d", -+ vcan_init))) { -+ printk(KERN_ERR "vcan: error allocating net_device\n"); -+ result = -ENOMEM; -+ goto out; -+ } else if ((result = register_netdev(vcan_devs[i])) < 0) { -+ printk(KERN_ERR "vcan: error %d registering " -+ "interface %s\n", -+ result, vcan_devs[i]->name); -+ free_netdev(vcan_devs[i]); -+ vcan_devs[i] = NULL; -+ goto out; -+ } else { -+ DBG("successfully registered interface %s\n", -+ vcan_devs[i]->name); -+ ndev++; -+ } -+ } -+ -+ if (ndev) -+ return 0; -+ -+ out: -+ for (i = 0; i < numdev; i++) { -+ if (vcan_devs[i]) { -+ unregister_netdev(vcan_devs[i]); -+ free_netdev(vcan_devs[i]); -+ } -+ } -+ -+ kfree(vcan_devs); -+ -+ return result; -+} -+ -+static __exit void vcan_cleanup_module(void) -+{ -+ int i; -+ -+ if (!vcan_devs) -+ return; -+ -+ for (i = 0; i < numdev; i++) { -+ if (vcan_devs[i]) { -+ unregister_netdev(vcan_devs[i]); -+ free_netdev(vcan_devs[i]); -+ } -+ } -+ -+ kfree(vcan_devs); -+} -+ -+module_init(vcan_init_module); -+module_exit(vcan_cleanup_module); -diff -N -u -r a/drivers/net/Makefile c/drivers/net/Makefile ---- a/drivers/net/Makefile 2007-03-09 09:52:04.000000000 +0100 -+++ c/drivers/net/Makefile 2007-03-09 13:39:10.000000000 +0100 -@@ -8,6 +8,7 @@ - obj-$(CONFIG_CHELSIO_T1) += chelsio/ - obj-$(CONFIG_CHELSIO_T3) += cxgb3/ - obj-$(CONFIG_EHEA) += ehea/ -+obj-$(CONFIG_CAN) += can/ - obj-$(CONFIG_BONDING) += bonding/ - obj-$(CONFIG_ATL1) += atl1/ - obj-$(CONFIG_GIANFAR) += gianfar_driver.o -diff -N -u -r a/include/linux/can/bcm.h c/include/linux/can/bcm.h ---- a/include/linux/can/bcm.h 1970-01-01 01:00:00.000000000 +0100 -+++ c/include/linux/can/bcm.h 2007-03-07 17:13:13.000000000 +0100 -@@ -0,0 +1,56 @@ -+/* -+ * linux/can/bcm.h -+ * -+ * Definitions for CAN Broadcast Manager (BCM) -+ * -+ * $Id: bcm.h 176 2007-03-07 16:12:46Z hartkopp $ -+ * -+ * Author: Oliver Hartkopp -+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research -+ * All rights reserved. -+ * -+ * Send feedback to -+ * -+ */ -+ -+#ifndef CAN_BCM_H -+#define CAN_BCM_H -+ -+struct bcm_msg_head { -+ int opcode; /* command */ -+ int flags; /* special flags */ -+ int count; /* run 'count' times ival1 then ival2 */ -+ struct timeval ival1, ival2; /* intervals */ -+ canid_t can_id; /* 32 Bit SFF/EFF. MSB set at EFF */ -+ int nframes; /* number of following can_frame's */ -+ struct can_frame frames[0]; -+}; -+ -+enum { -+ TX_SETUP = 1, /* create (cyclic) transmission task */ -+ TX_DELETE, /* remove (cyclic) transmission task */ -+ TX_READ, /* read properties of (cyclic) transmission task */ -+ TX_SEND, /* send one CAN frame */ -+ RX_SETUP, /* create RX content filter subscription */ -+ RX_DELETE, /* remove RX content filter subscription */ -+ RX_READ, /* read properties of RX content filter subscription */ -+ TX_STATUS, /* reply to TX_READ request */ -+ TX_EXPIRED, /* notification on performed transmissions (count=0) */ -+ RX_STATUS, /* reply to RX_READ request */ -+ RX_TIMEOUT, /* cyclic message is absent */ -+ RX_CHANGED /* updated CAN frame (detected content change) */ -+}; -+ -+#define SETTIMER 0x0001 -+#define STARTTIMER 0x0002 -+#define TX_COUNTEVT 0x0004 -+#define TX_ANNOUNCE 0x0008 -+#define TX_CP_CAN_ID 0x0010 -+#define RX_FILTER_ID 0x0020 -+#define RX_CHECK_DLC 0x0040 -+#define RX_NO_AUTOTIMER 0x0080 -+#define RX_ANNOUNCE_RESUME 0x0100 -+#define TX_RESET_MULTI_IDX 0x0200 -+#define RX_RTR_FRAME 0x0400 -+ -+#endif /* CAN_BCM_H */ -diff -N -u -r a/include/linux/can/core.h c/include/linux/can/core.h ---- a/include/linux/can/core.h 1970-01-01 01:00:00.000000000 +0100 -+++ c/include/linux/can/core.h 2007-03-09 17:24:11.000000000 +0100 -@@ -0,0 +1,56 @@ -+/* -+ * linux/can/core.h -+ * -+ * Protoypes and definitions for CAN protocol modules using the PF_CAN core -+ * -+ * $Id: core.h 177 2007-03-08 11:02:43Z hartkopp $ -+ * -+ * Authors: Oliver Hartkopp -+ * Urs Thuermann -+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research -+ * All rights reserved. -+ * -+ * Send feedback to -+ * -+ */ -+ -+#ifndef CAN_CORE_H -+#define CAN_CORE_H -+ -+#include -+#include -+#include -+ -+#define DNAME(dev) ((dev) ? (dev)->name : "any") -+ -+#define CAN_PROC_DIR "net/can" /* /proc/... */ -+ -+struct can_proto { -+ int type; -+ int protocol; -+ int capability; -+ struct proto_ops *ops; -+ struct proto *prot; -+}; -+ -+/* function prototypes for the CAN networklayer core (af_can.c) */ -+ -+void can_debug_skb(struct sk_buff *skb); -+void can_debug_cframe(const char *msg, struct can_frame *cframe, ...); -+ -+void can_proto_register(struct can_proto *cp); -+void can_proto_unregister(struct can_proto *cp); -+int can_rx_register(struct net_device *dev, canid_t can_id, canid_t mask, -+ void (*func)(struct sk_buff *, void *), void *data, -+ char *ident); -+int can_rx_unregister(struct net_device *dev, canid_t can_id, canid_t mask, -+ void (*func)(struct sk_buff *, void *), void *data); -+void can_dev_register(struct net_device *dev, -+ void (*func)(unsigned long msg, void *), void *data); -+void can_dev_unregister(struct net_device *dev, -+ void (*func)(unsigned long msg, void *), void *data); -+int can_send(struct sk_buff *skb, int loop); -+ -+unsigned long timeval2jiffies(struct timeval *tv, int round_up); -+ -+#endif /* CAN_CORE_H */ -diff -N -u -r a/include/linux/can/error.h c/include/linux/can/error.h ---- a/include/linux/can/error.h 1970-01-01 01:00:00.000000000 +0100 -+++ c/include/linux/can/error.h 2007-03-05 09:25:43.000000000 +0100 -@@ -0,0 +1,95 @@ -+/* -+ * linux/can/error.h -+ * -+ * Definitions of the CAN error frame to be filtered and passed to the user. -+ * -+ * $Id: error.h 162 2007-03-05 08:25:02Z hartkopp $ -+ * -+ * Author: Oliver Hartkopp -+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research -+ * All rights reserved. -+ * -+ * Send feedback to -+ * -+ */ -+ -+#ifndef CAN_ERROR_H -+#define CAN_ERROR_H -+ -+#define CAN_ERR_DLC 8 /* dlc for error frames */ -+ -+/* error class (mask) in can_id */ -+#define CAN_ERR_TX_TIMEOUT 0x00000001U /* TX timeout (by netdevice driver) */ -+#define CAN_ERR_LOSTARB 0x00000002U /* lost arbitration / data[0] */ -+#define CAN_ERR_CRTL 0x00000004U /* controller problems / data[1] */ -+#define CAN_ERR_PROT 0x00000008U /* protocol violations / data[2..3] */ -+#define CAN_ERR_TRX 0x00000010U /* transceiver status / data[4] */ -+#define CAN_ERR_ACK 0x00000020U /* received no ACK on transmission */ -+#define CAN_ERR_BUSOFF 0x00000040U /* bus off */ -+#define CAN_ERR_BUSERROR 0x00000080U /* bus error (may flood!) */ -+#define CAN_ERR_RESTARTED 0x00000100U /* controller restarted */ -+ -+/* arbitration lost in bit ... / data[0] */ -+#define CAN_ERR_LOSTARB_UNSPEC 0x00 /* unspecified */ -+ /* else bit number in bitstream */ -+ -+/* error status of CAN-controller / data[1] */ -+#define CAN_ERR_CRTL_UNSPEC 0x00 /* unspecified */ -+#define CAN_ERR_CRTL_RX_OVERFLOW 0x01 /* RX buffer overflow */ -+#define CAN_ERR_CRTL_TX_OVERFLOW 0x02 /* TX buffer overflow */ -+#define CAN_ERR_CRTL_RX_WARNING 0x04 /* reached warning level for RX errors */ -+#define CAN_ERR_CRTL_TX_WARNING 0x08 /* reached warning level for TX errors */ -+#define CAN_ERR_CRTL_RX_PASSIVE 0x10 /* reached error passive status RX */ -+#define CAN_ERR_CRTL_TX_PASSIVE 0x20 /* reached error passive status TX */ -+ /* (at least one error counter exceeds */ -+ /* the protocol-defined level of 127) */ -+ -+/* error in CAN protocol (type) / data[2] */ -+#define CAN_ERR_PROT_UNSPEC 0x00 /* unspecified */ -+#define CAN_ERR_PROT_BIT 0x01 /* single bit error */ -+#define CAN_ERR_PROT_FORM 0x02 /* frame format error */ -+#define CAN_ERR_PROT_STUFF 0x04 /* bit stuffing error */ -+#define CAN_ERR_PROT_BIT0 0x08 /* unable to send dominant bit */ -+#define CAN_ERR_PROT_BIT1 0x10 /* unable to send recessive bit */ -+#define CAN_ERR_PROT_OVERLOAD 0x20 /* bus overload */ -+#define CAN_ERR_PROT_ACTIVE 0x40 /* active error announcement */ -+#define CAN_ERR_PROT_TX 0x80 /* error occured on transmission */ -+ -+/* error in CAN protocol (location) / data[3] */ -+#define CAN_ERR_PROT_LOC_UNSPEC 0x00 /* unspecified */ -+#define CAN_ERR_PROT_LOC_SOF 0x03 /* start of frame */ -+#define CAN_ERR_PROT_LOC_ID28_21 0x02 /* ID bits 28 - 21 (SFF: 10 - 3) */ -+#define CAN_ERR_PROT_LOC_ID20_18 0x06 /* ID bits 20 - 18 (SFF: 2 - 0 )*/ -+#define CAN_ERR_PROT_LOC_SRTR 0x04 /* substitute RTR (SFF: RTR) */ -+#define CAN_ERR_PROT_LOC_IDE 0x05 /* identifier extension */ -+#define CAN_ERR_PROT_LOC_ID17_13 0x07 /* ID bits 17-13 */ -+#define CAN_ERR_PROT_LOC_ID12_05 0x0F /* ID bits 12-5 */ -+#define CAN_ERR_PROT_LOC_ID04_00 0x0E /* ID bits 4-0 */ -+#define CAN_ERR_PROT_LOC_RTR 0x0C /* RTR */ -+#define CAN_ERR_PROT_LOC_RES1 0x0D /* reserved bit 1 */ -+#define CAN_ERR_PROT_LOC_RES0 0x09 /* reserved bit 0 */ -+#define CAN_ERR_PROT_LOC_DLC 0x0B /* data length code */ -+#define CAN_ERR_PROT_LOC_DATA 0x0A /* data section */ -+#define CAN_ERR_PROT_LOC_CRC_SEQ 0x08 /* CRC sequence */ -+#define CAN_ERR_PROT_LOC_CRC_DEL 0x18 /* CRC delimiter */ -+#define CAN_ERR_PROT_LOC_ACK 0x19 /* ACK slot */ -+#define CAN_ERR_PROT_LOC_ACK_DEL 0x1B /* ACK delimiter */ -+#define CAN_ERR_PROT_LOC_EOF 0x1A /* end of frame */ -+#define CAN_ERR_PROT_LOC_INTERM 0x12 /* intermission */ -+ -+/* error status of CAN-transceiver / data[4] */ -+/* CANH CANL */ -+#define CAN_ERR_TRX_UNSPEC 0x00 /* 0000 0000 */ -+#define CAN_ERR_TRX_CANH_NO_WIRE 0x04 /* 0000 0100 */ -+#define CAN_ERR_TRX_CANH_SHORT_TO_BAT 0x05 /* 0000 0101 */ -+#define CAN_ERR_TRX_CANH_SHORT_TO_VCC 0x06 /* 0000 0110 */ -+#define CAN_ERR_TRX_CANH_SHORT_TO_GND 0x07 /* 0000 0111 */ -+#define CAN_ERR_TRX_CANL_NO_WIRE 0x40 /* 0100 0000 */ -+#define CAN_ERR_TRX_CANL_SHORT_TO_BAT 0x50 /* 0101 0000 */ -+#define CAN_ERR_TRX_CANL_SHORT_TO_VCC 0x60 /* 0110 0000 */ -+#define CAN_ERR_TRX_CANL_SHORT_TO_GND 0x70 /* 0111 0000 */ -+#define CAN_ERR_TRX_CANL_SHORT_TO_CANH 0x80 /* 1000 0000 */ -+ -+/* controller specific additional information / data[5..7] */ -+ -+#endif /* CAN_ERROR_H */ -diff -N -u -r a/include/linux/can/raw.h c/include/linux/can/raw.h ---- a/include/linux/can/raw.h 1970-01-01 01:00:00.000000000 +0100 -+++ c/include/linux/can/raw.h 2007-03-07 17:13:13.000000000 +0100 -@@ -0,0 +1,31 @@ -+/* -+ * linux/can/raw.h -+ * -+ * Definitions for raw CAN sockets -+ * -+ * $Id: raw.h 176 2007-03-07 16:12:46Z hartkopp $ -+ * -+ * Authors: Oliver Hartkopp -+ * Urs Thuermann -+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research -+ * All rights reserved. -+ * -+ * Send feedback to -+ * -+ */ -+ -+#ifndef CAN_RAW_H -+#define CAN_RAW_H -+ -+#include -+ -+#define SOL_CAN_RAW (SOL_CAN_BASE + CAN_RAW) -+ -+/* for socket options affecting the socket (not the global system) */ -+ -+#define CAN_RAW_FILTER 1 /* set 0 .. n can_filter(s) */ -+#define CAN_RAW_ERR_FILTER 2 /* set filter for error frames */ -+#define CAN_RAW_LOOPBACK 3 /* local loopback (default:on) */ -+#define CAN_RAW_RECV_OWN_MSGS 4 /* receive my own msgs (default:off) */ -+ -+#endif -diff -N -u -r a/include/linux/can/version.h c/include/linux/can/version.h ---- a/include/linux/can/version.h 1970-01-01 01:00:00.000000000 +0100 -+++ c/include/linux/can/version.h 2007-03-05 14:59:06.000000000 +0100 -@@ -0,0 +1,40 @@ -+/* -+ * linux/can/version.h -+ * -+ * Version information for the CAN network layer implementation -+ -+ * Author: Urs Thuermann -+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research -+ * All rights reserved. -+ * -+ * Send feedback to -+ * -+ */ -+ -+#ifndef CAN_VERSION_H -+#define CAN_VERSION_H -+ -+#define RCSID(s) asm(".section .rodata.str1.1,\"aMS\",@progbits,1\n\t" \ -+ ".string \"" s "\"\n\t.previous\n") -+ -+RCSID("$Id: version.h 170 2007-03-05 13:58:26Z hartkopp $"); -+ -+#define MAJORVERSION 2 -+#define MINORVERSION 0 -+#define PATCHLEVEL 0 -+#define EXTRAVERSION "-pre6" -+ -+#define LLCF_VERSION_CODE (((MAJORVERSION) << 16) + ((MINORVERSION) << 8) \ -+ + (PATCHLEVEL)) -+ -+/* stringification: these are the usual macros to stringify with macro -+ expansion. The str() macro does the expansion, the xstr() macro is -+ for the actual stringification. -+*/ -+#define str(arg) xstr(arg) -+#define xstr(arg) #arg -+ -+#define VERSION str(MAJORVERSION) "." str(MINORVERSION) "." str(PATCHLEVEL) \ -+ EXTRAVERSION -+ -+#endif /* CAN_VERSION_H */ -diff -N -u -r a/include/linux/can.h c/include/linux/can.h ---- a/include/linux/can.h 1970-01-01 01:00:00.000000000 +0100 -+++ c/include/linux/can.h 2007-03-05 11:14:57.000000000 +0100 -@@ -0,0 +1,77 @@ -+/* -+ * linux/can.h -+ * -+ * Definitions for CAN networklayer (socket addr / CAN frame / CAN filter) -+ * -+ * $Id: can.h 165 2007-03-05 10:14:18Z hartkopp $ -+ * -+ * Authors: Oliver Hartkopp -+ * Urs Thuermann -+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research -+ * All rights reserved. -+ * -+ * Send feedback to -+ * -+ */ -+ -+#ifndef CAN_H -+#define CAN_H -+ -+#include -+#include -+#include -+ -+/* controller area network (CAN) kernel definitions */ -+ -+/* special address description flags for the CAN_ID */ -+#define CAN_EFF_FLAG 0x80000000U /* EFF/SFF is set in the MSB */ -+#define CAN_RTR_FLAG 0x40000000U /* remote transmission request */ -+#define CAN_ERR_FLAG 0x20000000U /* error 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 /* omit EFF, RTR, ERR flags */ -+ -+typedef __u32 canid_t; -+ -+struct can_frame { -+ canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */ -+ __u8 can_dlc; /* data length code: 0 .. 8 */ -+ __u8 data[8] __attribute__ ((aligned(8))); -+}; -+ -+/* particular protocols of the protocol family PF_CAN */ -+#define CAN_RAW 1 /* RAW sockets */ -+#define CAN_BCM 2 /* Broadcast Manager */ -+#define CAN_TP16 3 /* VAG Transport Protocol v1.6 */ -+#define CAN_TP20 4 /* VAG Transport Protocol v2.0 */ -+#define CAN_MCNET 5 /* Bosch MCNet */ -+#define CAN_ISOTP 6 /* ISO 15765-2 Transport Protocol */ -+#define CAN_BAP 7 /* VAG Bedien- und Anzeigeprotokoll */ -+#define CAN_NPROTO 8 -+ -+#define SOL_CAN_BASE 100 -+ -+struct sockaddr_can { -+ sa_family_t can_family; -+ int can_ifindex; -+ union { -+ struct { canid_t rx_id, tx_id; } tp16; -+ struct { canid_t rx_id, tx_id; } tp20; -+ struct { canid_t rx_id, tx_id; } mcnet; -+ struct { canid_t rx_id, tx_id; } isotp; -+ struct { int sg_id, sg_type; } bap; -+ } can_addr; -+}; -+ -+typedef canid_t can_err_mask_t; -+ -+struct can_filter { -+ canid_t can_id; -+ canid_t can_mask; -+}; -+ -+#define CAN_INV_FILTER 0x20000000U /* to be set in can_filter.can_id */ -+ -+#endif /* CAN_H */ -diff -N -u -r a/include/linux/if_arp.h c/include/linux/if_arp.h ---- a/include/linux/if_arp.h 2007-02-04 19:44:54.000000000 +0100 -+++ c/include/linux/if_arp.h 2007-03-09 13:39:10.000000000 +0100 -@@ -52,6 +52,7 @@ - #define ARPHRD_ROSE 270 - #define ARPHRD_X25 271 /* CCITT X.25 */ - #define ARPHRD_HWX25 272 /* Boards with X.25 in firmware */ -+#define ARPHRD_CAN 280 /* Controller Area Network */ - #define ARPHRD_PPP 512 - #define ARPHRD_CISCO 513 /* Cisco HDLC */ - #define ARPHRD_HDLC ARPHRD_CISCO -diff -N -u -r a/include/linux/if_ether.h c/include/linux/if_ether.h ---- a/include/linux/if_ether.h 2007-02-04 19:44:54.000000000 +0100 -+++ c/include/linux/if_ether.h 2007-03-09 13:39:10.000000000 +0100 -@@ -88,6 +88,7 @@ - #define ETH_P_WAN_PPP 0x0007 /* Dummy type for WAN PPP frames*/ - #define ETH_P_PPP_MP 0x0008 /* Dummy type for PPP MP frames */ - #define ETH_P_LOCALTALK 0x0009 /* Localtalk pseudo type */ -+#define ETH_P_CAN 0x000C /* Controller Area Network */ - #define ETH_P_PPPTALK 0x0010 /* Dummy type for Atalk over PPP*/ - #define ETH_P_TR_802_2 0x0011 /* 802.2 frames */ - #define ETH_P_MOBITEX 0x0015 /* Mobitex (kaz@cafe.net) */ -diff -N -u -r a/include/linux/socket.h c/include/linux/socket.h ---- a/include/linux/socket.h 2007-03-09 09:52:17.000000000 +0100 -+++ c/include/linux/socket.h 2007-03-09 13:39:10.000000000 +0100 -@@ -185,6 +185,7 @@ - #define AF_PPPOX 24 /* PPPoX sockets */ - #define AF_WANPIPE 25 /* Wanpipe API Sockets */ - #define AF_LLC 26 /* Linux LLC */ -+#define AF_CAN 29 /* Controller Area Network */ - #define AF_TIPC 30 /* TIPC sockets */ - #define AF_BLUETOOTH 31 /* Bluetooth sockets */ - #define AF_IUCV 32 /* IUCV sockets */ -@@ -219,6 +220,7 @@ - #define PF_PPPOX AF_PPPOX - #define PF_WANPIPE AF_WANPIPE - #define PF_LLC AF_LLC -+#define PF_CAN AF_CAN - #define PF_TIPC AF_TIPC - #define PF_BLUETOOTH AF_BLUETOOTH - #define PF_IUCV AF_IUCV -diff -N -u -r a/include/linux/tty.h c/include/linux/tty.h ---- a/include/linux/tty.h 2007-03-09 09:52:17.000000000 +0100 -+++ c/include/linux/tty.h 2007-03-09 13:39:10.000000000 +0100 -@@ -24,7 +24,7 @@ - #define NR_PTYS CONFIG_LEGACY_PTY_COUNT /* Number of legacy ptys */ - #define NR_UNIX98_PTY_DEFAULT 4096 /* Default maximum for Unix98 ptys */ - #define NR_UNIX98_PTY_MAX (1 << MINORBITS) /* Absolute limit */ --#define NR_LDISCS 17 -+#define NR_LDISCS 18 - - /* line disciplines */ - #define N_TTY 0 -@@ -45,6 +45,7 @@ - #define N_SYNC_PPP 14 /* synchronous PPP */ - #define N_HCI 15 /* Bluetooth HCI UART */ - #define N_GIGASET_M101 16 /* Siemens Gigaset M101 serial DECT adapter */ -+#define N_SLCAN 17 /* Serial / USB serial CAN Adaptors */ - - /* - * This character is the same as _POSIX_VDISABLE: it cannot be used as -diff -N -u -r a/MAINTAINERS c/MAINTAINERS ---- a/MAINTAINERS 2007-03-09 09:51:50.000000000 +0100 -+++ c/MAINTAINERS 2007-03-09 13:39:10.000000000 +0100 -@@ -856,6 +856,15 @@ - T: git kernel.org:/pub/scm/linux/kernel/git/mchehab/v4l-dvb.git - S: Maintained - -+CAN NETWORK LAYER -+P: Urs Thuermann -+M: urs.thuermann@volkswagen.de -+P: Oliver Hartkopp -+M: oliver.hartkopp@volkswagen.de -+L: socketcan-core@lists.berlios.de -+W: http://developer.berlios.de/projects/socketcan/ -+S: Maintained -+ - CALGARY x86-64 IOMMU - P: Muli Ben-Yehuda - M: muli@il.ibm.com -diff -N -u -r a/net/can/af_can.c c/net/can/af_can.c ---- a/net/can/af_can.c 1970-01-01 01:00:00.000000000 +0100 -+++ c/net/can/af_can.c 2007-03-09 17:25:16.000000000 +0100 -@@ -0,0 +1,934 @@ -+/* -+ * af_can.c - Protocol family CAN core module -+ * (used by different CAN protocol modules) -+ * -+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research -+ * 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, the following disclaimer and -+ * the referenced file 'COPYING'. -+ * 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. Neither the name of Volkswagen nor the names of its contributors -+ * may be used to endorse or promote products derived from this software -+ * without specific prior written permission. -+ * -+ * Alternatively, provided that this notice is retained in full, this -+ * software may be distributed under the terms of the GNU General -+ * Public License ("GPL") version 2 as distributed in the 'COPYING' -+ * file from the main directory of the linux kernel source. -+ * -+ * The provided data structures and external interfaces from this code -+ * are not restricted to be used by modules with a GPL compatible license. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT -+ * OWNER 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. -+ * -+ * Send feedback to -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include "af_can.h" -+ -+ -+RCSID("$Id: af_can.c 177 2007-03-08 11:02:43Z hartkopp $"); -+ -+#define IDENT "af_can" -+static __initdata const char banner[] = KERN_INFO "CAN: Controller Area " -+ "Network PF_CAN core " VERSION "\n"; -+ -+MODULE_DESCRIPTION("Controller Area Network PF_CAN core"); -+MODULE_LICENSE("Dual BSD/GPL"); -+MODULE_AUTHOR("Urs Thuermann , " -+ "Oliver Hartkopp "); -+ -+int stats_timer = 1; /* default: on */ -+module_param(stats_timer, int, S_IRUGO); -+ -+#ifdef CONFIG_CAN_DEBUG_CORE -+static int debug = 0; -+module_param(debug, int, S_IRUGO); -+#define DBG(args...) (debug & 1 ? \ -+ (printk(KERN_DEBUG "CAN %s: ", __func__), \ -+ printk(args)) : 0) -+#define DBG_FRAME(args...) (debug & 2 ? can_debug_cframe(args) : 0) -+#define DBG_SKB(skb) (debug & 4 ? can_debug_skb(skb) : 0) -+#else -+#define DBG(args...) -+#define DBG_FRAME(args...) -+#define DBG_SKB(skb) -+#endif -+ -+static __init int can_init(void); -+static __exit void can_exit(void); -+ -+static int can_create(struct socket *sock, int protocol); -+static int can_notifier(struct notifier_block *nb, -+ unsigned long msg, void *data); -+static int can_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg); -+static int can_rcv(struct sk_buff *skb, struct net_device *dev, -+ struct packet_type *pt, struct net_device *orig_dev); -+static int can_rcv_filter(struct dev_rcv_lists *d, struct sk_buff *skb); -+static struct dev_rcv_lists *find_dev_rcv_lists(struct net_device *dev); -+static struct hlist_head *find_rcv_list(canid_t *can_id, canid_t *mask, -+ struct dev_rcv_lists *d); -+static void can_rcv_lists_delete(struct rcu_head *rp); -+static void can_rx_delete(struct rcu_head *rp); -+static void can_rx_delete_all(struct hlist_head *rl); -+ -+ -+struct notifier { -+ struct list_head list; -+ struct net_device *dev; -+ void (*func)(unsigned long msg, void *data); -+ void *data; -+}; -+ -+static LIST_HEAD(notifier_list); -+static rwlock_t notifier_lock = RW_LOCK_UNLOCKED; -+ -+HLIST_HEAD(rx_dev_list); -+static struct dev_rcv_lists rx_alldev_list; -+static spinlock_t rcv_lists_lock = SPIN_LOCK_UNLOCKED; -+ -+static struct kmem_cache *rcv_cache __read_mostly; -+ -+static struct packet_type can_packet = { -+ .type = __constant_htons(ETH_P_CAN), -+ .dev = NULL, -+ .func = can_rcv, -+}; -+ -+static struct net_proto_family can_family_ops = { -+ .family = PF_CAN, -+ .create = can_create, -+ .owner = THIS_MODULE, -+}; -+ -+/* notifier block for netdevice event */ -+static struct notifier_block can_netdev_notifier = { -+ .notifier_call = can_notifier, -+}; -+ -+/* table of registered CAN protocols */ -+static struct can_proto *proto_tab[CAN_NPROTO]; -+ -+extern struct timer_list stattimer; /* timer for statistics update */ -+extern struct s_stats stats; /* packet statistics */ -+extern struct s_pstats pstats; /* receive list statistics */ -+ -+module_init(can_init); -+module_exit(can_exit); -+ -+/**************************************************/ -+/* af_can module init/exit functions */ -+/**************************************************/ -+ -+static __init int can_init(void) -+{ -+ printk(banner); -+ -+ rcv_cache = kmem_cache_create("can_receiver", sizeof(struct receiver), -+ 0, 0, NULL, NULL); -+ if (!rcv_cache) -+ return -ENOMEM; -+ -+ /* Insert struct dev_rcv_lists for reception on all devices. -+ This struct is zero initialized which is correct for the -+ embedded hlist heads, the dev pointer, and the entries counter. -+ */ -+ -+ spin_lock_bh(&rcv_lists_lock); -+ hlist_add_head_rcu(&rx_alldev_list.list, &rx_dev_list); -+ spin_unlock_bh(&rcv_lists_lock); -+ -+ if (stats_timer) { -+ /* statistics init */ -+ init_timer(&stattimer); -+ } -+ -+ /* procfs init */ -+ can_init_proc(); -+ -+ /* protocol register */ -+ sock_register(&can_family_ops); -+ register_netdevice_notifier(&can_netdev_notifier); -+ dev_add_pack(&can_packet); -+ -+ return 0; -+} -+ -+static __exit void can_exit(void) -+{ -+ struct dev_rcv_lists *d; -+ struct hlist_node *n, *next; -+ -+ if (stats_timer) { -+ /* stop statistics timer */ -+ del_timer(&stattimer); -+ } -+ -+ /* procfs remove */ -+ can_remove_proc(); -+ -+ /* protocol unregister */ -+ dev_remove_pack(&can_packet); -+ unregister_netdevice_notifier(&can_netdev_notifier); -+ sock_unregister(PF_CAN); -+ -+ /* remove rx_dev_list */ -+ spin_lock_bh(&rcv_lists_lock); -+ hlist_del(&rx_alldev_list.list); -+ hlist_for_each_entry_safe(d, n, next, &rx_dev_list, list) { -+ hlist_del(&d->list); -+ kfree(d); -+ } -+ spin_unlock_bh(&rcv_lists_lock); -+ -+ kmem_cache_destroy(rcv_cache); -+} -+ -+/**************************************************/ -+/* af_can protocol functions */ -+/**************************************************/ -+ -+void can_proto_register(struct can_proto *cp) -+{ -+ int proto = cp->protocol; -+ if (proto < 0 || proto >= CAN_NPROTO) { -+ printk(KERN_ERR "CAN: protocol number %d out " -+ "of range\n", proto); -+ return; -+ } -+ if (proto_tab[proto]) { -+ printk(KERN_ERR "CAN: protocol %d already " -+ "registered\n", proto); -+ return; -+ } -+ -+ if (proto_register(cp->prot, 0) != 0) { -+ return; -+ } -+ proto_tab[proto] = cp; -+ -+ /* use generic ioctl function if the module doesn't bring its own */ -+ if (!cp->ops->ioctl) -+ cp->ops->ioctl = can_ioctl; -+} -+ -+void can_proto_unregister(struct can_proto *cp) -+{ -+ int proto = cp->protocol; -+ if (!proto_tab[proto]) { -+ printk(KERN_ERR "CAN: protocol %d is not registered\n", proto); -+ return; -+ } -+ proto_unregister(cp->prot); -+ proto_tab[proto] = NULL; -+} -+ -+void can_dev_register(struct net_device *dev, -+ void (*func)(unsigned long msg, void *), void *data) -+{ -+ struct notifier *n; -+ -+ DBG("called for %s\n", dev->name); -+ -+ if (!(n = kmalloc(sizeof(*n), GFP_KERNEL))) -+ return; -+ -+ n->dev = dev; -+ n->func = func; -+ n->data = data; -+ -+ write_lock(¬ifier_lock); -+ list_add(&n->list, ¬ifier_list); -+ write_unlock(¬ifier_lock); -+} -+ -+void can_dev_unregister(struct net_device *dev, -+ void (*func)(unsigned long msg, void *), void *data) -+{ -+ struct notifier *n, *next; -+ -+ DBG("called for %s\n", dev->name); -+ -+ write_lock(¬ifier_lock); -+ list_for_each_entry_safe(n, next, ¬ifier_list, list) { -+ if (n->dev == dev && n->func == func && n->data == data) { -+ list_del(&n->list); -+ kfree(n); -+ break; -+ } -+ } -+ write_unlock(¬ifier_lock); -+} -+ -+/**************************************************/ -+/* af_can socket functions */ -+/**************************************************/ -+ -+static void can_sock_destruct(struct sock *sk) -+{ -+ DBG("called for sock %p\n", sk); -+ -+ skb_queue_purge(&sk->sk_receive_queue); -+ if (sk->sk_protinfo) -+ kfree(sk->sk_protinfo); -+} -+ -+static int can_create(struct socket *sock, int protocol) -+{ -+ struct sock *sk; -+ struct can_proto *cp; -+ int ret; -+ -+ DBG("socket %p, type %d, proto %d\n", sock, sock->type, protocol); -+ -+ sock->state = SS_UNCONNECTED; -+ -+ if (protocol < 0 || protocol >= CAN_NPROTO) -+ return -EINVAL; -+ -+ DBG("looking up proto %d in proto_tab[]\n", protocol); -+ -+ /* try to load protocol module, when CONFIG_KMOD is defined */ -+ if (!proto_tab[protocol]) { -+ char module_name[30]; -+ sprintf(module_name, "can-proto-%d", protocol); -+ if (request_module(module_name) == -ENOSYS) -+ printk(KERN_INFO "CAN: request_module(%s) not" -+ " implemented.\n", module_name); -+ } -+ -+ /* check for success and correct type */ -+ if (!(cp = proto_tab[protocol]) || cp->type != sock->type) -+ return -EPROTONOSUPPORT; -+ -+ if (cp->capability >= 0 && !capable(cp->capability)) -+ return -EPERM; -+ -+ sock->ops = cp->ops; -+ -+ sk = sk_alloc(PF_CAN, GFP_KERNEL, cp->prot, 1); -+ if (!sk) -+ goto oom; -+ sock_init_data(sock, sk); -+ sk->sk_destruct = can_sock_destruct; -+ -+ DBG("created sock: %p\n", sk); -+ -+ ret = 0; -+ if (sk->sk_prot->init) -+ ret = sk->sk_prot->init(sk); -+ if (ret) { -+ /* we must release sk */ -+ sock_orphan(sk); -+ sock_put(sk); -+ return ret; -+ } -+ -+ return 0; -+ -+ oom: -+ return -ENOMEM; -+} -+ -+static int can_notifier(struct notifier_block *nb, -+ unsigned long msg, void *data) -+{ -+ struct net_device *dev = (struct net_device *)data; -+ struct notifier *n; -+ -+ DBG("called for %s, msg = %lu\n", dev->name, msg); -+ -+ if (dev->type != ARPHRD_CAN) -+ return NOTIFY_DONE; -+ -+ switch (msg) { -+ struct dev_rcv_lists *d; -+ int i; -+ -+ case NETDEV_REGISTER: -+ -+ /* create new dev_rcv_lists for this device */ -+ -+ DBG("creating new dev_rcv_lists for %s\n", dev->name); -+ if (!(d = kmalloc(sizeof(*d), -+ in_interrupt() ? GFP_ATOMIC : GFP_KERNEL))) { -+ printk(KERN_ERR "CAN: allocation of receive " -+ "list failed\n"); -+ return NOTIFY_DONE; -+ } -+ /* N.B. zeroing the struct is the correct initialization -+ for the embedded hlist_head structs. -+ Another list type, e.g. list_head, would require -+ explicit initialization. */ -+ memset(d, 0, sizeof(*d)); -+ d->dev = dev; -+ -+ spin_lock_bh(&rcv_lists_lock); -+ hlist_add_head_rcu(&d->list, &rx_dev_list); -+ spin_unlock_bh(&rcv_lists_lock); -+ -+ break; -+ -+ case NETDEV_UNREGISTER: -+ spin_lock_bh(&rcv_lists_lock); -+ -+ if (!(d = find_dev_rcv_lists(dev))) { -+ printk(KERN_ERR "CAN: notifier: receive list not " -+ "found for dev %s\n", dev->name); -+ goto unreg_out; -+ } -+ -+ hlist_del_rcu(&d->list); -+ -+ /* remove all receivers hooked at this netdevice */ -+ can_rx_delete_all(&d->rx_err); -+ can_rx_delete_all(&d->rx_all); -+ can_rx_delete_all(&d->rx_fil); -+ can_rx_delete_all(&d->rx_inv); -+ can_rx_delete_all(&d->rx_eff); -+ for (i = 0; i < 2048; i++) -+ can_rx_delete_all(&d->rx_sff[i]); -+ -+ unreg_out: -+ spin_unlock_bh(&rcv_lists_lock); -+ -+ if (d) -+ call_rcu(&d->rcu, can_rcv_lists_delete); -+ -+ break; -+ } -+ -+ read_lock(¬ifier_lock); -+ list_for_each_entry(n, ¬ifier_list, list) { -+ if (n->dev == dev) -+ n->func(msg, n->data); -+ } -+ read_unlock(¬ifier_lock); -+ -+ return NOTIFY_DONE; -+} -+ -+static int can_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) -+{ -+ struct sock *sk = sock->sk; -+ -+ switch (cmd) { -+ case SIOCGSTAMP: -+ return sock_get_timestamp(sk, (struct timeval __user *)arg); -+ default: -+ return -ENOIOCTLCMD; -+ } -+ return 0; -+} -+ -+/**************************************************/ -+/* af_can tx path */ -+/**************************************************/ -+ -+int can_send(struct sk_buff *skb, int loop) -+{ -+ int err; -+ -+ if (loop) { /* local loopback (default) */ -+ *(struct sock **)skb->cb = skb->sk; /* tx sock reference */ -+ -+ /* interface not capabable to do the loopback itself? */ -+ if (!(skb->dev->flags & IFF_LOOPBACK)) { -+ struct sk_buff *newskb = skb_clone(skb, GFP_ATOMIC); -+ newskb->protocol = htons(ETH_P_CAN); -+ newskb->ip_summed = CHECKSUM_UNNECESSARY; -+ netif_rx(newskb); /* perform local loopback here */ -+ } -+ } else -+ *(struct sock **)skb->cb = NULL; /* no loopback required */ -+ -+ if (!(skb->dev->flags & IFF_UP)) -+ err = -ENETDOWN; -+ else if ((err = dev_queue_xmit(skb)) > 0) /* send to netdevice */ -+ err = net_xmit_errno(err); -+ -+ /* update statistics */ -+ stats.tx_frames++; -+ stats.tx_frames_delta++; -+ -+ return err; -+} -+ -+/**************************************************/ -+/* af_can rx path */ -+/**************************************************/ -+ -+int can_rx_register(struct net_device *dev, canid_t can_id, canid_t mask, -+ void (*func)(struct sk_buff *, void *), void *data, -+ char *ident) -+{ -+ struct receiver *r; -+ struct hlist_head *rl; -+ struct dev_rcv_lists *d; -+ int ret = 0; -+ -+ /* insert new receiver (dev,canid,mask) -> (func,data) */ -+ -+ DBG("dev %p, id %03X, mask %03X, callback %p, data %p, ident %s\n", -+ dev, can_id, mask, func, data, ident); -+ -+ if (!(r = kmem_cache_alloc(rcv_cache, GFP_KERNEL))) { -+ ret = -ENOMEM; -+ goto out; -+ } -+ -+ spin_lock_bh(&rcv_lists_lock); -+ -+ if (!(d = find_dev_rcv_lists(dev))) { -+ DBG("receive list not found for dev %s, id %03X, mask %03X\n", -+ DNAME(dev), can_id, mask); -+ kmem_cache_free(rcv_cache, r); -+ ret = -ENODEV; -+ goto out_unlock; -+ } -+ -+ rl = find_rcv_list(&can_id, &mask, d); -+ -+ r->can_id = can_id; -+ r->mask = mask; -+ r->matches = 0; -+ r->func = func; -+ r->data = data; -+ r->ident = ident; -+ -+ hlist_add_head_rcu(&r->list, rl); -+ d->entries++; -+ -+ pstats.rcv_entries++; -+ if (pstats.rcv_entries_max < pstats.rcv_entries) -+ pstats.rcv_entries_max = pstats.rcv_entries; -+ -+ out_unlock: -+ spin_unlock_bh(&rcv_lists_lock); -+ out: -+ return ret; -+} -+ -+static void can_rcv_lists_delete(struct rcu_head *rp) -+{ -+ struct dev_rcv_lists *d = container_of(rp, struct dev_rcv_lists, rcu); -+ kfree(d); -+} -+ -+static void can_rx_delete(struct rcu_head *rp) -+{ -+ struct receiver *r = container_of(rp, struct receiver, rcu); -+ kmem_cache_free(rcv_cache, r); -+} -+ -+static void can_rx_delete_all(struct hlist_head *rl) -+{ -+ struct receiver *r; -+ struct hlist_node *n; -+ -+ hlist_for_each_entry_rcu(r, n, rl, list) { -+ hlist_del_rcu(&r->list); -+ call_rcu(&r->rcu, can_rx_delete); -+ } -+} -+ -+int can_rx_unregister(struct net_device *dev, canid_t can_id, canid_t mask, -+ void (*func)(struct sk_buff *, void *), void *data) -+{ -+ struct receiver *r; -+ struct hlist_head *rl; -+ struct hlist_node *next; -+ struct dev_rcv_lists *d; -+ int ret = 0; -+ -+ DBG("dev %p, id %03X, mask %03X, callback %p, data %p\n", -+ dev, can_id, mask, func, data); -+ -+ r = NULL; -+ -+ spin_lock_bh(&rcv_lists_lock); -+ -+ if (!(d = find_dev_rcv_lists(dev))) { -+ DBG("receive list not found for dev %s, id %03X, mask %03X\n", -+ DNAME(dev), can_id, mask); -+ ret = -ENODEV; -+ goto out; -+ } -+ -+ rl = find_rcv_list(&can_id, &mask, d); -+ -+ /* Search the receiver list for the item to delete. This should -+ * exist, since no receiver may be unregistered that hasn't -+ * been registered before. -+ */ -+ -+ hlist_for_each_entry(r, next, rl, list) { -+ if (r->can_id == can_id && r->mask == mask -+ && r->func == func && r->data == data) -+ break; -+ } -+ -+ /* Check for bug in CAN protocol implementations: -+ * If no matching list item was found, the list cursor variable next -+ * will be NULL, while r will point to the last item of the list. -+ */ -+ -+ if (!next) { -+ DBG("receive list entry not found for " -+ "dev %s, id %03X, mask %03X\n", DNAME(dev), can_id, mask); -+ ret = -EINVAL; -+ r = NULL; -+ goto out; -+ } -+ -+ hlist_del_rcu(&r->list); -+ d->entries--; -+ -+ if (pstats.rcv_entries > 0) -+ pstats.rcv_entries--; -+ -+ out: -+ spin_unlock_bh(&rcv_lists_lock); -+ -+ /* schedule the receiver item for deletion */ -+ if (r) -+ call_rcu(&r->rcu, can_rx_delete); -+ -+ return ret; -+} -+ -+static int can_rcv(struct sk_buff *skb, struct net_device *dev, -+ struct packet_type *pt, struct net_device *orig_dev) -+{ -+ struct dev_rcv_lists *d; -+ int matches; -+ -+ DBG("received skbuff on device %s, ptype %04x\n", -+ dev->name, ntohs(pt->type)); -+ DBG_SKB(skb); -+ DBG_FRAME("af_can: can_rcv: received CAN frame", -+ (struct can_frame *)skb->data); -+ -+ /* update statistics */ -+ stats.rx_frames++; -+ stats.rx_frames_delta++; -+ -+ rcu_read_lock(); -+ -+ /* deliver the packet to sockets listening on all devices */ -+ matches = can_rcv_filter(&rx_alldev_list, skb); -+ -+ /* find receive list for this device */ -+ if ((d = find_dev_rcv_lists(dev))) -+ matches += can_rcv_filter(d, skb); -+ -+ rcu_read_unlock(); -+ -+ /* free the skbuff allocated by the netdevice driver */ -+ DBG("freeing skbuff %p\n", skb); -+ kfree_skb(skb); -+ -+ if (matches > 0) { -+ stats.matches++; -+ stats.matches_delta++; -+ } -+ -+ return 0; -+} -+ -+ -+static inline void deliver(struct sk_buff *skb, struct receiver *r) -+{ -+ struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC); -+ DBG("skbuff %p cloned to %p\n", skb, clone); -+ if (clone) { -+ r->func(clone, r->data); -+ r->matches++; /* update specific statistics */ -+ } -+} -+ -+static int can_rcv_filter(struct dev_rcv_lists *d, struct sk_buff *skb) -+{ -+ struct receiver *r; -+ struct hlist_node *n; -+ int matches = 0; -+ struct can_frame *cf = (struct can_frame*)skb->data; -+ canid_t can_id = cf->can_id; -+ -+ if (d->entries == 0) -+ return 0; -+ -+ if (can_id & CAN_ERR_FLAG) { -+ /* check for error frame entries only */ -+ hlist_for_each_entry_rcu(r, n, &d->rx_err, list) { -+ if (can_id & r->mask) { -+ DBG("match on rx_err skbuff %p\n", skb); -+ deliver(skb, r); -+ matches++; -+ } -+ } -+ goto out; -+ } -+ -+ /* check for unfiltered entries */ -+ hlist_for_each_entry_rcu(r, n, &d->rx_all, list) { -+ DBG("match on rx_all skbuff %p\n", skb); -+ deliver(skb, r); -+ matches++; -+ } -+ -+ /* check for can_id/mask entries */ -+ hlist_for_each_entry_rcu(r, n, &d->rx_fil, list) { -+ if ((can_id & r->mask) == r->can_id) { -+ DBG("match on rx_fil skbuff %p\n", skb); -+ deliver(skb, r); -+ matches++; -+ } -+ } -+ -+ /* check for inverted can_id/mask entries */ -+ hlist_for_each_entry_rcu(r, n, &d->rx_inv, list) { -+ if ((can_id & r->mask) != r->can_id) { -+ DBG("match on rx_inv skbuff %p\n", skb); -+ deliver(skb, r); -+ matches++; -+ } -+ } -+ -+ /* check CAN_ID specific entries */ -+ if (can_id & CAN_EFF_FLAG) { -+ hlist_for_each_entry_rcu(r, n, &d->rx_eff, list) { -+ if (r->can_id == can_id) { -+ DBG("match on rx_eff skbuff %p\n", skb); -+ deliver(skb, r); -+ matches++; -+ } -+ } -+ } else { -+ can_id &= CAN_SFF_MASK; -+ hlist_for_each_entry_rcu(r, n, &d->rx_sff[can_id], list) { -+ DBG("match on rx_sff skbuff %p\n", skb); -+ deliver(skb, r); -+ matches++; -+ } -+ } -+ -+ out: -+ return matches; -+} -+ -+static struct dev_rcv_lists *find_dev_rcv_lists(struct net_device *dev) -+{ -+ struct dev_rcv_lists *d; -+ struct hlist_node *n; -+ -+ /* find receive list for this device */ -+ -+ /* The hlist_for_each_entry*() macros curse through the list -+ * using the pointer variable n and set d to the containing -+ * struct in each list iteration. Therefore, after list -+ * iteration, d is unmodified when the list is empty, and it -+ * points to last list element, when the list is non-empty -+ * but no match in the loop body is found. I.e. d is *not* -+ * NULL when no match is found. We can, however, use the -+ * cursor variable n to decide if a match was found. -+ */ -+ -+ hlist_for_each_entry(d, n, &rx_dev_list, list) -+ if (d->dev == dev) -+ break; -+ -+ return n ? d : NULL; -+} -+ -+static struct hlist_head *find_rcv_list(canid_t *can_id, canid_t *mask, -+ struct dev_rcv_lists *d) -+{ -+ canid_t inv = *can_id & CAN_INV_FILTER; /* save flag before masking */ -+ -+ if (*mask & CAN_ERR_FLAG) { /* filter error frames */ -+ *mask &= CAN_ERR_MASK; /* clear CAN_ERR_FLAG in list entry */ -+ return &d->rx_err; -+ } -+ -+ /* ensure valid values in can_mask */ -+ if (*mask & CAN_EFF_FLAG) -+ *mask &= (CAN_EFF_MASK | CAN_EFF_FLAG | CAN_RTR_FLAG); -+ else -+ *mask &= (CAN_SFF_MASK | CAN_RTR_FLAG); -+ -+ *can_id &= *mask; /* reduce condition testing at receive time */ -+ -+ if (inv) /* inverse can_id/can_mask filter */ -+ return &d->rx_inv; -+ -+ if (!(*mask)) /* mask == 0 => no condition testing at receive time */ -+ return &d->rx_all; -+ -+ /* use extra filterset for the subscription of exactly *one* can_id */ -+ if (*can_id & CAN_EFF_FLAG) { -+ if (*mask == (CAN_EFF_MASK | CAN_EFF_FLAG)) -+ return &d->rx_eff; /* use-case for hash-table here? */ -+ } else { -+ if (*mask == CAN_SFF_MASK) -+ return &d->rx_sff[*can_id]; -+ } -+ -+ return &d->rx_fil; /* default: filter via can_id/can_mask */ -+} -+ -+/**************************************************/ -+/* af_can utility stuff */ -+/**************************************************/ -+ -+unsigned long timeval2jiffies(struct timeval *tv, int round_up) -+{ -+ unsigned long jif; -+ unsigned long sec = tv->tv_sec; -+ unsigned long usec = tv->tv_usec; -+ -+ if (sec > ULONG_MAX / HZ) /* check for overflow */ -+ return ULONG_MAX; -+ -+ if (round_up) /* any usec below one HZ? */ -+ usec += 1000000 / HZ - 1; /* pump it up */ -+ -+ jif = usec / (1000000 / HZ); -+ -+ if (sec * HZ > ULONG_MAX - jif) /* check for overflow */ -+ return ULONG_MAX; -+ else -+ return jif + sec * HZ; -+} -+ -+ -+/**************************************************/ -+/* af_can debugging stuff */ -+/**************************************************/ -+ -+#ifdef CONFIG_CAN_DEBUG_CORE -+ -+void can_debug_cframe(const char *msg, struct can_frame *cf, ...) -+{ -+ va_list ap; -+ int len; -+ int dlc, i; -+ char buf[1024]; -+ -+ len = sprintf(buf, KERN_DEBUG); -+ va_start(ap, cf); -+ len += snprintf(buf + len, sizeof(buf) - 64, msg, ap); -+ buf[len++] = ':'; -+ buf[len++] = ' '; -+ va_end(ap); -+ -+ if ((dlc = cf->can_dlc) > 8) -+ dlc = 8; -+ -+ if (cf->can_id & CAN_EFF_FLAG) -+ len += sprintf(buf + len, "<%08X> [%X] ", -+ cf->can_id & CAN_EFF_MASK, dlc); -+ else -+ len += sprintf(buf + len, "<%03X> [%X] ", -+ cf->can_id & CAN_SFF_MASK, dlc); -+ -+ for (i = 0; i < dlc; i++) -+ len += sprintf(buf + len, "%02X ", cf->data[i]); -+ -+ if (cf->can_id & CAN_RTR_FLAG) -+ len += sprintf(buf + len, "(RTR)"); -+ -+ buf[len++] = '\n'; -+ buf[len] = '\0'; -+ printk(buf); -+} -+ -+void can_debug_skb(struct sk_buff *skb) -+{ -+ int len, nbytes, i; -+ char buf[1024]; -+ -+ len = sprintf(buf, -+ KERN_DEBUG " skbuff at %p, dev: %d, proto: %04x\n" -+ KERN_DEBUG " users: %d, dataref: %d, nr_frags: %d, " -+ "h,d,t,e,l: %p %+d %+d %+d, %d", -+ skb, skb->dev ? skb->dev->ifindex : -1, -+ ntohs(skb->protocol), -+ atomic_read(&skb->users), -+ atomic_read(&(skb_shinfo(skb)->dataref)), -+ skb_shinfo(skb)->nr_frags, -+ skb->head, skb->data - skb->head, -+ skb->tail - skb->head, skb->end - skb->head, skb->len); -+ nbytes = skb->end - skb->head; -+ for (i = 0; i < nbytes; i++) { -+ if (i % 16 == 0) -+ len += sprintf(buf + len, "\n" KERN_DEBUG " "); -+ if (len < sizeof(buf) - 16) { -+ len += sprintf(buf + len, " %02x", skb->head[i]); -+ } else { -+ len += sprintf(buf + len, "..."); -+ break; -+ } -+ } -+ buf[len++] = '\n'; -+ buf[len] = '\0'; -+ printk(buf); -+} -+ -+EXPORT_SYMBOL(can_debug_cframe); -+EXPORT_SYMBOL(can_debug_skb); -+ -+#endif -+ -+/**************************************************/ -+/* Exported symbols */ -+/**************************************************/ -+EXPORT_SYMBOL(can_proto_register); -+EXPORT_SYMBOL(can_proto_unregister); -+EXPORT_SYMBOL(can_rx_register); -+EXPORT_SYMBOL(can_rx_unregister); -+EXPORT_SYMBOL(can_dev_register); -+EXPORT_SYMBOL(can_dev_unregister); -+EXPORT_SYMBOL(can_send); -+EXPORT_SYMBOL(timeval2jiffies); -diff -N -u -r a/net/can/af_can.h c/net/can/af_can.h ---- a/net/can/af_can.h 1970-01-01 01:00:00.000000000 +0100 -+++ c/net/can/af_can.h 2007-03-09 13:47:12.000000000 +0100 -@@ -0,0 +1,119 @@ -+/* -+ * $Id: af_can.h 177 2007-03-08 11:02:43Z hartkopp $ -+ * -+ * Copyright (c) 2002-2005 Volkswagen Group Electronic Research -+ * 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, the following disclaimer and -+ * the referenced file 'COPYING'. -+ * 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. Neither the name of Volkswagen nor the names of its contributors -+ * may be used to endorse or promote products derived from this software -+ * without specific prior written permission. -+ * -+ * Alternatively, provided that this notice is retained in full, this -+ * software may be distributed under the terms of the GNU General -+ * Public License ("GPL") version 2 as distributed in the 'COPYING' -+ * file from the main directory of the linux kernel source. -+ * -+ * The provided data structures and external interfaces from this code -+ * are not restricted to be used by modules with a GPL compatible license. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT -+ * OWNER 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. -+ * -+ * Send feedback to -+ * -+ */ -+ -+#ifndef AF_CAN_H -+#define AF_CAN_H -+ -+#include -+#include -+#include -+#include -+ -+#include -+ -+/* af_can rx dispatcher structures */ -+ -+struct receiver { -+ struct hlist_node list; -+ struct rcu_head rcu; -+ canid_t can_id; -+ canid_t mask; -+ unsigned long matches; -+ void (*func)(struct sk_buff *, void *); -+ void *data; -+ char *ident; -+}; -+ -+struct dev_rcv_lists { -+ struct hlist_node list; -+ struct rcu_head rcu; -+ struct net_device *dev; -+ struct hlist_head rx_err; -+ struct hlist_head rx_all; -+ struct hlist_head rx_fil; -+ struct hlist_head rx_inv; -+ struct hlist_head rx_sff[0x800]; -+ struct hlist_head rx_eff; -+ int entries; -+}; -+ -+/* statistic structures */ -+ -+struct s_stats { -+ unsigned long jiffies_init; -+ -+ unsigned long rx_frames; -+ unsigned long tx_frames; -+ unsigned long matches; -+ -+ unsigned long total_rx_rate; -+ unsigned long total_tx_rate; -+ unsigned long total_rx_match_ratio; -+ -+ unsigned long current_rx_rate; -+ unsigned long current_tx_rate; -+ unsigned long current_rx_match_ratio; -+ -+ unsigned long max_rx_rate; -+ unsigned long max_tx_rate; -+ unsigned long max_rx_match_ratio; -+ -+ unsigned long rx_frames_delta; -+ unsigned long tx_frames_delta; -+ unsigned long matches_delta; -+}; /* can be reset e.g. by can_init_stats() */ -+ -+struct s_pstats { -+ unsigned long stats_reset; -+ unsigned long rcv_entries; -+ unsigned long rcv_entries_max; -+}; /* persistent statistics */ -+ -+ -+/* function prototypes for the CAN networklayer procfs (proc.c) */ -+ -+void can_init_proc(void); -+void can_remove_proc(void); -+ -+#endif /* AF_CAN_H */ -diff -N -u -r a/net/can/bcm.c c/net/can/bcm.c ---- a/net/can/bcm.c 1970-01-01 01:00:00.000000000 +0100 -+++ c/net/can/bcm.c 2007-03-09 17:26:51.000000000 +0100 -@@ -0,0 +1,1600 @@ -+/* -+ * bcm.c - Broadcast Manager to filter/send (cyclic) CAN content -+ * -+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research -+ * 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, the following disclaimer and -+ * the referenced file 'COPYING'. -+ * 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. Neither the name of Volkswagen nor the names of its contributors -+ * may be used to endorse or promote products derived from this software -+ * without specific prior written permission. -+ * -+ * Alternatively, provided that this notice is retained in full, this -+ * software may be distributed under the terms of the GNU General -+ * Public License ("GPL") version 2 as distributed in the 'COPYING' -+ * file from the main directory of the linux kernel source. -+ * -+ * The provided data structures and external interfaces from this code -+ * are not restricted to be used by modules with a GPL compatible license. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT -+ * OWNER 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. -+ * -+ * Send feedback to -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+RCSID("$Id: bcm.c 179 2007-03-09 07:36:49Z hartkopp $"); -+ -+#ifdef CONFIG_CAN_DEBUG_CORE -+static int debug = 0; -+module_param(debug, int, S_IRUGO); -+#define DBG(args...) (debug & 1 ? \ -+ (printk(KERN_DEBUG "BCM %s: ", __func__), \ -+ printk(args)) : 0) -+#define DBG_FRAME(args...) (debug & 2 ? can_debug_cframe(args) : 0) -+#define DBG_SKB(skb) (debug & 4 ? can_debug_skb(skb) : 0) -+#else -+#define DBG(args...) -+#define DBG_FRAME(args...) -+#define DBG_SKB(skb) -+#endif -+ -+/* use of last_frames[index].can_dlc */ -+#define RX_RECV 0x40 /* received data for this element */ -+#define RX_THR 0x80 /* element not been sent due to throttle feature */ -+#define BCM_CAN_DLC_MASK 0x0F /* clean private flags in can_dlc by masking */ -+ -+/* get best masking value for can_rx_register() for a given single can_id */ -+#define REGMASK(id) ((id & CAN_RTR_FLAG) | ((id & CAN_EFF_FLAG) ? \ -+ (CAN_EFF_MASK | CAN_EFF_FLAG) : CAN_SFF_MASK)) -+ -+#define IDENT "bcm" -+static __initdata const char banner[] = KERN_INFO -+ "CAN: broadcast manager (bcm) socket protocol " VERSION "\n"; -+ -+MODULE_DESCRIPTION("PF_CAN bcm sockets"); -+MODULE_LICENSE("Dual BSD/GPL"); -+MODULE_AUTHOR("Oliver Hartkopp "); -+ -+#define GET_U64(p) (*(u64*)(p)->data) /* easy access */ -+ -+struct bcm_op { -+ struct list_head list; -+ int ifindex; -+ canid_t can_id; -+ int flags; -+ unsigned long j_ival1, j_ival2, j_lastmsg; -+ unsigned long frames_abs, frames_filtered; -+ struct timer_list timer, thrtimer; -+ struct timeval ival1, ival2; -+ struct timeval rx_stamp; -+ int rx_ifindex; -+ int count; -+ int nframes; -+ int currframe; -+ struct can_frame *frames; -+ struct can_frame *last_frames; -+ struct sock *sk; -+}; -+ -+struct bcm_opt { -+ int bound; -+ int ifindex; -+ struct list_head rx_ops; -+ struct list_head tx_ops; -+ unsigned long dropped_usr_msgs; -+ struct proc_dir_entry *bcm_proc_read; -+ char procname [9]; /* pointer printed in ASCII with \0 */ -+}; -+ -+static struct proc_dir_entry *proc_dir = NULL; -+ -+static int bcm_init(struct sock *sk); -+static void bcm_notifier(unsigned long msg, void *data); -+static int bcm_release(struct socket *sock); -+static int bcm_connect(struct socket *sock, struct sockaddr *uaddr, int len, -+ int flags); -+static int bcm_sendmsg(struct kiocb *iocb, struct socket *sock, -+ struct msghdr *msg, size_t size); -+static int bcm_recvmsg(struct kiocb *iocb, struct socket *sock, -+ struct msghdr *msg, size_t size, int flags); -+static unsigned int bcm_poll(struct file *file, struct socket *sock, -+ poll_table *wait); -+ -+static int bcm_read_proc(char *page, char **start, off_t off, -+ int count, int *eof, void *data); -+ -+static void bcm_tx_timeout_handler(unsigned long data); -+static int bcm_tx_send(struct msghdr *msg, int ifindex, struct sock *sk); -+static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg, -+ int ifindex, struct sock *sk); -+static void bcm_can_tx(struct bcm_op *op); -+ -+static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg, -+ int ifindex, struct sock *sk); -+static void bcm_rx_handler(struct sk_buff *skb, void *op); -+static void bcm_rx_timeout_handler(unsigned long data); -+static void bcm_rx_thr_handler(unsigned long data); -+static void bcm_rx_cmp_to_index(struct bcm_op *op, int index, -+ struct can_frame *rxdata); -+static void bcm_rx_changed(struct bcm_op *op, struct can_frame *data); -+static void bcm_rx_starttimer(struct bcm_op *op); -+static void bcm_rx_update_and_send(struct bcm_op *op, -+ struct can_frame *lastdata, -+ struct can_frame *rxdata); -+static void bcm_send_to_user(struct bcm_op *op, struct bcm_msg_head *head, -+ struct can_frame *frames, struct timeval *tv); -+ -+static int bcm_delete_tx_op(struct list_head *ops, canid_t can_id, -+ int ifindex); -+static int bcm_delete_rx_op(struct list_head *ops, canid_t can_id, -+ int ifindex); -+static void bcm_remove_op(struct bcm_op *op); -+static int bcm_read_op(struct list_head *ops, struct bcm_msg_head *msg_head, -+ int ifindex); -+static struct bcm_op *bcm_find_op(struct list_head *ops, canid_t can_id, -+ int ifindex); -+ -+static struct proto_ops bcm_ops = { -+ .family = PF_CAN, -+ .release = bcm_release, -+ .bind = sock_no_bind, -+ .connect = bcm_connect, -+ .socketpair = sock_no_socketpair, -+ .accept = sock_no_accept, -+ .getname = sock_no_getname, -+ .poll = bcm_poll, -+ .ioctl = NULL, /* use can_ioctl() from af_can.c */ -+ .listen = sock_no_listen, -+ .shutdown = sock_no_shutdown, -+ .setsockopt = sock_no_setsockopt, -+ .getsockopt = sock_no_getsockopt, -+ .sendmsg = bcm_sendmsg, -+ .recvmsg = bcm_recvmsg, -+ .mmap = sock_no_mmap, -+ .sendpage = sock_no_sendpage, -+}; -+ -+#ifdef CONFIG_CAN_BCM_USER -+#define BCM_CAP (-1) -+#else -+#define BCM_CAP CAP_NET_RAW -+#endif -+ -+struct bcm_sock { -+ struct sock sk; -+ struct bcm_opt opt; -+}; -+ -+#define bcm_sk(sk) (&((struct bcm_sock *)(sk))->opt) -+ -+static struct proto bcm_proto = { -+ .name = "CAN_BCM", -+ .owner = THIS_MODULE, -+ .obj_size = sizeof(struct bcm_sock), -+ .init = bcm_init, -+}; -+ -+static struct can_proto bcm_can_proto = { -+ .type = SOCK_DGRAM, -+ .protocol = CAN_BCM, -+ .capability = BCM_CAP, -+ .ops = &bcm_ops, -+ .prot = &bcm_proto, -+}; -+ -+#define CFSIZ sizeof(struct can_frame) -+#define OPSIZ sizeof(struct bcm_op) -+#define MHSIZ sizeof(struct bcm_msg_head) -+ -+static int __init bcm_module_init(void) -+{ -+ printk(banner); -+ -+ can_proto_register(&bcm_can_proto); -+ -+ /* create /proc/net/can/bcm directory */ -+ proc_dir = proc_mkdir(CAN_PROC_DIR"/"IDENT, NULL); -+ -+ if (proc_dir) -+ proc_dir->owner = THIS_MODULE; -+ -+ return 0; -+} -+ -+static void __exit bcm_module_exit(void) -+{ -+ can_proto_unregister(&bcm_can_proto); -+ -+ if (proc_dir) -+ remove_proc_entry(CAN_PROC_DIR"/"IDENT, NULL); -+ -+} -+ -+/**************************************************/ -+/* initial settings at socket creation time */ -+/**************************************************/ -+ -+static int bcm_init(struct sock *sk) -+{ -+ struct bcm_opt *bo = bcm_sk(sk); -+ -+ bo->bound = 0; -+ bo->ifindex = 0; -+ bo->dropped_usr_msgs = 0; -+ bo->bcm_proc_read = NULL; -+ -+ INIT_LIST_HEAD(&bo->tx_ops); -+ INIT_LIST_HEAD(&bo->rx_ops); -+ -+ return 0; -+} -+ -+/**************************************************/ -+/* handling of netdevice problems */ -+/**************************************************/ -+ -+static void bcm_notifier(unsigned long msg, void *data) -+{ -+ struct sock *sk = (struct sock *)data; -+ struct bcm_opt *bo = bcm_sk(sk); -+ -+ DBG("called for sock %p\n", sk); -+ -+ switch (msg) { -+ case NETDEV_UNREGISTER: -+ bo->bound = 0; -+ bo->ifindex = 0; -+ /* fallthrough */ -+ case NETDEV_DOWN: -+ sk->sk_err = ENETDOWN; -+ if (!sock_flag(sk, SOCK_DEAD)) -+ sk->sk_error_report(sk); -+ } -+} -+ -+/**************************************************/ -+/* standard socket functions */ -+/**************************************************/ -+ -+static int bcm_release(struct socket *sock) -+{ -+ struct sock *sk = sock->sk; -+ struct bcm_opt *bo = bcm_sk(sk); -+ struct bcm_op *op, *next; -+ -+ DBG("socket %p, sk %p\n", sock, sk); -+ -+ /* remove bcm_ops, timer, rx_unregister(), etc. */ -+ -+ list_for_each_entry_safe(op, next, &bo->tx_ops, list) { -+ DBG("removing tx_op %p for can_id %03X\n", op, op->can_id); -+ bcm_remove_op(op); -+ } -+ -+ list_for_each_entry_safe(op, next, &bo->rx_ops, list) { -+ DBG("removing rx_op %p for can_id %03X\n", op, op->can_id); -+ -+ /* Don't care if we're bound or not (due to netdev problems) */ -+ /* can_rx_unregister() is always a save thing to do here */ -+ if (op->ifindex) { -+ struct net_device *dev = dev_get_by_index(op->ifindex); -+ if (dev) { -+ can_rx_unregister(dev, op->can_id, -+ REGMASK(op->can_id), -+ bcm_rx_handler, op); -+ dev_put(dev); -+ } -+ } else -+ can_rx_unregister(NULL, op->can_id, -+ REGMASK(op->can_id), -+ bcm_rx_handler, op); -+ -+ bcm_remove_op(op); -+ } -+ -+ /* remove procfs entry */ -+ if ((proc_dir) && (bo->bcm_proc_read)) { -+ remove_proc_entry(bo->procname, proc_dir); -+ } -+ -+ /* remove device notifier */ -+ if (bo->ifindex) { -+ struct net_device *dev = dev_get_by_index(bo->ifindex); -+ if (dev) { -+ can_dev_unregister(dev, bcm_notifier, sk); -+ dev_put(dev); -+ } -+ } -+ -+ sock_put(sk); -+ -+ return 0; -+} -+ -+static int bcm_connect(struct socket *sock, struct sockaddr *uaddr, int len, -+ int flags) -+{ -+ struct sockaddr_can *addr = (struct sockaddr_can *)uaddr; -+ struct sock *sk = sock->sk; -+ struct bcm_opt *bo = bcm_sk(sk); -+ -+ if (bo->bound) -+ return -EISCONN; -+ -+ /* bind a device to this socket */ -+ if (addr->can_ifindex) { -+ struct net_device *dev = dev_get_by_index(addr->can_ifindex); -+ if (!dev) { -+ DBG("could not find device index %d\n", -+ addr->can_ifindex); -+ return -ENODEV; -+ } -+ bo->ifindex = dev->ifindex; -+ can_dev_register(dev, bcm_notifier, sk); /* register notif. */ -+ dev_put(dev); -+ -+ DBG("socket %p bound to device %s (idx %d)\n", -+ sock, dev->name, dev->ifindex); -+ } else { -+ /* no notifier for ifindex = 0 ('any' CAN device) */ -+ bo->ifindex = 0; -+ } -+ -+ bo->bound = 1; -+ -+ if (proc_dir) { -+ /* unique socket address as filename */ -+ sprintf(bo->procname, "%p", sock); -+ bo->bcm_proc_read = create_proc_read_entry(bo->procname, 0644, -+ proc_dir, -+ bcm_read_proc, sk); -+ } -+ -+ return 0; -+} -+ -+static int bcm_sendmsg(struct kiocb *iocb, struct socket *sock, -+ struct msghdr *msg, size_t size) -+{ -+ struct sock *sk = sock->sk; -+ struct bcm_opt *bo = bcm_sk(sk); -+ int ifindex = bo->ifindex; /* default ifindex for this bcm_op */ -+ struct bcm_msg_head msg_head; -+ int ret; /* read bytes or error codes as return value */ -+ -+ if (!bo->bound) { -+ DBG("sock %p not bound\n", sk); -+ return -ENOTCONN; -+ } -+ -+ /* check for alternative ifindex for this bcm_op */ -+ -+ if (!ifindex && msg->msg_name) { /* no bound device as default */ -+ struct sockaddr_can *addr = -+ (struct sockaddr_can *)msg->msg_name; -+ if (addr->can_family != AF_CAN) -+ return -EINVAL; -+ ifindex = addr->can_ifindex; /* ifindex from sendto() */ -+ -+ if (ifindex && !dev_get_by_index(ifindex)) { -+ DBG("device %d not found\n", ifindex); -+ return -ENODEV; -+ } -+ } -+ -+ /* read message head information */ -+ -+ if ((ret = memcpy_fromiovec((u8*)&msg_head, msg->msg_iov, -+ MHSIZ)) < 0) -+ return ret; -+ -+ DBG("opcode %d for can_id %03X\n", msg_head.opcode, msg_head.can_id); -+ -+ switch (msg_head.opcode) { -+ -+ case TX_SETUP: -+ -+ ret = bcm_tx_setup(&msg_head, msg, ifindex, sk); -+ break; -+ -+ case RX_SETUP: -+ -+ ret = bcm_rx_setup(&msg_head, msg, ifindex, sk); -+ break; -+ -+ case TX_DELETE: -+ -+ if (bcm_delete_tx_op(&bo->tx_ops, msg_head.can_id, ifindex)) -+ ret = MHSIZ; -+ else -+ ret = -EINVAL; -+ break; -+ -+ case RX_DELETE: -+ -+ if (bcm_delete_rx_op(&bo->rx_ops, msg_head.can_id, ifindex)) -+ ret = MHSIZ; -+ else -+ ret = -EINVAL; -+ break; -+ -+ case TX_READ: -+ -+ /* reuse msg_head for the reply */ -+ msg_head.opcode = TX_STATUS; /* reply to TX_READ */ -+ ret = bcm_read_op(&bo->tx_ops, &msg_head, ifindex); -+ break; -+ -+ case RX_READ: -+ -+ /* reuse msg_head for the reply */ -+ msg_head.opcode = RX_STATUS; /* reply to RX_READ */ -+ ret = bcm_read_op(&bo->rx_ops, &msg_head, ifindex); -+ break; -+ -+ case TX_SEND: -+ -+ if (msg_head.nframes < 1) /* we need at least one can_frame */ -+ return -EINVAL; -+ -+ ret = bcm_tx_send(msg, ifindex, sk); -+ break; -+ -+ default: -+ -+ DBG("Unknown opcode %d\n", msg_head.opcode); -+ ret = -EINVAL; -+ break; -+ } -+ -+ return ret; -+} -+ -+static int bcm_recvmsg(struct kiocb *iocb, struct socket *sock, -+ struct msghdr *msg, size_t size, int flags) -+{ -+ struct sock *sk = sock->sk; -+ struct sk_buff *skb; -+ int error = 0; -+ int noblock; -+ int err; -+ -+ DBG("socket %p, sk %p\n", sock, sk); -+ -+ noblock = flags & MSG_DONTWAIT; -+ flags &= ~MSG_DONTWAIT; -+ if (!(skb = skb_recv_datagram(sk, flags, noblock, &error))) { -+ return error; -+ } -+ -+ DBG("delivering skbuff %p\n", skb); -+ DBG_SKB(skb); -+ -+ if (skb->len < size) -+ size = skb->len; -+ if ((err = memcpy_toiovec(msg->msg_iov, skb->data, size)) < 0) { -+ skb_free_datagram(sk, skb); -+ return err; -+ } -+ -+ sock_recv_timestamp(msg, sk, skb); -+ -+ if (msg->msg_name) { -+ msg->msg_namelen = sizeof(struct sockaddr_can); -+ memcpy(msg->msg_name, skb->cb, msg->msg_namelen); -+ } -+ -+ DBG("freeing sock %p, skbuff %p\n", sk, skb); -+ skb_free_datagram(sk, skb); -+ -+ return size; -+} -+ -+static unsigned int bcm_poll(struct file *file, struct socket *sock, -+ poll_table *wait) -+{ -+ unsigned int mask = 0; -+ -+ DBG("socket %p\n", sock); -+ -+ mask = datagram_poll(file, sock, wait); -+ return mask; -+} -+ -+/**************************************************/ -+/* helper functions for bcm_sendmsg() */ -+/**************************************************/ -+ -+static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg, -+ int ifindex, struct sock *sk) -+{ -+ struct bcm_opt *bo = bcm_sk(sk); -+ struct bcm_op *op; -+ int i, err; -+ -+ if (!ifindex) /* we need a real device to send frames */ -+ return -ENODEV; -+ -+ if (msg_head->nframes < 1) /* we need at least one can_frame */ -+ return -EINVAL; -+ -+ /* check the given can_id */ -+ -+ if ((op = bcm_find_op(&bo->tx_ops, msg_head->can_id, ifindex))) { -+ -+ /* update existing BCM operation */ -+ -+ DBG("TX_SETUP: modifying existing tx_op %p for can_id %03X\n", -+ op, msg_head->can_id); -+ -+ /* Do we need more space for the can_frames than currently */ -+ /* allocated? -> This is a _really_ unusual use-case and */ -+ /* therefore (complexity / locking) it is not supported. */ -+ if (msg_head->nframes > op->nframes) -+ return -E2BIG; -+ -+ /* update can_frames content */ -+ for (i = 0; i < msg_head->nframes; i++) { -+ if ((err = memcpy_fromiovec((u8*)&op->frames[i], -+ msg->msg_iov, CFSIZ)) < 0) -+ return err; -+ -+ if (msg_head->flags & TX_CP_CAN_ID) { -+ /* copy can_id into frame */ -+ op->frames[i].can_id = msg_head->can_id; -+ } -+ } -+ -+ } else { -+ /* insert new BCM operation for the given can_id */ -+ -+ if (!(op = kmalloc(OPSIZ, GFP_KERNEL))) -+ return -ENOMEM; -+ -+ memset(op, 0, OPSIZ); /* init to zero, e.g. for timers */ -+ -+ DBG("TX_SETUP: creating new tx_op %p for can_id %03X\n", -+ op, msg_head->can_id); -+ -+ op->can_id = msg_head->can_id; -+ -+ /* create array for can_frames and copy the data */ -+ if (!(op->frames = kmalloc(msg_head->nframes * CFSIZ, -+ GFP_KERNEL))) { -+ kfree(op); -+ return -ENOMEM; -+ } -+ -+ for (i = 0; i < msg_head->nframes; i++) { -+ if ((err = memcpy_fromiovec((u8*)&op->frames[i], -+ msg->msg_iov, -+ CFSIZ)) < 0) { -+ kfree(op->frames); -+ kfree(op); -+ return err; -+ } -+ -+ if (msg_head->flags & TX_CP_CAN_ID) { -+ /* copy can_id into frame */ -+ op->frames[i].can_id = msg_head->can_id; -+ } -+ } -+ -+ /* tx_ops never compare with previous received messages */ -+ op->last_frames = NULL; -+ -+ /* bcm_can_tx / bcm_tx_timeout_handler needs this */ -+ op->sk = sk; -+ -+ op->ifindex = ifindex; -+ -+ /* initialize uninitialized (kmalloc) structure */ -+ init_timer(&op->timer); -+ -+ /* currently unused in tx_ops */ -+ init_timer(&op->thrtimer); -+ -+ /* handler for tx_ops */ -+ op->timer.function = bcm_tx_timeout_handler; -+ -+ /* timer.data points to this op-structure */ -+ op->timer.data = (unsigned long)op; -+ -+ /* add this bcm_op to the list of the tx_ops */ -+ list_add(&op->list, &bo->tx_ops); -+ -+ } /* if ((op = bcm_find_op(&bo->tx_ops, msg_head->can_id, ifindex))) */ -+ -+ if (op->nframes != msg_head->nframes) { -+ op->nframes = msg_head->nframes; -+ /* start multiple frame transmission with index 0 */ -+ op->currframe = 0; -+ } -+ -+ /* check flags */ -+ -+ op->flags = msg_head->flags; -+ -+ if (op->flags & TX_RESET_MULTI_IDX) { -+ /* start multiple frame transmission with index 0 */ -+ op->currframe = 0; -+ } -+ -+ if (op->flags & SETTIMER) { -+ -+ /* set timer values */ -+ -+ op->count = msg_head->count; -+ op->ival1 = msg_head->ival1; -+ op->ival2 = msg_head->ival2; -+ op->j_ival1 = timeval2jiffies(&msg_head->ival1, 1); -+ op->j_ival2 = timeval2jiffies(&msg_head->ival2, 1); -+ -+ DBG("TX_SETUP: SETTIMER count=%d j_ival1=%ld j_ival2=%ld\n", -+ op->count, op->j_ival1, op->j_ival2); -+ -+ /* disable an active timer due to zero values? */ -+ if (!op->j_ival1 && !op->j_ival2) { -+ del_timer(&op->timer); -+ DBG("TX_SETUP: SETTIMER disabled timer.\n"); -+ } -+ } -+ -+ if ((op->flags & STARTTIMER) && -+ ((op->j_ival1 && op->count) || op->j_ival2)) { -+ -+ del_timer(&op->timer); -+ -+ /* spec: send can_frame when starting timer */ -+ op->flags |= TX_ANNOUNCE; -+ -+ if (op->j_ival1 && (op->count > 0)){ -+ op->timer.expires = jiffies + op->j_ival1; -+ /* op->count-- is done in bcm_tx_timeout_handler */ -+ DBG("TX_SETUP: adding timer ival1. func=%p data=%p " -+ "exp=0x%08X\n", -+ op->timer.function, -+ (char*) op->timer.data, -+ (unsigned int) op->timer.expires); -+ } else{ -+ op->timer.expires = jiffies + op->j_ival2; -+ DBG("TX_SETUP: adding timer ival2. func=%p data=%p " -+ "exp=0x%08X\n", -+ op->timer.function, -+ (char*) op->timer.data, -+ (unsigned int) op->timer.expires); -+ } -+ -+ add_timer(&op->timer); -+ } -+ -+ if (op->flags & TX_ANNOUNCE) -+ bcm_can_tx(op); -+ -+ return msg_head->nframes * CFSIZ + MHSIZ; -+} -+ -+static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg, -+ int ifindex, struct sock *sk) -+{ -+ struct bcm_opt *bo = bcm_sk(sk); -+ struct bcm_op *op; -+ int do_rx_register; -+ int err; -+ -+ if ((msg_head->flags & RX_FILTER_ID) || (!(msg_head->nframes))) { -+ /* be robust against wrong usage ... */ -+ msg_head->flags |= RX_FILTER_ID; -+ msg_head->nframes = 0; /* ignore trailing garbage */ -+ } -+ -+ if ((msg_head->flags & RX_RTR_FRAME) && -+ ((msg_head->nframes != 1) || -+ (!(msg_head->can_id & CAN_RTR_FLAG)))) { -+ -+ DBG("RX_SETUP: bad RX_RTR_FRAME setup!\n"); -+ return -EINVAL; -+ } -+ -+ /* check the given can_id */ -+ -+ if ((op = bcm_find_op(&bo->rx_ops, msg_head->can_id, ifindex))) { -+ -+ /* update existing BCM operation */ -+ -+ DBG("RX_SETUP: modifying existing rx_op %p for can_id %03X\n", -+ op, msg_head->can_id); -+ -+ /* Do we need more space for the can_frames than currently */ -+ /* allocated? -> This is a _really_ unusual use-case and */ -+ /* therefore (complexity / locking) it is not supported. */ -+ if (msg_head->nframes > op->nframes) -+ return -E2BIG; -+ -+ if (msg_head->nframes) { -+ /* update can_frames content */ -+ if ((err = memcpy_fromiovec((u8*)op->frames, -+ msg->msg_iov, -+ msg_head->nframes -+ * CFSIZ) < 0)) -+ return err; -+ -+ /* clear last_frames to indicate 'nothing received' */ -+ memset(op->last_frames, 0, msg_head->nframes * CFSIZ); -+ } -+ -+ op->nframes = msg_head->nframes; -+ /* Only an update -> do not call can_rx_register() */ -+ do_rx_register = 0; -+ -+ } else { -+ /* insert new BCM operation for the given can_id */ -+ -+ if (!(op = kmalloc(OPSIZ, GFP_KERNEL))) -+ return -ENOMEM; -+ -+ memset(op, 0, OPSIZ); /* init to zero, e.g. for timers */ -+ -+ DBG("RX_SETUP: creating new rx_op %p for can_id %03X\n", -+ op, msg_head->can_id); -+ -+ op->can_id = msg_head->can_id; -+ op->nframes = msg_head->nframes; -+ -+ if (msg_head->nframes) { -+ -+ /* create array for can_frames and copy the data */ -+ if (!(op->frames = kmalloc(msg_head->nframes * CFSIZ, -+ GFP_KERNEL))) { -+ kfree(op); -+ return -ENOMEM; -+ } -+ -+ if ((err = memcpy_fromiovec((u8*)op->frames, -+ msg->msg_iov, -+ msg_head->nframes -+ * CFSIZ)) < 0) { -+ kfree(op->frames); -+ kfree(op); -+ return err; -+ } -+ -+ /* create array for received can_frames */ -+ if (!(op->last_frames = kmalloc(msg_head->nframes -+ * CFSIZ, -+ GFP_KERNEL))) { -+ kfree(op->frames); -+ kfree(op); -+ return -ENOMEM; -+ } -+ -+ /* clear last_frames to indicate 'nothing received' */ -+ memset(op->last_frames, 0, msg_head->nframes * CFSIZ); -+ } else { -+ /* op->frames = NULL due to memset */ -+ -+ /* even when we have the RX_FILTER_ID case, we need */ -+ /* to store the last frame for the throttle feature */ -+ -+ /* create array for received can_frames */ -+ if (!(op->last_frames = kmalloc(CFSIZ, GFP_KERNEL))) { -+ kfree(op); -+ return -ENOMEM; -+ } -+ -+ /* clear last_frames to indicate 'nothing received' */ -+ memset(op->last_frames, 0, CFSIZ); -+ } -+ -+ op->sk = sk; /* bcm_delete_rx_op() needs this */ -+ op->ifindex = ifindex; -+ -+ /* initialize uninitialized (kmalloc) structure */ -+ init_timer(&op->timer); -+ -+ /* init throttle timer for RX_CHANGED */ -+ init_timer(&op->thrtimer); -+ -+ /* handler for rx timeouts */ -+ op->timer.function = bcm_rx_timeout_handler; -+ -+ /* timer.data points to this op-structure */ -+ op->timer.data = (unsigned long)op; -+ -+ /* handler for RX_CHANGED throttle timeouts */ -+ op->thrtimer.function = bcm_rx_thr_handler; -+ -+ /* timer.data points to this op-structure */ -+ op->thrtimer.data = (unsigned long)op; -+ -+ op->thrtimer.expires = 0; /* mark disabled timer */ -+ -+ /* add this bcm_op to the list of the tx_ops */ -+ list_add(&op->list, &bo->rx_ops); -+ -+ do_rx_register = 1; /* call can_rx_register() */ -+ -+ } /* if ((op = bcm_find_op(&bo->rx_ops, msg_head->can_id, ifindex))) */ -+ -+ -+ /* check flags */ -+ -+ op->flags = msg_head->flags; -+ -+ if (op->flags & RX_RTR_FRAME) { -+ -+ /* no timers in RTR-mode */ -+ del_timer(&op->thrtimer); -+ del_timer(&op->timer); -+ -+ /* funny feature in RX(!)_SETUP only for RTR-mode: */ -+ /* copy can_id into frame BUT without RTR-flag to */ -+ /* prevent a full-load-loopback-test ... ;-] */ -+ if ((op->flags & TX_CP_CAN_ID) || -+ (op->frames[0].can_id == op->can_id)) -+ op->frames[0].can_id = op->can_id & ~CAN_RTR_FLAG; -+ -+ } else { -+ if (op->flags & SETTIMER) { -+ -+ /* set timer value */ -+ -+ op->ival1 = msg_head->ival1; -+ op->j_ival1 = timeval2jiffies(&msg_head->ival1, 1); -+ op->ival2 = msg_head->ival2; -+ op->j_ival2 = timeval2jiffies(&msg_head->ival2, 1); -+ -+ DBG("RX_SETUP: SETTIMER j_ival1=%ld j_ival2=%ld\n", -+ op->j_ival1, op->j_ival2); -+ -+ /* disable an active timer due to zero value? */ -+ if (!op->j_ival1) { -+ del_timer(&op->timer); -+ DBG("RX_SETUP: disabled timer rx timeouts.\n"); -+ } -+ -+ /* free currently blocked msgs ? */ -+ if (op->thrtimer.expires) { /* blocked by timer? */ -+ DBG("RX_SETUP: unblocking throttled msgs.\n"); -+ del_timer(&op->thrtimer); -+ /* send blocked msgs hereafter */ -+ op->thrtimer.expires = jiffies + 2; -+ add_timer(&op->thrtimer); -+ } -+ /* if (op->j_ival2) is zero, no (new) throttling */ -+ /* will happen. For details see functions */ -+ /* bcm_rx_update_and_send() and bcm_rx_thr_handler() */ -+ } -+ -+ if ((op->flags & STARTTIMER) && op->j_ival1) { -+ -+ del_timer(&op->timer); -+ -+ op->timer.expires = jiffies + op->j_ival1; -+ -+ DBG("RX_SETUP: adding timer ival1. func=%p data=%p" -+ " exp=0x%08X\n", -+ (char *) op->timer.function, -+ (char *) op->timer.data, -+ (unsigned int) op->timer.expires); -+ -+ add_timer(&op->timer); -+ } -+ } -+ -+ /* now we can register for can_ids, if we added a new bcm_op */ -+ if (do_rx_register) { -+ DBG("RX_SETUP: can_rx_register() for can_id %03X. " -+ "rx_op is %p\n", op->can_id, op); -+ -+ if (ifindex) { -+ struct net_device *dev = dev_get_by_index(ifindex); -+ -+ if (dev) { -+ can_rx_register(dev, op->can_id, -+ REGMASK(op->can_id), -+ bcm_rx_handler, op, IDENT); -+ dev_put(dev); -+ } -+ } else -+ can_rx_register(NULL, op->can_id, REGMASK(op->can_id), -+ bcm_rx_handler, op, IDENT); -+ } -+ -+ return msg_head->nframes * CFSIZ + MHSIZ; -+} -+ -+static int bcm_tx_send(struct msghdr *msg, int ifindex, struct sock *sk) -+{ -+ struct sk_buff *skb; -+ struct net_device *dev; -+ int err; -+ -+ /* just copy and send one can_frame */ -+ -+ if (!ifindex) /* we need a real device to send frames */ -+ return -ENODEV; -+ -+ skb = alloc_skb(CFSIZ, GFP_KERNEL); -+ -+ if (!skb) -+ return -ENOMEM; -+ -+ if ((err = memcpy_fromiovec(skb_put(skb, CFSIZ), msg->msg_iov, -+ CFSIZ)) < 0) { -+ kfree_skb(skb); -+ return err; -+ } -+ -+ DBG_FRAME("BCM: TX_SEND: sending frame", -+ (struct can_frame *)skb->data); -+ dev = dev_get_by_index(ifindex); -+ -+ if (!dev) { -+ kfree_skb(skb); -+ return -ENODEV; -+ } -+ -+ skb->dev = dev; -+ skb->sk = sk; -+ can_send(skb, 1); /* send with loopback */ -+ dev_put(dev); -+ -+ return CFSIZ + MHSIZ; -+} -+ -+static int bcm_read_op(struct list_head *ops, struct bcm_msg_head *msg_head, -+ int ifindex) -+{ -+ struct bcm_op *op; -+ int ret; -+ -+ if ((op = bcm_find_op(ops, msg_head->can_id, ifindex))) { -+ -+ DBG("TRX_READ: sending status for can_id %03X\n", -+ msg_head->can_id); -+ /* put current values into msg_head */ -+ msg_head->flags = op->flags; -+ msg_head->count = op->count; -+ msg_head->ival1 = op->ival1; -+ msg_head->ival2 = op->ival2; -+ msg_head->nframes = op->nframes; -+ -+ bcm_send_to_user(op, msg_head, op->frames, NULL); -+ -+ ret = MHSIZ; -+ -+ } else { -+ -+ DBG("TRX_READ: did not find op for can_id %03X\n", -+ msg_head->can_id); -+ ret = -EINVAL; -+ } -+ -+ return ret; -+} -+ -+/**************************************************/ -+/* procfs functions */ -+/**************************************************/ -+ -+static char *bcm_proc_getifname(int ifindex) -+{ -+ struct net_device *dev; -+ -+ if (!ifindex) -+ return "any"; -+ -+ dev = __dev_get_by_index(ifindex); /* no usage counting */ -+ if (dev) -+ return dev->name; -+ -+ return "???"; -+} -+ -+static int bcm_read_proc(char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int len = 0; -+ struct sock *sk = (struct sock *)data; -+ struct bcm_opt *bo = bcm_sk(sk); -+ struct bcm_op *op; -+ -+ len += snprintf(page + len, PAGE_SIZE - len, ">>> socket %p", -+ sk->sk_socket); -+ len += snprintf(page + len, PAGE_SIZE - len, " / sk %p", sk); -+ len += snprintf(page + len, PAGE_SIZE - len, " / bo %p", bo); -+ len += snprintf(page + len, PAGE_SIZE - len, " / dropped %lu", -+ bo->dropped_usr_msgs); -+ len += snprintf(page + len, PAGE_SIZE - len, " / bound %s", -+ bcm_proc_getifname(bo->ifindex)); -+ len += snprintf(page + len, PAGE_SIZE - len, " <<<\n"); -+ -+ list_for_each_entry(op, &bo->rx_ops, list) { -+ -+ unsigned long reduction; -+ -+ /* print only active entries & prevent division by zero */ -+ if (!op->frames_abs) -+ continue; -+ -+ len += snprintf(page + len, PAGE_SIZE - len, -+ "rx_op: %03X %-5s ", -+ op->can_id, bcm_proc_getifname(op->ifindex)); -+ len += snprintf(page + len, PAGE_SIZE - len, "[%d]%c ", -+ op->nframes, -+ (op->flags & RX_CHECK_DLC)?'d':' '); -+ if (op->j_ival1) -+ len += snprintf(page + len, PAGE_SIZE - len, -+ "timeo=%ld ", op->j_ival1); -+ -+ if (op->j_ival2) -+ len += snprintf(page + len, PAGE_SIZE - len, -+ "thr=%ld ", op->j_ival2); -+ -+ len += snprintf(page + len, PAGE_SIZE - len, -+ "# recv %ld (%ld) => reduction: ", -+ op->frames_filtered, op->frames_abs); -+ -+ reduction = 100 - (op->frames_filtered * 100) / op->frames_abs; -+ -+ len += snprintf(page + len, PAGE_SIZE - len, "%s%ld%%\n", -+ (reduction == 100)?"near ":"", reduction); -+ -+ if (len > PAGE_SIZE - 200) { -+ /* mark output cut off */ -+ len += snprintf(page + len, PAGE_SIZE - len, "(..)\n"); -+ break; -+ } -+ } -+ -+ list_for_each_entry(op, &bo->tx_ops, list) { -+ -+ len += snprintf(page + len, PAGE_SIZE - len, -+ "tx_op: %03X %s [%d] ", -+ op->can_id, bcm_proc_getifname(op->ifindex), -+ op->nframes); -+ if (op->j_ival1) -+ len += snprintf(page + len, PAGE_SIZE - len, "t1=%ld ", -+ op->j_ival1); -+ -+ if (op->j_ival2) -+ len += snprintf(page + len, PAGE_SIZE - len, "t2=%ld ", -+ op->j_ival2); -+ -+ len += snprintf(page + len, PAGE_SIZE - len, "# sent %ld\n", -+ op->frames_abs); -+ -+ if (len > PAGE_SIZE - 100) { -+ /* mark output cut off */ -+ len += snprintf(page + len, PAGE_SIZE - len, "(..)\n"); -+ break; -+ } -+ } -+ -+ len += snprintf(page + len, PAGE_SIZE - len, "\n"); -+ -+ *eof = 1; -+ return len; -+} -+ -+/**************************************************/ -+/* bcm_op handling tx path */ -+/**************************************************/ -+ -+static void bcm_can_tx(struct bcm_op *op) -+{ -+ struct sk_buff *skb; -+ struct net_device *dev; -+ struct can_frame *cf = &op->frames[op->currframe]; -+ -+ DBG_FRAME("BCM: bcm_can_tx: sending frame", cf); -+ -+ if (!op->ifindex) -+ return; /* no target device -> exit */ -+ -+ dev = dev_get_by_index(op->ifindex); -+ -+ if (!dev) -+ return; /* should this bcm_op remove itself here? */ -+ -+ skb = alloc_skb(CFSIZ, -+ in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); -+ -+ if (!skb) -+ goto out; /* no memory */ -+ -+ memcpy(skb_put(skb, CFSIZ), cf, CFSIZ); -+ -+ skb->dev = dev; -+ skb->sk = op->sk; -+ can_send(skb, 1); /* send with loopback */ -+ -+ op->currframe++; -+ op->frames_abs++; /* statistics */ -+ -+ /* reached last frame? */ -+ if (op->currframe >= op->nframes) -+ op->currframe = 0; -+ out: -+ dev_put(dev); -+} -+ -+static void bcm_tx_timeout_handler(unsigned long data) -+{ -+ struct bcm_op *op = (struct bcm_op*)data; -+ -+ DBG("Called with bcm_op %p\n", op); -+ -+ if (op->j_ival1 && (op->count > 0)) { -+ -+ op->count--; -+ -+ if (!op->count && (op->flags & TX_COUNTEVT)) { -+ /* create notification to user */ -+ -+ struct bcm_msg_head msg_head; -+ -+ DBG("sending TX_EXPIRED for can_id %03X\n", -+ op->can_id); -+ -+ msg_head.opcode = TX_EXPIRED; -+ msg_head.flags = op->flags; -+ msg_head.count = op->count; -+ msg_head.ival1 = op->ival1; -+ msg_head.ival2 = op->ival2; -+ msg_head.can_id = op->can_id; -+ msg_head.nframes = 0; -+ -+ bcm_send_to_user(op, &msg_head, NULL, NULL); -+ } -+ } -+ -+ DBG("count=%d j_ival1=%ld j_ival2=%ld\n", -+ op->count, op->j_ival1, op->j_ival2); -+ -+ if (op->j_ival1 && (op->count > 0)) { -+ -+ op->timer.expires = jiffies + op->j_ival1; -+ add_timer(&op->timer); -+ -+ DBG("adding timer ival1. func=%p data=%p exp=0x%08X\n", -+ op->timer.function, -+ (char*) op->timer.data, -+ (unsigned int) op->timer.expires); -+ -+ bcm_can_tx(op); /* send (next) frame */ -+ } else { -+ if (op->j_ival2) { -+ op->timer.expires = jiffies + op->j_ival2; -+ add_timer(&op->timer); -+ -+ DBG("adding timer ival2. func=%p data=%p exp=0x%08X\n", -+ op->timer.function, -+ (char*) op->timer.data, -+ (unsigned int) op->timer.expires); -+ -+ bcm_can_tx(op); /* send (next) frame */ -+ } else -+ DBG("no timer restart\n"); -+ } -+ -+ return; -+ -+} -+ -+/**************************************************/ -+/* bcm_op handling rx path */ -+/**************************************************/ -+ -+static void bcm_rx_handler(struct sk_buff *skb, void *data) -+{ -+ struct bcm_op *op = (struct bcm_op*)data; -+ struct can_frame rxframe; -+ int i; -+ -+ del_timer(&op->timer); /* disable timeout */ -+ -+ DBG("Called with bcm_op %p\n", op); -+ -+ if (skb->len == sizeof(rxframe)) { -+ memcpy(&rxframe, skb->data, sizeof(rxframe)); -+ skb_get_timestamp(skb, &op->rx_stamp); /* save rx timestamp */ -+ /* save originator for recvfrom() */ -+ op->rx_ifindex = skb->dev->ifindex; -+ op->frames_abs++; /* statistics */ -+ kfree_skb(skb); -+ DBG("got can_frame with can_id %03X\n", rxframe.can_id); -+ } else { -+ DBG("Wrong skb->len = %d\n", skb->len); -+ kfree_skb(skb); -+ return; -+ } -+ -+ DBG_FRAME("BCM: bcm_rx_handler: CAN frame", &rxframe); -+ -+ if (op->can_id != rxframe.can_id) { -+ DBG("ERROR! Got wrong can_id %03X! Expected %03X.\n", -+ rxframe.can_id, op->can_id); -+ return; -+ } -+ -+ if (op->flags & RX_RTR_FRAME) { /* send reply for RTR-request */ -+ DBG("RTR-request\n"); -+ bcm_can_tx(op); /* send op->frames[0] to CAN device */ -+ return; -+ } -+ -+ if (op->flags & RX_FILTER_ID) { /* the easiest case */ -+ DBG("Easy does it with RX_FILTER_ID\n"); -+ bcm_rx_update_and_send(op, &op->last_frames[0], &rxframe); -+ bcm_rx_starttimer(op); -+ return; -+ } -+ -+ if (op->nframes == 1) { /* simple compare with index 0 */ -+ DBG("Simple compare\n"); -+ bcm_rx_cmp_to_index(op, 0, &rxframe); -+ bcm_rx_starttimer(op); -+ return; -+ } -+ -+ if (op->nframes > 1) { /* multiplex compare */ -+ -+ DBG("Multiplex compare\n"); -+ /* find the first multiplex mask that fits */ -+ /* MUX-mask is in index 0 */ -+ -+ for (i=1; i < op->nframes; i++) { -+ -+ if ((GET_U64(&op->frames[0]) & GET_U64(&rxframe)) == -+ (GET_U64(&op->frames[0]) & -+ GET_U64(&op->frames[i]))) { -+ DBG("found MUX index %d\n", i); -+ bcm_rx_cmp_to_index(op, i, &rxframe); -+ break; -+ } -+ } -+ bcm_rx_starttimer(op); -+ } -+} -+ -+static void bcm_rx_cmp_to_index(struct bcm_op *op, int index, -+ struct can_frame *rxdata) -+{ -+ /* no one uses the MSBs of can_dlc for comparation, */ -+ /* so we use it here to detect the first time of reception */ -+ -+ if (!(op->last_frames[index].can_dlc & RX_RECV)) { /* first time? */ -+ DBG("first time :)\n"); -+ bcm_rx_update_and_send(op, &op->last_frames[index], rxdata); -+ return; -+ } -+ -+ /* do a real check in can_data */ -+ -+ DBG("op->frames[index].data = 0x%016llx\n", -+ GET_U64(&op->frames[index])); -+ DBG("op->last_frames[index].data = 0x%016llx\n", -+ GET_U64(&op->last_frames[index])); -+ DBG("rxdata->data = 0x%016llx\n", GET_U64(rxdata)); -+ -+ if ((GET_U64(&op->frames[index]) & GET_U64(rxdata)) != -+ (GET_U64(&op->frames[index]) & GET_U64(&op->last_frames[index]))) { -+ DBG("relevant data change :)\n"); -+ bcm_rx_update_and_send(op, &op->last_frames[index], rxdata); -+ return; -+ } -+ -+ -+ if (op->flags & RX_CHECK_DLC) { -+ -+ /* do a real check in dlc */ -+ -+ if (rxdata->can_dlc != (op->last_frames[index].can_dlc & -+ BCM_CAN_DLC_MASK)) { -+ DBG("dlc change :)\n"); -+ bcm_rx_update_and_send(op, &op->last_frames[index], -+ rxdata); -+ return; -+ } -+ } -+ DBG("no relevant change :(\n"); -+} -+ -+static void bcm_rx_update_and_send(struct bcm_op *op, -+ struct can_frame *lastdata, -+ struct can_frame *rxdata) -+{ -+ unsigned long nexttx = op->j_lastmsg + op->j_ival2; -+ -+ memcpy(lastdata, rxdata, CFSIZ); -+ lastdata->can_dlc |= RX_RECV; /* mark as used */ -+ -+ /* throttle bcm_rx_changed ? */ -+ if ((op->thrtimer.expires) || /* somebody else is already waiting OR */ -+ ((op->j_ival2) && (nexttx > jiffies))) { /* we have to wait */ -+ -+ lastdata->can_dlc |= RX_THR; /* mark as 'throttled' */ -+ -+ if (!(op->thrtimer.expires)) { /* start only the first time */ -+ op->thrtimer.expires = nexttx; -+ add_timer(&op->thrtimer); -+ -+ DBG("adding thrtimer. func=%p data=%p exp=0x%08X\n", -+ op->thrtimer.function, -+ (char*) op->thrtimer.data, -+ (unsigned int) op->thrtimer.expires); -+ } -+ } else -+ bcm_rx_changed(op, rxdata); /* send RX_CHANGED to the user */ -+} -+ -+static void bcm_rx_starttimer(struct bcm_op *op) -+{ -+ if (op->flags & RX_NO_AUTOTIMER) -+ return; -+ -+ if (op->j_ival1) { -+ -+ op->timer.expires = jiffies + op->j_ival1; -+ -+ DBG("adding rx timeout timer ival1. func=%p data=%p " -+ "exp=0x%08X\n", -+ op->timer.function, -+ (char*) op->timer.data, -+ (unsigned int) op->timer.expires); -+ -+ add_timer(&op->timer); -+ } -+} -+ -+ -+static void bcm_rx_changed(struct bcm_op *op, struct can_frame *data) -+{ -+ struct bcm_msg_head head; -+ -+ op->j_lastmsg = jiffies; -+ op->frames_filtered++; /* statistics */ -+ -+ if (op->frames_filtered > ULONG_MAX/100) -+ op->frames_filtered = op->frames_abs = 0; /* restart */ -+ -+ DBG("setting j_lastmsg to 0x%08X for rx_op %p\n", -+ (unsigned int) op->j_lastmsg, op); -+ DBG("sending notification\n"); -+ -+ head.opcode = RX_CHANGED; -+ head.flags = op->flags; -+ head.count = op->count; -+ head.ival1 = op->ival1; -+ head.ival2 = op->ival2; -+ head.can_id = op->can_id; -+ head.nframes = 1; -+ -+ bcm_send_to_user(op, &head, data, &op->rx_stamp); -+} -+ -+ -+static void bcm_rx_timeout_handler(unsigned long data) -+{ -+ struct bcm_op *op = (struct bcm_op*)data; -+ struct bcm_msg_head msg_head; -+ -+ DBG("sending RX_TIMEOUT for can_id %03X. op is %p\n", op->can_id, op); -+ -+ msg_head.opcode = RX_TIMEOUT; -+ msg_head.flags = op->flags; -+ msg_head.count = op->count; -+ msg_head.ival1 = op->ival1; -+ msg_head.ival2 = op->ival2; -+ msg_head.can_id = op->can_id; -+ msg_head.nframes = 0; -+ -+ bcm_send_to_user(op, &msg_head, NULL, NULL); -+ -+ /* no restart of the timer is done here! */ -+ -+ /* if user wants to be informed, when cyclic CAN-Messages come back */ -+ if ((op->flags & RX_ANNOUNCE_RESUME) && op->last_frames) { -+ /* clear received can_frames to indicate 'nothing received' */ -+ memset(op->last_frames, 0, op->nframes * CFSIZ); -+ DBG("RX_ANNOUNCE_RESTART\n"); -+ } -+ -+} -+ -+static void bcm_rx_thr_handler(unsigned long data) -+{ -+ struct bcm_op *op = (struct bcm_op*)data; -+ int i = 0; -+ -+ op->thrtimer.expires = 0; /* mark disabled / consumed timer */ -+ -+ if (op->nframes > 1){ -+ -+ DBG("sending MUX RX_CHANGED for can_id %03X. op is %p\n", -+ op->can_id, op); -+ /* for MUX filter we start at index 1 */ -+ for (i=1; inframes; i++){ -+ if ((op->last_frames) && -+ (op->last_frames[i].can_dlc & RX_THR)){ -+ op->last_frames[i].can_dlc &= ~RX_THR; -+ bcm_rx_changed(op, &op->last_frames[i]); -+ } -+ } -+ } else { -+ -+ DBG("sending simple RX_CHANGED for can_id %03X. op is %p\n", -+ op->can_id, op); -+ /* for RX_FILTER_ID and simple filter */ -+ if (op->last_frames && (op->last_frames[0].can_dlc & RX_THR)){ -+ op->last_frames[0].can_dlc &= ~RX_THR; -+ bcm_rx_changed(op, &op->last_frames[0]); -+ } -+ } -+} -+ -+static void bcm_send_to_user(struct bcm_op *op, struct bcm_msg_head *head, -+ struct can_frame *frames, struct timeval *tv) -+{ -+ struct sk_buff *skb; -+ struct can_frame *firstframe; -+ struct sock *sk = op->sk; -+ int datalen = head->nframes * CFSIZ; -+ struct sockaddr_can *addr; -+ int err; -+ -+ skb = alloc_skb(sizeof(*head) + datalen, -+ in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); -+ if (!skb) -+ return; -+ -+ memcpy(skb_put(skb, sizeof(*head)), head, sizeof(*head)); -+ /* can_frames starting here */ -+ firstframe = (struct can_frame *) skb->tail; -+ -+ if (tv) -+ skb_set_timestamp(skb, tv); /* restore timestamp */ -+ -+ addr = (struct sockaddr_can *)skb->cb; -+ memset(addr, 0, sizeof(*addr)); -+ addr->can_family = AF_CAN; -+ /* restore originator for recvfrom() */ -+ addr->can_ifindex = op->rx_ifindex; -+ -+ if (head->nframes){ -+ memcpy(skb_put(skb, datalen), frames, datalen); -+ -+ /* the BCM uses the can_dlc-element of the can_frame */ -+ /* structure for internal purposes. This is only */ -+ /* relevant for updates that are generated by the */ -+ /* BCM, where nframes is 1 */ -+ if (head->nframes == 1) -+ firstframe->can_dlc &= BCM_CAN_DLC_MASK; -+ } -+ if ((err = sock_queue_rcv_skb(sk, skb)) < 0) { -+ struct bcm_opt *bo = bcm_sk(sk); -+ DBG("sock_queue_rcv_skb failed: %d\n", err); -+ kfree_skb(skb); -+ bo->dropped_usr_msgs++; /* don't care about overflows */ -+ } -+} -+ -+/**************************************************/ -+/* bcm_op handling: find & delete bcm_op elements */ -+/**************************************************/ -+ -+static struct bcm_op *bcm_find_op(struct list_head *ops, canid_t can_id, -+ int ifindex) -+{ -+ struct bcm_op *op; -+ -+ list_for_each_entry(op, ops, list) -+ if ((op->can_id == can_id) && (op->ifindex == ifindex)) -+ return op; -+ -+ return NULL; -+} -+ -+static int bcm_delete_rx_op(struct list_head *ops, canid_t can_id, int ifindex) -+{ -+ struct bcm_op *op, *n; -+ -+ list_for_each_entry_safe(op, n, ops, list) { -+ if ((op->can_id == can_id) && (op->ifindex == ifindex)) { -+ DBG("removing rx_op %p for can_id %03X\n", -+ op, op->can_id); -+ -+ /* Don't care if we're bound or not (due to netdev */ -+ /* problems) can_rx_unregister() is always a save */ -+ /* thing to do here. */ -+ if (op->ifindex) { -+ struct net_device *dev = -+ dev_get_by_index(op->ifindex); -+ if (dev) { -+ can_rx_unregister(dev, op->can_id, -+ REGMASK(op->can_id), -+ bcm_rx_handler, op); -+ dev_put(dev); -+ } -+ } else -+ can_rx_unregister(NULL, op->can_id, -+ REGMASK(op->can_id), -+ bcm_rx_handler, op); -+ -+ list_del(&op->list); -+ bcm_remove_op(op); -+ return 1; /* done */ -+ } -+ } -+ -+ return 0; /* not found */ -+} -+ -+static int bcm_delete_tx_op(struct list_head *ops, canid_t can_id, int ifindex) -+{ -+ struct bcm_op *op, *n; -+ -+ list_for_each_entry_safe(op, n, ops, list) { -+ if ((op->can_id == can_id) && (op->ifindex == ifindex)) { -+ DBG("removing rx_op %p for can_id %03X\n", -+ op, op->can_id); -+ list_del(&op->list); -+ bcm_remove_op(op); -+ return 1; /* done */ -+ } -+ } -+ -+ return 0; /* not found */ -+} -+ -+static void bcm_remove_op(struct bcm_op *op) -+{ -+ del_timer(&op->timer); -+ del_timer(&op->thrtimer); -+ if (op->frames) -+ kfree(op->frames); -+ if (op->last_frames) -+ kfree(op->last_frames); -+ kfree(op); -+ -+ return; -+} -+ -+module_init(bcm_module_init); -+module_exit(bcm_module_exit); -diff -N -u -r a/net/can/Kconfig c/net/can/Kconfig ---- a/net/can/Kconfig 1970-01-01 01:00:00.000000000 +0100 -+++ c/net/can/Kconfig 2007-03-09 13:47:12.000000000 +0100 -@@ -0,0 +1,71 @@ -+# -+# Controller Area Network (CAN) network layer core configuration -+# -+ -+menuconfig CAN -+ depends on NET -+ tristate "CAN bus subsystem support" -+ ---help--- -+ Controller Area Network (CAN) is a slow (up to 1Mbit/s) serial -+ communications protocol was developed by Bosch at 1991 mainly for -+ automotive, but now widely used in marine (NMEA2000), industrial and -+ medical applications. -+ More information is contained in the directory . -+ -+ If you want CAN support, you should say Y here and also to the -+ specific driver for your controller(s) below. -+ -+ This CAN support can also be built as a module. If so, the module -+ will be called can.ko. -+ -+config CAN_RAW -+ tristate "Raw CAN Protocol (raw access with CAN-ID filtering)" -+ depends on CAN -+ default N -+ ---help--- -+ The Raw CAN protocol option offers access to the CAN bus via -+ the BSD socket API. You probably want to use the raw socket in -+ most cases where no higher level protocol is being used. The raw -+ socket has several filter options e.g. ID-Masking / Errorframes. -+ To receive/send raw CAN messages, use AF_CAN with protocol CAN_RAW. -+ -+config CAN_RAW_USER -+ bool "Allow non-root users to access Raw CAN Protocol sockets" -+ depends on CAN_RAW -+ default N -+ ---help--- -+ Say Y here if you want non-root users to be able to access CAN_RAW- -+ sockets. This may lead to a security hole. -+ -+config CAN_BCM -+ tristate "Broadcast Manager CAN Protocol (with content filtering)" -+ depends on CAN -+ default N -+ ---help--- -+ The Broadcast Manager offers content filtering, timeout monitoring, -+ sending of RTR-frames and cyclic CAN messages without permanent user -+ interaction. The BCM can be 'programmed' via the BSD socket API and -+ informs you on demand e.g. only on content updates / timeouts. -+ You probably want to use the bcm socket in most cases where cyclic -+ CAN messages are used on the bus (e.g. in automotive environments). -+ To use the Broadcast Manager, use AF_CAN with protocol CAN_BCM. -+ -+config CAN_BCM_USER -+ bool "Allow non-root users to access CAN broadcast manager sockets" -+ depends on CAN_BCM -+ default N -+ ---help--- -+ Say Y here if you want non-root users to be able to access CAN_BCM- -+ sockets. This may lead to a security hole. -+ -+config CAN_DEBUG_CORE -+ bool "CAN Core debugging messages" -+ depends on CAN -+ ---help--- -+ Say Y here if you want the CAN core to produce a bunch of debug -+ messages to the system log. Select this if you are having a -+ problem with CAN support and want to see more of what is going on. -+ -+ -+source "drivers/net/can/Kconfig" -+ -diff -N -u -r a/net/can/Makefile c/net/can/Makefile ---- a/net/can/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ c/net/can/Makefile 2007-03-09 13:47:12.000000000 +0100 -@@ -0,0 +1,12 @@ -+# -+# Makefile for the Linux Controller Area Network core. -+# -+ -+obj-$(CONFIG_CAN) += can.o -+can-objs := af_can.o proc.o -+ -+obj-$(CONFIG_CAN_RAW) += can-raw.o -+can-raw-objs := raw.o -+ -+obj-$(CONFIG_CAN_BCM) += can-bcm.o -+can-bcm-objs := bcm.o -diff -N -u -r a/net/can/proc.c c/net/can/proc.c ---- a/net/can/proc.c 1970-01-01 01:00:00.000000000 +0100 -+++ c/net/can/proc.c 2007-03-09 13:47:12.000000000 +0100 -@@ -0,0 +1,663 @@ -+/* -+ * proc.c - procfs support for Protocol family CAN core module -+ * -+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research -+ * 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, the following disclaimer and -+ * the referenced file 'COPYING'. -+ * 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. Neither the name of Volkswagen nor the names of its contributors -+ * may be used to endorse or promote products derived from this software -+ * without specific prior written permission. -+ * -+ * Alternatively, provided that this notice is retained in full, this -+ * software may be distributed under the terms of the GNU General -+ * Public License ("GPL") version 2 as distributed in the 'COPYING' -+ * file from the main directory of the linux kernel source. -+ * -+ * The provided data structures and external interfaces from this code -+ * are not restricted to be used by modules with a GPL compatible license. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT -+ * OWNER 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. -+ * -+ * Send feedback to -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include "af_can.h" -+ -+RCSID("$Id: proc.c 177 2007-03-08 11:02:43Z hartkopp $"); -+ -+/* proc filenames */ -+ -+#define CAN_PROC_VERSION "version" -+#define CAN_PROC_STATS "stats" -+#define CAN_PROC_RESET_STATS "reset_stats" -+#define CAN_PROC_RCVLIST_ALL "rcvlist_all" -+#define CAN_PROC_RCVLIST_FIL "rcvlist_fil" -+#define CAN_PROC_RCVLIST_INV "rcvlist_inv" -+#define CAN_PROC_RCVLIST_SFF "rcvlist_sff" -+#define CAN_PROC_RCVLIST_EFF "rcvlist_eff" -+#define CAN_PROC_RCVLIST_ERR "rcvlist_err" -+ -+static void can_init_stats(int caller); -+static void can_stat_update(unsigned long data); -+ -+static struct proc_dir_entry *can_create_proc_readentry(const char *name, -+ mode_t mode, read_proc_t* read_proc, void *data); -+static void can_remove_proc_readentry(const char *name); -+static unsigned long calc_rate(unsigned long oldjif, unsigned long newjif, -+ unsigned long count); -+ -+static int can_proc_read_version(char *page, char **start, off_t off, -+ int count, int *eof, void *data); -+static int can_proc_read_stats(char *page, char **start, off_t off, -+ int count, int *eof, void *data); -+static int can_proc_read_reset_stats(char *page, char **start, off_t off, -+ int count, int *eof, void *data); -+static int can_proc_read_rcvlist_all(char *page, char **start, off_t off, -+ int count, int *eof, void *data); -+static int can_proc_read_rcvlist_fil(char *page, char **start, off_t off, -+ int count, int *eof, void *data); -+static int can_proc_read_rcvlist_inv(char *page, char **start, off_t off, -+ int count, int *eof, void *data); -+static int can_proc_read_rcvlist_sff(char *page, char **start, off_t off, -+ int count, int *eof, void *data); -+static int can_proc_read_rcvlist_eff(char *page, char **start, off_t off, -+ int count, int *eof, void *data); -+static int can_proc_read_rcvlist_err(char *page, char **start, off_t off, -+ int count, int *eof, void *data); -+ -+static struct proc_dir_entry *can_dir = NULL; -+static struct proc_dir_entry *pde_version = NULL; -+static struct proc_dir_entry *pde_stats = NULL; -+static struct proc_dir_entry *pde_reset_stats = NULL; -+static struct proc_dir_entry *pde_rcvlist_all = NULL; -+static struct proc_dir_entry *pde_rcvlist_fil = NULL; -+static struct proc_dir_entry *pde_rcvlist_inv = NULL; -+static struct proc_dir_entry *pde_rcvlist_sff = NULL; -+static struct proc_dir_entry *pde_rcvlist_eff = NULL; -+static struct proc_dir_entry *pde_rcvlist_err = NULL; -+ -+struct timer_list stattimer; /* timer for statistics update */ -+ -+struct s_stats stats; /* statistics */ -+struct s_pstats pstats; -+ -+extern struct hlist_head rx_dev_list; /* rx dispatcher structures */ -+extern int stats_timer; /* module parameter. default: on */ -+ -+/**************************************************/ -+/* procfs init / remove */ -+/**************************************************/ -+ -+void can_init_proc(void) -+{ -+ -+ /* procfs init */ -+ -+ /* create /proc/can directory */ -+ can_dir = proc_mkdir(CAN_PROC_DIR, NULL); -+ -+ if (!can_dir) { -+ printk(KERN_INFO "CAN: failed to create CAN_PROC_DIR. " -+ "CONFIG_PROC_FS missing?\n"); -+ return; -+ } -+ -+ can_dir->owner = THIS_MODULE; -+ -+ /* own procfs entries from the AF_CAN core */ -+ pde_version = can_create_proc_readentry( -+ CAN_PROC_VERSION, 0644, can_proc_read_version, NULL); -+ pde_stats = can_create_proc_readentry( -+ CAN_PROC_STATS, 0644, can_proc_read_stats, NULL); -+ pde_reset_stats = can_create_proc_readentry( -+ CAN_PROC_RESET_STATS, 0644, can_proc_read_reset_stats, NULL); -+ pde_rcvlist_all = can_create_proc_readentry( -+ CAN_PROC_RCVLIST_ALL, 0644, can_proc_read_rcvlist_all, NULL); -+ pde_rcvlist_fil = can_create_proc_readentry( -+ CAN_PROC_RCVLIST_FIL, 0644, can_proc_read_rcvlist_fil, NULL); -+ pde_rcvlist_inv = can_create_proc_readentry( -+ CAN_PROC_RCVLIST_INV, 0644, can_proc_read_rcvlist_inv, NULL); -+ pde_rcvlist_sff = can_create_proc_readentry( -+ CAN_PROC_RCVLIST_SFF, 0644, can_proc_read_rcvlist_sff, NULL); -+ pde_rcvlist_eff = can_create_proc_readentry( -+ CAN_PROC_RCVLIST_EFF, 0644, can_proc_read_rcvlist_eff, NULL); -+ pde_rcvlist_err = can_create_proc_readentry( -+ CAN_PROC_RCVLIST_ERR, 0644, can_proc_read_rcvlist_err, NULL); -+ -+ if (stats_timer) { -+ /* the statistics are updated every second (timer triggered) */ -+ stattimer.function = can_stat_update; -+ stattimer.data = 0; -+ stattimer.expires = jiffies + HZ; /* every second */ -+ add_timer(&stattimer); /* start statistics timer */ -+ } -+} -+ -+void can_remove_proc(void) -+{ -+ /* procfs remove */ -+ if (pde_version) -+ can_remove_proc_readentry(CAN_PROC_VERSION); -+ -+ if (pde_stats) -+ can_remove_proc_readentry(CAN_PROC_STATS); -+ -+ if (pde_reset_stats) -+ can_remove_proc_readentry(CAN_PROC_RESET_STATS); -+ -+ if (pde_rcvlist_all) -+ can_remove_proc_readentry(CAN_PROC_RCVLIST_ALL); -+ -+ if (pde_rcvlist_fil) -+ can_remove_proc_readentry(CAN_PROC_RCVLIST_FIL); -+ -+ if (pde_rcvlist_inv) -+ can_remove_proc_readentry(CAN_PROC_RCVLIST_INV); -+ -+ if (pde_rcvlist_sff) -+ can_remove_proc_readentry(CAN_PROC_RCVLIST_SFF); -+ -+ if (pde_rcvlist_eff) -+ can_remove_proc_readentry(CAN_PROC_RCVLIST_EFF); -+ -+ if (pde_rcvlist_err) -+ can_remove_proc_readentry(CAN_PROC_RCVLIST_ERR); -+ -+ if (can_dir) -+ remove_proc_entry(CAN_PROC_DIR, NULL); -+} -+ -+/**************************************************/ -+/* proc read functions */ -+/**************************************************/ -+ -+static int can_print_rcvlist(char *page, int len, struct hlist_head *rx_list, -+ struct net_device *dev) -+{ -+ struct receiver *r; -+ struct hlist_node *n; -+ -+ rcu_read_lock(); -+ hlist_for_each_entry_rcu(r, n, rx_list, list) { -+ char *fmt = r->can_id & CAN_EFF_FLAG ? /* EFF & CAN_ID_ALL */ -+ " %-5s %08X %08x %08x %08x %8ld %s\n" : -+ " %-5s %03X %08x %08x %08x %8ld %s\n"; -+ -+ len += snprintf(page + len, PAGE_SIZE - len, fmt, -+ DNAME(dev), r->can_id, r->mask, -+ (unsigned int)r->func, (unsigned int)r->data, -+ r->matches, r->ident); -+ -+ /* does a typical line fit into the current buffer? */ -+ /* 100 Bytes before end of buffer */ -+ if (len > PAGE_SIZE - 100) { -+ /* mark output cut off */ -+ len += snprintf(page + len, PAGE_SIZE - len, -+ " (..)\n"); -+ break; -+ } -+ } -+ rcu_read_unlock(); -+ -+ return len; -+} -+ -+static int can_print_recv_banner(char *page, int len) -+{ -+ /* can1. 00000000 00000000 00000000 -+ ....... 0 tp20 */ -+ len += snprintf(page + len, PAGE_SIZE - len, -+ " device can_id can_mask function" -+ " userdata matches ident\n"); -+ -+ return len; -+} -+ -+static int can_proc_read_stats(char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int len = 0; -+ -+ len += snprintf(page + len, PAGE_SIZE - len, "\n"); -+ len += snprintf(page + len, PAGE_SIZE - len, -+ " %8ld transmitted frames (TXF)\n", stats.tx_frames); -+ len += snprintf(page + len, PAGE_SIZE - len, -+ " %8ld received frames (RXF)\n", stats.rx_frames); -+ len += snprintf(page + len, PAGE_SIZE - len, -+ " %8ld matched frames (RXMF)\n", stats.matches); -+ -+ len += snprintf(page + len, PAGE_SIZE - len, "\n"); -+ -+ len += snprintf(page + len, PAGE_SIZE - len, -+ " %8ld %% total match ratio (RXMR)\n", -+ stats.total_rx_match_ratio); -+ -+ len += snprintf(page + len, PAGE_SIZE - len, -+ " %8ld frames/s total tx rate (TXR)\n", -+ stats.total_tx_rate); -+ len += snprintf(page + len, PAGE_SIZE - len, -+ " %8ld frames/s total rx rate (RXR)\n", -+ stats.total_rx_rate); -+ -+ len += snprintf(page + len, PAGE_SIZE - len, "\n"); -+ -+ len += snprintf(page + len, PAGE_SIZE - len, -+ " %8ld %% current match ratio (CRXMR)\n", -+ stats.current_rx_match_ratio); -+ -+ len += snprintf(page + len, PAGE_SIZE - len, -+ " %8ld frames/s current tx rate (CTXR)\n", -+ stats.current_tx_rate); -+ len += snprintf(page + len, PAGE_SIZE - len, -+ " %8ld frames/s current rx rate (CRXR)\n", -+ stats.current_rx_rate); -+ -+ len += snprintf(page + len, PAGE_SIZE - len, "\n"); -+ -+ len += snprintf(page + len, PAGE_SIZE - len, -+ " %8ld %% max match ratio (MRXMR)\n", -+ stats.max_rx_match_ratio); -+ -+ len += snprintf(page + len, PAGE_SIZE - len, -+ " %8ld frames/s max tx rate (MTXR)\n", -+ stats.max_tx_rate); -+ len += snprintf(page + len, PAGE_SIZE - len, -+ " %8ld frames/s max rx rate (MRXR)\n", -+ stats.max_rx_rate); -+ -+ len += snprintf(page + len, PAGE_SIZE - len, "\n"); -+ -+ len += snprintf(page + len, PAGE_SIZE - len, -+ " %8ld current receive list entries (CRCV)\n", -+ pstats.rcv_entries); -+ len += snprintf(page + len, PAGE_SIZE - len, -+ " %8ld maximum receive list entries (MRCV)\n", -+ pstats.rcv_entries_max); -+ -+ if (pstats.stats_reset) -+ len += snprintf(page + len, PAGE_SIZE - len, -+ "\n %8ld statistic resets (STR)\n", -+ pstats.stats_reset); -+ -+ len += snprintf(page + len, PAGE_SIZE - len, "\n"); -+ -+ *eof = 1; -+ return len; -+} -+ -+static int can_proc_read_reset_stats(char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int len = 0; -+ -+ can_init_stats(1); -+ -+ len += snprintf(page + len, PAGE_SIZE - len, -+ "CAN statistic reset #%ld done.\n", -+ pstats.stats_reset); -+ -+ *eof = 1; -+ return len; -+} -+ -+static int can_proc_read_version(char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int len = 0; -+ -+ len += snprintf(page + len, PAGE_SIZE - len, -+ "%06X [ Volkswagen Group - Low Level CAN Framework" -+ " (LLCF) v%s ]\n", LLCF_VERSION_CODE, VERSION); -+ *eof = 1; -+ return len; -+} -+ -+static int can_proc_read_rcvlist_all(char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int len = 0; -+ struct dev_rcv_lists *d; -+ struct hlist_node *n; -+ -+ /* RX_ALL */ -+ len += snprintf(page + len, PAGE_SIZE - len, -+ "\nreceive list 'rx_all':\n"); -+ -+ /* find receive list for this device */ -+ rcu_read_lock(); -+ hlist_for_each_entry_rcu(d, n, &rx_dev_list, list) { -+ -+ if (!hlist_empty(&d->rx_all)) { -+ len = can_print_recv_banner(page, len); -+ len = can_print_rcvlist(page, len, &d->rx_all, d->dev); -+ } else -+ len += snprintf(page + len, PAGE_SIZE - len, -+ " (%s: no entry)\n", DNAME(d->dev)); -+ -+ if (len > PAGE_SIZE - 100) -+ break; /* exit on end of buffer */ -+ } -+ rcu_read_unlock(); -+ -+ len += snprintf(page + len, PAGE_SIZE - len, "\n"); -+ -+ *eof = 1; -+ return len; -+} -+ -+static int can_proc_read_rcvlist_fil(char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int len = 0; -+ struct dev_rcv_lists *d; -+ struct hlist_node *n; -+ -+ /* RX_FIL */ -+ len += snprintf(page + len, PAGE_SIZE - len, -+ "\nreceive list 'rx_fil':\n"); -+ -+ /* find receive list for this device */ -+ rcu_read_lock(); -+ hlist_for_each_entry_rcu(d, n, &rx_dev_list, list) { -+ -+ if (!hlist_empty(&d->rx_fil)) { -+ len = can_print_recv_banner(page, len); -+ len = can_print_rcvlist(page, len, &d->rx_fil, d->dev); -+ } else -+ len += snprintf(page + len, PAGE_SIZE - len, -+ " (%s: no entry)\n", DNAME(d->dev)); -+ -+ if (len > PAGE_SIZE - 100) -+ break; /* exit on end of buffer */ -+ } -+ rcu_read_unlock(); -+ -+ len += snprintf(page + len, PAGE_SIZE - len, "\n"); -+ -+ *eof = 1; -+ return len; -+} -+ -+static int can_proc_read_rcvlist_inv(char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int len = 0; -+ struct dev_rcv_lists *d; -+ struct hlist_node *n; -+ -+ /* RX_INV */ -+ len += snprintf(page + len, PAGE_SIZE - len, -+ "\nreceive list 'rx_inv':\n"); -+ -+ /* find receive list for this device */ -+ rcu_read_lock(); -+ hlist_for_each_entry_rcu(d, n, &rx_dev_list, list) { -+ -+ if (!hlist_empty(&d->rx_inv)) { -+ len = can_print_recv_banner(page, len); -+ len = can_print_rcvlist(page, len, &d->rx_inv, d->dev); -+ } else -+ len += snprintf(page + len, PAGE_SIZE - len, -+ " (%s: no entry)\n", DNAME(d->dev)); -+ -+ if (len > PAGE_SIZE - 100) -+ break; /* exit on end of buffer */ -+ } -+ rcu_read_unlock(); -+ -+ len += snprintf(page + len, PAGE_SIZE - len, "\n"); -+ -+ *eof = 1; -+ return len; -+} -+ -+static int can_proc_read_rcvlist_sff(char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int len = 0; -+ struct dev_rcv_lists *d; -+ struct hlist_node *n; -+ -+ /* RX_SFF */ -+ len += snprintf(page + len, PAGE_SIZE - len, -+ "\nreceive list 'rx_sff':\n"); -+ -+ /* find receive list for this device */ -+ rcu_read_lock(); -+ hlist_for_each_entry_rcu(d, n, &rx_dev_list, list) { -+ int i, all_empty = 1; -+ /* check wether at least one list is non-empty */ -+ for (i = 0; i < 0x800; i++) -+ if (!hlist_empty(&d->rx_sff[i])) { -+ all_empty = 0; -+ break; -+ } -+ -+ if (!all_empty) { -+ len = can_print_recv_banner(page, len); -+ for (i = 0; i < 0x800; i++) { -+ if (!hlist_empty(&d->rx_sff[i]) && -+ len < PAGE_SIZE - 100) -+ len = can_print_rcvlist(page, len, -+ &d->rx_sff[i], -+ d->dev); -+ } -+ } else -+ len += snprintf(page + len, PAGE_SIZE - len, -+ " (%s: no entry)\n", DNAME(d->dev)); -+ -+ if (len > PAGE_SIZE - 100) -+ break; /* exit on end of buffer */ -+ } -+ rcu_read_unlock(); -+ -+ len += snprintf(page + len, PAGE_SIZE - len, "\n"); -+ -+ *eof = 1; -+ return len; -+} -+ -+static int can_proc_read_rcvlist_eff(char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int len = 0; -+ struct dev_rcv_lists *d; -+ struct hlist_node *n; -+ -+ /* RX_EFF */ -+ len += snprintf(page + len, PAGE_SIZE - len, -+ "\nreceive list 'rx_eff':\n"); -+ -+ /* find receive list for this device */ -+ rcu_read_lock(); -+ hlist_for_each_entry_rcu(d, n, &rx_dev_list, list) { -+ -+ if (!hlist_empty(&d->rx_eff)) { -+ len = can_print_recv_banner(page, len); -+ len = can_print_rcvlist(page, len, &d->rx_eff, d->dev); -+ } else -+ len += snprintf(page + len, PAGE_SIZE - len, -+ " (%s: no entry)\n", DNAME(d->dev)); -+ -+ if (len > PAGE_SIZE - 100) -+ break; /* exit on end of buffer */ -+ } -+ rcu_read_unlock(); -+ -+ len += snprintf(page + len, PAGE_SIZE - len, "\n"); -+ -+ *eof = 1; -+ return len; -+} -+ -+static int can_proc_read_rcvlist_err(char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int len = 0; -+ struct dev_rcv_lists *d; -+ struct hlist_node *n; -+ -+ /* RX_ERR */ -+ len += snprintf(page + len, PAGE_SIZE - len, -+ "\nreceive list 'rx_err':\n"); -+ -+ /* find receive list for this device */ -+ rcu_read_lock(); -+ hlist_for_each_entry_rcu(d, n, &rx_dev_list, list) { -+ -+ if (!hlist_empty(&d->rx_err)) { -+ len = can_print_recv_banner(page, len); -+ len = can_print_rcvlist(page, len, &d->rx_err, d->dev); -+ } else -+ len += snprintf(page + len, PAGE_SIZE - len, -+ " (%s: no entry)\n", DNAME(d->dev)); -+ -+ if (len > PAGE_SIZE - 100) -+ break; /* exit on end of buffer */ -+ } -+ rcu_read_unlock(); -+ -+ len += snprintf(page + len, PAGE_SIZE - len, "\n"); -+ -+ *eof = 1; -+ return len; -+} -+ -+/**************************************************/ -+/* proc utility functions */ -+/**************************************************/ -+ -+static struct proc_dir_entry *can_create_proc_readentry(const char *name, -+ mode_t mode, -+ read_proc_t* read_proc, -+ void *data) -+{ -+ if (can_dir) -+ return create_proc_read_entry(name, mode, can_dir, read_proc, -+ data); -+ else -+ return NULL; -+} -+ -+static void can_remove_proc_readentry(const char *name) -+{ -+ if (can_dir) -+ remove_proc_entry(name, can_dir); -+} -+ -+static unsigned long calc_rate(unsigned long oldjif, unsigned long newjif, -+ unsigned long count) -+{ -+ unsigned long ret = 0; -+ -+ if (oldjif == newjif) -+ return 0; -+ -+ /* see can_rcv() - this should NEVER happen! */ -+ if (count > (ULONG_MAX / HZ)) { -+ printk(KERN_ERR "CAN: calc_rate: count exceeded! %ld\n", -+ count); -+ return 99999999; -+ } -+ -+ ret = (count * HZ) / (newjif - oldjif); -+ -+ return ret; -+} -+ -+/**************************************************/ -+/* af_can statistics stuff */ -+/**************************************************/ -+ -+static void can_init_stats(int caller) -+{ -+ memset(&stats, 0, sizeof(stats)); -+ stats.jiffies_init = jiffies; -+ pstats.stats_reset++; -+} -+ -+static void can_stat_update(unsigned long data) -+{ -+ unsigned long j = jiffies; /* snapshot */ -+ -+ //DBG("CAN: can_stat_update() jiffies = %ld\n", j); -+ -+ if (j < stats.jiffies_init) /* jiffies overflow */ -+ can_init_stats(2); -+ -+ /* stats.rx_frames is the definitively max. statistic value */ -+ -+ /* prevent overflow in calc_rate() */ -+ if (stats.rx_frames > (ULONG_MAX / HZ)) -+ can_init_stats(3); /* restart */ -+ -+ /* matches overflow - very improbable */ -+ if (stats.matches > (ULONG_MAX / 100)) -+ can_init_stats(4); -+ -+ /* calc total values */ -+ if (stats.rx_frames) -+ stats.total_rx_match_ratio = (stats.matches * 100) / -+ stats.rx_frames; -+ -+ stats.total_tx_rate = calc_rate(stats.jiffies_init, j, -+ stats.tx_frames); -+ stats.total_rx_rate = calc_rate(stats.jiffies_init, j, -+ stats.rx_frames); -+ -+ /* calc current values */ -+ if (stats.rx_frames_delta) -+ stats.current_rx_match_ratio = -+ (stats.matches_delta * 100) / stats.rx_frames_delta; -+ -+ stats.current_tx_rate = calc_rate(0, HZ, stats.tx_frames_delta); -+ stats.current_rx_rate = calc_rate(0, HZ, stats.rx_frames_delta); -+ -+ /* check / update maximum values */ -+ if (stats.max_tx_rate < stats.current_tx_rate) -+ stats.max_tx_rate = stats.current_tx_rate; -+ -+ if (stats.max_rx_rate < stats.current_rx_rate) -+ stats.max_rx_rate = stats.current_rx_rate; -+ -+ if (stats.max_rx_match_ratio < stats.current_rx_match_ratio) -+ stats.max_rx_match_ratio = stats.current_rx_match_ratio; -+ -+ /* clear values for 'current rate' calculation */ -+ stats.tx_frames_delta = 0; -+ stats.rx_frames_delta = 0; -+ stats.matches_delta = 0; -+ -+ /* restart timer */ -+ stattimer.expires = jiffies + HZ; /* every second */ -+ add_timer(&stattimer); -+} -diff -N -u -r a/net/can/raw.c c/net/can/raw.c ---- a/net/can/raw.c 1970-01-01 01:00:00.000000000 +0100 -+++ c/net/can/raw.c 2007-03-09 17:27:37.000000000 +0100 -@@ -0,0 +1,724 @@ -+/* -+ * raw.c - Raw sockets for protocol family CAN -+ * -+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research -+ * 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, the following disclaimer and -+ * the referenced file 'COPYING'. -+ * 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. Neither the name of Volkswagen nor the names of its contributors -+ * may be used to endorse or promote products derived from this software -+ * without specific prior written permission. -+ * -+ * Alternatively, provided that this notice is retained in full, this -+ * software may be distributed under the terms of the GNU General -+ * Public License ("GPL") version 2 as distributed in the 'COPYING' -+ * file from the main directory of the linux kernel source. -+ * -+ * The provided data structures and external interfaces from this code -+ * are not restricted to be used by modules with a GPL compatible license. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT -+ * OWNER 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. -+ * -+ * Send feedback to -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+RCSID("$Id: raw.c 177 2007-03-08 11:02:43Z hartkopp $"); -+ -+#define IDENT "raw" -+static __initdata const char banner[] = KERN_INFO "CAN: raw socket protocol" -+ " " VERSION "\n"; -+ -+MODULE_DESCRIPTION("PF_CAN raw sockets"); -+MODULE_LICENSE("Dual BSD/GPL"); -+MODULE_AUTHOR("Urs Thuermann "); -+ -+#ifdef CONFIG_CAN_DEBUG_CORE -+static int debug = 0; -+module_param(debug, int, S_IRUGO); -+#define DBG(args...) (debug & 1 ? \ -+ (printk(KERN_DEBUG "RAW %s: ", __func__), \ -+ printk(args)) : 0) -+#define DBG_SKB(skb) (debug & 4 ? can_debug_skb(skb) : 0) -+#else -+#define DBG(args...) -+#define DBG_SKB(skb) -+#endif -+ -+static int raw_init(struct sock *sk); -+static int raw_release(struct socket *sock); -+static int raw_bind (struct socket *sock, struct sockaddr *uaddr, int len); -+static int raw_getname(struct socket *sock, struct sockaddr *uaddr, -+ int *len, int peer); -+static unsigned int raw_poll(struct file *file, struct socket *sock, -+ poll_table *wait); -+static int raw_setsockopt(struct socket *sock, int level, int optname, -+ char __user *optval, int optlen); -+static int raw_getsockopt(struct socket *sock, int level, int optname, -+ char __user *optval, int __user *optlen); -+static int raw_sendmsg(struct kiocb *iocb, struct socket *sock, -+ struct msghdr *msg, size_t size); -+static int raw_recvmsg(struct kiocb *iocb, struct socket *sock, -+ struct msghdr *msg, size_t size, int flags); -+static void raw_rcv(struct sk_buff *skb, void *data); -+static void raw_notifier(unsigned long msg, void *data); -+ -+static void raw_add_filters(struct net_device *dev, struct sock *sk); -+static void raw_remove_filters(struct net_device *dev, struct sock *sk); -+ -+ -+static struct proto_ops raw_ops = { -+ .family = PF_CAN, -+ .release = raw_release, -+ .bind = raw_bind, -+ .connect = sock_no_connect, -+ .socketpair = sock_no_socketpair, -+ .accept = sock_no_accept, -+ .getname = raw_getname, -+ .poll = raw_poll, -+ .ioctl = NULL, /* use can_ioctl() from af_can.c */ -+ .listen = sock_no_listen, -+ .shutdown = sock_no_shutdown, -+ .setsockopt = raw_setsockopt, -+ .getsockopt = raw_getsockopt, -+ .sendmsg = raw_sendmsg, -+ .recvmsg = raw_recvmsg, -+ .mmap = sock_no_mmap, -+ .sendpage = sock_no_sendpage, -+}; -+ -+ -+/* A raw socket has a list of can_filters attached to it, each receiving -+ the CAN frames matching that filter. If the filter list is empty, -+ no CAN frames will be received by the socket. The default after -+ opening the socket, is to have one filter which receives all frames. -+ The filter list is allocated dynamically with the exception of the -+ list containing only one item. This common case is optimized by -+ storing the single filter in dfilter, to avoid using dynamic memory. -+*/ -+ -+struct raw_opt { -+ int bound; -+ int ifindex; -+ int loopback; -+ int recv_own_msgs; -+ int count; /* number of active filters */ -+ struct can_filter dfilter; /* default/single filter */ -+ struct can_filter *filter; /* pointer to filter(s) */ -+ can_err_mask_t err_mask; -+}; -+ -+#ifdef CONFIG_CAN_RAW_USER -+#define RAW_CAP (-1) -+#else -+#define RAW_CAP CAP_NET_RAW -+#endif -+ -+#undef CAN_RAW_SUPPORT_REBIND /* use bind on already bound socket */ -+ -+struct raw_sock { -+ struct sock sk; -+ struct raw_opt opt; -+}; -+ -+#define raw_sk(sk) (&((struct raw_sock *)(sk))->opt) -+ -+static struct proto raw_proto = { -+ .name = "CAN_RAW", -+ .owner = THIS_MODULE, -+ .obj_size = sizeof(struct raw_sock), -+ .init = raw_init, -+}; -+ -+static struct can_proto raw_can_proto = { -+ .type = SOCK_RAW, -+ .protocol = CAN_RAW, -+ .capability = RAW_CAP, -+ .ops = &raw_ops, -+ .prot = &raw_proto, -+}; -+ -+#define MASK_ALL 0 -+ -+static __init int raw_module_init(void) -+{ -+ printk(banner); -+ -+ can_proto_register(&raw_can_proto); -+ return 0; -+} -+ -+static __exit void raw_module_exit(void) -+{ -+ can_proto_unregister(&raw_can_proto); -+} -+ -+static int raw_init(struct sock *sk) -+{ -+ struct raw_opt *ro = raw_sk(sk); -+ -+ ro->bound = 0; -+ -+ /* set default filter to single entry dfilter */ -+ ro->dfilter.can_id = 0; -+ ro->dfilter.can_mask = MASK_ALL; -+ ro->filter = &ro->dfilter; -+ ro->count = 1; -+ -+ /* set default loopback behaviour */ -+ ro->loopback = 1; -+ ro->recv_own_msgs = 0; -+ -+ return 0; -+} -+ -+static int raw_release(struct socket *sock) -+{ -+ struct sock *sk = sock->sk; -+ struct raw_opt *ro = raw_sk(sk); -+ struct net_device *dev = NULL; -+ -+ DBG("socket %p, sk %p, refcnt %d\n", sock, sk, -+ atomic_read(&sk->sk_refcnt)); -+ -+ if (ro->bound && ro->ifindex) -+ dev = dev_get_by_index(ro->ifindex); -+ -+ /* remove current filters & unregister */ -+ if (ro->bound) -+ raw_remove_filters(dev, sk); -+ if (ro->count > 1) -+ kfree(ro->filter); -+ -+ /* remove current error mask */ -+ if (ro->err_mask && ro->bound) -+ can_rx_unregister(dev, 0, ro->err_mask | CAN_ERR_FLAG, -+ raw_rcv, sk); -+ -+ if (dev) { -+ can_dev_unregister(dev, raw_notifier, sk); -+ dev_put(dev); -+ } -+ -+ sock_put(sk); -+ -+ return 0; -+} -+ -+static int raw_bind(struct socket *sock, struct sockaddr *uaddr, int len) -+{ -+ struct sockaddr_can *addr = (struct sockaddr_can *)uaddr; -+ struct sock *sk = sock->sk; -+ struct raw_opt *ro = raw_sk(sk); -+ struct net_device *dev; -+ -+ DBG("socket %p to device %d\n", sock, addr->can_ifindex); -+ -+ if (len < sizeof(*addr)) -+ return -EINVAL; -+ -+ if (ro->bound) { -+#ifdef CAN_RAW_SUPPORT_REBIND -+ /* remove current bindings / notifier */ -+ if (ro->ifindex) { -+ dev = dev_get_by_index(ro->ifindex); -+ if (!dev) { -+ DBG("could not find device %d\n", -+ addr->can_ifindex); -+ return -ENODEV; -+ } -+ if (!(dev->flags & IFF_UP)) { -+ sk->sk_err = ENETDOWN; -+ if (!sock_flag(sk, SOCK_DEAD)) -+ sk->sk_error_report(sk); -+ goto out; -+ } -+ can_dev_unregister(dev, raw_notifier, sk); -+ } else -+ dev = NULL; -+ -+ /* unregister current filters for this device */ -+ raw_remove_filters(dev, sk); -+ -+ if (dev) -+ dev_put(dev); -+ -+ ro->bound = 0; -+#else -+ return -EINVAL; -+#endif -+ } -+ -+ if (addr->can_ifindex) { -+ dev = dev_get_by_index(addr->can_ifindex); -+ if (!dev) { -+ DBG("could not find device %d\n", addr->can_ifindex); -+ return -ENODEV; -+ } -+ if (!(dev->flags & IFF_UP)) { -+ sk->sk_err = ENETDOWN; -+ if (!sock_flag(sk, SOCK_DEAD)) -+ sk->sk_error_report(sk); -+ goto out; -+ } -+ can_dev_register(dev, raw_notifier, sk); -+ } else -+ dev = NULL; -+ -+ ro->ifindex = addr->can_ifindex; -+ -+ raw_add_filters(dev, sk); /* filters set by default/setsockopt */ -+ -+ if (ro->err_mask) /* error frame filter set by setsockopt */ -+ can_rx_register(dev, 0, ro->err_mask | CAN_ERR_FLAG, -+ raw_rcv, sk, IDENT); -+ -+ ro->bound = 1; -+ -+ out: -+ if (dev) -+ dev_put(dev); -+ -+ return 0; -+} -+ -+static int raw_getname(struct socket *sock, struct sockaddr *uaddr, -+ int *len, int peer) -+{ -+ struct sockaddr_can *addr = (struct sockaddr_can *)uaddr; -+ struct sock *sk = sock->sk; -+ struct raw_opt *ro = raw_sk(sk); -+ -+ if (peer) -+ return -EOPNOTSUPP; -+ -+ addr->can_family = AF_CAN; -+ addr->can_ifindex = ro->ifindex; -+ *len = sizeof(*addr); -+ -+ return 0; -+} -+ -+static unsigned int raw_poll(struct file *file, struct socket *sock, -+ poll_table *wait) -+{ -+ unsigned int mask = 0; -+ -+ DBG("socket %p\n", sock); -+ -+ mask = datagram_poll(file, sock, wait); -+ return mask; -+} -+ -+static int raw_setsockopt(struct socket *sock, int level, int optname, -+ char __user *optval, int optlen) -+{ -+ struct sock *sk = sock->sk; -+ struct raw_opt *ro = raw_sk(sk); -+ struct can_filter *filter = NULL; /* dyn. alloc'ed filters */ -+ struct can_filter sfilter; /* single filter */ -+ struct net_device *dev = NULL; -+ can_err_mask_t err_mask = 0; -+ int count = 0; -+ int err; -+ -+ if (level != SOL_CAN_RAW) -+ return -EINVAL; -+ -+ switch (optname) { -+ case CAN_RAW_FILTER: -+ if (optlen % sizeof(struct can_filter) != 0) -+ return -EINVAL; -+ -+ count = optlen / sizeof(struct can_filter); -+ -+ if (count > 1) { /* does not fit into dfilter */ -+ if (!(filter = kmalloc(optlen, GFP_KERNEL))) -+ return -ENOMEM; -+ if ((err = copy_from_user(filter, optval, optlen))) { -+ kfree(filter); -+ return err; -+ } -+ } else if (count == 1) { -+ if ((err = copy_from_user(&sfilter, optval, optlen))) -+ return err; -+ } -+ -+ if (ro->bound && ro->ifindex) -+ dev = dev_get_by_index(ro->ifindex); -+ -+ /* remove current filters & unregister */ -+ if (ro->bound) -+ raw_remove_filters(dev, sk); -+ if (ro->count > 1) -+ kfree(ro->filter); -+ -+ if (count == 1) { /* copy data for single filter */ -+ ro->dfilter = sfilter; -+ filter = &ro->dfilter; -+ } -+ -+ /* add new filters & register */ -+ ro->filter = filter; -+ ro->count = count; -+ if (ro->bound) -+ raw_add_filters(dev, sk); -+ -+ if (dev) -+ dev_put(dev); -+ -+ break; -+ -+ case CAN_RAW_ERR_FILTER: -+ if (optlen != sizeof(err_mask)) -+ return -EINVAL; -+ if ((err = copy_from_user(&err_mask, optval, optlen))) -+ return err; -+ -+ err_mask &= CAN_ERR_MASK; -+ -+ if (ro->bound && ro->ifindex) -+ dev = dev_get_by_index(ro->ifindex); -+ -+ /* remove current error mask */ -+ if (ro->err_mask && ro->bound) -+ can_rx_unregister(dev, 0, ro->err_mask | CAN_ERR_FLAG, -+ raw_rcv, sk); -+ -+ /* add new error mask */ -+ ro->err_mask = err_mask; -+ if (ro->err_mask && ro->bound) -+ can_rx_register(dev, 0, ro->err_mask | CAN_ERR_FLAG, -+ raw_rcv, sk, IDENT); -+ -+ if (dev) -+ dev_put(dev); -+ -+ break; -+ -+ case CAN_RAW_LOOPBACK: -+ if (optlen != sizeof(ro->loopback)) -+ return -EINVAL; -+ if ((err = copy_from_user(&ro->loopback, optval, optlen))) -+ return err; -+ break; -+ -+ case CAN_RAW_RECV_OWN_MSGS: -+ if (optlen != sizeof(ro->recv_own_msgs)) -+ return -EINVAL; -+ if ((err = copy_from_user(&ro->recv_own_msgs, optval, optlen))) -+ return err; -+ break; -+ -+ default: -+ return -ENOPROTOOPT; -+ } -+ return 0; -+} -+ -+static int raw_getsockopt(struct socket *sock, int level, int optname, -+ char __user *optval, int __user *optlen) -+{ -+ struct sock *sk = sock->sk; -+ struct raw_opt *ro = raw_sk(sk); -+ struct can_filter *filter = ro->filter; -+ int count = ro->count; -+ int len; -+ -+ if (level != SOL_CAN_RAW) -+ return -EINVAL; -+ -+ switch (optname) { -+ case CAN_RAW_FILTER: -+ if (get_user(len, optlen)) -+ return -EFAULT; -+ -+ if (count && filter) { -+ int filter_size = count * sizeof(struct can_filter); -+ if (len < filter_size) -+ return -EINVAL; -+ if (len > filter_size) -+ len = filter_size; -+ if (copy_to_user(optval, filter, len)) -+ return -EFAULT; -+ } else -+ len = 0; -+ -+ if (put_user(len, optlen)) -+ return -EFAULT; -+ -+ break; -+ -+ case CAN_RAW_ERR_FILTER: -+ if (get_user(len, optlen)) -+ return -EFAULT; -+ -+ if (len < sizeof(can_err_mask_t)) -+ return -EINVAL; -+ -+ if (len > sizeof(can_err_mask_t)) -+ len = sizeof(can_err_mask_t); -+ -+ if (copy_to_user(optval, &ro->err_mask, len)) -+ return -EFAULT; -+ -+ if (put_user(len, optlen)) -+ return -EFAULT; -+ -+ break; -+ -+ case CAN_RAW_LOOPBACK: -+ if (get_user(len, optlen)) -+ return -EFAULT; -+ -+ if (len < sizeof(int)) -+ return -EINVAL; -+ -+ if (len > sizeof(int)) -+ len = sizeof(int); -+ -+ if (copy_to_user(optval, &ro->loopback, len)) -+ return -EFAULT; -+ -+ if (put_user(len, optlen)) -+ return -EFAULT; -+ -+ break; -+ -+ case CAN_RAW_RECV_OWN_MSGS: -+ if (get_user(len, optlen)) -+ return -EFAULT; -+ -+ if (len < sizeof(int)) -+ return -EINVAL; -+ -+ if (len > sizeof(int)) -+ len = sizeof(int); -+ -+ if (copy_to_user(optval, &ro->recv_own_msgs, len)) -+ return -EFAULT; -+ -+ if (put_user(len, optlen)) -+ return -EFAULT; -+ -+ break; -+ -+ default: -+ return -ENOPROTOOPT; -+ } -+ return 0; -+} -+ -+static void raw_add_filters(struct net_device *dev, struct sock *sk) -+{ -+ struct raw_opt *ro = raw_sk(sk); -+ struct can_filter *filter = ro->filter; -+ int i; -+ -+ for (i = 0; i < ro->count; i++) { -+ can_rx_register(dev, filter[i].can_id, filter[i].can_mask, -+ raw_rcv, sk, IDENT); -+ DBG("filter can_id %08X, can_mask %08X%s, sk %p\n", -+ filter[i].can_id, filter[i].can_mask, -+ filter[i].can_id & CAN_INV_FILTER ? " (inv)" : "", sk); -+ } -+} -+ -+static void raw_remove_filters(struct net_device *dev, struct sock *sk) -+{ -+ struct raw_opt *ro = raw_sk(sk); -+ struct can_filter *filter = ro->filter; -+ int i; -+ -+ for (i = 0; i < ro->count; i++) { -+ can_rx_unregister(dev, filter[i].can_id, filter[i].can_mask, -+ raw_rcv, sk); -+ DBG("filter can_id %08X, can_mask %08X%s, sk %p\n", -+ filter[i].can_id, filter[i].can_mask, -+ filter[i].can_id & CAN_INV_FILTER ? " (inv)" : "", sk); -+ } -+} -+ -+static int raw_sendmsg(struct kiocb *iocb, struct socket *sock, -+ struct msghdr *msg, size_t size) -+{ -+ struct sock *sk = sock->sk; -+ struct raw_opt *ro = raw_sk(sk); -+ struct sk_buff *skb; -+ struct net_device *dev; -+ int ifindex; -+ int err; -+ -+ DBG("socket %p, sk %p\n", sock, sk); -+ -+ if (msg->msg_name) { -+ struct sockaddr_can *addr = -+ (struct sockaddr_can *)msg->msg_name; -+ if (addr->can_family != AF_CAN) -+ return -EINVAL; -+ ifindex = addr->can_ifindex; -+ } else -+ ifindex = ro->ifindex; -+ -+ if (!(dev = dev_get_by_index(ifindex))) { -+ DBG("device %d not found\n", ifindex); -+ return -ENXIO; -+ } -+ -+ if (!(skb = alloc_skb(size, GFP_KERNEL))) { -+ dev_put(dev); -+ return -ENOMEM; -+ } -+ -+ if ((err = memcpy_fromiovec(skb_put(skb, size), -+ msg->msg_iov, size)) < 0) { -+ kfree_skb(skb); -+ dev_put(dev); -+ return err; -+ } -+ skb->dev = dev; -+ skb->sk = sk; -+ -+ DBG("sending skbuff to interface %d\n", ifindex); -+ DBG_SKB(skb); -+ -+ err = can_send(skb, ro->loopback); -+ -+ dev_put(dev); -+ -+ if (err) -+ return err; -+ -+ return size; -+} -+ -+static int raw_recvmsg(struct kiocb *iocb, struct socket *sock, -+ struct msghdr *msg, size_t size, int flags) -+{ -+ struct sock *sk = sock->sk; -+ struct sk_buff *skb; -+ int error = 0; -+ int noblock; -+ -+ DBG("socket %p, sk %p\n", sock, sk); -+ -+ noblock = flags & MSG_DONTWAIT; -+ flags &= ~MSG_DONTWAIT; -+ -+ if (!(skb = skb_recv_datagram(sk, flags, noblock, &error))) -+ return error; -+ -+ DBG("delivering skbuff %p\n", skb); -+ DBG_SKB(skb); -+ -+ if (size < skb->len) -+ msg->msg_flags |= MSG_TRUNC; -+ else -+ size = skb->len; -+ -+ if ((error = memcpy_toiovec(msg->msg_iov, skb->data, size)) < 0) { -+ skb_free_datagram(sk, skb); -+ return error; -+ } -+ -+ sock_recv_timestamp(msg, sk, skb); -+ -+ if (msg->msg_name) { -+ msg->msg_namelen = sizeof(struct sockaddr_can); -+ memcpy(msg->msg_name, skb->cb, msg->msg_namelen); -+ } -+ -+ DBG("freeing sock %p, skbuff %p\n", sk, skb); -+ skb_free_datagram(sk, skb); -+ -+ return size; -+} -+ -+static void raw_rcv(struct sk_buff *skb, void *data) -+{ -+ struct sock *sk = (struct sock*)data; -+ struct raw_opt *ro = raw_sk(sk); -+ struct sockaddr_can *addr; -+ int error; -+ -+ DBG("received skbuff %p, sk %p\n", skb, sk); -+ DBG_SKB(skb); -+ -+ if (!ro->recv_own_msgs) { -+ if (*(struct sock **)skb->cb == sk) { /* tx sock reference */ -+ DBG("trashed own tx msg\n"); -+ kfree_skb(skb); -+ return; -+ } -+ } -+ -+ addr = (struct sockaddr_can *)skb->cb; -+ memset(addr, 0, sizeof(*addr)); -+ addr->can_family = AF_CAN; -+ addr->can_ifindex = skb->dev->ifindex; -+ -+ if ((error = sock_queue_rcv_skb(sk, skb)) < 0) { -+ DBG("sock_queue_rcv_skb failed: %d\n", error); -+ DBG("freeing skbuff %p\n", skb); -+ kfree_skb(skb); -+ } -+} -+ -+static void raw_notifier(unsigned long msg, void *data) -+{ -+ struct sock *sk = (struct sock *)data; -+ struct raw_opt *ro = raw_sk(sk); -+ -+ DBG("called for sock %p\n", sk); -+ -+ switch (msg) { -+ case NETDEV_UNREGISTER: -+ ro->ifindex = 0; -+ ro->bound = 0; -+ /* fallthrough */ -+ case NETDEV_DOWN: -+ sk->sk_err = ENETDOWN; -+ if (!sock_flag(sk, SOCK_DEAD)) -+ sk->sk_error_report(sk); -+ break; -+ } -+} -+ -+ -+module_init(raw_module_init); -+module_exit(raw_module_exit); -diff -N -u -r a/net/ipv6/addrconf.c c/net/ipv6/addrconf.c ---- a/net/ipv6/addrconf.c 2007-03-09 09:52:20.000000000 +0100 -+++ c/net/ipv6/addrconf.c 2007-03-09 13:39:10.000000000 +0100 -@@ -2178,6 +2178,10 @@ - struct inet6_dev *idev = __in6_dev_get(dev); - int run_pending = 0; - -+ /* more non ipv6 compatible dev types to skip here? */ -+ if (dev->type == ARPHRD_CAN) -+ return NOTIFY_OK; -+ - switch(event) { - case NETDEV_REGISTER: - if (!idev) { -diff -N -u -r a/net/Kconfig c/net/Kconfig ---- a/net/Kconfig 2007-03-09 09:52:18.000000000 +0100 -+++ c/net/Kconfig 2007-03-09 13:39:10.000000000 +0100 -@@ -217,6 +217,7 @@ - endmenu - - source "net/ax25/Kconfig" -+source "net/can/Kconfig" - source "net/irda/Kconfig" - source "net/bluetooth/Kconfig" - source "net/ieee80211/Kconfig" -diff -N -u -r a/net/Makefile c/net/Makefile ---- a/net/Makefile 2007-03-09 09:52:18.000000000 +0100 -+++ c/net/Makefile 2007-03-09 13:39:10.000000000 +0100 -@@ -34,6 +34,7 @@ - obj-$(CONFIG_NETROM) += netrom/ - obj-$(CONFIG_ROSE) += rose/ - obj-$(CONFIG_AX25) += ax25/ -+obj-$(CONFIG_CAN) += can/ - obj-$(CONFIG_IRDA) += irda/ - obj-$(CONFIG_BT) += bluetooth/ - obj-$(CONFIG_SUNRPC) += sunrpc/ -- 2.39.2