+++ /dev/null
-SUBJECT
-CAN: Add new PF_CAN protocol family, SVN r322
-ESUBJECT
-
-This patch series applies against linux-2.6.22-rc3 and is derived from
-Subversion revision r322 of http://svn.berlios.de/svnroot/repos/socketcan.
-It adds a new protocol family to Linux for communication on the CAN
-(Controller Area Network) using the socket API.
-
-The current implementation supports two protocols in the family, a raw
-protocol for sending and receiving raw CAN frames, and a broadcast
-manager protocol, which effeciently handles periodically sent
-broadcast messages, which are typical in CAN environments.
-
-There is also a virtual CAN network driver which only loops back sent
-CAN frames. Drivers for real CAN hardware are also being worked on
-and are nearly complete. These will be released later, or you can find
-them in the subversion repository at
-http://svn.berlios.de/svnroot/repos/socketcan.
-
-Additional information about the concepts of the CAN protocol family
-can be found in the file Documentation/networking/can.txt, added by
-patch 7/7.
-
-Userspace tools (can-utils) and test suites for the different CAN
-protocols can also be found in the subversion repository.
net/core/sock.c | 4 ++--
5 files changed, 8 insertions(+), 3 deletions(-)
-Index: linux-2.6.22-rc3/include/linux/if_arp.h
+Index: linux-2.6.22-rc5/include/linux/if_arp.h
===================================================================
---- linux-2.6.22-rc3.orig/include/linux/if_arp.h 2007-05-29 10:03:02.%N +0200
-+++ linux-2.6.22-rc3/include/linux/if_arp.h 2007-05-29 10:03:24.%N +0200
+--- linux-2.6.22-rc5.orig/include/linux/if_arp.h 2007-06-20 14:10:41.000000000 +0200
++++ linux-2.6.22-rc5/include/linux/if_arp.h 2007-06-20 14:11:00.000000000 +0200
@@ -52,6 +52,7 @@
#define ARPHRD_ROSE 270
#define ARPHRD_X25 271 /* CCITT X.25 */
#define ARPHRD_PPP 512
#define ARPHRD_CISCO 513 /* Cisco HDLC */
#define ARPHRD_HDLC ARPHRD_CISCO
-Index: linux-2.6.22-rc3/include/linux/if_ether.h
+Index: linux-2.6.22-rc5/include/linux/if_ether.h
===================================================================
---- linux-2.6.22-rc3.orig/include/linux/if_ether.h 2007-05-29 10:03:02.%N +0200
-+++ linux-2.6.22-rc3/include/linux/if_ether.h 2007-05-29 10:03:24.%N +0200
+--- linux-2.6.22-rc5.orig/include/linux/if_ether.h 2007-06-20 14:10:41.000000000 +0200
++++ linux-2.6.22-rc5/include/linux/if_ether.h 2007-06-20 14:11:00.000000000 +0200
@@ -90,6 +90,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_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) */
-Index: linux-2.6.22-rc3/include/linux/socket.h
+Index: linux-2.6.22-rc5/include/linux/socket.h
===================================================================
---- linux-2.6.22-rc3.orig/include/linux/socket.h 2007-05-29 10:03:02.%N +0200
-+++ linux-2.6.22-rc3/include/linux/socket.h 2007-05-29 10:03:24.%N +0200
+--- linux-2.6.22-rc5.orig/include/linux/socket.h 2007-06-20 14:10:41.000000000 +0200
++++ linux-2.6.22-rc5/include/linux/socket.h 2007-06-20 14:11:00.000000000 +0200
@@ -185,6 +185,7 @@
#define AF_PPPOX 24 /* PPPoX sockets */
#define AF_WANPIPE 25 /* Wanpipe API Sockets */
#define PF_TIPC AF_TIPC
#define PF_BLUETOOTH AF_BLUETOOTH
#define PF_IUCV AF_IUCV
-Index: linux-2.6.22-rc3/include/linux/tty.h
+Index: linux-2.6.22-rc5/include/linux/tty.h
===================================================================
---- linux-2.6.22-rc3.orig/include/linux/tty.h 2007-05-29 10:03:02.%N +0200
-+++ linux-2.6.22-rc3/include/linux/tty.h 2007-05-29 10:03:24.%N +0200
+--- linux-2.6.22-rc5.orig/include/linux/tty.h 2007-06-20 14:10:41.000000000 +0200
++++ linux-2.6.22-rc5/include/linux/tty.h 2007-06-20 14:11:00.000000000 +0200
@@ -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 */
/*
* This character is the same as _POSIX_VDISABLE: it cannot be used as
-Index: linux-2.6.22-rc3/net/core/sock.c
+Index: linux-2.6.22-rc5/net/core/sock.c
===================================================================
---- linux-2.6.22-rc3.orig/net/core/sock.c 2007-05-27 07:40:22.%N +0200
-+++ linux-2.6.22-rc3/net/core/sock.c 2007-05-29 10:08:43.%N +0200
+--- linux-2.6.22-rc5.orig/net/core/sock.c 2007-06-20 14:10:41.000000000 +0200
++++ linux-2.6.22-rc5/net/core/sock.c 2007-06-20 14:11:00.000000000 +0200
@@ -153,7 +153,7 @@
"sk_lock-AF_ASH" , "sk_lock-AF_ECONET" , "sk_lock-AF_ATMSVC" ,
"sk_lock-21" , "sk_lock-AF_SNA" , "sk_lock-AF_IRDA" ,
---
include/linux/can.h | 98 ++++
- include/linux/can/core.h | 88 +++
+ include/linux/can/core.h | 80 +++
include/linux/can/error.h | 95 ++++
net/Kconfig | 1
net/Makefile | 1
net/can/Kconfig | 25 +
net/can/Makefile | 6
- net/can/af_can.c | 1070 ++++++++++++++++++++++++++++++++++++++++++++++
- net/can/af_can.h | 120 +++++
- net/can/proc.c | 530 ++++++++++++++++++++++
- 10 files changed, 2034 insertions(+)
+ net/can/af_can.c | 997 ++++++++++++++++++++++++++++++++++++++++++++++
+ net/can/af_can.h | 121 +++++
+ net/can/proc.c | 530 ++++++++++++++++++++++++
+ 10 files changed, 1954 insertions(+)
-Index: linux-2.6.22-rc3/include/linux/can.h
+Index: linux-2.6.22-rc5-git5/include/linux/can.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22-rc3/include/linux/can.h 2007-05-29 10:14:54.%N +0200
++++ linux-2.6.22-rc5-git5/include/linux/can.h 2007-06-21 14:03:14.000000000 +0200
@@ -0,0 +1,98 @@
+/*
+ * linux/can.h
+#define CAN_INV_FILTER 0x20000000U /* to be set in can_filter.can_id */
+
+#endif /* CAN_H */
-Index: linux-2.6.22-rc3/include/linux/can/core.h
+Index: linux-2.6.22-rc5-git5/include/linux/can/core.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22-rc3/include/linux/can/core.h 2007-05-29 10:14:54.%N +0200
-@@ -0,0 +1,88 @@
++++ linux-2.6.22-rc5-git5/include/linux/can/core.h 2007-06-21 14:03:14.000000000 +0200
+@@ -0,0 +1,80 @@
+/*
+ * linux/can/core.h
+ *
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+
-+#define CAN_VERSION "20070523"
++#define CAN_VERSION "20070619"
+
+/* increment this number each time you change some user-space interface */
+#define CAN_ABI_VERSION "8"
+ void (*func)(struct sk_buff *, void *),
+ void *data);
+
-+extern int can_dev_register(struct net_device *dev,
-+ void (*func)(unsigned long msg, void *),
-+ void *data);
-+
-+extern int can_dev_unregister(struct net_device *dev,
-+ void (*func)(unsigned long msg, void *),
-+ void *data);
-+
+extern int can_send(struct sk_buff *skb, int loop);
+
+#ifdef CONFIG_CAN_DEBUG_CORE
+#endif
+
+#endif /* CAN_CORE_H */
-Index: linux-2.6.22-rc3/net/Kconfig
+Index: linux-2.6.22-rc5-git5/net/Kconfig
===================================================================
---- linux-2.6.22-rc3.orig/net/Kconfig 2007-05-29 10:03:02.%N +0200
-+++ linux-2.6.22-rc3/net/Kconfig 2007-05-29 10:14:54.%N +0200
+--- linux-2.6.22-rc5-git5.orig/net/Kconfig 2007-06-21 14:02:05.000000000 +0200
++++ linux-2.6.22-rc5-git5/net/Kconfig 2007-06-21 14:03:14.000000000 +0200
@@ -210,6 +210,7 @@
endmenu
source "net/irda/Kconfig"
source "net/bluetooth/Kconfig"
source "net/rxrpc/Kconfig"
-Index: linux-2.6.22-rc3/net/Makefile
+Index: linux-2.6.22-rc5-git5/net/Makefile
===================================================================
---- linux-2.6.22-rc3.orig/net/Makefile 2007-05-29 10:03:02.%N +0200
-+++ linux-2.6.22-rc3/net/Makefile 2007-05-29 10:14:54.%N +0200
+--- linux-2.6.22-rc5-git5.orig/net/Makefile 2007-06-21 14:02:05.000000000 +0200
++++ linux-2.6.22-rc5-git5/net/Makefile 2007-06-21 14:03:14.000000000 +0200
@@ -34,6 +34,7 @@
obj-$(CONFIG_NETROM) += netrom/
obj-$(CONFIG_ROSE) += rose/
obj-$(CONFIG_IRDA) += irda/
obj-$(CONFIG_BT) += bluetooth/
obj-$(CONFIG_SUNRPC) += sunrpc/
-Index: linux-2.6.22-rc3/net/can/Kconfig
+Index: linux-2.6.22-rc5-git5/net/can/Kconfig
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22-rc3/net/can/Kconfig 2007-05-30 12:38:26.%N +0200
++++ linux-2.6.22-rc5-git5/net/can/Kconfig 2007-06-21 15:34:24.000000000 +0200
@@ -0,0 +1,25 @@
+#
+# Controller Area Network (CAN) network layer core configuration
+ 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.
-Index: linux-2.6.22-rc3/net/can/Makefile
+Index: linux-2.6.22-rc5-git5/net/can/Makefile
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22-rc3/net/can/Makefile 2007-05-30 12:38:26.%N +0200
++++ linux-2.6.22-rc5-git5/net/can/Makefile 2007-06-21 15:34:24.000000000 +0200
@@ -0,0 +1,6 @@
+#
+# Makefile for the Linux Controller Area Network core.
+
+obj-$(CONFIG_CAN) += can.o
+can-objs := af_can.o proc.o
-Index: linux-2.6.22-rc3/net/can/af_can.c
+Index: linux-2.6.22-rc5-git5/net/can/af_can.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22-rc3/net/can/af_can.c 2007-05-29 10:14:54.%N +0200
-@@ -0,0 +1,1070 @@
++++ linux-2.6.22-rc5-git5/net/can/af_can.c 2007-06-21 15:34:35.000000000 +0200
+@@ -0,0 +1,997 @@
+/*
+ * af_can.c - Protocol family CAN core module
+ * (used by different CAN protocol modules)
+#include "af_can.h"
+
+#define IDENT "core"
-+static __initdata const char banner[] =
-+ KERN_INFO "can: controller area network core # "
-+ CAN_VERSION_STRING "\n";
++static __initdata const char banner[] = KERN_INFO
++ "can: controller area network core (" CAN_VERSION_STRING ")\n";
+
+MODULE_DESCRIPTION("Controller Area Network PF_CAN core");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_PARM_DESC(debug, "debug print mask: 1:debug, 2:frames, 4:skbs");
+#endif
+
-+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 DEFINE_RWLOCK(notifier_lock);
-+
+HLIST_HEAD(rx_dev_list);
+static struct dev_rcv_lists rx_alldev_list;
+static DEFINE_SPINLOCK(rcv_lists_lock);
+ sprintf(module_name, "can-proto-%d", protocol);
+ ret = request_module(module_name);
+
-+ /* In case of error we only print a message but don't
++ /*
++ * In case of error we only print a message but don't
+ * return the error code immediately. Below we will
+ * return -EPROTONOSUPPORT
+ */
+ * 0 on success
+ * -ENETDOWN when the selected interface is down
+ * -ENOBUFS on full driver queue (see net_xmit_errno())
++ * -ENOMEM when local loopback failed at calling skb_clone()
+ */
+int can_send(struct sk_buff *skb, int loop)
+{
-+ struct sock **tx_sk = (struct sock **)skb->cb;
+ int err;
+
+ if (skb->dev->type != ARPHRD_CAN) {
+ return -EPERM;
+ }
+
++ if (!(skb->dev->flags & IFF_UP)) {
++ kfree_skb(skb);
++ return -ENETDOWN;
++ }
++
++ skb->protocol = htons(ETH_P_CAN);
++
+ if (loop) {
-+ /* local loopback of sent CAN frames (default) */
++ /* local loopback of sent CAN frames */
+
+ /* indication for the CAN driver: do loopback */
-+ *tx_sk = skb->sk;
++ skb->pkt_type = PACKET_LOOPBACK;
+
+ /*
-+ * The reference to the originating sock may be also required
-+ * by the receiving socket to indicate (and ignore) his own
-+ * sent data. Example: can_raw sockopt CAN_RAW_RECV_OWN_MSGS
++ * The reference to the originating sock may be required
++ * by the receiving socket to check whether the frame is
++ * its own. Example: can_raw sockopt CAN_RAW_RECV_OWN_MSGS
++ * Therefore we have to ensure that skb->sk remains the
++ * reference to the originating sock by restoring skb->sk
++ * after each skb_clone() or skb_orphan() usage.
+ */
+
-+ /* interface not capabable to do the loopback itself? */
+ if (!(skb->dev->flags & IFF_LOOPBACK)) {
++ /*
++ * If the interface is not capable to do loopback
++ * itself, we do it here.
++ */
+ struct sk_buff *newskb = skb_clone(skb, GFP_ATOMIC);
+
-+ /* perform the local loopback here */
-+ newskb->protocol = htons(ETH_P_CAN);
++ if (!newskb) {
++ kfree_skb(skb);
++ return -ENOMEM;
++ }
++
++ newskb->sk = skb->sk;
++ newskb->iif = 0;
+ newskb->ip_summed = CHECKSUM_UNNECESSARY;
++ newskb->pkt_type = PACKET_BROADCAST;
+ netif_rx(newskb);
+ }
+ } else {
+ /* indication for the CAN driver: no loopback required */
-+ *tx_sk = NULL;
++ skb->pkt_type = PACKET_HOST;
+ }
+
-+ if (!(skb->dev->flags & IFF_UP))
-+ return -ENETDOWN;
-+
+ /* send to netdevice */
+ err = dev_queue_xmit(skb);
+ if (err > 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);
++ DBG("dev %p (%s), id %03X, mask %03X, callback %p, data %p, "
++ "ident %s\n", dev, DNAME(dev), can_id, mask, func, data, ident);
+
+ r = kmem_cache_alloc(rcv_cache, GFP_KERNEL);
+ if (!r)
+}
+EXPORT_SYMBOL(can_rx_register);
+
-+static void can_rx_delete_list(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);
-+ kmem_cache_free(rcv_cache, r);
-+ }
-+}
-+
+/*
+ * can_rx_delete_device - rcu callback for dev_rcv_lists structure removal
+ */
+static void can_rx_delete_device(struct rcu_head *rp)
+{
+ struct dev_rcv_lists *d = container_of(rp, struct dev_rcv_lists, rcu);
-+ int i;
-+
-+ /* remove all receivers hooked at this netdevice */
-+ can_rx_delete_list(&d->rx[RX_ERR]);
-+ can_rx_delete_list(&d->rx[RX_ALL]);
-+ can_rx_delete_list(&d->rx[RX_FIL]);
-+ can_rx_delete_list(&d->rx[RX_INV]);
-+ can_rx_delete_list(&d->rx[RX_EFF]);
-+
-+ for (i = 0; i < 2048; i++)
-+ can_rx_delete_list(&d->rx_sff[i]);
+
++ DBG("removing dev_rcv_list at %p\n", d);
+ kfree(d);
+}
+
+{
+ struct receiver *r = container_of(rp, struct receiver, rcu);
+
++ DBG("removing receiver at %p\n", r);
+ kmem_cache_free(rcv_cache, r);
+}
+
+ 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);
++ DBG("dev %p (%s), id %03X, mask %03X, callback %p, data %p\n",
++ dev, DNAME(dev), can_id, mask, func, data);
+
+ spin_lock_bh(&rcv_lists_lock);
+
+ "dev %s, id %03X, mask %03X\n", DNAME(dev), can_id, mask);
+ ret = -EINVAL;
+ r = NULL;
++ d = NULL;
+ goto out;
+ }
+
+ if (pstats.rcv_entries > 0)
+ pstats.rcv_entries--;
+
++ /* remove device structure requested by NETDEV_UNREGISTER */
++ if (d->remove_on_zero_entries && !d->entries) {
++ DBG("removing dev_rcv_list for %s on zero entries\n",
++ dev->name);
++ hlist_del_rcu(&d->list);
++ } else
++ d = NULL;
++
+ out:
+ spin_unlock_bh(&rcv_lists_lock);
+
+ if (r)
+ call_rcu(&r->rcu, can_rx_delete_receiver);
+
++ /* schedule the device structure for deletion */
++ if (d)
++ call_rcu(&d->rcu, can_rx_delete_device);
++
+ return ret;
+}
+EXPORT_SYMBOL(can_rx_unregister);
+
+ DBG("skbuff %p cloned to %p\n", skb, clone);
+ if (clone) {
++ clone->sk = skb->sk;
++ clone->iif = skb->iif;
+ r->func(clone, r->data);
+ r->matches++;
+ }
+}
+
+/*
-+ * af_can debugging stuff
-+ */
-+
-+#ifdef CONFIG_CAN_DEBUG_CORE
-+
-+#define DBG_BSIZE 1024
-+
-+/**
-+ * can_debug_cframe - print CAN frame
-+ * @msg: pointer to message printed before the given CAN frame
-+ * @cf: pointer to CAN frame
-+ */
-+void can_debug_cframe(const char *msg, struct can_frame *cf, ...)
-+{
-+ va_list ap;
-+ int len;
-+ int dlc, i;
-+ char *buf;
-+
-+ buf = kmalloc(DBG_BSIZE, GFP_ATOMIC);
-+ if (!buf)
-+ return;
-+
-+ len = sprintf(buf, KERN_DEBUG);
-+ va_start(ap, cf);
-+ len += snprintf(buf + len, DBG_BSIZE - 64, msg, ap);
-+ buf[len++] = ':';
-+ buf[len++] = ' ';
-+ va_end(ap);
-+
-+ dlc = cf->can_dlc;
-+ if (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);
-+ kfree(buf);
-+}
-+EXPORT_SYMBOL(can_debug_cframe);
-+
-+/**
-+ * can_debug_skb - print socket buffer content to kernel log
-+ * @skb: pointer to socket buffer
-+ */
-+void can_debug_skb(struct sk_buff *skb)
-+{
-+ int len, nbytes, i;
-+ char *buf;
-+
-+ buf = kmalloc(DBG_BSIZE, GFP_ATOMIC);
-+ if (!buf)
-+ return;
-+
-+ 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 < DBG_BSIZE - 16) {
-+ len += sprintf(buf + len, " %02x", skb->head[i]);
-+ } else {
-+ len += sprintf(buf + len, "...");
-+ break;
-+ }
-+ }
-+ buf[len++] = '\n';
-+ buf[len] = '\0';
-+ printk(buf);
-+ kfree(buf);
-+}
-+EXPORT_SYMBOL(can_debug_skb);
-+
-+#endif
-+
-+/*
+ * af_can protocol functions
+ */
+
+ int err = 0;
+
+ if (proto < 0 || proto >= CAN_NPROTO) {
-+ printk(KERN_ERR "can: protocol number %d out "
-+ "of range\n", proto);
++ printk(KERN_ERR "can: protocol number %d out of range\n",
++ proto);
+ return -EINVAL;
+ }
+ if (proto_tab[proto]) {
-+ printk(KERN_ERR "can: protocol %d already "
-+ "registered\n", proto);
++ printk(KERN_ERR "can: protocol %d already registered\n",
++ proto);
+ return -EBUSY;
+ }
+
+}
+EXPORT_SYMBOL(can_proto_unregister);
+
-+/**
-+ * can_dev_register - subscribe notifier for CAN device status changes
-+ * @dev: pointer to netdevice
-+ * @func: callback function on status change
-+ * @data: returned parameter for callback function
-+ *
-+ * Description:
-+ * Invokes the callback function with the status 'msg' and the given
-+ * parameter 'data' on a status change of the given CAN network device.
-+ *
-+ * Return:
-+ * 0 on success
-+ * -ENOMEM on missing mem to create subscription entry
-+ * -ENODEV unknown device
-+ */
-+int 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 (!dev || dev->type != ARPHRD_CAN)
-+ return -ENODEV;
-+
-+ n = kmalloc(sizeof(*n), GFP_KERNEL);
-+ if (!n)
-+ return -ENOMEM;
-+
-+ n->dev = dev;
-+ n->func = func;
-+ n->data = data;
-+
-+ write_lock(¬ifier_lock);
-+ list_add(&n->list, ¬ifier_list);
-+ write_unlock(¬ifier_lock);
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL(can_dev_register);
-+
-+/**
-+ * can_dev_unregister - unsubscribe notifier for CAN device status changes
-+ * @dev: pointer to netdevice
-+ * @func: callback function on filter match
-+ * @data: returned parameter for callback function
-+ *
-+ * Description:
-+ * Removes subscription entry depending on given (subscription) values.
-+ *
-+ * Return:
-+ * 0 on success
-+ * -EINVAL on missing subscription entry
++/*
++ * af_can notifier to create/remove CAN netdevice specific structs
+ */
-+int can_dev_unregister(struct net_device *dev,
-+ void (*func)(unsigned long msg, void *), void *data)
-+{
-+ struct notifier *n, *next;
-+ int ret = -EINVAL;
-+
-+ 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);
-+ ret = 0;
-+ break;
-+ }
-+ }
-+ write_unlock(¬ifier_lock);
-+
-+ return ret;
-+}
-+EXPORT_SYMBOL(can_dev_unregister);
-+
-+static int can_notifier(struct notifier_block *nb,
-+ unsigned long msg, void *data)
++static int can_notifier(struct notifier_block *nb, unsigned long msg,
++ void *data)
+{
+ struct net_device *dev = (struct net_device *)data;
-+ struct notifier *n;
+ struct dev_rcv_lists *d;
+
-+ DBG("called for %s, msg = %lu\n", dev->name, msg);
++ DBG("msg %ld for dev %p (%s idx %d)\n",
++ msg, dev, dev->name, dev->ifindex);
+
+ if (dev->type != ARPHRD_CAN)
+ return NOTIFY_DONE;
+ d = kzalloc(sizeof(*d),
+ in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
+ if (!d) {
-+ printk(KERN_ERR "can: allocation of receive "
-+ "list failed\n");
++ printk(KERN_ERR
++ "can: allocation of receive list failed\n");
+ return NOTIFY_DONE;
+ }
+ d->dev = dev;
+ spin_lock_bh(&rcv_lists_lock);
+
+ d = find_dev_rcv_lists(dev);
-+ if (d)
-+ hlist_del_rcu(&d->list);
-+ else
++ if (d) {
++ DBG("remove dev_rcv_list for %s (%d entries)\n",
++ dev->name, d->entries);
++
++ if (d->entries) {
++ d->remove_on_zero_entries = 1;
++ d = NULL;
++ } else
++ hlist_del_rcu(&d->list);
++ } else
+ printk(KERN_ERR "can: notifier: receive list not "
+ "found for dev %s\n", dev->name);
+
+ 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;
+}
+
+/*
++ * af_can debugging stuff
++ */
++
++#ifdef CONFIG_CAN_DEBUG_CORE
++
++#define DBG_BSIZE 1024
++
++/**
++ * can_debug_cframe - print CAN frame
++ * @msg: pointer to message printed before the given CAN frame
++ * @cf: pointer to CAN frame
++ */
++void can_debug_cframe(const char *msg, struct can_frame *cf, ...)
++{
++ va_list ap;
++ int len;
++ int dlc, i;
++ char *buf;
++
++ buf = kmalloc(DBG_BSIZE, GFP_ATOMIC);
++ if (!buf)
++ return;
++
++ len = sprintf(buf, KERN_DEBUG);
++ va_start(ap, cf);
++ len += snprintf(buf + len, DBG_BSIZE - 64, msg, ap);
++ buf[len++] = ':';
++ buf[len++] = ' ';
++ va_end(ap);
++
++ dlc = cf->can_dlc;
++ if (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);
++ kfree(buf);
++}
++EXPORT_SYMBOL(can_debug_cframe);
++
++/**
++ * can_debug_skb - print socket buffer content to kernel log
++ * @skb: pointer to socket buffer
++ */
++void can_debug_skb(struct sk_buff *skb)
++{
++ int len, nbytes, i;
++ char *buf;
++
++ buf = kmalloc(DBG_BSIZE, GFP_ATOMIC);
++ if (!buf)
++ return;
++
++ 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 < DBG_BSIZE - 16) {
++ len += sprintf(buf + len, " %02x", skb->head[i]);
++ } else {
++ len += sprintf(buf + len, "...");
++ break;
++ }
++ }
++ buf[len++] = '\n';
++ buf[len] = '\0';
++ printk(buf);
++ kfree(buf);
++}
++EXPORT_SYMBOL(can_debug_skb);
++
++#endif
++
++/*
+ * af_can module init/exit functions
+ */
+
+ return -ENOMEM;
+
+ /*
-+ * Insert struct dev_rcv_lists for reception on all devices.
++ * Insert rx_alldev_list 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.
+ */
+
+module_init(can_init);
+module_exit(can_exit);
-Index: linux-2.6.22-rc3/net/can/af_can.h
+Index: linux-2.6.22-rc5-git5/net/can/af_can.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22-rc3/net/can/af_can.h 2007-05-29 10:14:54.%N +0200
-@@ -0,0 +1,120 @@
++++ linux-2.6.22-rc5-git5/net/can/af_can.h 2007-06-21 14:03:14.000000000 +0200
+@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research
+ * All rights reserved.
+ struct net_device *dev;
+ struct hlist_head rx[RX_MAX];
+ struct hlist_head rx_sff[0x800];
++ int remove_on_zero_entries;
+ int entries;
+};
+
+extern struct hlist_head rx_dev_list; /* rx dispatcher structures */
+
+#endif /* AF_CAN_H */
-Index: linux-2.6.22-rc3/net/can/proc.c
+Index: linux-2.6.22-rc5-git5/net/can/proc.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22-rc3/net/can/proc.c 2007-05-29 10:14:54.%N +0200
++++ linux-2.6.22-rc5-git5/net/can/proc.c 2007-06-21 14:03:14.000000000 +0200
@@ -0,0 +1,530 @@
+/*
+ * proc.c - procfs support for Protocol family CAN core module
+ if (can_dir)
+ remove_proc_entry(CAN_PROC_DIR, NULL);
+}
-Index: linux-2.6.22-rc3/include/linux/can/error.h
+Index: linux-2.6.22-rc5-git5/include/linux/can/error.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22-rc3/include/linux/can/error.h 2007-05-30 12:42:27.%N +0200
++++ linux-2.6.22-rc5-git5/include/linux/can/error.h 2007-06-21 14:03:14.000000000 +0200
@@ -0,0 +1,95 @@
+/*
+ * linux/can/error.h
Signed-Off-By: Urs Thuermann <urs.thuermann@volkswagen.de>
---
- include/linux/can/raw.h | 31 ++
+ include/linux/can/raw.h | 31 +
net/can/Kconfig | 26 +
net/can/Makefile | 3
- net/can/raw.c | 703 ++++++++++++++++++++++++++++++++++++++++++++++++
- 4 files changed, 763 insertions(+)
+ net/can/raw.c | 751 ++++++++++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 811 insertions(+)
-Index: linux-2.6.22-rc2-git3/include/linux/can/raw.h
+Index: linux-2.6.22-rc5-git5/include/linux/can/raw.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22-rc2-git3/include/linux/can/raw.h 2007-05-23 12:25:52.%N +0200
++++ linux-2.6.22-rc5-git5/include/linux/can/raw.h 2007-06-21 14:05:26.000000000 +0200
@@ -0,0 +1,31 @@
+/*
+ * linux/can/raw.h
+};
+
+#endif
-Index: linux-2.6.22-rc2-git3/net/can/Kconfig
+Index: linux-2.6.22-rc5-git5/net/can/Kconfig
===================================================================
---- linux-2.6.22-rc2-git3.orig/net/can/Kconfig 2007-05-23 12:25:51.%N +0200
-+++ linux-2.6.22-rc2-git3/net/can/Kconfig 2007-05-23 12:25:52.%N +0200
+--- linux-2.6.22-rc5-git5.orig/net/can/Kconfig 2007-06-21 14:03:50.000000000 +0200
++++ linux-2.6.22-rc5-git5/net/can/Kconfig 2007-06-21 14:05:26.000000000 +0200
@@ -16,6 +16,32 @@
If you want CAN support, you should say Y here and also to the
specific driver for your controller(s) below.
config CAN_DEBUG_CORE
bool "CAN Core debugging messages"
depends on CAN
-Index: linux-2.6.22-rc2-git3/net/can/Makefile
+Index: linux-2.6.22-rc5-git5/net/can/Makefile
===================================================================
---- linux-2.6.22-rc2-git3.orig/net/can/Makefile 2007-05-23 12:25:51.%N +0200
-+++ linux-2.6.22-rc2-git3/net/can/Makefile 2007-05-23 12:25:52.%N +0200
+--- linux-2.6.22-rc5-git5.orig/net/can/Makefile 2007-06-21 14:03:50.000000000 +0200
++++ linux-2.6.22-rc5-git5/net/can/Makefile 2007-06-21 14:05:26.000000000 +0200
@@ -4,3 +4,6 @@
obj-$(CONFIG_CAN) += can.o
+
+obj-$(CONFIG_CAN_RAW) += can-raw.o
+can-raw-objs := raw.o
-Index: linux-2.6.22-rc2-git3/net/can/raw.c
+Index: linux-2.6.22-rc5-git5/net/can/raw.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22-rc2-git3/net/can/raw.c 2007-05-23 12:25:52.%N +0200
-@@ -0,0 +1,703 @@
++++ linux-2.6.22-rc5-git5/net/can/raw.c 2007-06-21 14:05:42.000000000 +0200
+@@ -0,0 +1,751 @@
+/*
+ * raw.c - Raw sockets for protocol family CAN
+ *
+#define IDENT "raw"
+#define CAN_RAW_VERSION CAN_VERSION
+static __initdata const char banner[] =
-+ KERN_INFO "can: raw protocol # rev " CAN_RAW_VERSION "\n";
++ KERN_INFO "can: raw protocol (rev " CAN_RAW_VERSION ")\n";
+
+MODULE_DESCRIPTION("PF_CAN raw protocol");
+MODULE_LICENSE("Dual BSD/GPL");
+ * storing the single filter in dfilter, to avoid using dynamic memory.
+ */
+
-+struct raw_opt {
++struct raw_sock {
++ struct sock sk;
+ int bound;
+ int ifindex;
++ struct notifier_block notifier;
+ 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;
-+ spinlock_t lock;
+};
+
-+struct raw_sock {
-+ struct sock sk;
-+ struct raw_opt opt;
-+};
-+
-+static inline struct raw_opt *raw_sk(const struct sock *sk)
++static inline struct raw_sock *raw_sk(const struct sock *sk)
+{
-+ return &((struct raw_sock *)sk)->opt;
-+}
-+
-+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:
-+ spin_lock(&ro->lock);
-+ ro->ifindex = 0;
-+ ro->bound = 0;
-+ spin_unlock(&ro->lock);
-+ /* fallthrough */
-+ case NETDEV_DOWN:
-+ sk->sk_err = ENETDOWN;
-+ if (!sock_flag(sk, SOCK_DEAD))
-+ sk->sk_error_report(sk);
-+ break;
-+ }
++ return (struct raw_sock *)sk;
+}
+
+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;
++ struct raw_sock *ro = raw_sk(sk);
+ int error;
+
+ DBG("received skbuff %p, sk %p\n", skb, sk);
+
+ if (!ro->recv_own_msgs) {
+ /* check the received tx sock reference */
-+ if (*(struct sock **)skb->cb == sk) {
++ if (skb->sk == sk) {
+ 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;
-+
+ error = sock_queue_rcv_skb(sk, skb);
+ if (error < 0) {
+ DBG("sock_queue_rcv_skb failed: %d\n", error);
+ }
+}
+
-+static void raw_add_filters(struct net_device *dev, struct sock *sk)
++static void raw_enable_filters(struct net_device *dev, struct sock *sk)
+{
-+ struct raw_opt *ro = raw_sk(sk);
++ struct raw_sock *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);
++
++ can_rx_register(dev, filter[i].can_id, filter[i].can_mask,
++ raw_rcv, sk, IDENT);
+ }
+}
+
-+static void raw_remove_filters(struct net_device *dev, struct sock *sk)
++static void raw_enable_errfilter(struct net_device *dev, struct sock *sk)
++{
++ struct raw_sock *ro = raw_sk(sk);
++
++ if (ro->err_mask)
++ can_rx_register(dev, 0, ro->err_mask | CAN_ERR_FLAG,
++ raw_rcv, sk, IDENT);
++}
++
++static void raw_disable_filters(struct net_device *dev, struct sock *sk)
+{
-+ struct raw_opt *ro = raw_sk(sk);
++ struct raw_sock *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);
++
++ can_rx_unregister(dev, filter[i].can_id, filter[i].can_mask,
++ raw_rcv, sk);
+ }
+}
+
++static void raw_disable_errfilter(struct net_device *dev, struct sock *sk)
++{
++ struct raw_sock *ro = raw_sk(sk);
++
++ if (ro->err_mask)
++ can_rx_unregister(dev, 0, ro->err_mask | CAN_ERR_FLAG,
++ raw_rcv, sk);
++}
++
++static int raw_notifier(struct notifier_block *nb,
++ unsigned long msg, void *data)
++{
++ struct net_device *dev = (struct net_device *)data;
++ struct raw_sock *ro = container_of(nb, struct raw_sock, notifier);
++ struct sock *sk = &ro->sk;
++
++ DBG("msg %ld for dev %p (%s idx %d) sk %p ro->ifindex %d\n",
++ msg, dev, dev->name, dev->ifindex, sk, ro->ifindex);
++
++ if (dev->type != ARPHRD_CAN)
++ return NOTIFY_DONE;
++
++ if (ro->ifindex != dev->ifindex)
++ return NOTIFY_DONE;
++
++ switch (msg) {
++
++ case NETDEV_UNREGISTER:
++ lock_sock(sk);
++ /* remove current filters & unregister */
++ if (ro->bound) {
++ raw_disable_filters(dev, sk);
++ raw_disable_errfilter(dev, sk);
++ }
++
++ if (ro->count > 1)
++ kfree(ro->filter);
++
++ ro->ifindex = 0;
++ ro->bound = 0;
++ ro->count = 0;
++ release_sock(sk);
++
++ sk->sk_err = ENODEV;
++ if (!sock_flag(sk, SOCK_DEAD))
++ sk->sk_error_report(sk);
++ break;
++
++ case NETDEV_DOWN:
++ sk->sk_err = ENETDOWN;
++ if (!sock_flag(sk, SOCK_DEAD))
++ sk->sk_error_report(sk);
++ break;
++ }
++
++ return NOTIFY_DONE;
++}
++
+static int raw_init(struct sock *sk)
+{
-+ struct raw_opt *ro = raw_sk(sk);
++ struct raw_sock *ro = raw_sk(sk);
+
+ ro->bound = 0;
++ ro->ifindex = 0;
+
+ /* set default filter to single entry dfilter */
+ ro->dfilter.can_id = 0;
+ ro->loopback = 1;
+ ro->recv_own_msgs = 0;
+
-+ spin_lock_init(&ro->lock);
++ /* set notifier */
++ ro->notifier.notifier_call = raw_notifier;
++
++ register_netdevice_notifier(&ro->notifier);
+
+ 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;
++ struct raw_sock *ro = raw_sk(sk);
+
+ DBG("socket %p, sk %p, refcnt %d\n", sock, sk,
+ atomic_read(&sk->sk_refcnt));
+
-+ spin_lock(&ro->lock);
-+ if (ro->bound && ro->ifindex)
-+ dev = dev_get_by_index(ro->ifindex);
-+ spin_unlock(&ro->lock);
++ unregister_netdevice_notifier(&ro->notifier);
++
++ lock_sock(sk);
+
+ /* remove current filters & unregister */
-+ if (ro->bound)
-+ raw_remove_filters(dev, sk);
++ if (ro->bound) {
++ if (ro->ifindex) {
++ struct net_device *dev = dev_get_by_index(ro->ifindex);
++ if (dev) {
++ raw_disable_filters(dev, sk);
++ raw_disable_errfilter(dev, sk);
++ dev_put(dev);
++ }
++ } else {
++ raw_disable_filters(NULL, sk);
++ raw_disable_errfilter(NULL, 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);
-+ }
++ ro->ifindex = 0;
++ ro->bound = 0;
++ ro->count = 0;
+
++ release_sock(sk);
+ sock_put(sk);
+
+ return 0;
+{
+ struct sockaddr_can *addr = (struct sockaddr_can *)uaddr;
+ struct sock *sk = sock->sk;
-+ struct raw_opt *ro = raw_sk(sk);
-+ struct net_device *dev;
++ struct raw_sock *ro = raw_sk(sk);
+ int err = 0;
++ int notify_enetdown = 0;
+
+ DBG("socket %p to device %d\n", sock, addr->can_ifindex);
+
+ return -EINVAL;
+
+ lock_sock(sk);
-+ spin_lock(&ro->lock);
+
+ if (ro->bound) {
-+ /* remove current bindings / notifier */
++ /* unregister current filters for this device */
+ if (ro->ifindex) {
-+ dev = dev_get_by_index(ro->ifindex);
-+ if (!dev) {
-+ DBG("could not find device %d\n",
-+ addr->can_ifindex);
-+ err = -ENODEV;
-+ goto out;
++ struct net_device *dev = dev_get_by_index(ro->ifindex);
++ if (dev) {
++ raw_disable_filters(dev, sk);
++ raw_disable_errfilter(dev, sk);
++ dev_put(dev);
+ }
-+ 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;
++ ro->ifindex = 0;
+
-+ /* unregister current filters for this device */
-+ raw_remove_filters(dev, sk);
-+
-+ if (dev)
-+ dev_put(dev);
++ } else {
++ raw_disable_filters(NULL, sk);
++ raw_disable_errfilter(NULL, sk);
++ }
+
+ ro->bound = 0;
+ }
+
+ if (addr->can_ifindex) {
-+ dev = dev_get_by_index(addr->can_ifindex);
++ struct net_device *dev = dev_get_by_index(addr->can_ifindex);
+ if (!dev) {
+ DBG("could not find device %d\n", addr->can_ifindex);
+ err = -ENODEV;
+ goto out;
+ }
-+ if (!(dev->flags & IFF_UP)) {
-+ sk->sk_err = ENETDOWN;
-+ if (!sock_flag(sk, SOCK_DEAD))
-+ sk->sk_error_report(sk);
++ if (dev->type != ARPHRD_CAN) {
++ DBG("device %d no CAN device\n", addr->can_ifindex);
++ dev_put(dev);
++ err = -ENODEV;
+ goto out;
+ }
-+ can_dev_register(dev, raw_notifier, sk);
-+ } else
-+ dev = NULL;
++ if (!(dev->flags & IFF_UP))
++ notify_enetdown = 1;
+
-+ ro->ifindex = addr->can_ifindex;
++ ro->ifindex = dev->ifindex;
+
-+ /* filters set by default/setsockopt */
-+ raw_add_filters(dev, sk);
++ /* filters set by default/setsockopt */
++ raw_enable_filters(dev, sk);
++ raw_enable_errfilter(dev, sk);
++ dev_put(dev);
+
-+ /* error frame filter set by setsockopt */
-+ if (ro->err_mask)
-+ can_rx_register(dev, 0, ro->err_mask | CAN_ERR_FLAG,
-+ raw_rcv, sk, IDENT);
++ } else {
++ ro->ifindex = 0;
++
++ /* filters set by default/setsockopt */
++ raw_enable_filters(NULL, sk);
++ raw_enable_errfilter(NULL, sk);
++ }
+
+ ro->bound = 1;
+
+ out:
-+ spin_unlock(&ro->lock);
+ release_sock(sk);
+
-+ if (dev)
-+ dev_put(dev);
++ if (notify_enetdown) {
++ sk->sk_err = ENETDOWN;
++ if (!sock_flag(sk, SOCK_DEAD))
++ sk->sk_error_report(sk);
++ }
+
+ return err;
+}
+{
+ struct sockaddr_can *addr = (struct sockaddr_can *)uaddr;
+ struct sock *sk = sock->sk;
-+ struct raw_opt *ro = raw_sk(sk);
++ struct raw_sock *ro = raw_sk(sk);
+
+ if (peer)
+ return -EOPNOTSUPP;
+
+ addr->can_family = AF_CAN;
+ addr->can_ifindex = ro->ifindex;
++
+ *len = sizeof(*addr);
+
+ return 0;
+ char __user *optval, int optlen)
+{
+ struct sock *sk = sock->sk;
-+ struct raw_opt *ro = raw_sk(sk);
++ struct raw_sock *ro = raw_sk(sk);
+ struct can_filter *filter = NULL; /* dyn. alloc'ed filters */
+ struct can_filter sfilter; /* single filter */
+ struct net_device *dev = NULL;
+
+ lock_sock(sk);
+
-+ spin_lock(&ro->lock);
+ if (ro->bound && ro->ifindex)
+ dev = dev_get_by_index(ro->ifindex);
-+ spin_unlock(&ro->lock);
+
+ /* remove current filters & unregister */
+ if (ro->bound)
-+ raw_remove_filters(dev, sk);
++ raw_disable_filters(dev, sk);
+
+ if (ro->count > 1)
+ kfree(ro->filter);
+ ro->filter = filter;
+ ro->count = count;
+ if (ro->bound)
-+ raw_add_filters(dev, sk);
++ raw_enable_filters(dev, sk);
+
+ if (dev)
+ dev_put(dev);
+
+ err_mask &= CAN_ERR_MASK;
+
++ lock_sock(sk);
++
+ 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);
++ if (ro->bound)
++ raw_disable_errfilter(dev, 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);
++
++ /* add new error mask */
++ if (ro->bound)
++ raw_enable_errfilter(dev, sk);
+
+ if (dev)
+ dev_put(dev);
+
++ release_sock(sk);
++
+ break;
+
+ case CAN_RAW_LOOPBACK:
+ 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;
++ struct raw_sock *ro = raw_sk(sk);
+ int len;
-+ void *val = NULL;
++ void *val;
++ int err = 0;
+
+ if (level != SOL_CAN_RAW)
+ return -EINVAL;
+ switch (optname) {
+
+ case CAN_RAW_FILTER:
-+ if (count && filter) {
-+ int filter_size = count * sizeof(struct can_filter);
-+ if (len > filter_size)
-+ len = filter_size;
-+ val = filter;
++ lock_sock(sk);
++ if (ro->count > 0) {
++ int fsize = ro->count * sizeof(struct can_filter);
++ if (len > fsize)
++ len = fsize;
++ err = copy_to_user(optval, ro->filter, len);
+ } else
+ len = 0;
-+ break;
++ release_sock(sk);
++
++ if (!err)
++ err = put_user(len, optlen);
++ return err;
+
+ case CAN_RAW_ERR_FILTER:
+ if (len > sizeof(can_err_mask_t))
+ struct msghdr *msg, size_t size)
+{
+ struct sock *sk = sock->sk;
-+ struct raw_opt *ro = raw_sk(sk);
++ struct raw_sock *ro = raw_sk(sk);
+ struct sk_buff *skb;
+ struct net_device *dev;
+ int ifindex;
+ 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);
++ struct sockaddr_can *addr = msg->msg_name;
++ msg->msg_namelen = sizeof(*addr);
++ memset(addr, 0, sizeof(*addr));
++ addr->can_family = AF_CAN;
++ addr->can_ifindex = skb->iif;
+ }
+
+ DBG("freeing sock %p, skbuff %p\n", sk, skb);
include/linux/can/bcm.h | 65 +
net/can/Kconfig | 28
net/can/Makefile | 3
- net/can/bcm.c | 1671 ++++++++++++++++++++++++++++++++++++++++++++++++
- 4 files changed, 1767 insertions(+)
+ net/can/bcm.c | 1750 ++++++++++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 1846 insertions(+)
-Index: linux-2.6.22-rc2-git3/include/linux/can/bcm.h
+Index: linux-2.6.22-rc5-git5/include/linux/can/bcm.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22-rc2-git3/include/linux/can/bcm.h 2007-05-23 12:25:52.%N +0200
++++ linux-2.6.22-rc5-git5/include/linux/can/bcm.h 2007-06-21 14:08:38.000000000 +0200
@@ -0,0 +1,65 @@
+/*
+ * linux/can/bcm.h
+#define RX_RTR_FRAME 0x0400
+
+#endif /* CAN_BCM_H */
-Index: linux-2.6.22-rc2-git3/net/can/Kconfig
+Index: linux-2.6.22-rc5-git5/net/can/Kconfig
===================================================================
---- linux-2.6.22-rc2-git3.orig/net/can/Kconfig 2007-05-23 12:25:52.%N +0200
-+++ linux-2.6.22-rc2-git3/net/can/Kconfig 2007-05-23 12:25:52.%N +0200
+--- linux-2.6.22-rc5-git5.orig/net/can/Kconfig 2007-06-21 14:05:26.000000000 +0200
++++ linux-2.6.22-rc5-git5/net/can/Kconfig 2007-06-21 14:08:38.000000000 +0200
@@ -42,6 +42,34 @@
Say Y here if you want non-root users to be able to access CAN_RAW
sockets.
config CAN_DEBUG_CORE
bool "CAN Core debugging messages"
depends on CAN
-Index: linux-2.6.22-rc2-git3/net/can/Makefile
+Index: linux-2.6.22-rc5-git5/net/can/Makefile
===================================================================
---- linux-2.6.22-rc2-git3.orig/net/can/Makefile 2007-05-23 12:25:52.%N +0200
-+++ linux-2.6.22-rc2-git3/net/can/Makefile 2007-05-23 12:25:52.%N +0200
+--- linux-2.6.22-rc5-git5.orig/net/can/Makefile 2007-06-21 14:05:26.000000000 +0200
++++ linux-2.6.22-rc5-git5/net/can/Makefile 2007-06-21 14:08:38.000000000 +0200
@@ -7,3 +7,6 @@
obj-$(CONFIG_CAN_RAW) += can-raw.o
+
+obj-$(CONFIG_CAN_BCM) += can-bcm.o
+can-bcm-objs := bcm.o
-Index: linux-2.6.22-rc2-git3/net/can/bcm.c
+Index: linux-2.6.22-rc5-git5/net/can/bcm.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22-rc2-git3/net/can/bcm.c 2007-05-23 12:25:52.%N +0200
-@@ -0,0 +1,1671 @@
++++ linux-2.6.22-rc5-git5/net/can/bcm.c 2007-06-21 14:08:51.000000000 +0200
+@@ -0,0 +1,1750 @@
+/*
+ * bcm.c - Broadcast Manager to filter/send (cyclic) CAN content
+ *
+#define IDENT "bcm"
+#define CAN_BCM_VERSION CAN_VERSION
+static __initdata const char banner[] = KERN_INFO
-+ "can: broadcast manager protocol # rev " CAN_BCM_VERSION "\n";
++ "can: broadcast manager protocol (rev " CAN_BCM_VERSION ")\n";
+
+MODULE_DESCRIPTION("PF_CAN broadcast manager protocol");
+MODULE_LICENSE("Dual BSD/GPL");
+ unsigned long frames_abs, frames_filtered;
+ struct timer_list timer, thrtimer;
+ struct timeval ival1, ival2;
-+ struct timeval rx_stamp;
++ ktime_t rx_stamp;
+ int rx_ifindex;
+ int count;
+ int nframes;
+ struct can_frame sframe;
+ struct can_frame last_sframe;
+ 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 */
++ struct net_device *rx_reg_dev;
+};
+
+static struct proc_dir_entry *proc_dir = NULL;
+#endif
+
+struct bcm_sock {
-+ struct sock sk;
-+ struct bcm_opt opt;
++ struct sock sk;
++ int bound;
++ int ifindex;
++ struct notifier_block notifier;
++ 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 inline struct bcm_opt *bcm_sk(const struct sock *sk)
++static inline struct bcm_sock *bcm_sk(const struct sock *sk)
+{
-+ return &((struct bcm_sock *)sk)->opt;
++ return (struct bcm_sock *)sk;
+}
+
+#define CFSIZ sizeof(struct can_frame)
+{
+ int len = 0;
+ struct sock *sk = (struct sock *)data;
-+ struct bcm_opt *bo = bcm_sk(sk);
++ struct bcm_sock *bo = bcm_sk(sk);
+ struct bcm_op *op;
+
+ len += snprintf(page + len, PAGE_SIZE - len, ">>> socket %p",
+ * (consisting of bcm_msg_head + x CAN frames)
+ */
+static void bcm_send_to_user(struct bcm_op *op, struct bcm_msg_head *head,
-+ struct can_frame *frames, struct timeval *tv)
++ struct can_frame *frames, int has_timestamp)
+{
+ 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,
+ /* 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;
++ if (has_timestamp) {
++ /* restore rx timestamp */
++ skb->tstamp = op->rx_stamp;
++ }
++
+ /* restore originator for recvfrom() */
-+ addr->can_ifindex = op->rx_ifindex;
++ skb->iif = op->rx_ifindex;
+
+ if (head->nframes) {
+ memcpy(skb_put(skb, datalen), frames, datalen);
+
+ err = sock_queue_rcv_skb(sk, skb);
+ if (err < 0) {
-+ struct bcm_opt *bo = bcm_sk(sk);
++ struct bcm_sock *bo = bcm_sk(sk);
+
+ DBG("sock_queue_rcv_skb failed: %d\n", err);
+ kfree_skb(skb);
+ msg_head.can_id = op->can_id;
+ msg_head.nframes = 0;
+
-+ bcm_send_to_user(op, &msg_head, NULL, NULL);
++ bcm_send_to_user(op, &msg_head, NULL, 0);
+ }
+ }
+
+ head.can_id = op->can_id;
+ head.nframes = 1;
+
-+ bcm_send_to_user(op, &head, data, &op->rx_stamp);
++ bcm_send_to_user(op, &head, data, 1);
+}
+
+/*
+ msg_head.can_id = op->can_id;
+ msg_head.nframes = 0;
+
-+ bcm_send_to_user(op, &msg_head, NULL, NULL);
++ bcm_send_to_user(op, &msg_head, NULL, 0);
+
+ /* no restart of the timer is done here! */
+
+ if (skb->len == sizeof(rxframe)) {
+ memcpy(&rxframe, skb->data, sizeof(rxframe));
+ /* save rx timestamp */
-+ skb_get_timestamp(skb, &op->rx_stamp);
++ op->rx_stamp = skb->tstamp;
+ /* save originator for recvfrom() */
+ op->rx_ifindex = skb->dev->ifindex;
+ /* update statistics */
+ return;
+}
+
++static void bcm_rx_unreg(struct net_device *dev, struct bcm_op *op)
++{
++ if (op->rx_reg_dev == dev) {
++ can_rx_unregister(dev, op->can_id, REGMASK(op->can_id),
++ bcm_rx_handler, op);
++
++ /* mark as removed subscription */
++ op->rx_reg_dev = NULL;
++ } else
++ printk(KERN_ERR "can-bcm: bcm_rx_unreg: registered device "
++ "mismatch %p %p\n", op->rx_reg_dev, dev);
++}
++
+/*
+ * bcm_delete_rx_op - find and remove a rx op (returns number of removed ops)
+ */
+ * 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);
++ /*
++ * Only remove subscriptions that had not
++ * been removed due to NETDEV_UNREGISTER
++ * in bcm_notifier()
++ */
++ if (op->rx_reg_dev) {
++ struct net_device *dev;
++
++ dev = dev_get_by_index(op->ifindex);
++ if (dev) {
++ bcm_rx_unreg(dev, op);
++ dev_put(dev);
++ }
+ }
-+
+ } else
+ can_rx_unregister(NULL, op->can_id,
+ REGMASK(op->can_id),
+ msg_head->ival2 = op->ival2;
+ msg_head->nframes = op->nframes;
+
-+ bcm_send_to_user(op, msg_head, op->frames, NULL);
++ bcm_send_to_user(op, msg_head, op->frames, 0);
+
+ return MHSIZ;
+}
+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_sock *bo = bcm_sk(sk);
+ struct bcm_op *op;
+ int i, err;
+
+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_sock *bo = bcm_sk(sk);
+ struct bcm_op *op;
+ int do_rx_register;
+ int err;
+ can_rx_register(dev, op->can_id,
+ REGMASK(op->can_id),
+ bcm_rx_handler, op, IDENT);
++ op->rx_reg_dev = dev;
+ dev_put(dev);
+ }
+
+ struct msghdr *msg, size_t size)
+{
+ struct sock *sk = sock->sk;
-+ struct bcm_opt *bo = bcm_sk(sk);
++ struct bcm_sock *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 */
+
+ ifindex = addr->can_ifindex; /* ifindex from sendto() */
+
-+ if (ifindex && !dev_get_by_index(ifindex)) {
-+ DBG("device %d not found\n", ifindex);
-+ return -ENODEV;
++ if (ifindex) {
++ struct net_device *dev = dev_get_by_index(ifindex);
++
++ if (!dev) {
++ DBG("device %d not found\n", ifindex);
++ return -ENODEV;
++ }
++
++ if (dev->type != ARPHRD_CAN) {
++ DBG("device %d no CAN device\n", ifindex);
++ dev_put(dev);
++ return -ENODEV;
++ }
++
++ dev_put(dev);
+ }
+ }
+
+}
+
+/*
++ * notification handler for netdevice status changes
++ */
++static int bcm_notifier(struct notifier_block *nb, unsigned long msg,
++ void *data)
++{
++ struct net_device *dev = (struct net_device *)data;
++ struct bcm_sock *bo = container_of(nb, struct bcm_sock, notifier);
++ struct sock *sk = &bo->sk;
++ struct bcm_op *op;
++ int notify_enodev = 0;
++
++ DBG("msg %ld for dev %p (%s idx %d) sk %p bo->ifindex %d\n",
++ msg, dev, dev->name, dev->ifindex, sk, bo->ifindex);
++
++ if (dev->type != ARPHRD_CAN)
++ return NOTIFY_DONE;
++
++ switch (msg) {
++
++ case NETDEV_UNREGISTER:
++ lock_sock(sk);
++
++ /* remove device specific receive entries */
++ list_for_each_entry(op, &bo->rx_ops, list)
++ if (op->rx_reg_dev == dev)
++ bcm_rx_unreg(dev, op);
++
++ /* remove device reference, if this is our bound device */
++ if (bo->bound && bo->ifindex == dev->ifindex) {
++ bo->bound = 0;
++ bo->ifindex = 0;
++ notify_enodev = 1;
++ }
++
++ release_sock(sk);
++
++ if (notify_enodev) {
++ sk->sk_err = ENODEV;
++ if (!sock_flag(sk, SOCK_DEAD))
++ sk->sk_error_report(sk);
++ }
++ break;
++
++ case NETDEV_DOWN:
++ if (bo->bound && bo->ifindex == dev->ifindex) {
++ sk->sk_err = ENETDOWN;
++ if (!sock_flag(sk, SOCK_DEAD))
++ sk->sk_error_report(sk);
++ }
++ }
++
++ return NOTIFY_DONE;
++}
++
++/*
+ * initial settings for all BCM sockets to be set at socket creation time
+ */
+static int bcm_init(struct sock *sk)
+{
-+ struct bcm_opt *bo = bcm_sk(sk);
++ struct bcm_sock *bo = bcm_sk(sk);
+
+ bo->bound = 0;
+ bo->ifindex = 0;
+ INIT_LIST_HEAD(&bo->tx_ops);
+ INIT_LIST_HEAD(&bo->rx_ops);
+
-+ return 0;
-+}
++ /* set notifier */
++ bo->notifier.notifier_call = bcm_notifier;
+
-+/*
-+ * notification handler for netdevice status changes
-+ */
-+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) {
++ register_netdevice_notifier(&bo->notifier);
+
-+ 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);
-+ }
++ return 0;
+}
+
+/*
+static int bcm_release(struct socket *sock)
+{
+ struct sock *sk = sock->sk;
-+ struct bcm_opt *bo = bcm_sk(sk);
++ struct bcm_sock *bo = bcm_sk(sk);
+ struct bcm_op *op, *next;
+
+ DBG("socket %p, sk %p\n", sock, sk);
+
+ /* remove bcm_ops, timer, rx_unregister(), etc. */
+
++ unregister_netdevice_notifier(&bo->notifier);
++
++ lock_sock(sk);
++
+ 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);
+ * can_rx_unregister() is always a save thing to do here.
+ */
+ if (op->ifindex) {
-+ struct net_device *dev = dev_get_by_index(op->ifindex);
++ /*
++ * Only remove subscriptions that had not
++ * been removed due to NETDEV_UNREGISTER
++ * in bcm_notifier()
++ */
++ if (op->rx_reg_dev) {
++ struct net_device *dev;
+
-+ if (dev) {
-+ can_rx_unregister(dev, op->can_id,
-+ REGMASK(op->can_id),
-+ bcm_rx_handler, op);
-+ dev_put(dev);
++ dev = dev_get_by_index(op->ifindex);
++ if (dev) {
++ bcm_rx_unreg(dev, op);
++ dev_put(dev);
++ }
+ }
-+
+ } else
+ can_rx_unregister(NULL, op->can_id,
+ REGMASK(op->can_id),
+ 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);
-+ }
++ /* remove device reference */
++ if (bo->bound) {
++ bo->bound = 0;
++ bo->ifindex = 0;
+ }
+
++ release_sock(sk);
+ sock_put(sk);
+
+ return 0;
+{
+ struct sockaddr_can *addr = (struct sockaddr_can *)uaddr;
+ struct sock *sk = sock->sk;
-+ struct bcm_opt *bo = bcm_sk(sk);
++ struct bcm_sock *bo = bcm_sk(sk);
+
+ if (bo->bound)
+ return -EISCONN;
+ addr->can_ifindex);
+ return -ENODEV;
+ }
++
++ if (dev->type != ARPHRD_CAN) {
++ DBG("device %d no CAN device\n", addr->can_ifindex);
++ dev_put(dev);
++ 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) */
++ /* no interface reference for ifindex = 0 ('any' CAN device) */
+ bo->ifindex = 0;
+ }
+
+ 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);
++ struct sockaddr_can *addr = msg->msg_name;
++ msg->msg_namelen = sizeof(*addr);
++ memset(addr, 0, sizeof(*addr));
++ addr->can_family = AF_CAN;
++ addr->can_ifindex = skb->iif;
+ }
+
+ DBG("freeing sock %p, skbuff %p\n", sk, skb);
---
drivers/net/Makefile | 1
- drivers/net/can/Kconfig | 25 +++
+ drivers/net/can/Kconfig | 25 ++++
drivers/net/can/Makefile | 5
- drivers/net/can/vcan.c | 308 +++++++++++++++++++++++++++++++++++++++++++++++
+ drivers/net/can/vcan.c | 287 +++++++++++++++++++++++++++++++++++++++++++++++
net/can/Kconfig | 3
- 5 files changed, 342 insertions(+)
+ 5 files changed, 321 insertions(+)
-Index: linux-2.6.22-rc2-git3/drivers/net/Makefile
+Index: linux-2.6.22-rc5/drivers/net/Makefile
===================================================================
---- linux-2.6.22-rc2-git3.orig/drivers/net/Makefile 2007-05-23 12:25:10.%N +0200
-+++ linux-2.6.22-rc2-git3/drivers/net/Makefile 2007-05-23 12:25:53.%N +0200
+--- linux-2.6.22-rc5.orig/drivers/net/Makefile 2007-06-20 14:10:41.000000000 +0200
++++ linux-2.6.22-rc5/drivers/net/Makefile 2007-06-20 14:11:19.000000000 +0200
@@ -8,6 +8,7 @@
obj-$(CONFIG_CHELSIO_T1) += chelsio/
obj-$(CONFIG_CHELSIO_T3) += cxgb3/
obj-$(CONFIG_BONDING) += bonding/
obj-$(CONFIG_ATL1) += atl1/
obj-$(CONFIG_GIANFAR) += gianfar_driver.o
-Index: linux-2.6.22-rc2-git3/drivers/net/can/Kconfig
+Index: linux-2.6.22-rc5/drivers/net/can/Kconfig
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22-rc2-git3/drivers/net/can/Kconfig 2007-05-23 12:25:53.%N +0200
++++ linux-2.6.22-rc5/drivers/net/can/Kconfig 2007-06-20 14:11:19.000000000 +0200
@@ -0,0 +1,25 @@
+menu "CAN Device Drivers"
+ depends on CAN
+ on.
+
+endmenu
-Index: linux-2.6.22-rc2-git3/drivers/net/can/Makefile
+Index: linux-2.6.22-rc5/drivers/net/can/Makefile
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22-rc2-git3/drivers/net/can/Makefile 2007-05-23 12:25:53.%N +0200
++++ linux-2.6.22-rc5/drivers/net/can/Makefile 2007-06-20 14:11:19.000000000 +0200
@@ -0,0 +1,5 @@
+#
+# Makefile for the Linux Controller Area Network drivers.
+#
+
+obj-$(CONFIG_CAN_VCAN) += vcan.o
-Index: linux-2.6.22-rc2-git3/drivers/net/can/vcan.c
+Index: linux-2.6.22-rc5/drivers/net/can/vcan.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22-rc2-git3/drivers/net/can/vcan.c 2007-05-23 12:25:53.%N +0200
-@@ -0,0 +1,308 @@
++++ linux-2.6.22-rc5/drivers/net/can/vcan.c 2007-06-20 14:11:19.000000000 +0200
+@@ -0,0 +1,287 @@
+/*
+ * vcan.c - Virtual CAN interface
+ *
+ stats->rx_bytes += skb->len;
+
+ skb->protocol = htons(ETH_P_CAN);
++ skb->pkt_type = PACKET_BROADCAST;
+ skb->dev = dev;
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+ stats->tx_packets++;
+ stats->tx_bytes += skb->len;
+
-+ /* tx socket reference pointer: Loopback required if not NULL */
-+ loop = *(struct sock **)skb->cb != NULL;
++ /* set flag whether this packet has to be looped back */
++ loop = skb->pkt_type == PACKET_LOOPBACK;
+
+ if (!loopback) {
+ /* no loopback handling available inside this driver */
+ /* perform standard loopback handling for CAN network interfaces */
+
+ if (loop) {
++ struct sock *srcsk = skb->sk;
++
+ if (atomic_read(&skb->users) != 1) {
+ struct sk_buff *old_skb = skb;
+
+ skb_orphan(skb);
+
+ /* receive with packet counting */
++ skb->sk = srcsk;
+ vcan_rx(skb, dev);
+ } else {
+ /* no looped packets => no counting */
+ 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);
-+ 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);
-+ return 0;
-+}
-+
-+
+static struct net_device_stats *vcan_get_stats(struct net_device *dev)
+{
+ struct net_device_stats *stats = netdev_priv(dev);
+
+ 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);
+}
+
+module_init(vcan_init_module);
+module_exit(vcan_cleanup_module);
-Index: linux-2.6.22-rc2-git3/net/can/Kconfig
+Index: linux-2.6.22-rc5/net/can/Kconfig
===================================================================
---- linux-2.6.22-rc2-git3.orig/net/can/Kconfig 2007-05-23 12:25:52.%N +0200
-+++ linux-2.6.22-rc2-git3/net/can/Kconfig 2007-05-23 12:25:53.%N +0200
+--- linux-2.6.22-rc5.orig/net/can/Kconfig 2007-06-20 14:11:13.000000000 +0200
++++ linux-2.6.22-rc5/net/can/Kconfig 2007-06-20 14:11:19.000000000 +0200
@@ -77,3 +77,6 @@
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
MAINTAINERS | 9 +++++++++
2 files changed, 25 insertions(+)
-Index: linux-2.6.22-rc2-git3/CREDITS
+Index: linux-2.6.22-rc5/CREDITS
===================================================================
---- linux-2.6.22-rc2-git3.orig/CREDITS 2007-05-27 07:40:05.%N +0200
-+++ linux-2.6.22-rc2-git3/CREDITS 2007-05-27 07:41:06.%N +0200
+--- linux-2.6.22-rc5.orig/CREDITS 2007-06-20 14:10:41.000000000 +0200
++++ linux-2.6.22-rc5/CREDITS 2007-06-20 14:11:27.000000000 +0200
@@ -1330,6 +1330,14 @@
S: 5623 HZ Eindhoven
S: The Netherlands
N: Jon Tombs
E: jon@gte.esi.us.es
W: http://www.esi.us.es/~jon
-Index: linux-2.6.22-rc2-git3/MAINTAINERS
+Index: linux-2.6.22-rc5/MAINTAINERS
===================================================================
---- linux-2.6.22-rc2-git3.orig/MAINTAINERS 2007-05-27 07:40:05.%N +0200
-+++ linux-2.6.22-rc2-git3/MAINTAINERS 2007-05-27 07:41:06.%N +0200
-@@ -943,6 +943,15 @@
+--- linux-2.6.22-rc5.orig/MAINTAINERS 2007-06-20 14:10:41.000000000 +0200
++++ linux-2.6.22-rc5/MAINTAINERS 2007-06-20 14:11:27.000000000 +0200
+@@ -951,6 +951,15 @@
L: video4linux-list@redhat.com
S: Maintained
Documentation/networking/can.txt | 635 ++++++++++++++++++++++++++++++++++++++
2 files changed, 637 insertions(+)
-Index: linux-2.6.22-rc3/Documentation/networking/can.txt
+Index: linux-2.6.22-rc5/Documentation/networking/can.txt
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22-rc3/Documentation/networking/can.txt 2007-05-29 10:14:54.%N +0200
++++ linux-2.6.22-rc5/Documentation/networking/can.txt 2007-06-20 14:11:31.000000000 +0200
@@ -0,0 +1,635 @@
+============================================================================
+
+ Klaus Hitschler (PEAK driver integration)
+ Uwe Koppe (CAN netdevices with PF_PACKET approach)
+ Michael Schulze (driver layer loopback requirement, RT CAN drivers review)
-Index: linux-2.6.22-rc3/Documentation/networking/00-INDEX
+Index: linux-2.6.22-rc5/Documentation/networking/00-INDEX
===================================================================
---- linux-2.6.22-rc3.orig/Documentation/networking/00-INDEX 2007-04-26 05:08:32.%N +0200
-+++ linux-2.6.22-rc3/Documentation/networking/00-INDEX 2007-05-30 12:37:31.%N +0200
+--- linux-2.6.22-rc5.orig/Documentation/networking/00-INDEX 2007-06-20 14:10:41.000000000 +0200
++++ linux-2.6.22-rc5/Documentation/networking/00-INDEX 2007-06-20 14:11:31.000000000 +0200
@@ -26,6 +26,8 @@
- info on the driver for Baycom style amateur radio modems
bridge.txt
--- /dev/null
+SUBJECT
+CAN: Add new PF_CAN protocol family, try #3
+ESUBJECT
+
+Hello Dave,
+
+this is the third post of the patch series that adds the PF_CAN
+protocol family for the Controller Area Network.
+
+Since our last post we have changed the code quite a lot:
+
+* Use sbk->sk and skb->pkt_type instead of skb->cb to pass loopback
+ flags and originating socket down to the driver and back to the
+ receiving socket. Thanks to Patrick McHardy for pointing out our
+ wrong use of sbk->cb.
+
+* Use skb->iif instead of skb->cb to pass receiving interface from
+ raw_rcv() and bcm_rcv() up to raw_recvmsg() and bcm_recvmsg().
+
+* Set skb->protocol when sending CAN frames to netdevices.
+
+* Removed struct raw_opt and struct bcm_opt and integrated these
+ directly into struct raw_sock and bcm_sock resp., like most other
+ proto implementations do.
+
+* We have found and fixed race conditions between raw_bind(),
+ raw_{set,get}sockopt() and raw_notifier(). This resulted in
+ - complete removal of our own notifier list infrastructure in
+ af_can.c. raw.c and bcm.c now use normal netdevice notifiers.
+ - removal of ro->lock spinlock. We use lock_sock(sk) now.
+ - changed deletion of dev_rcv_lists, which are now marked for
+ deletion in the netdevice notifier in af_can.c and are actually
+ deleted when all entries have been deleted using can_rx_unregister().
+
+* Follow changes in 2.6.22 (e.g. ktime_t timestamps in skb).
+
+* Removed obsolete code from vcan.c, as pointed out by Stephen Hemminger.
+
+This patch series applies against linux-2.6.22-rc5-git5 and is derived from
+Subversion revision r390 of http://svn.berlios.de/svnroot/repos/socketcan.
+It can be found in the directory
+http://svn.berlios.de/svnroot/repos/socketcan/trunk/patch-series/<version>.
+
+This patch doesn't touch anything in the kernel except for the allocation
+of a couple of numbers for protocol, arp hw type, and a line discipline.
+
+Please consider this patch series for integration into your tree.
+
+Thanks very much for your work!
+
+Best regards,
+
+Urs Thuermann
+Oliver Hartkopp