netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC v3 0/6] CAN: add SAE J1939 protocol
@ 2011-03-14 13:20 Kurt Van Dijck
       [not found] ` <20110314132004.GA333-MxZ6Iy/zr/UdbCeoMzGj59i2O/JbrIOy@public.gmane.org>
  0 siblings, 1 reply; 30+ messages in thread
From: Kurt Van Dijck @ 2011-03-14 13:20 UTC (permalink / raw)
  To: socketcan-core-0fE9KPoRgkgATYTw5x5z8w, netdev-u79uwXL29TY76Z2rM5mHXA

This series adds SAE J1939 support to the current net-next-2.6.
For the rtnetlink operations to work, a 2.6.38-rc1 is required.

1/6: can: extend sockaddr_can to include j1939 members
2/6: can: add rtnetlink support
3/6: can: make struct proto const
4/6: j1939: initial import of SAE J1939
5/6: j1939: add documentation & MAINTAINERS
6/6: iproute2: use CAN & J1939

Still a lot of things probably need explanation...

Kind regards,
Kurt Van Dijck
EIA Electronics

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [RFC v3 1/6] can: extend sockaddr_can to include j1939 members
       [not found] ` <20110314132004.GA333-MxZ6Iy/zr/UdbCeoMzGj59i2O/JbrIOy@public.gmane.org>
@ 2011-03-14 13:24   ` Kurt Van Dijck
  2011-03-14 14:15     ` Eric Dumazet
  2011-03-14 13:26   ` [RFC v3 2/6] can: add rtnetlink support Kurt Van Dijck
                     ` (5 subsequent siblings)
  6 siblings, 1 reply; 30+ messages in thread
From: Kurt Van Dijck @ 2011-03-14 13:24 UTC (permalink / raw)
  To: socketcan-core-0fE9KPoRgkgATYTw5x5z8w, netdev-u79uwXL29TY76Z2rM5mHXA

This patch prepares struct sockaddr_can for SAE J1939.
The size of this structure increases. To stay binary compatible,
the required_size macro is introduced for existing CAN protocols.

Signed-off-by: Kurt Van Dijck <kurt.van.dijck-/BeEPy95v10@public.gmane.org>
---
diff --git a/include/linux/can.h b/include/linux/can.h
index d183333..9c2523c 100644
--- a/include/linux/can.h
+++ b/include/linux/can.h
@@ -67,7 +67,8 @@ struct can_frame {
 #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_NPROTO	7
+#define CAN_J1939	7 /* SAE J1939 */
+#define CAN_NPROTO	8
 
 #define SOL_CAN_BASE 100
 
@@ -84,6 +85,23 @@ struct sockaddr_can {
 		/* transport protocol class address information (e.g. ISOTP) */
 		struct { canid_t rx_id, tx_id; } tp;
 
+		/* J1939 address information */
+		struct {
+			/* 8 byte name when using dynamic addressing */
+			__u64 name;
+			/*
+			 * pgn:
+			 * 8bit: PS in PDU2 case, else 0
+			 * 8bit: PF
+			 * 1bit: DP
+			 * 1bit: reserved
+			 */
+			__u32 pgn;
+
+			/* 1byte address */
+			__u8 addr;
+		} j1939;
+
 		/* reserved for future CAN protocols address information */
 	} can_addr;
 };
diff --git a/include/linux/can/core.h b/include/linux/can/core.h
index 6c507be..653c33e 100644
--- a/include/linux/can/core.h
+++ b/include/linux/can/core.h
@@ -42,6 +42,15 @@ struct can_proto {
 	struct proto     *prot;
 };
 
+/*
+ * required_size
+ * macro to find the minimum size of a struct
+ * that includes a requested member
+ */
+#define required_size(member, struct_type) \
+	(offsetof(typeof(struct_type), member) + \
+	 sizeof(((typeof(struct_type) *)(0))->member))
+
 /* function prototypes for the CAN networklayer core (af_can.c) */
 
 extern int  can_proto_register(struct can_proto *cp);
diff --git a/net/can/bcm.c b/net/can/bcm.c
index 092dc88..b286e45 100644
--- a/net/can/bcm.c
+++ b/net/can/bcm.c
@@ -1256,7 +1256,7 @@ static int bcm_sendmsg(struct kiocb *iocb, struct socket *sock,
 		struct sockaddr_can *addr =
 			(struct sockaddr_can *)msg->msg_name;
 
-		if (msg->msg_namelen < sizeof(*addr))
+		if (msg->msg_namelen < required_size(can_ifindex, *addr))
 			return -EINVAL;
 
 		if (addr->can_family != AF_CAN)
@@ -1493,7 +1493,7 @@ static int bcm_connect(struct socket *sock, struct sockaddr *uaddr, int len,
 	struct sock *sk = sock->sk;
 	struct bcm_sock *bo = bcm_sk(sk);
 
-	if (len < sizeof(*addr))
+	if (len < required_size(can_ifindex, *addr))
 		return -EINVAL;
 
 	if (bo->bound)
diff --git a/net/can/raw.c b/net/can/raw.c
index 883e9d7..a5f1f41 100644
--- a/net/can/raw.c
+++ b/net/can/raw.c
@@ -350,7 +350,7 @@ static int raw_bind(struct socket *sock, struct sockaddr *uaddr, int len)
 	int err = 0;
 	int notify_enetdown = 0;
 
-	if (len < sizeof(*addr))
+	if (len < required_size(can_ifindex, *addr))
 		return -EINVAL;
 
 	lock_sock(sk);
@@ -649,7 +649,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct socket *sock,
 		struct sockaddr_can *addr =
 			(struct sockaddr_can *)msg->msg_name;
 
-		if (msg->msg_namelen < sizeof(*addr))
+		if (msg->msg_namelen < required_size(can_ifindex, *addr))
 			return -EINVAL;
 
 		if (addr->can_family != AF_CAN)

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [RFC v3 2/6] can: add rtnetlink support
       [not found] ` <20110314132004.GA333-MxZ6Iy/zr/UdbCeoMzGj59i2O/JbrIOy@public.gmane.org>
  2011-03-14 13:24   ` [RFC v3 1/6] can: extend sockaddr_can to include j1939 members Kurt Van Dijck
@ 2011-03-14 13:26   ` Kurt Van Dijck
  2011-03-14 13:47   ` [RFC v3 3/6] can: make struct proto const Kurt Van Dijck
                     ` (4 subsequent siblings)
  6 siblings, 0 replies; 30+ messages in thread
From: Kurt Van Dijck @ 2011-03-14 13:26 UTC (permalink / raw)
  To: socketcan-core-0fE9KPoRgkgATYTw5x5z8w, netdev-u79uwXL29TY76Z2rM5mHXA

This patch adds rtnetlink support for AF_CAN. This support is really
a multiplexer towards the different CAN protocols.

Signed-off-by: Kurt Van Dijck <kurt.van.dijck-/BeEPy95v10@public.gmane.org>
---
diff --git a/include/linux/can/core.h b/include/linux/can/core.h
index 653c33e..430c446 100644
--- a/include/linux/can/core.h
+++ b/include/linux/can/core.h
@@ -18,6 +18,7 @@
 #include <linux/can.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
+#include <net/rtnetlink.h>
 
 #define CAN_VERSION "20090105"
 
@@ -40,6 +41,28 @@ struct can_proto {
 	int              protocol;
 	struct proto_ops *ops;
 	struct proto     *prot;
+
+	const struct rtnl_af_ops *rtnl_link_ops;
+	/*
+	 * hooks for rtnl hooks
+	 * for the *dump* functions, cb->args[0] is reserved
+	 * for use by af_can.c, so keep your fingers off.
+	 */
+	rtnl_doit_func rtnl_new_addr;
+	rtnl_doit_func rtnl_del_addr;
+	rtnl_dumpit_func rtnl_dump_addr;
+};
+
+/*
+ * this is quite a dirty hack:
+ * reuse the second byte of a rtnetlink msg
+ * to indicate the precise protocol.
+ * The major problem is that is may conflict
+ * with the prefixlen in struct ifaddrmsg.
+ */
+struct rtgencanmsg {
+	unsigned char		rtgen_family;
+	unsigned char		can_protocol;
 };
 
 /*
@@ -53,8 +76,8 @@ struct can_proto {
 
 /* function prototypes for the CAN networklayer core (af_can.c) */
 
-extern int  can_proto_register(struct can_proto *cp);
-extern void can_proto_unregister(struct can_proto *cp);
+extern int  can_proto_register(const struct can_proto *cp);
+extern void can_proto_unregister(const struct can_proto *cp);
 
 extern int  can_rx_register(struct net_device *dev, canid_t can_id,
 			    canid_t mask,
diff --git a/net/can/af_can.c b/net/can/af_can.c
index 702be5a..db59c6e 100644
--- a/net/can/af_can.c
+++ b/net/can/af_can.c
@@ -3,6 +3,7 @@
  *            (used by different CAN protocol modules)
  *
  * Copyright (c) 2002-2007 Volkswagen Group Electronic Research
+ * Copyright (C) 2011 Kurt Van Dijck <kurt.van.dijck-/BeEPy95v10@public.gmane.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -69,7 +70,8 @@ static __initdata const char banner[] = KERN_INFO
 MODULE_DESCRIPTION("Controller Area Network PF_CAN core");
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_AUTHOR("Urs Thuermann <urs.thuermann-l29pVbxQd1IUtdQbppsyvg@public.gmane.org>, "
-	      "Oliver Hartkopp <oliver.hartkopp-l29pVbxQd1IUtdQbppsyvg@public.gmane.org>");
+	      "Oliver Hartkopp <oliver.hartkopp-l29pVbxQd1IUtdQbppsyvg@public.gmane.org>, "
+	      "Kurt Van Dijck <kurt.van.dijck-/BeEPy95v10@public.gmane.org>");
 
 MODULE_ALIAS_NETPROTO(PF_CAN);
 
@@ -84,7 +86,7 @@ static DEFINE_SPINLOCK(can_rcvlists_lock);
 static struct kmem_cache *rcv_cache __read_mostly;
 
 /* table of registered CAN protocols */
-static struct can_proto *proto_tab[CAN_NPROTO] __read_mostly;
+static const struct can_proto *proto_tab[CAN_NPROTO];
 static DEFINE_SPINLOCK(proto_tab_lock);
 
 struct timer_list can_stattimer;   /* timer for statistics update */
@@ -92,6 +94,48 @@ struct s_stats    can_stats;       /* packet statistics */
 struct s_pstats   can_pstats;      /* receive list statistics */
 
 /*
+ * can protocol lookup
+ */
+#define CGP_F_LOAD	0x01 /* try to load protocol when absent */
+static inline const struct can_proto *can_get_proto(int protocol, int flags)
+{
+	const struct can_proto *cp;
+
+	if (protocol < 0 || protocol >= CAN_NPROTO)
+		return ERR_PTR(-EINVAL);
+
+#ifdef CONFIG_MODULES
+	/* try to load protocol module kernel is modular */
+	if (!proto_tab[protocol] && (flags & CGP_F_LOAD)) {
+		int ret;
+
+		ret = request_module("can-proto-%d", protocol);
+		/*
+		 * In case of error we only print a message but don't
+		 * return the error code immediately.  Below we will
+		 * return -EPROTONOSUPPORT
+		 */
+		if (ret)
+			pr_err_ratelimited("can: request_module "
+			       "(can-proto-%d) failed.\n", protocol);
+	}
+#endif
+
+	spin_lock(&proto_tab_lock);
+	cp = proto_tab[protocol];
+	if (cp && !try_module_get(cp->prot->owner))
+		cp = 0;
+	spin_unlock(&proto_tab_lock);
+	if (!cp)
+		cp = ERR_PTR(-ENOPROTOOPT);
+	return cp;
+}
+
+static inline void can_put_proto(const struct can_proto *cp)
+{
+	module_put(cp->prot->owner);
+}
+/*
  * af_can socket functions
  */
 
@@ -118,46 +162,22 @@ static int can_create(struct net *net, struct socket *sock, int protocol,
 		      int kern)
 {
 	struct sock *sk;
-	struct can_proto *cp;
+	const struct can_proto *cp;
 	int err = 0;
 
 	sock->state = SS_UNCONNECTED;
 
-	if (protocol < 0 || protocol >= CAN_NPROTO)
-		return -EINVAL;
-
 	if (!net_eq(net, &init_net))
 		return -EAFNOSUPPORT;
 
-#ifdef CONFIG_MODULES
-	/* try to load protocol module kernel is modular */
-	if (!proto_tab[protocol]) {
-		err = request_module("can-proto-%d", protocol);
-
-		/*
-		 * In case of error we only print a message but don't
-		 * return the error code immediately.  Below we will
-		 * return -EPROTONOSUPPORT
-		 */
-		if (err && printk_ratelimit())
-			printk(KERN_ERR "can: request_module "
-			       "(can-proto-%d) failed.\n", protocol);
-	}
-#endif
-
-	spin_lock(&proto_tab_lock);
-	cp = proto_tab[protocol];
-	if (cp && !try_module_get(cp->prot->owner))
-		cp = NULL;
-	spin_unlock(&proto_tab_lock);
-
+	cp = can_get_proto(protocol, CGP_F_LOAD);
 	/* check for available protocol and correct usage */
 
-	if (!cp)
-		return -EPROTONOSUPPORT;
+	if (IS_ERR(cp))
+		return PTR_ERR(cp);
 
 	if (cp->type != sock->type) {
-		err = -EPROTONOSUPPORT;
+		err = -ESOCKTNOSUPPORT;
 		goto errout;
 	}
 
@@ -182,7 +202,7 @@ static int can_create(struct net *net, struct socket *sock, int protocol,
 	}
 
  errout:
-	module_put(cp->prot->owner);
+	can_put_proto(cp);
 	return err;
 }
 
@@ -678,7 +698,7 @@ drop:
  *  -EBUSY  protocol already in use
  *  -ENOBUF if proto_register() fails
  */
-int can_proto_register(struct can_proto *cp)
+int can_proto_register(const struct can_proto *cp)
 {
 	int proto = cp->protocol;
 	int err = 0;
@@ -718,7 +738,7 @@ EXPORT_SYMBOL(can_proto_register);
  * can_proto_unregister - unregister CAN transport protocol
  * @cp: pointer to CAN protocol structure
  */
-void can_proto_unregister(struct can_proto *cp)
+void can_proto_unregister(const struct can_proto *cp)
 {
 	int proto = cp->protocol;
 
@@ -809,6 +829,206 @@ static struct notifier_block can_netdev_notifier __read_mostly = {
 	.notifier_call = can_notifier,
 };
 
+/*
+ * RTNETLINK
+ */
+static int can_rtnl_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+{
+	int ret, protocol;
+	const struct can_proto *cp;
+	rtnl_doit_func fn;
+
+	protocol = ((struct rtgencanmsg *)NLMSG_DATA(nlh))->can_protocol;
+	/* since rtnl_lock is held, dont try to load protocol */
+	cp = can_get_proto(protocol, 0);
+	if (IS_ERR(cp))
+		return PTR_ERR(cp);
+
+	switch (nlh->nlmsg_type) {
+	case RTM_NEWADDR:
+		fn = cp->rtnl_new_addr;
+		break;
+	case RTM_DELADDR:
+		fn = cp->rtnl_del_addr;
+		break;
+	default:
+		fn = 0;
+		break;
+	}
+	if (fn)
+		ret = fn(skb, nlh, arg);
+	else
+		ret = -EPROTONOSUPPORT;
+	can_put_proto(cp);
+	return ret;
+}
+
+static int can_rtnl_dumpit(struct sk_buff *skb, struct netlink_callback *cb,
+		int offset)
+{
+	int ret, j;
+	const struct can_proto *cp;
+	rtnl_dumpit_func fn;
+
+	ret = 0;
+	for (j = cb->args[0]; j < CAN_NPROTO; ++j) {
+		/* save state */
+		cb->args[0] = j;
+		cp = can_get_proto(j, 0);
+		if (IS_ERR(cp))
+			/* we are looping, any error is our own fault */
+			continue;
+		fn = *((rtnl_dumpit_func *)(&((const uint8_t *)cp)[offset]));
+		if (fn)
+			ret = fn(skb, cb);
+		can_put_proto(cp);
+		if (ret < 0)
+			/* suspend this skb */
+			return ret;
+	}
+	return ret;
+}
+
+static int can_rtnl_dump_addr(struct sk_buff *skb, struct netlink_callback *cb)
+{
+	return can_rtnl_dumpit(skb, cb,
+			offsetof(struct can_proto, rtnl_dump_addr));
+}
+
+/*
+ * LINK AF properties
+ */
+static size_t can_get_link_af_size(const struct net_device *dev)
+{
+	int ret, j, total;
+	const struct can_proto *cp;
+
+	if (!net_eq(dev_net(dev), &init_net) || (dev->type != ARPHRD_CAN))
+		return 0;
+
+	total = 0;
+	for (j = 0; j < CAN_NPROTO; ++j) {
+		cp = can_get_proto(j, 0);
+		if (IS_ERR(cp))
+			/* no worry */
+			continue;
+		ret = 0;
+		if (cp->rtnl_link_ops && cp->rtnl_link_ops->get_link_af_size)
+			ret = cp->rtnl_link_ops->get_link_af_size(dev) +
+				nla_total_size(sizeof(struct nlattr));
+		can_put_proto(cp);
+		if (ret < 0)
+			return ret;
+		total += ret;
+	}
+	return nla_total_size(total);
+}
+
+static int can_fill_link_af(struct sk_buff *skb, const struct net_device *dev)
+{
+	int ret, j, n;
+	struct nlattr *nla;
+	const struct can_proto *cp;
+
+	if (!net_eq(dev_net(dev), &init_net) || (dev->type != ARPHRD_CAN))
+		return -ENODATA;
+
+	n = 0;
+	for (j = 0; j < CAN_NPROTO; ++j) {
+		cp = can_get_proto(j, 0);
+		if (IS_ERR(cp))
+			/* no worry */
+			continue;
+		if (cp->rtnl_link_ops && cp->rtnl_link_ops->fill_link_af) {
+			nla = nla_nest_start(skb, j);
+			if (!nla)
+				goto nla_put_failure;
+
+			ret = cp->rtnl_link_ops->fill_link_af(skb, dev);
+			/*
+			 * Caller may return ENODATA to indicate that there
+			 * was no data to be dumped. This is not an error, it
+			 * means we should trim the attribute header and
+			 * continue.
+			 */
+			if (ret == -ENODATA)
+				nla_nest_cancel(skb, nla);
+			else if (ret < 0)
+				goto nla_put_failure;
+			nla_nest_end(skb, nla);
+			++n;
+		}
+		can_put_proto(cp);
+	}
+	return n ? 0 : -ENODATA;
+
+nla_put_failure:
+	nla_nest_cancel(skb, nla);
+	can_put_proto(cp);
+	return -EMSGSIZE;
+}
+
+static int can_validate_link_af(const struct net_device *dev,
+				 const struct nlattr *nla)
+{
+	int ret, rem;
+	const struct can_proto *cp;
+	struct nlattr *prot;
+
+	if (!net_eq(dev_net(dev), &init_net) || (dev->type != ARPHRD_CAN))
+		return -EPROTONOSUPPORT;
+
+	nla_for_each_nested(prot, nla, rem) {
+		cp = can_get_proto(nla_type(prot), 0);
+		if (IS_ERR(cp))
+			return PTR_ERR(cp);
+		if (!cp->rtnl_link_ops)
+			ret = -EPROTONOSUPPORT;
+		else if (!cp->rtnl_link_ops->validate_link_af)
+			ret = 0;
+		else
+			ret = cp->rtnl_link_ops->validate_link_af(dev, prot);
+		can_put_proto(cp);
+		if (ret < 0)
+			return ret;
+	}
+	return 0;
+}
+
+static int can_set_link_af(struct net_device *dev, const struct nlattr *nla)
+{
+	int ret, rem;
+	const struct can_proto *cp;
+	struct nlattr *prot;
+
+	if (!net_eq(dev_net(dev), &init_net) || (dev->type != ARPHRD_CAN))
+		return -EPROTONOSUPPORT;
+
+	nla_for_each_nested(prot, nla, rem) {
+		cp = can_get_proto(nla_type(prot), 0);
+		if (IS_ERR(cp))
+			return PTR_ERR(cp);
+		if (!cp->rtnl_link_ops || !cp->rtnl_link_ops->set_link_af)
+			ret = -EPROTONOSUPPORT;
+		else
+			ret = cp->rtnl_link_ops->set_link_af(dev, prot);
+		can_put_proto(cp);
+		if (ret < 0)
+			return ret;
+	}
+	return 0;
+}
+
+static struct rtnl_af_ops can_rtnl_af_ops = {
+	.family		  = AF_CAN,
+	.fill_link_af	  = can_fill_link_af,
+	.get_link_af_size = can_get_link_af_size,
+	.validate_link_af = can_validate_link_af,
+	.set_link_af	  = can_set_link_af,
+};
+
+/* exported init */
+
 static __init int can_init(void)
 {
 	printk(banner);
@@ -834,6 +1054,11 @@ static __init int can_init(void)
 	register_netdevice_notifier(&can_netdev_notifier);
 	dev_add_pack(&can_packet);
 
+	rtnl_af_register(&can_rtnl_af_ops);
+	rtnl_register(PF_CAN, RTM_NEWADDR, can_rtnl_doit, NULL);
+	rtnl_register(PF_CAN, RTM_DELADDR, can_rtnl_doit, NULL);
+	rtnl_register(PF_CAN, RTM_GETADDR, NULL, can_rtnl_dump_addr);
+
 	return 0;
 }
 
@@ -844,6 +1069,11 @@ static __exit void can_exit(void)
 	if (stats_timer)
 		del_timer(&can_stattimer);
 
+	rtnl_unregister(PF_CAN, RTM_NEWADDR);
+	rtnl_unregister(PF_CAN, RTM_DELADDR);
+	rtnl_unregister(PF_CAN, RTM_GETADDR);
+	rtnl_af_unregister(&can_rtnl_af_ops);
+
 	can_remove_proc();
 
 	/* protocol unregister */
diff --git a/net/can/bcm.c b/net/can/bcm.c
index b286e45..ac1961d 100644
--- a/net/can/bcm.c
+++ b/net/can/bcm.c
@@ -1596,7 +1596,7 @@ static struct proto bcm_proto __read_mostly = {
 	.init       = bcm_init,
 };
 
-static struct can_proto bcm_can_proto __read_mostly = {
+static const struct can_proto bcm_can_proto = {
 	.type       = SOCK_DGRAM,
 	.protocol   = CAN_BCM,
 	.ops        = &bcm_ops,
diff --git a/net/can/raw.c b/net/can/raw.c
index a5f1f41..9ad3dfc 100644
--- a/net/can/raw.c
+++ b/net/can/raw.c
@@ -769,7 +769,7 @@ static struct proto raw_proto __read_mostly = {
 	.init       = raw_init,
 };
 
-static struct can_proto raw_can_proto __read_mostly = {
+static const struct can_proto raw_can_proto = {
 	.type       = SOCK_RAW,
 	.protocol   = CAN_RAW,
 	.ops        = &raw_ops,

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [RFC v3 3/6] can: make struct proto const
       [not found] ` <20110314132004.GA333-MxZ6Iy/zr/UdbCeoMzGj59i2O/JbrIOy@public.gmane.org>
  2011-03-14 13:24   ` [RFC v3 1/6] can: extend sockaddr_can to include j1939 members Kurt Van Dijck
  2011-03-14 13:26   ` [RFC v3 2/6] can: add rtnetlink support Kurt Van Dijck
@ 2011-03-14 13:47   ` Kurt Van Dijck
  2011-03-14 14:09     ` Eric Dumazet
  2011-03-14 13:56   ` [RFC v3 4/6] j1939: initial import of SAE J1939 Kurt Van Dijck
                     ` (3 subsequent siblings)
  6 siblings, 1 reply; 30+ messages in thread
From: Kurt Van Dijck @ 2011-03-14 13:47 UTC (permalink / raw)
  To: socketcan-core-0fE9KPoRgkgATYTw5x5z8w, netdev-u79uwXL29TY76Z2rM5mHXA

can_ioctl is the only reason for struct proto to be non-const.
script/check-patch.pl suggests struct proto be const.
This patch performs the necessary change.

Signed-off-by: Kurt Van Dijck <kurt.van.dijck-/BeEPy95v10@public.gmane.org>
---
diff --git a/include/linux/can/core.h b/include/linux/can/core.h
index 430c446..0767cc6 100644
--- a/include/linux/can/core.h
+++ b/include/linux/can/core.h
@@ -39,7 +39,7 @@
 struct can_proto {
 	int              type;
 	int              protocol;
-	struct proto_ops *ops;
+	const struct proto_ops *ops;
 	struct proto     *prot;
 
 	const struct rtnl_af_ops *rtnl_link_ops;
@@ -78,6 +78,8 @@ struct rtgencanmsg {
 
 extern int  can_proto_register(const struct can_proto *cp);
 extern void can_proto_unregister(const struct can_proto *cp);
+extern int can_sock_ioctl(struct socket *sock, unsigned int cmd,
+		unsigned long arg);
 
 extern int  can_rx_register(struct net_device *dev, canid_t can_id,
 			    canid_t mask,
diff --git a/net/can/af_can.c b/net/can/af_can.c
index db59c6e..c1f8c05 100644
--- a/net/can/af_can.c
+++ b/net/can/af_can.c
@@ -139,7 +139,7 @@ static inline void can_put_proto(const struct can_proto *cp)
  * af_can socket functions
  */
 
-static int can_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+int can_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
 	struct sock *sk = sock->sk;
 
@@ -152,6 +152,7 @@ static int can_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 		return -ENOIOCTLCMD;
 	}
 }
+EXPORT_SYMBOL(can_sock_ioctl);
 
 static void can_sock_destruct(struct sock *sk)
 {
@@ -720,10 +721,6 @@ int can_proto_register(const struct can_proto *cp)
 		err = -EBUSY;
 	} else {
 		proto_tab[proto] = cp;
-
-		/* use generic ioctl function if not defined by module */
-		if (!cp->ops->ioctl)
-			cp->ops->ioctl = can_ioctl;
 	}
 	spin_unlock(&proto_tab_lock);
 
diff --git a/net/can/bcm.c b/net/can/bcm.c
index ac1961d..fd89542 100644
--- a/net/can/bcm.c
+++ b/net/can/bcm.c
@@ -1569,7 +1569,7 @@ static int bcm_recvmsg(struct kiocb *iocb, struct socket *sock,
 	return size;
 }
 
-static struct proto_ops bcm_ops __read_mostly = {
+static const struct proto_ops bcm_ops = {
 	.family        = PF_CAN,
 	.release       = bcm_release,
 	.bind          = sock_no_bind,
@@ -1578,7 +1578,7 @@ static struct proto_ops bcm_ops __read_mostly = {
 	.accept        = sock_no_accept,
 	.getname       = sock_no_getname,
 	.poll          = datagram_poll,
-	.ioctl         = NULL,		/* use can_ioctl() from af_can.c */
+	.ioctl         = can_sock_ioctl,
 	.listen        = sock_no_listen,
 	.shutdown      = sock_no_shutdown,
 	.setsockopt    = sock_no_setsockopt,
diff --git a/net/can/raw.c b/net/can/raw.c
index 9ad3dfc..8581596 100644
--- a/net/can/raw.c
+++ b/net/can/raw.c
@@ -742,7 +742,7 @@ static int raw_recvmsg(struct kiocb *iocb, struct socket *sock,
 	return size;
 }
 
-static struct proto_ops raw_ops __read_mostly = {
+static const struct proto_ops raw_ops = {
 	.family        = PF_CAN,
 	.release       = raw_release,
 	.bind          = raw_bind,
@@ -751,7 +751,7 @@ static struct proto_ops raw_ops __read_mostly = {
 	.accept        = sock_no_accept,
 	.getname       = raw_getname,
 	.poll          = datagram_poll,
-	.ioctl         = NULL,		/* use can_ioctl() from af_can.c */
+	.ioctl         = can_sock_ioctl,
 	.listen        = sock_no_listen,
 	.shutdown      = sock_no_shutdown,
 	.setsockopt    = raw_setsockopt,

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [RFC v3 4/6] j1939: initial import of SAE J1939
       [not found] ` <20110314132004.GA333-MxZ6Iy/zr/UdbCeoMzGj59i2O/JbrIOy@public.gmane.org>
                     ` (2 preceding siblings ...)
  2011-03-14 13:47   ` [RFC v3 3/6] can: make struct proto const Kurt Van Dijck
@ 2011-03-14 13:56   ` Kurt Van Dijck
  2011-03-14 13:59   ` [RFC v3 5/6] j1939: add documentation and MAINTAINERS Kurt Van Dijck
                     ` (2 subsequent siblings)
  6 siblings, 0 replies; 30+ messages in thread
From: Kurt Van Dijck @ 2011-03-14 13:56 UTC (permalink / raw)
  To: socketcan-core-0fE9KPoRgkgATYTw5x5z8w, netdev-u79uwXL29TY76Z2rM5mHXA

This patch contains the main SAE J1939 stack.

scripts/checkpatch.pl reports 3 errors like:
ERROR: return is not a function, parentheses are not required
#3819: FILE: net/can/j1939/transport.c:246:
+       return (dat[2] << 8) + (dat[1] << 0);

I don't see how to fix the checkpatch.pl error _and_ improving
the code.

Signed-off-by: Kurt Van Dijck <kurt.van.dijck-/BeEPy95v10@public.gmane.org>
---
diff --git a/include/linux/can/Kbuild b/include/linux/can/Kbuild
index 8cb05aa..0364eef 100644
--- a/include/linux/can/Kbuild
+++ b/include/linux/can/Kbuild
@@ -2,3 +2,4 @@ header-y += raw.h
 header-y += bcm.h
 header-y += error.h
 header-y += netlink.h
+header-y += j1939.h
diff --git a/include/linux/can/j1939.h b/include/linux/can/j1939.h
new file mode 100644
index 0000000..87d28e9
--- /dev/null
+++ b/include/linux/can/j1939.h
@@ -0,0 +1,100 @@
+/*
+ * j1939.h
+ *
+ * Copyright (c) 2010-2011 EIA Electronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _J1939_H_
+#define _J1939_H_
+
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/can.h>
+
+#define J1939_IDLE_ADDR	0xfe
+#define J1939_NO_ADDR	0xff
+#define J1939_NO_NAME	0
+#define J1939_NO_PGN	0x7ffff
+/*
+ * J1939 Parameter Group Number
+ *
+ * bit 0-7	: PDU Specific (PS)
+ * bit 8-15	: PDU Format (PF)
+ * bit 16	: Data Page (DP)
+ * bit 17	: Reserved (R)
+ * bit 19-31	: set to zero
+ */
+typedef __u32 pgn_t;
+
+/*
+ * J1939 Priority
+ *
+ * bit 0-2	: Priority (P)
+ * bit 3-7	: set to zero
+ */
+typedef __u8 priority_t;
+
+/*
+ * J1939 NAME
+ *
+ * bit 0-20	: Identity Number
+ * bit 21-31	: Manufacturer Code
+ * bit 32-34	: ECU Instance
+ * bit 35-39	: Function Instance
+ * bit 40-47	: Function
+ * bit 48	: Reserved
+ * bit 49-55	: Vehicle System
+ * bit 56-59	: Vehicle System Instance
+ * bit 60-62	: Industry Group
+ * bit 63	: Arbitrary Address Capable
+ */
+typedef __u64 name_t;
+
+/*
+ * J1939 socket options
+ */
+#define SOL_CAN_J1939 (SOL_CAN_BASE + CAN_J1939)
+enum {
+	SO_J1939_FILTER = 1,	/* set filters */
+	SO_J1939_PROMISC = 2,	/* set/clr promiscuous mode */
+	SO_J1939_RECV_OWN = 3,
+	SO_J1939_SEND_PRIO = 4,
+	SO_J1939_DEST_MASK = 5, /* mask names in connect() & sendto() */
+};
+
+enum {
+	SCM_J1939_DEST_ADDR = 1,
+	SCM_J1939_DEST_NAME = 2,
+	SCM_J1939_PRIO = 3,
+};
+
+struct j1939_filter {
+	name_t name;
+	name_t name_mask;
+	__u8 addr;
+	__u8 addr_mask;
+	pgn_t pgn;
+	pgn_t pgn_mask;
+};
+
+/*
+ * RTNETLINK
+ */
+enum {
+	IFLA_J1939_UNSPEC,
+	IFLA_J1939_ENABLE,
+	IFLA_J1939_MAX,
+};
+
+enum {
+	IFA_J1939_UNSPEC,
+	IFA_J1939_ADDR,
+	IFA_J1939_NAME,
+	IFA_J1939_MAX,
+};
+
+#endif /* _J1939_H_ */
diff --git a/net/can/Kconfig b/net/can/Kconfig
index 89395b2..7feb58c 100644
--- a/net/can/Kconfig
+++ b/net/can/Kconfig
@@ -40,5 +40,6 @@ config CAN_BCM
 	  CAN messages are used on the bus (e.g. in automotive environments).
 	  To use the Broadcast Manager, use AF_CAN with protocol CAN_BCM.
 
+source "net/can/j1939/Kconfig"
 
 source "drivers/net/can/Kconfig"
diff --git a/net/can/Makefile b/net/can/Makefile
index 2d3894b..953d851 100644
--- a/net/can/Makefile
+++ b/net/can/Makefile
@@ -10,3 +10,5 @@ can-raw-y		:= raw.o
 
 obj-$(CONFIG_CAN_BCM)	+= can-bcm.o
 can-bcm-y		:= bcm.o
+
+obj-$(CONFIG_CAN_J1939)	+= j1939/
diff --git a/net/can/j1939/Kconfig b/net/can/j1939/Kconfig
new file mode 100644
index 0000000..74d2a86
--- /dev/null
+++ b/net/can/j1939/Kconfig
@@ -0,0 +1,22 @@
+#
+# SAE J1939 network layer core configuration
+#
+
+config CAN_J1939
+	tristate "SAE J1939"
+	depends on CAN
+	---help---
+	  SAE J1939
+	  Say Y to have in-kernel support for j1939 socket type. This
+	  allows communication according to SAE j1939.
+	  The relevant parts in kernel are
+	  SAE j1939-21 (datalink & transport protocol)
+	  & SAE j1939-81 (network management).
+
+config CAN_J1939_DEBUG
+	bool "debug SAE J1939"
+	depends on CAN_J1939
+	default n
+	---help---
+	  Say Y to add extra debug code (via printk) in the j1939 stack
+
diff --git a/net/can/j1939/Makefile b/net/can/j1939/Makefile
new file mode 100644
index 0000000..7ca2fc9
--- /dev/null
+++ b/net/can/j1939/Makefile
@@ -0,0 +1,14 @@
+
+obj-$(CONFIG_CAN_J1939)	+= can-j1939.o
+
+can-j1939-objs := main.o \
+	proc.o bus.o \
+	rtnl.o \
+	socket.o \
+	address-claim.o transport.o \
+	promisc.o filter.o
+
+ifeq ($(CONFIG_CAN_J1939_DEBUG),y)
+	EXTRA_CFLAGS += -DDEBUG
+endif
+
diff --git a/net/can/j1939/address-claim.c b/net/can/j1939/address-claim.c
new file mode 100644
index 0000000..4793b9f
--- /dev/null
+++ b/net/can/j1939/address-claim.c
@@ -0,0 +1,527 @@
+/*
+ * Copyright (c) 2010-2011 EIA Electronics
+ *
+ * Authors:
+ * Pieter Beyens <pieter.beyens-/BeEPy95v10@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the version 2 of the GNU General Public License
+ * as published by the Free Software Foundation
+ */
+
+/*
+ * J1939 Address Claiming.
+ * Address Claiming in the kernel
+ * - keeps track of the AC states of ECU's,
+ * - resolves NAME<=>SA taking into account the AC states of ECU's.
+ *
+ * All Address Claim msgs (including host-originated msg) are processed
+ * at the receive path (a sent msg is always received again via CAN echo).
+ * As such, the processing of AC msgs is done in the order on which msgs
+ * are sent on the bus.
+ *
+ * This module doesn't send msgs itself (e.g. replies on Address Claims),
+ * this is the responsibility of a user space application or daemon.
+ */
+
+#include <linux/skbuff.h>
+#include <linux/byteorder/generic.h>
+
+#include "j1939-priv.h"
+
+static void ac_sm_step(struct j1939_ecu *ecu, int event, int new_sa);
+
+#define J1939_STACK_MODULE	"AC "
+#define j1939_ac_err(...)	j1939_err(J1939_STACK_MODULE __VA_ARGS__)
+#define j1939_ac_warning(...)	j1939_warning(J1939_STACK_MODULE __VA_ARGS__)
+#define j1939_ac_debug(...)	j1939_debug(J1939_STACK_MODULE __VA_ARGS__)
+
+#define PGN_REQUEST		0x00EA00
+#define PGN_ADDRESS_CLAIMED	0x00EE00
+
+#define NULL_ADDRESS		0xFE
+#define BROADCAST		0xFF
+
+#define CANDATA2NAME(data) le64_to_cpu(*(name_t *)(data))
+
+/* ECU address claiming states. */
+enum {
+	STATE_AC_SA_NONE = 0, /* no address claimed */
+	STATE_AC_SA_PENDING, /* address claim pending (waiting for 250ms) */
+	STATE_AC_SA_CLAIMED, /* successfully claimed sa */
+	STATE_AC_MAX /* do not remove */
+};
+
+/* State to name mapping. */
+static const char *st2name[STATE_AC_MAX] = {
+	"sa none",
+	"sa pending",
+	"sa claimed",
+};
+
+/* ECU address claiming events. */
+enum {
+	EVENT_AC_TX, /* tx of ac msg:
+	 * msg will be processed at rx side (via CAN intf echo)
+	 * but might already block outgoing traffic
+	 */
+	EVENT_AC_SA_CC,	/* cannot claim sa, 2 reasons:
+	 * rx of cannot claim msg or,
+	 * rx of address claim msg of conflicting ecu with higher prio
+	 */
+	EVENT_AC_SA_CL,	/* sa can be claimed, reason:
+	 * rx of address claim msg
+	 */
+	EVENT_AC_TIMEOUT, /* (250ms) timer expired */
+	EVENT_AC_MAX /* do not remove */
+};
+
+/* Event to name mapping. */
+static const char *ev2name[EVENT_AC_MAX] = {
+	"ac tx",
+	"sa cc",
+	"sa cl",
+	"timeout"
+};
+
+/* Impossible state change: print error. */
+static void ac_sm_bug(struct j1939_ecu *ecu, int new_sa)
+{
+	j1939_ac_err("BUG: invalid state change\n");
+}
+
+/*
+ * Process tx of an ac.
+ * The new_sa will be processed when the msg is received via CAN intf echo.
+ * Don't change source address as it can still be used for at rx side.
+ * Avoid further state changes (by cancelling the timer)
+ * until the ac msg (or another one) is received again.
+ */
+static void ac_sm_tx(struct j1939_ecu *ecu, int new_sa)
+{
+	if (new_sa != ecu->sa) {
+		hrtimer_try_to_cancel(&ecu->ac_timer);
+		ecu->block_tx = 1;
+	}
+}
+
+/*
+ * Process cannot claim sa
+ * as a result of cannot claim msg or lower prio name.
+ */
+static void ac_sm_sa_cc(struct j1939_ecu *ecu, int new_sa)
+{
+	hrtimer_try_to_cancel(&ecu->ac_timer);
+	ecu->ac_state = STATE_AC_SA_NONE;
+	j1939_ecu_set_address(ecu, -1);
+}
+
+/*
+ * Process address claim.
+ */
+static void ac_sm_sa_cl(struct j1939_ecu *ecu, int new_sa)
+{
+	if (ecu->sa == new_sa)
+		return;
+
+	hrtimer_try_to_cancel(&ecu->ac_timer);
+	ecu->ac_state = STATE_AC_SA_PENDING;
+	j1939_ecu_set_address(ecu, new_sa);
+	hrtimer_start(&ecu->ac_timer, ktime_set(0, 250000000),
+			HRTIMER_MODE_REL);
+}
+
+/*
+ * Process timer expiry.
+ */
+static void ac_sm_timeout(struct j1939_ecu *ecu, int new_sa)
+{
+	ecu->ac_state = STATE_AC_SA_CLAIMED;
+	ecu->block_tx = 0;
+}
+
+/*
+ * Address Claiming state machine.
+ * Redundant (unnecessary) state transitions get NULL.
+ * Invalid (impossible) state transitions dump an error (ac_sm_bug).
+ */
+static void (*const ac_sm[STATE_AC_MAX][EVENT_AC_MAX])
+	(struct j1939_ecu *ecu, int new_sa) = {
+	/* TX, SA_CC, SA_CL, TIMEOUT */
+	[STATE_AC_SA_NONE] = {
+		NULL, NULL, ac_sm_sa_cl, ac_sm_bug, },
+	[STATE_AC_SA_PENDING] = {
+		ac_sm_tx, ac_sm_sa_cc, ac_sm_sa_cl, ac_sm_timeout, },
+	[STATE_AC_SA_CLAIMED] = {
+		ac_sm_tx, ac_sm_sa_cc, ac_sm_sa_cl, ac_sm_bug, },
+};
+
+/*
+ * Progress state machine one step.
+ */
+static void ac_sm_step(struct j1939_ecu *ecu, int event, int new_sa)
+{
+	char *str;
+	char out[100];
+
+	str = out;
+	memset(out, '\0', 100);
+
+	BUG_ON(!ecu);
+	BUG_ON(event >= EVENT_AC_MAX || event < 0);
+
+	write_lock_bh(&ecu->ac_lock);
+
+	str += sprintf(str, "%i:%016llx (%02x,%s)",
+			ecu->ifindex, ecu->name,
+			(ecu->sa > 0) ? ecu->sa : 0x1ff,
+			st2name[ecu->ac_state]);
+	str += sprintf(str, " =[%s,0x%02x]=> ", ev2name[event], new_sa);
+
+	if (ac_sm[ecu->ac_state][event])
+		ac_sm[ecu->ac_state][event](ecu, new_sa);
+
+	str += sprintf(str, "(%02x,%s)",
+			(ecu->sa > 0) ? ecu->sa : 0x1ff,
+			st2name[ecu->ac_state]);
+
+	write_unlock_bh(&ecu->ac_lock);
+
+	j1939_ac_debug("%s\n", out);
+}
+
+static inline int ac_msg_is_address_claimed(pgn_t pgn, int sa)
+{
+	return (pgn == PGN_ADDRESS_CLAIMED) && (sa != NULL_ADDRESS);
+}
+
+static inline int ac_msg_is_cannot_claim(pgn_t pgn, int sa)
+{
+	return (pgn == PGN_ADDRESS_CLAIMED) && (sa == NULL_ADDRESS);
+}
+
+static inline int ac_msg_is_request_for_address_claimed(pgn_t pgn,
+		const unsigned char *d, unsigned int len)
+{
+	pgn_t req_pgn;
+
+	if (len < 3)
+		return 0;
+	/* Little Endian safe */
+	req_pgn = (d[0] << 0) | (d[1] << 8) | (d[2] << 16);
+	return (pgn == PGN_REQUEST) && (PGN_ADDRESS_CLAIMED == req_pgn);
+}
+
+/*
+ * Resolve a NAME to a SA, taking into account ac state.
+ * Returns invalid sa (<0) in case of failure.
+ */
+static int ac_name2sa(name_t name, int ifindex, int check_block_tx)
+{
+	int sa;
+	struct j1939_ecu *ecu = j1939_ecu_find_by_name(name, ifindex);
+
+	if (!ecu)
+		return -1;
+
+	read_lock_bh(&ecu->ac_lock);
+	if (ecu->ac_state == STATE_AC_SA_CLAIMED) {
+		if (check_block_tx && ecu->block_tx)
+			sa = -1;
+		else
+			sa = ecu->sa;
+	} else {
+		sa = -1;
+	}
+	read_unlock_bh(&ecu->ac_lock);
+
+	put_j1939_ecu(ecu);
+	return sa;
+}
+
+/*
+ * Resolve SA to NAME, taking into account ac state.
+ * Returns invalid name (=0) in case of failure.
+ */
+static name_t ac_sa2name(int sa, int ifindex)
+{
+	name_t name;
+	struct j1939_ecu *ecu = j1939_ecu_find_by_addr(sa, ifindex);
+
+	if (!ecu)
+		return 0;
+
+	read_lock_bh(&ecu->ac_lock);
+	if (ecu->ac_state == STATE_AC_SA_CLAIMED)
+		name = ecu->name;
+	else
+		name = 0;
+	read_unlock_bh(&ecu->ac_lock);
+
+	put_j1939_ecu(ecu);
+	return name;
+}
+
+static int ac_process_outgoing_address_claim(struct j1939_sk_buff_cb *sk_addr,
+		unsigned char *data, unsigned int len)
+{
+	int err = 0;
+	struct j1939_ecu *ecu;
+
+	if (len != 8) {
+		j1939_ac_warning("tx: invalid data length\n");
+		return -EPROTO;
+	}
+
+	if (sk_addr->src.name != CANDATA2NAME(data)) {
+		j1939_ac_warning("tx: src name (0x%016llx) != "
+				"data (0x%016llx)\n",
+				(long long)sk_addr->src.name,
+				(long long)CANDATA2NAME(data));
+		return -EPROTO;
+	}
+
+	if (sk_addr->src.addr == BROADCAST) {
+		j1939_ac_warning("tx: address claim with broadcast sa\n");
+		return -EPROTO;
+	}
+
+	/* ac must always be a broadcast */
+	if (sk_addr->dst.addr != BROADCAST) {
+		j1939_ac_warning("tx: address claim with da, not broadcast\n");
+		return -EPROTO;
+	}
+
+	/* if no matching ecu (name, ifindex) is found
+	 * then ecu will be created at the receive path of the AC msg. */
+	ecu = j1939_ecu_find_by_name(sk_addr->src.name, sk_addr->ifindex);
+
+	if (ecu) {
+		ac_sm_step(ecu, EVENT_AC_TX, sk_addr->src.addr);
+		put_j1939_ecu(ecu);
+	}
+	return err;
+}
+
+int j1939_send_address_claim(struct sk_buff *skb)
+{
+	int ret;
+	int sa;
+	struct j1939_sk_buff_cb *sk_addr = (struct j1939_sk_buff_cb *)skb->cb;
+
+	/*
+	 * network mgmt: address claiming msgs
+	 */
+	if (sk_addr->pgn == PGN_ADDRESS_CLAIMED) {
+		ret = ac_process_outgoing_address_claim(sk_addr, skb->data,
+				skb->len);
+		if (ret < 0)
+			j1939_ac_warning("tx drop: invalid address claim\n");
+		/* return both when failure & when successfull */
+		return ret;
+	}
+
+	/*
+	 * assign source address
+	 */
+	if (sk_addr->src.name) {
+		sa = ac_name2sa(sk_addr->src.name, sk_addr->ifindex,
+				1/* check block tx*/);
+		if (sa >= 0)
+			sk_addr->src.addr = sa;
+		else if (ac_msg_is_request_for_address_claimed(sk_addr->pgn,
+					skb->data, skb->len))
+			sk_addr->src.addr = NULL_ADDRESS;
+		else {
+			j1939_ac_warning("tx drop: invalid sa for name "
+					"0x%016llx\n", sk_addr->src.name);
+			return -EADDRNOTAVAIL;
+		}
+	}
+
+	/*
+	 * assign destination address
+	 */
+	if (sk_addr->dst.name) {
+		sa = ac_name2sa(sk_addr->dst.name, sk_addr->ifindex, 0);
+		if (sa >= 0) {
+			sk_addr->dst.addr = sa;
+		} else {
+			j1939_ac_warning("tx drop: invalid da for name "
+					"0x%016llx\n", sk_addr->dst.name);
+			return -EADDRNOTAVAIL;
+		}
+	}
+	return 0;
+}
+
+static struct j1939_ecu *ac_ecu_get(name_t name, int ifindex, uint8_t new_sa)
+{
+	struct j1939_ecu *ecu;
+	int ret;
+
+	ecu = j1939_ecu_find_by_name(name, ifindex);
+	if (ecu)
+		return ecu;
+
+	ecu = j1939_ecu_alloc(ifindex, name);
+	if (!ecu) {
+		j1939_ac_err("rx: failed to alloc ecu\n");
+		ret = -ENOMEM;
+		goto fail;
+	}
+	ecu->flags |= ECUFLAG_REMOTE;
+	ecu->sa = new_sa;
+	ret = j1939_ecu_register(ecu);
+	if (ret < 0) {
+		j1939_ac_err("rx: failed to register ecu\n");
+		goto fail_free;
+	}
+
+	if (!get_j1939_ecu(ecu)) {
+		ret = -EINVAL;
+		j1939_ac_err("rx: failed to incr ref of ecu\n");
+		goto fail_unreg;
+	}
+
+	return ecu;
+
+fail_unreg:
+	j1939_ecu_unregister(ecu);
+fail_free:
+	j1939_ecu_free(ecu);
+fail:
+	return ERR_PTR(ret);
+}
+
+/*
+ * Update the ac state of an ecu and resolves conflicts.
+ */
+static void ac_ecu_update(struct j1939_ecu *ecu, int new_sa)
+{
+	int event = EVENT_AC_MAX;
+
+	if (new_sa == NULL_ADDRESS) {
+		/* cannot claim */
+		event = EVENT_AC_SA_CC;
+	} else {
+		/* claim for sa => resolve conflicts */
+		int ev_conflict = EVENT_AC_MAX;
+		struct j1939_ecu *ecu_conflict;
+
+		ecu_conflict = j1939_ecu_find_by_addr(new_sa, ecu->ifindex);
+		if (ecu_conflict == ecu) {
+			put_j1939_ecu(ecu_conflict);
+			ecu_conflict = NULL;
+		}
+
+		if (!ecu_conflict) {
+			event = EVENT_AC_SA_CL;
+		} else if (!ecu_conflict->name) {
+			/*
+			 * a local, static ecu was using this address
+			 * This is stupid.
+			 * There's no point in contesting the address,
+			 * assume noone had claimed it
+			 * (which is in fact, true).
+			 * Both Pieter & Kurt are not really sure
+			 * EVENT_AC_SA_CL is the right thing to do here.
+			 */
+			j1939_ac_err("bus conflict on 0x%02x "
+					"with static ECU\n", new_sa);
+			event = EVENT_AC_SA_CL;
+		} else if (ecu->name < ecu_conflict->name) {
+			ev_conflict = EVENT_AC_SA_CC;
+			event = EVENT_AC_SA_CL;
+		} else if (ecu_conflict->name < ecu->name) {
+			ev_conflict = EVENT_AC_SA_CL;
+			event = EVENT_AC_SA_CC;
+		} else {
+			if (ecu_conflict)
+				put_j1939_ecu(ecu_conflict);
+			j1939_ac_err("2 ecu's with same name on bus?\n");
+			return;
+		}
+		if (ecu_conflict && ecu_conflict->name)
+			ac_sm_step(ecu_conflict, ev_conflict, new_sa);
+		if (ecu_conflict)
+			put_j1939_ecu(ecu_conflict);
+	}
+	ac_sm_step(ecu, event, new_sa);
+}
+
+static int ac_process_incoming_address_claim(struct j1939_sk_buff_cb *sk_addr,
+		unsigned char *data, unsigned int len)
+{
+	struct j1939_ecu *ecu;
+	name_t name;
+
+	if (len < 8) {
+		j1939_ac_warning("rx: address claim with dlc < 8\n");
+		return -EPROTO;
+	}
+
+	name = CANDATA2NAME(data);
+	if (!name) {
+		j1939_ac_warning("rx: address claim without name\n");
+		return -EPROTO;
+	}
+
+	if (!j1939_address_is_valid(sk_addr->src.addr)) {
+		j1939_ac_warning("rx: address claim with broadcast sa\n");
+		return -EPROTO;
+	}
+
+	sk_addr->src.name = name;
+	ecu = ac_ecu_get(name, sk_addr->ifindex, sk_addr->src.addr);
+	if (IS_ERR(ecu))
+		return PTR_ERR(ecu);
+
+	sk_addr->src.flags = ecu->flags;
+	ecu->rxtime = ktime_get();
+	ac_ecu_update(ecu, sk_addr->src.addr);
+
+	put_j1939_ecu(ecu);
+	return 0;
+}
+
+int j1939_recv_address_claim(struct sk_buff *skb)
+{
+	struct j1939_sk_buff_cb *sk_addr = (struct j1939_sk_buff_cb *)skb->cb;
+
+	/*
+	 * network mgmt
+	 */
+	if (sk_addr->pgn == PGN_ADDRESS_CLAIMED) {
+		int ret;
+		ret = ac_process_incoming_address_claim(sk_addr,
+				skb->data, skb->len);
+		if (ret)
+			return ret;
+	} else if (j1939_address_is_unicast(sk_addr->src.addr)) {
+		/*
+		 * assign source name
+		 */
+		sk_addr->src.name =
+			ac_sa2name(sk_addr->src.addr, sk_addr->ifindex);
+	}
+
+	/*
+	 * assign dest name
+	 */
+	if (j1939_address_is_unicast(sk_addr->dst.addr))
+		sk_addr->dst.name =
+			ac_sa2name(sk_addr->dst.addr, sk_addr->ifindex);
+
+	return 0;
+}
+
+enum hrtimer_restart j1939_ac_timer_handler(struct hrtimer *hrtimer)
+{
+	struct j1939_ecu *ecu =
+		container_of(hrtimer, struct j1939_ecu, ac_timer);
+
+	ac_sm_step(ecu, EVENT_AC_TIMEOUT, ecu->sa);
+	return HRTIMER_NORESTART;
+}
+
diff --git a/net/can/j1939/bus.c b/net/can/j1939/bus.c
new file mode 100644
index 0000000..78973c2
--- /dev/null
+++ b/net/can/j1939/bus.c
@@ -0,0 +1,533 @@
+/*
+ * Copyright (c) 2010-2011 EIA Electronics
+ *
+ * Authors:
+ * Kurt Van Dijck <kurt.van.dijck-/BeEPy95v10@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the version 2 of the GNU General Public License
+ * as published by the Free Software Foundation
+ */
+
+/*
+ * j1939-bus.c - bus for j1939 remote devices
+ * Since rtnetlink, no real bus is used.
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/workqueue.h>
+
+#include "j1939-priv.h"
+
+#define jseg_dbg(jseg, fmt, ...) \
+	pr_debug("j1939-%i: " fmt, (jseg)->ifindex, ##__VA_ARGS__)
+
+#define ecu_dbg(ecu, fmt, ...) \
+	pr_debug("j1939-%i,%016llx,%02x: " fmt, (ecu)->ifindex, (ecu)->name, \
+		((ecu)->sa >= 0) ? (ecu)->sa : J1939_NO_ADDR, ##__VA_ARGS__)
+#define ecu_alert(ecu, fmt, ...) \
+	pr_alert("j1939-%i,%016llx,%02x: " fmt, (ecu)->ifindex, (ecu)->name, \
+		((ecu)->sa >= 0) ? (ecu)->sa : J1939_NO_ADDR, ##__VA_ARGS__)
+
+static inline
+struct j1939_segment *j1939_ecu_to_segment(struct j1939_ecu *ecu)
+{
+	return ecu->parent;
+}
+
+static struct {
+	struct list_head list;
+	spinlock_t lock;
+} segments;
+
+struct j1939_segment *j1939_segment_find(int ifindex)
+{
+	struct j1939_segment *jseg;
+
+	spin_lock_bh(&segments.lock);
+	list_for_each_entry(jseg, &segments.list, flist) {
+		if (jseg->ifindex == ifindex) {
+			get_j1939_segment(jseg);
+			goto found;
+		}
+	}
+	jseg = NULL;
+found:
+	spin_unlock_bh(&segments.lock);
+	return jseg;
+}
+
+/*
+ * segment device interface
+ */
+static inline void jseg_release(struct j1939_segment *jseg)
+{
+	kfree(jseg);
+}
+static void cb_put_j1939_segment(struct kref *kref)
+{
+	jseg_release(container_of(kref, struct j1939_segment, kref));
+}
+void put_j1939_segment(struct j1939_segment *segment)
+{
+	kref_put(&segment->kref, cb_put_j1939_segment);
+}
+
+int j1939_segment_register(struct net_device *netdev)
+{
+	int ret;
+	struct j1939_segment *jseg;
+
+	jseg = j1939_segment_find(netdev->ifindex);
+	if (jseg) {
+		put_j1939_segment(jseg);
+		ret = -EALREADY;
+		goto fail_exist;
+	}
+	jseg = kzalloc(sizeof(*jseg), GFP_KERNEL);
+	if (!jseg) {
+		ret = -ENOMEM;
+		goto fail_malloc;
+	}
+	rwlock_init(&jseg->lock);
+	INIT_LIST_HEAD(&jseg->ecus);
+	INIT_LIST_HEAD(&jseg->flist);
+	jseg->ifindex = netdev->ifindex;
+
+	kref_init(&jseg->kref);
+
+	spin_lock_bh(&segments.lock);
+	list_add_tail(&jseg->flist, &segments.list);
+	spin_unlock_bh(&segments.lock);
+
+	jseg_dbg(jseg, "register\n");
+	return 0;
+
+fail_malloc:
+fail_exist:
+	return ret;
+}
+
+void j1939_segment_unregister(struct j1939_segment *jseg)
+{
+	struct j1939_ecu *ecu;
+
+	if (!jseg)
+		return;
+
+	spin_lock_bh(&segments.lock);
+	list_del_init(&jseg->flist);
+	spin_unlock_bh(&segments.lock);
+
+	write_lock_bh(&jseg->lock);
+	while (!list_empty(&jseg->ecus)) {
+		ecu = list_first_entry(&jseg->ecus, struct j1939_ecu, list);
+		write_unlock_bh(&jseg->lock);
+		j1939_ecu_unregister(ecu);
+		write_lock_bh(&jseg->lock);
+	}
+	write_unlock_bh(&jseg->lock);
+	jseg_dbg(jseg, "unregister\n");
+	put_j1939_segment(jseg);
+}
+
+/*
+ * ECU device interface
+ */
+void j1939_ecu_free(struct j1939_ecu *ecu)
+{
+	hrtimer_try_to_cancel(&ecu->ac_timer);
+	kfree(ecu);
+}
+EXPORT_SYMBOL_GPL(j1939_ecu_free);
+
+static void cb_put_j1939_ecu(struct kref *kref)
+{
+	j1939_ecu_free(container_of(kref, struct j1939_ecu, kref));
+}
+void put_j1939_ecu(struct j1939_ecu *ecu)
+{
+	kref_put(&ecu->kref, cb_put_j1939_ecu);
+}
+
+struct j1939_ecu *j1939_ecu_alloc(int ifindex, name_t name)
+{
+	struct j1939_ecu *ecu;
+
+	if (!name) {
+		pr_alert("%s(%i, 0), no name\n", __func__, ifindex);
+		return NULL;
+	}
+	ecu = kzalloc(sizeof(*ecu), GFP_KERNEL);
+	if (!ecu)
+		return NULL;
+	kref_init(&ecu->kref);
+	ecu->sa = J1939_IDLE_ADDR;
+	ecu->name = name;
+	ecu->ifindex = ifindex;
+
+	/* address claiming init */
+	hrtimer_init(&ecu->ac_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	ecu->ac_timer.function = j1939_ac_timer_handler;
+	rwlock_init(&ecu->ac_lock);
+
+	INIT_LIST_HEAD(&ecu->list);
+	return ecu;
+}
+EXPORT_SYMBOL_GPL(j1939_ecu_alloc);
+
+int j1939_ecu_register(struct j1939_ecu *ecu)
+{
+	int ret;
+	struct j1939_segment *parent;
+	struct list_head *lst;
+	struct j1939_ecu *dut;
+
+	if (ecu->ifindex < 0) {
+		ecu_alert(ecu, "register with no ifindex\n");
+		return -EINVAL;
+	}
+	parent = j1939_segment_find(ecu->ifindex);
+	if (!parent) {
+		ecu_alert(ecu, "parent not found\n");
+		return -EINVAL;
+	}
+	ecu->parent = parent;
+
+	/* first add to internal list */
+	write_lock_bh(&parent->lock);
+	if (ecu->name) {
+		/* test for duplicate name */
+		list_for_each(lst, &ecu->list) {
+			dut = list_entry(lst, struct j1939_ecu, list);
+			if (dut->name == ecu->name) {
+				ecu_alert(ecu, "duplicate name\n");
+				ret = -EEXIST;
+				goto fail_duplicate;
+			}
+		}
+	}
+	list_add_tail(&ecu->list, &parent->ecus);
+	if (j1939_address_is_unicast(ecu->sa))
+		parent->ents[ecu->sa].ecu = ecu;
+	write_unlock_bh(&parent->lock);
+
+	put_j1939_segment(parent);
+	ecu_dbg(ecu, "register\n");
+	return 0;
+
+fail_duplicate:
+	write_unlock_bh(&parent->lock);
+
+	put_j1939_segment(parent);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(j1939_ecu_register);
+
+void j1939_ecu_unregister(struct j1939_ecu *ecu)
+{
+	struct j1939_segment *parent;
+
+	if (!ecu)
+		return;
+
+	ecu_dbg(ecu, "unregister\n");
+	parent = j1939_ecu_to_segment(ecu);
+	get_j1939_segment(parent);
+	j1939_ecu_set_address(ecu, -1);
+	write_lock_bh(&parent->lock);
+	list_del_init(&ecu->list);
+	write_unlock_bh(&parent->lock);
+	put_j1939_ecu(ecu);
+	put_j1939_segment(parent);
+}
+EXPORT_SYMBOL_GPL(j1939_ecu_unregister);
+
+struct j1939_ecu *j1939_ecu_find_by_addr(int sa, int ifindex)
+{
+	struct j1939_ecu *ecu;
+	struct j1939_segment *parent;
+
+	if (!j1939_address_is_unicast(sa))
+		return NULL;
+	parent = j1939_segment_find(ifindex);
+	if (!parent)
+		return NULL;
+	read_lock_bh(&parent->lock);
+	ecu = parent->ents[sa].ecu;
+	if (ecu)
+		get_j1939_ecu(ecu);
+	read_unlock_bh(&parent->lock);
+	put_j1939_segment(parent);
+	return ecu;
+}
+EXPORT_SYMBOL_GPL(j1939_ecu_find_by_addr);
+
+struct j1939_ecu *j1939_ecu_find_segment_default_tx(int ifindex,
+		name_t *name, uint8_t *addr)
+{
+	struct j1939_ecu *ecu;
+	struct j1939_segment *parent;
+	struct addr_ent *paddr;
+	int j;
+
+	if (ifindex <= 0)
+		return ERR_PTR(-EINVAL);
+	parent = j1939_segment_find(ifindex);
+	if (!parent)
+		return ERR_PTR(-ENETUNREACH);
+	read_lock_bh(&parent->lock);
+	list_for_each_entry(ecu, &parent->ecus, list) {
+		if (ecu->flags & ECUFLAG_LOCAL) {
+			get_j1939_ecu(ecu);
+			if (name)
+				*name = ecu->name;
+			if (addr)
+				*addr = ecu->sa;
+			goto found;
+		}
+	}
+	ecu = NULL;
+	for (j = 0, paddr = parent->ents; j < J1939_IDLE_ADDR; ++j, ++paddr) {
+		if (paddr->ecu)
+			continue;
+		if (paddr->flags & ECUFLAG_LOCAL) {
+			if (name)
+				*name = 0;
+			if (addr)
+				*addr = j;
+			goto found;
+		}
+	}
+	ecu = ERR_PTR(-EHOSTDOWN);
+found:
+	read_unlock_bh(&parent->lock);
+	put_j1939_segment(parent);
+	return ecu;
+}
+EXPORT_SYMBOL_GPL(j1939_ecu_find_segment_default_tx);
+
+/* find ecu in segment (having segment's kref & readlock) */
+static struct j1939_ecu *_j1939_segment_find_name_masked(
+		name_t name, name_t mask, struct j1939_segment *parent)
+{
+	struct j1939_ecu *ecu;
+
+	if (!name)
+		return NULL;
+	if (!parent)
+		return NULL;
+	name &= mask;
+	list_for_each_entry(ecu, &parent->ecus, list) {
+		if ((ecu->name & mask) == name)
+			return get_j1939_ecu(ecu);
+	}
+	return NULL;
+}
+/* find ecu in segment (having segment's kref) */
+static struct j1939_ecu *j1939_segment_find_name_masked(
+		name_t name, name_t mask, struct j1939_segment *parent)
+{
+	struct j1939_ecu *ecu;
+
+	if (!name || !parent)
+		return NULL;
+	read_lock_bh(&parent->lock);
+	ecu = _j1939_segment_find_name_masked(name, mask, parent);
+	read_unlock_bh(&parent->lock);
+	return ecu;
+}
+struct j1939_ecu *j1939_ecu_find_name_masked(name_t name, name_t mask,
+		int ifindex)
+{
+	struct j1939_ecu *ecu;
+	struct j1939_segment *jseg;
+
+	if (!name)
+		return NULL;
+	if (ifindex) {
+		jseg = j1939_segment_find(ifindex);
+		if (!jseg)
+			return NULL;
+		ecu = j1939_segment_find_name_masked(name, mask, jseg);
+		put_j1939_segment(jseg);
+		return ecu;
+	}
+	/* iterate segments */
+	spin_lock_bh(&segments.lock);
+	list_for_each_entry(jseg, &segments.list, flist) {
+		get_j1939_segment(jseg);
+		ecu = j1939_segment_find_name_masked(name, mask, jseg);
+		put_j1939_segment(jseg);
+		if (ecu)
+			goto found;
+	}
+	ecu = NULL;
+found:
+	spin_unlock_bh(&segments.lock);
+	return ecu;
+}
+EXPORT_SYMBOL_GPL(j1939_ecu_find_name_masked);
+
+static void _clear_ecu_flags(struct j1939_ecu *ecu, struct addr_ent *ent)
+{
+	int clearflags = ECUFLAG_LOCAL | ECUFLAG_REMOTE;
+
+	/*
+	 * when the SA is a static one too,
+	 * prevent it from getting cleared.
+	 */
+	clearflags = ECUFLAG_REMOTE |
+		((ent->flags & ECUFLAG_STATIC) ? 0 : ECUFLAG_LOCAL);
+	ent->flags &= ~(ecu->flags & clearflags);
+}
+
+int j1939_ecu_set_address(struct j1939_ecu *ecu, int sa)
+{
+	struct j1939_segment *parent = j1939_ecu_to_segment(ecu);
+	struct addr_ent *ent;
+
+	write_lock_bh(&parent->lock);
+	if (j1939_address_is_unicast(ecu->sa)) {
+		ent = &parent->ents[ecu->sa];
+		if (ent->ecu == ecu) {
+			ent->ecu = NULL;
+			_clear_ecu_flags(ecu, ent);
+		}
+	}
+	if (j1939_address_is_unicast(sa)) {
+		ent = &parent->ents[ecu->sa];
+		if (ent->ecu) {
+			ent->ecu->sa = J1939_IDLE_ADDR;
+			_clear_ecu_flags(ecu, ent);
+		}
+		ent->ecu = ecu;
+		ent->flags |= ecu->flags;
+	}
+	ecu->sa = sa;
+	write_unlock_bh(&parent->lock);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(j1939_ecu_set_address);
+
+/* PROC */
+static int j1939_proc_addr(struct seq_file *sqf, void *v)
+{
+	struct j1939_segment *jseg;
+	struct net_device *netdev;
+	struct addr_ent *paddr;
+	int j;
+	ktime_t now;
+	struct timeval tv;
+
+	now = ktime_get();
+	seq_printf(sqf, "iface\tSA\tflags\trxtime\n");
+	spin_lock_bh(&segments.lock);
+	list_for_each_entry(jseg, &segments.list, flist) {
+		get_j1939_segment(jseg);
+		netdev = dev_get_by_index(&init_net, jseg->ifindex);
+		if (!netdev) {
+			pr_alert("j1939 proc: ifindex %i not found\n",
+				jseg->ifindex);
+			put_j1939_segment(jseg);
+			continue;
+		}
+		read_lock_bh(&jseg->lock);
+		for (j = 0, paddr = jseg->ents; j < J1939_IDLE_ADDR;
+				++j, ++paddr) {
+			tv = ktime_to_timeval(ktime_sub(now, paddr->rxtime));
+			if (!paddr->flags && !paddr->ecu)
+				continue;
+			seq_printf(sqf, "%s\t%02x\t%c%c%c%c\t-%lu.%06lu\n",
+				netdev->name, j,
+				(paddr->flags & ECUFLAG_STATIC) ? 'S' : '-',
+				(paddr->flags & ECUFLAG_LOCAL) ? 'L' : '-',
+				(paddr->flags & ECUFLAG_REMOTE) ? 'R' : '-',
+				paddr->ecu ? 'E' : '.',
+				tv.tv_sec, tv.tv_usec);
+		}
+		read_unlock_bh(&jseg->lock);
+		dev_put(netdev);
+		put_j1939_segment(jseg);
+	}
+	spin_unlock_bh(&segments.lock);
+	return 0;
+}
+
+static int j1939_proc_ecu(struct seq_file *sqf, void *v)
+{
+	struct j1939_segment *jseg;
+	struct j1939_ecu *ecu;
+	struct net_device *netdev;
+	ktime_t now;
+	struct timeval tv;
+	char sa[4];
+
+	now = ktime_get();
+	seq_printf(sqf, "iface\taddr\tname\tflags\trxtime\n");
+	spin_lock_bh(&segments.lock);
+	list_for_each_entry(jseg, &segments.list, flist) {
+		get_j1939_segment(jseg);
+		netdev = dev_get_by_index(&init_net, jseg->ifindex);
+		if (!netdev) {
+			pr_alert("j1939 proc: ifindex %i not found\n",
+				jseg->ifindex);
+			put_j1939_segment(jseg);
+			continue;
+		}
+		read_lock_bh(&jseg->lock);
+		list_for_each_entry(ecu, &jseg->ecus, list) {
+			tv = ktime_to_timeval(ktime_sub(now, ecu->rxtime));
+			if (ecu->sa < 0)
+				strcpy(sa, "-");
+			else
+				snprintf(sa, sizeof(sa), "%02x", ecu->sa);
+			seq_printf(sqf, "%s\t%s\t%016llx\t%c\t-%lu.%06lu\n",
+				netdev->name, sa,
+				(unsigned long long)ecu->name,
+				(ecu->flags & ECUFLAG_LOCAL) ? 'L' : 'R',
+				tv.tv_sec, tv.tv_usec);
+		}
+		read_unlock_bh(&jseg->lock);
+		dev_put(netdev);
+		put_j1939_segment(jseg);
+	}
+	spin_unlock_bh(&segments.lock);
+	return 0;
+}
+
+/* exported init */
+int __init j1939bus_module_init(void)
+{
+	INIT_LIST_HEAD(&segments.list);
+	spin_lock_init(&segments.lock);
+	j1939_proc_add("addr", j1939_proc_addr, NULL);
+	j1939_proc_add("ecu", j1939_proc_ecu, NULL);
+	return 0;
+}
+
+void j1939bus_module_exit(void)
+{
+	struct j1939_segment *jseg;
+	struct net_device *netdev;
+
+	spin_lock_bh(&segments.lock);
+	while (!list_empty(&segments.list)) {
+		jseg = list_first_entry(&segments.list,
+				struct j1939_segment, flist);
+		netdev = dev_get_by_index(&init_net, jseg->ifindex);
+		spin_unlock_bh(&segments.lock);
+		j1939_segment_detach(netdev);
+		dev_put(netdev);
+		spin_lock_bh(&segments.lock);
+	}
+	spin_unlock_bh(&segments.lock);
+
+	j1939_proc_remove("ecu");
+	j1939_proc_remove("addr");
+}
+
+
diff --git a/net/can/j1939/filter.c b/net/can/j1939/filter.c
new file mode 100644
index 0000000..47fc52c
--- /dev/null
+++ b/net/can/j1939/filter.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2010-2011 EIA Electronics
+ *
+ * Authors:
+ * Pieter Beyens <pieter.beyens-/BeEPy95v10@public.gmane.org>
+ * Kurt Van Dijck <kurt.van.dijck-/BeEPy95v10@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the version 2 of the GNU General Public License
+ * as published by the Free Software Foundation
+ */
+
+#include <linux/list.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+
+#include "j1939-priv.h"
+
+static LIST_HEAD(filters);
+DEFINE_RWLOCK(j1939_receiver_rwlock); /* protects the filter list */
+
+struct filter {
+	struct list_head list;
+	void *vp;
+	void (*fn)(struct sk_buff *, void *);
+};
+
+int j1939_recv_distribute(struct sk_buff *skb)
+{
+	struct filter *filter;
+
+	read_lock(&j1939_receiver_rwlock);
+	list_for_each_entry(filter, &filters, list)
+		filter->fn(skb, filter->vp);
+	read_unlock(&j1939_receiver_rwlock);
+
+	return 0;
+}
+
+int j1939_recv_add(void *vp, void (*fn)(struct sk_buff *, void *))
+{
+	struct filter *f;
+
+	f = kzalloc(sizeof(*f), GFP_KERNEL);
+	if (!f)
+		return -ENOMEM;
+
+	f->vp = vp;
+	f->fn = fn;
+
+	j1939_recv_suspend();
+	list_add(&f->list, &filters);
+	j1939_recv_resume();
+	return 0;
+}
+
+int j1939_recv_remove(void *vp, void (*fn)(struct sk_buff *, void *))
+{
+	struct filter *filter;
+	int found = 0;
+
+	j1939_recv_suspend();
+	list_for_each_entry(filter, &filters, list) {
+		if ((filter->vp == vp) && (filter->fn == fn)) {
+			list_del_init(&filter->list);
+			kfree(filter);
+			found = 1;
+			break;
+		}
+	}
+	j1939_recv_resume();
+	return found ? 0 : -ENOENT;
+}
+
diff --git a/net/can/j1939/j1939-priv.h b/net/can/j1939/j1939-priv.h
new file mode 100644
index 0000000..64008e9
--- /dev/null
+++ b/net/can/j1939/j1939-priv.h
@@ -0,0 +1,287 @@
+/*
+ * j1939-priv.h
+ *
+ * Copyright (c) 2010-2011 EIA Electronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _J1939_PRIV_H_
+#define _J1939_PRIV_H_
+
+#include <linux/kref.h>
+#include <linux/list.h>
+#include <net/sock.h>
+
+#include <linux/seq_file.h>
+#include <linux/proc_fs.h>
+#include <linux/module.h>
+#include <linux/can/j1939.h>
+#include <linux/atomic.h>
+
+/* TODO: return ENETRESET on busoff. */
+
+#define ECUFLAG_LOCAL	0x01
+#define ECUFLAG_REMOTE	0x02
+#define ECUFLAG_STATIC	0x04
+/*
+ * j1939 devices
+ */
+struct j1939_ecu {
+	struct list_head list;
+	name_t		name;
+	int		flags;
+	ktime_t		rxtime;
+	int		ifindex;
+	int		sa;
+	int		ac_state;
+	struct hrtimer	ac_timer;
+	uint8_t		block_tx; /*
+	 * Outgoing traffic can be blocked by an outgoing Address Claim msg,
+	 * The Address Claim msg itself is processed
+	 * when it's received again via CAN intf echo.
+	 * State changes (ac_state) are only done at rx path.
+	 */
+	rwlock_t	ac_lock; /*
+	 * protects members which are updated by address claiming logic:
+	 * sa, ac_state, ac_timer, block_tx
+	 */
+	struct kref kref;
+	struct j1939_segment *parent;
+};
+#define to_j1939_ecu(x) container_of((x), struct j1939_ecu, dev)
+
+struct j1939_segment {
+	struct list_head ecus; /*
+	 * local list entry in parent
+	 * These allow irq (& softirq) context lookups on j1939 devices
+	 * This approach (seperate lists) is done as the other 2 alternatives
+	 * are not easier or even wrong
+	 * 1) using the pure kobject methods involves mutexes, which are not
+	 *    allowed in irq context.
+	 * 2) duplicating data structures would require a lot of synchronization
+	 *    code
+	 * usage:
+	 */
+	rwlock_t lock; /*
+	 * segments need a lock to protect the above list
+	 */
+	struct list_head flist; /*
+	 * list entry for use by interrupt lookup routines
+	 */
+	int		ifindex;
+	struct addr_ent {
+		struct j1939_ecu *ecu;
+		int flags;
+		ktime_t rxtime;
+	} ents[256];
+	/*
+	 * list of 256 ecu ptrs, that cache the claimed addresses.
+	 * also protected by the above lock
+	 * don't use directly, use j1939_ecu_set_address() instead
+	 */
+	struct kref kref;
+};
+#define to_j1939_segment(x) container_of((x), struct j1939_segment, dev)
+
+extern void put_j1939_ecu(struct j1939_ecu *ecu);
+extern void put_j1939_segment(struct j1939_segment *segment);
+static inline struct j1939_ecu *get_j1939_ecu(struct j1939_ecu *dut)
+{
+	kref_get(&dut->kref);
+	return dut;
+}
+static inline struct j1939_segment *get_j1939_segment(struct j1939_segment *dut)
+{
+	kref_get(&dut->kref);
+	return dut;
+}
+
+/*
+ * conversion function between (struct sock | struct sk_buff)->sk_priority
+ * from linux and j1939 priority field
+ */
+static inline int j1939_prio(int sk_priority)
+{
+	if (sk_priority < 0)
+		return 6; /* default */
+	else if (sk_priority > 7)
+		return 0;
+	else
+		return 7 - sk_priority;
+}
+static inline int j1939_to_sk_priority(int j1939_prio)
+{
+	return 7 - j1939_prio;
+}
+
+static inline int j1939_address_is_valid(int sa)
+{
+	return (sa >= 0) && (sa < 0xff);
+}
+
+static inline int j1939_address_is_unicast(int sa)
+{
+	return (sa >= 0) && (sa < 0xfe);
+}
+
+static inline int pgn_is_pdu1(pgn_t pgn)
+{
+	return (pgn & 0xff00) < 0xf000;
+}
+
+#define NO_PGN	0x40000
+static inline int pgn_is_valid(pgn_t pgn)
+{
+	return (pgn < NO_PGN);
+}
+
+extern struct j1939_ecu *j1939_ecu_find_by_addr(int sa, int ifindex);
+extern struct j1939_ecu *j1939_ecu_find_name_masked(
+		name_t name, name_t mask, int ifindex);
+static inline struct j1939_ecu *j1939_ecu_find_by_name(name_t name, int ifindex)
+{
+	return j1939_ecu_find_name_masked(name, 0xffffffffffffffffULL, ifindex);
+}
+/* find_by_name, with kref & read_lock taken */
+extern int j1939_ecu_set_address(struct j1939_ecu *, int sa);
+extern struct j1939_ecu *j1939_ecu_find_segment_default_tx(
+		int ifindex, name_t *pname, uint8_t *paddr);
+
+extern void j1939_put_promisc_receiver(int ifindex);
+extern void j1939_get_promisc_receiver(int ifindex);
+
+extern int j1939_proc_add(const char *file,
+		int (*seq_show)(struct seq_file *sqf, void *v),
+		write_proc_t write);
+extern void j1939_proc_remove(const char *file);
+
+extern const char j1939_procname[];
+/* j1939 printk */
+#define j1939_printk(level, ...) printk(level "J1939 " __VA_ARGS__)
+
+#define j1939_err(...)		j1939_printk(KERN_ERR , __VA_ARGS__)
+#define j1939_warning(...)	j1939_printk(KERN_WARNING , __VA_ARGS__)
+#define j1939_notice(...)	j1939_printk(KERN_NOTICE , __VA_ARGS__)
+#define j1939_info(...)		j1939_printk(KERN_INFO , __VA_ARGS__)
+#ifdef DEBUG
+#define j1939_debug(...)	j1939_printk(KERN_DEBUG , __VA_ARGS__)
+#else
+#define j1939_debug(...)
+#endif
+
+struct sk_buff;
+
+/* control buffer of the sk_buff */
+struct j1939_sk_buff_cb {
+	int ifindex;
+	priority_t priority;
+	struct {
+		name_t name;
+		uint8_t addr;
+		int flags;
+	} src, dst;
+	pgn_t pgn;
+	int msg_flags;
+	/* for tx, MSG_SYN will be used to sync on sockets */
+};
+#define J1939_MSG_RESERVED	MSG_SYN
+#define J1939_MSG_SYNC		MSG_SYN
+
+static inline int j1939cb_is_broadcast(const struct j1939_sk_buff_cb *cb)
+{
+	return (!cb->dst.name && (cb->dst.addr >= 0xff));
+}
+
+/* J1939 stack */
+enum {
+	j1939_level_can,
+	j1939_level_transport,
+	j1939_level_sky,
+};
+
+#define RESULT_STOP	1
+/*
+ * return RESULT_STOP when stack processing may stop.
+ * it is up to the stack entry itself to kfree_skb() the sk_buff
+ */
+
+extern int j1939_send(struct sk_buff *, int level);
+extern int j1939_recv(struct sk_buff *, int level);
+
+/* stack entries */
+extern int j1939_recv_promisc(struct sk_buff *);
+extern int j1939_send_transport(struct sk_buff *);
+extern int j1939_recv_transport(struct sk_buff *);
+extern int j1939_send_address_claim(struct sk_buff *);
+extern int j1939_recv_address_claim(struct sk_buff *);
+
+extern int j1939_recv_distribute(struct sk_buff *);
+
+/* network management */
+extern struct j1939_ecu *j1939_ecu_alloc(int ifindex, name_t name);
+extern void j1939_ecu_free(struct j1939_ecu *); /*
+	 * should no be used for registered ecu's
+	 */
+extern int j1939_ecu_register(struct j1939_ecu *);
+extern void j1939_ecu_unregister(struct j1939_ecu *);
+
+extern int j1939_segment_attach(struct net_device *);
+extern int j1939_segment_detach(struct net_device *);
+
+extern int j1939_segment_register(struct net_device *);
+extern void j1939_segment_unregister(struct j1939_segment *);
+extern struct j1939_segment *j1939_segment_find(int ifindex);
+
+extern void j1939sk_netdev_event(int ifindex, int error_code);
+
+/* add/remove receiver */
+extern int j1939_recv_add(void *vp, void (*fn)(struct sk_buff *, void *));
+extern int j1939_recv_remove(void *vp, void (*fn)(struct sk_buff *, void *));
+
+/*
+ * provide public access to this lock
+ * so sparse can verify the context balance
+ */
+extern rwlock_t j1939_receiver_rwlock;
+static inline void j1939_recv_suspend(void)
+{
+	write_lock_bh(&j1939_receiver_rwlock);
+}
+
+static inline void j1939_recv_resume(void)
+{
+	write_unlock_bh(&j1939_receiver_rwlock);
+}
+
+/* locks the recv module */
+extern void j1939_recv_suspend(void);
+extern void j1939_recv_resume(void);
+
+/* address claiming timer callback */
+enum hrtimer_restart j1939_ac_timer_handler(struct hrtimer *hrtimer);
+/*
+ * decrement pending skb for a j1939 socket
+ */
+extern void j1939_sock_pending_del(struct sock *sk);
+
+/* seperate module-init/modules-exit's */
+extern __init int j1939_proc_module_init(void);
+extern __init int j1939bus_module_init(void);
+extern __init int j1939sk_module_init(void);
+extern __init int j1939tp_module_init(void);
+
+extern void j1939_proc_module_exit(void);
+extern void j1939bus_module_exit(void);
+extern void j1939sk_module_exit(void);
+extern void j1939tp_module_exit(void);
+
+/* rtnetlink */
+extern const struct rtnl_af_ops j1939_rtnl_af_ops;
+extern int j1939rtnl_new_addr(struct sk_buff *, struct nlmsghdr *, void *arg);
+extern int j1939rtnl_del_addr(struct sk_buff *, struct nlmsghdr *, void *arg);
+extern int j1939rtnl_dump_addr(struct sk_buff *, struct netlink_callback *);
+
+#endif /* _J1939_PRIV_H_ */
diff --git a/net/can/j1939/main.c b/net/can/j1939/main.c
new file mode 100644
index 0000000..71963d5
--- /dev/null
+++ b/net/can/j1939/main.c
@@ -0,0 +1,454 @@
+/*
+ * Copyright (c) 2010-2011 EIA Electronics
+ *
+ * Authors:
+ * Kurt Van Dijck <kurt.van.dijck-/BeEPy95v10@public.gmane.org>
+ * Pieter Beyens <pieter.beyens-/BeEPy95v10@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the version 2 of the GNU General Public License
+ * as published by the Free Software Foundation
+ */
+
+/*
+ * Core of can-j1939 that links j1939 to CAN.
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/socket.h>
+#include <linux/list.h>
+#include <linux/if_arp.h>
+#include <net/tcp_states.h>
+
+#include <linux/can.h>
+#include <linux/can/core.h>
+#include "j1939-priv.h"
+
+MODULE_DESCRIPTION("PF_CAN SAE J1939");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("EIA Electronics (Kurt Van Dijck & Pieter Beyens)");
+
+static struct {
+	struct notifier_block notifier;
+} s;
+
+/* LOWLEVEL CAN interface */
+
+/* CAN_HDR: #bytes before can_frame data part */
+#define CAN_HDR	(offsetof(struct can_frame, data))
+/* CAN_FTR: #bytes beyond data part */
+#define CAN_FTR	(sizeof(struct can_frame)-CAN_HDR-\
+		sizeof(((struct can_frame *)0)->data))
+
+static void j1939_recv_ecu_flags(struct sk_buff *skb, void *data)
+{
+	struct j1939_segment *jseg = data;
+	struct j1939_sk_buff_cb *cb = (void *)skb->cb;
+	struct addr_ent *paddr;
+
+	if (!jseg)
+		return;
+	write_lock_bh(&jseg->lock);
+	paddr = &jseg->ents[cb->src.addr];
+	paddr->rxtime = ktime_get();
+	if (paddr->ecu) {
+		cb->src.flags = paddr->ecu->flags;
+		paddr->ecu->rxtime = paddr->rxtime;
+	} else {
+		if (!paddr->flags)
+			paddr->flags |= ECUFLAG_REMOTE;
+		cb->src.flags = paddr->flags;
+	}
+
+	if (j1939_address_is_unicast(cb->dst.addr)) {
+		paddr = &jseg->ents[cb->dst.addr];
+		if (paddr->ecu) {
+			cb->dst.flags = paddr->ecu->flags;
+		} else {
+			if (!paddr->flags)
+				paddr->flags |= ECUFLAG_REMOTE;
+			cb->dst.flags = paddr->flags;
+		}
+	}
+	write_unlock_bh(&jseg->lock);
+}
+
+/* lowest layer */
+static void j1939_can_recv(struct sk_buff *skb, void *data)
+{
+	int orig_len;
+	struct j1939_sk_buff_cb *sk_addr;
+	struct can_frame *msg;
+	uint8_t saved_cb[sizeof(skb->cb)];
+
+	BUILD_BUG_ON(sizeof(*sk_addr) > sizeof(skb->cb));
+	/*
+	 * get a pointer to the header of the skb
+	 * the skb payload (pointer) is moved, so that the next skb_data
+	 * returns the actual payload
+	 */
+	msg = (void *)skb->data;
+	orig_len = skb->len;
+	skb_pull(skb, CAN_HDR);
+	/* fix length, set to dlc, with 8 maximum */
+	skb_trim(skb, min_t(uint8_t, msg->can_dlc, 8));
+
+	/* set addr */
+	sk_addr = (struct j1939_sk_buff_cb *)skb->cb;
+	memcpy(saved_cb, sk_addr, sizeof(saved_cb));
+	memset(sk_addr, 0, sizeof(*sk_addr));
+	if (skb->dev)
+		sk_addr->ifindex = skb->dev->ifindex;
+	sk_addr->priority = (msg->can_id & 0x1c000000) >> 26;
+	sk_addr->src.addr = msg->can_id & 0xff;
+	sk_addr->pgn = (msg->can_id & 0x3ffff00) >> 8;
+	if (pgn_is_pdu1(sk_addr->pgn)) {
+		/* Type 1: with destination address */
+		sk_addr->dst.addr = sk_addr->pgn & 0xff;
+		/* normalize pgn: strip dst address */
+		sk_addr->pgn &= 0x3ff00;
+	} else {
+		/* set broadcast address */
+		sk_addr->dst.addr = J1939_NO_ADDR;
+	}
+	j1939_recv_ecu_flags(skb, data);
+	j1939_recv(skb, j1939_level_can);
+
+	/* restore the original skb, should always work */
+	skb_push(skb, CAN_HDR);
+	/* no safety check, it just restores the skbuf's contents */
+	__skb_trim(skb, orig_len);
+	memcpy(sk_addr, saved_cb, sizeof(saved_cb));
+}
+
+static int j1939_send_can(struct sk_buff *skb)
+{
+	int ret, dlc;
+	canid_t canid;
+	struct j1939_sk_buff_cb *sk_addr;
+	struct net_device *netdev = NULL;
+	struct can_frame *msg;
+
+	dlc = skb->len;
+	if (dlc > 8)
+		return -EMSGSIZE;
+	ret = pskb_expand_head(skb, SKB_DATA_ALIGN(CAN_HDR),
+			CAN_FTR + (8-dlc), GFP_ATOMIC);
+	if (ret < 0)
+		return ret;
+
+	msg = (void *)skb_push(skb, CAN_HDR);
+	BUG_ON(!msg);
+	/* make it a full can frame */
+	skb_put(skb, CAN_FTR + (8 - dlc));
+
+	sk_addr = (struct j1939_sk_buff_cb *)skb->cb;
+	canid = CAN_EFF_FLAG |
+		(sk_addr->src.addr & 0xff) |
+		((sk_addr->priority & 0x7) << 26);
+	if (pgn_is_pdu1(sk_addr->pgn))
+		canid |= ((sk_addr->pgn & 0x3ff00) << 8) |
+			((sk_addr->dst.addr & 0xff) << 8);
+	else
+		canid |= ((sk_addr->pgn & 0x3ffff) << 8);
+
+	msg->can_id = canid;
+	msg->can_dlc = dlc;
+
+	/* set net_device */
+	ret = -ENODEV;
+	if (!skb->dev) {
+		if (!sk_addr->ifindex)
+			goto failed;
+		netdev = dev_get_by_index(&init_net, sk_addr->ifindex);
+		if (!netdev)
+			goto failed;
+		skb->dev = netdev;
+	}
+
+	/* fix the 'always free' policy of can_send */
+	skb = skb_get(skb);
+	ret = can_send(skb, 1);
+	if (!ret) {
+		/* free when can_send succeeded */
+		kfree_skb(skb);
+		/* is this necessary ? */
+		ret = RESULT_STOP;
+	}
+failed:
+	if (netdev)
+		dev_put(netdev);
+	return ret;
+}
+
+static int j1939_send_normalize(struct sk_buff *skb)
+{
+	struct j1939_sk_buff_cb *cb = (void *)skb->cb;
+	struct j1939_segment *jseg;
+	struct addr_ent *paddr;
+	struct j1939_ecu *ecu;
+	int ret = 0;
+
+	/* apply sanity checks */
+	cb->pgn &= (pgn_is_pdu1(cb->pgn)) ? 0x3ff00 : 0x3ffff;
+	if (cb->priority > 7)
+		cb->priority = 6;
+
+	/* verify source */
+	if (!cb->ifindex)
+		return -ENETUNREACH;
+	jseg = j1939_segment_find(cb->ifindex);
+	if (!jseg)
+		return -ENETUNREACH;
+	read_lock_bh(&jseg->lock);
+	/* verify source */
+	if (cb->src.name) {
+		ecu = j1939_ecu_find_by_name(cb->src.name, cb->ifindex);
+		cb->src.flags = ecu ? ecu->flags : 0;
+		if (ecu)
+			put_j1939_ecu(ecu);
+	} else if (j1939_address_is_unicast(cb->src.addr)) {
+		paddr = &jseg->ents[cb->src.addr];
+		cb->src.flags = paddr->flags;
+	} else if (cb->src.addr == J1939_IDLE_ADDR) {
+		/* allow always */
+		cb->src.flags = ECUFLAG_LOCAL;
+	} else {
+		/* J1939_NO_ADDR */
+		cb->src.flags = 0;
+	}
+	if (cb->src.flags & ECUFLAG_REMOTE) {
+		ret = -EREMOTE;
+		goto failed;
+	} else if (!(cb->src.flags & ECUFLAG_LOCAL)) {
+		ret = -EADDRNOTAVAIL;
+		goto failed;
+	}
+
+	/* verify destination */
+	if (cb->dst.name) {
+		ecu = j1939_ecu_find_by_name(cb->dst.name, cb->ifindex);
+		if (!ecu) {
+			ret = -EADDRNOTAVAIL;
+			goto failed;
+		}
+		cb->dst.flags = ecu->flags;
+		put_j1939_ecu(ecu);
+	} else if (cb->dst.addr == J1939_IDLE_ADDR) {
+		/* not a valid destination */
+		ret = -EADDRNOTAVAIL;
+		goto failed;
+	} else if (j1939_address_is_unicast(cb->dst.addr)) {
+		paddr = &jseg->ents[cb->dst.addr];
+		cb->dst.flags = paddr->flags;
+	} else {
+		cb->dst.flags = 0;
+	}
+
+	ret = 0;
+failed:
+	read_unlock_bh(&jseg->lock);
+	put_j1939_segment(jseg);
+	return ret;
+}
+
+/* TOPLEVEL interface */
+int j1939_recv(struct sk_buff *skb, int level)
+{
+	int ret;
+
+	/* this stack operates with fallthrough switch statement */
+	switch (level) {
+	default:
+		WARN_ONCE(1, "%s: unsupported level %i\n", __func__, level);
+		return 0;
+	case j1939_level_can:
+		ret = j1939_recv_address_claim(skb);
+		if (unlikely(ret))
+			break;
+		ret = j1939_recv_promisc(skb);
+		if (unlikely(ret))
+			break;
+		ret = j1939_recv_transport(skb);
+		if (unlikely(ret))
+			break;
+	case j1939_level_transport:
+	case j1939_level_sky:
+		ret = j1939_recv_distribute(skb);
+		break;
+	}
+	if (ret == RESULT_STOP)
+		return 0;
+	return ret;
+
+}
+EXPORT_SYMBOL_GPL(j1939_recv);
+
+int j1939_send(struct sk_buff *skb, int level)
+{
+	int ret;
+	struct sock *sk = NULL;
+
+	/* this stack operates with fallthrough switch statement */
+	switch (level) {
+	default:
+		WARN_ONCE(1, "%s: unsupported level %i\n", __func__, level);
+	case j1939_level_sky:
+		sk = skb->sk;
+		if (sk)
+			sock_hold(sk);
+		ret = j1939_send_normalize(skb);
+		if (unlikely(ret))
+			break;
+		ret = j1939_send_transport(skb);
+		if (unlikely(ret))
+			break;
+	case j1939_level_transport:
+		ret = j1939_send_address_claim(skb);
+		if (unlikely(ret))
+			break;
+	case j1939_level_can:
+		ret = j1939_send_can(skb);
+		break;
+	}
+	if (ret == RESULT_STOP)
+		ret = 0;
+	else if (!ret && sk)
+		j1939_sock_pending_del(sk);
+	if (sk)
+		sock_put(sk);
+	return ret;
+
+}
+EXPORT_SYMBOL_GPL(j1939_send);
+
+/* NETDEV MANAGEMENT */
+
+#define J1939_CAN_ID	CAN_EFF_FLAG
+#define J1939_CAN_MASK	(CAN_EFF_FLAG | CAN_RTR_FLAG)
+int j1939_segment_attach(struct net_device *netdev)
+{
+	int ret;
+	struct j1939_segment *jseg;
+
+	if (!netdev)
+		return -ENODEV;
+	if (netdev->type != ARPHRD_CAN)
+		return -EAFNOSUPPORT;
+
+	ret = j1939_segment_register(netdev);
+	if (ret < 0)
+		goto fail_register;
+	jseg = j1939_segment_find(netdev->ifindex);
+	ret = can_rx_register(netdev, J1939_CAN_ID, J1939_CAN_MASK,
+			j1939_can_recv, jseg, "j1939");
+	if (ret < 0)
+		goto fail_can_rx;
+	return 0;
+
+fail_can_rx:
+	j1939_segment_unregister(jseg);
+	put_j1939_segment(jseg);
+fail_register:
+	return ret;
+}
+
+int j1939_segment_detach(struct net_device *netdev)
+{
+	struct j1939_segment *jseg;
+
+	BUG_ON(!netdev);
+	jseg = j1939_segment_find(netdev->ifindex);
+	if (!jseg)
+		return -EHOSTDOWN;
+	can_rx_unregister(netdev, J1939_CAN_ID, J1939_CAN_MASK,
+			j1939_can_recv, jseg);
+	j1939_segment_unregister(jseg);
+	put_j1939_segment(jseg);
+	j1939sk_netdev_event(netdev->ifindex, EHOSTDOWN);
+	return 0;
+}
+
+static int j1939_notifier(struct notifier_block *nb,
+			unsigned long msg, void *data)
+{
+	struct net_device *netdev = (struct net_device *)data;
+	struct j1939_segment *jseg;
+
+	if (!net_eq(dev_net(netdev), &init_net))
+		return NOTIFY_DONE;
+
+	if (netdev->type != ARPHRD_CAN)
+		return NOTIFY_DONE;
+
+	switch (msg) {
+	case NETDEV_UNREGISTER:
+		jseg = j1939_segment_find(netdev->ifindex);
+		if (!jseg)
+			break;
+		j1939_segment_unregister(jseg);
+		j1939sk_netdev_event(netdev->ifindex, ENODEV);
+		break;
+
+	case NETDEV_DOWN:
+		j1939sk_netdev_event(netdev->ifindex, ENETDOWN);
+		break;
+	}
+
+	return NOTIFY_DONE;
+}
+
+/* MODULE interface */
+
+static __init int j1939_module_init(void)
+{
+	int ret;
+
+	pr_info("can: SAE J1939\n");
+
+	ret = j1939_proc_module_init();
+	if (ret < 0)
+		goto fail_proc;
+
+	s.notifier.notifier_call = j1939_notifier;
+	register_netdevice_notifier(&s.notifier);
+
+	ret = j1939bus_module_init();
+	if (ret < 0)
+		goto fail_bus;
+	ret = j1939sk_module_init();
+	if (ret < 0)
+		goto fail_sk;
+	ret = j1939tp_module_init();
+	if (ret < 0)
+		goto fail_tp;
+	return 0;
+
+	j1939tp_module_exit();
+fail_tp:
+	j1939sk_module_exit();
+fail_sk:
+	j1939bus_module_exit();
+fail_bus:
+	unregister_netdevice_notifier(&s.notifier);
+
+	j1939_proc_module_exit();
+fail_proc:
+	return ret;
+}
+
+static __exit void j1939_module_exit(void)
+{
+	j1939tp_module_exit();
+	j1939sk_module_exit();
+	j1939bus_module_exit();
+
+	unregister_netdevice_notifier(&s.notifier);
+
+	j1939_proc_module_exit();
+}
+
+module_init(j1939_module_init);
+module_exit(j1939_module_exit);
diff --git a/net/can/j1939/proc.c b/net/can/j1939/proc.c
new file mode 100644
index 0000000..76acfa0
--- /dev/null
+++ b/net/can/j1939/proc.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2010-2011 EIA Electronics
+ *
+ * Authors:
+ * Kurt Van Dijck <kurt.van.dijck-/BeEPy95v10@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the version 2 of the GNU General Public License
+ * as published by the Free Software Foundation
+ */
+
+#include <linux/version.h>
+#include <linux/string.h>
+#include <linux/seq_file.h>
+#include <linux/proc_fs.h>
+#include <linux/uaccess.h>
+
+#include "j1939-priv.h"
+
+const char j1939_procname[] = "can-j1939";
+
+static struct proc_dir_entry *rootdir;
+
+static int j1939_proc_open(struct inode *inode, struct file *file)
+{
+	struct proc_dir_entry *pde = PDE(inode);
+	int (*fn)(struct seq_file *sqf, void *v) = pde->data;
+
+	return single_open(file, fn, pde);
+}
+
+/* copied from fs/proc/generic.c */
+static ssize_t
+proc_file_write(struct file *file, const char __user *buffer,
+		size_t count, loff_t *ppos)
+{
+	struct inode *inode = file->f_path.dentry->d_inode;
+	struct proc_dir_entry *dp;
+
+	dp = PDE(inode);
+
+	if (!dp->write_proc)
+		return -EIO;
+
+	/* FIXME: does this routine need ppos?  probably... */
+	return dp->write_proc(file, buffer, count, dp->data);
+}
+
+static const struct file_operations j1939_proc_ops = {
+	.owner		= THIS_MODULE,
+	.open		= j1939_proc_open,
+	.read		= seq_read,
+	.write		= proc_file_write,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+int j1939_proc_add(const char *file,
+		int (*seq_show)(struct seq_file *sqf, void *v),
+		write_proc_t write)
+{
+	struct proc_dir_entry *pde;
+	int mode = 0;
+
+	if (seq_show)
+		mode |= 0444;
+	if (write)
+		mode |= 0200;
+
+	if (!rootdir)
+		return -ENODEV;
+	pde = proc_create(file, mode, rootdir, &j1939_proc_ops);
+	if (!pde)
+		goto fail_create;
+	pde->data = seq_show;
+	pde->write_proc = write;
+	return 0;
+
+fail_create:
+	return -ENOENT;
+}
+EXPORT_SYMBOL(j1939_proc_add);
+
+void j1939_proc_remove(const char *file)
+{
+	remove_proc_entry(file, rootdir);
+}
+EXPORT_SYMBOL(j1939_proc_remove);
+
+__init int j1939_proc_module_init(void)
+{
+	/* create /proc/net/can directory */
+	rootdir = proc_mkdir(j1939_procname, init_net.proc_net);
+	if (!rootdir)
+		return -EINVAL;
+	return 0;
+}
+
+void j1939_proc_module_exit(void)
+{
+	if (rootdir)
+		proc_net_remove(&init_net, j1939_procname);
+}
+
diff --git a/net/can/j1939/promisc.c b/net/can/j1939/promisc.c
new file mode 100644
index 0000000..14be755
--- /dev/null
+++ b/net/can/j1939/promisc.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2010-2011 EIA Electronics
+ *
+ * Authors:
+ * Kurt Van Dijck <kurt.van.dijck-/BeEPy95v10@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the version 2 of the GNU General Public License
+ * as published by the Free Software Foundation
+ */
+
+#include <linux/version.h>
+#include <linux/skbuff.h>
+#include <linux/sysctl.h>
+#include "j1939-priv.h"
+
+static atomic_t n_promisc = ATOMIC_INIT(0);
+
+void j1939_get_promisc_receiver(int ifindex)
+{
+	atomic_inc(&n_promisc);
+}
+EXPORT_SYMBOL_GPL(j1939_get_promisc_receiver);
+
+void j1939_put_promisc_receiver(int ifindex)
+{
+	atomic_dec(&n_promisc);
+}
+EXPORT_SYMBOL_GPL(j1939_put_promisc_receiver);
+
+int j1939_recv_promisc(struct sk_buff *skb)
+{
+	struct j1939_sk_buff_cb *cb = (void *)skb->cb;
+
+	if ((cb->src.flags & ECUFLAG_REMOTE) &&
+		(cb->dst.flags & ECUFLAG_REMOTE)) {
+		if (!atomic_read(&n_promisc))
+			/* stop receive path */
+			return RESULT_STOP;
+	}
+	return 0;
+}
+
diff --git a/net/can/j1939/rtnl.c b/net/can/j1939/rtnl.c
new file mode 100644
index 0000000..3345b51
--- /dev/null
+++ b/net/can/j1939/rtnl.c
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 2011 EIA Electronics
+ *
+ * Authors:
+ * Kurt Van Dijck <kurt.van.dijck-/BeEPy95v10@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the version 2 of the GNU General Public License
+ * as published by the Free Software Foundation
+ */
+
+/*
+ * j1939-rtnl.c - netlink addressing interface
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/if_arp.h>
+
+#include "j1939-priv.h"
+
+static const struct nla_policy j1939_ifa_policy[IFA_J1939_MAX] = {
+	[IFA_J1939_ADDR] = { .type = NLA_U8, },
+	[IFA_J1939_NAME] = { .type = NLA_U64, },
+};
+
+int j1939rtnl_del_addr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+{
+	int ret;
+	struct ifaddrmsg *ifm;
+	struct j1939_segment *jseg;
+	uint8_t jaddr = J1939_NO_ADDR;
+	uint64_t jname = J1939_NO_NAME;
+
+	struct nlattr *nla, *tb[IFA_J1939_MAX];
+
+	if (!net_eq(sock_net(skb->sk), &init_net))
+		return -EINVAL;
+
+	nla = nlmsg_find_attr(nlh, sizeof(*ifm), IFA_LOCAL);
+	if (!nla)
+		return -EINVAL;
+
+	nla_parse_nested(tb, IFA_J1939_MAX-1, nla, j1939_ifa_policy);
+	if (tb[IFA_J1939_ADDR])
+		jaddr = nla_get_u8(tb[IFA_J1939_ADDR]);
+	if (tb[IFA_J1939_NAME])
+		jname = be64_to_cpu(nla_get_u64(tb[IFA_J1939_NAME]));
+
+	ifm = nlmsg_data(nlh);
+	jseg = j1939_segment_find(ifm->ifa_index);
+	if (!jseg)
+		return -EHOSTDOWN;
+
+	ret = 0;
+	if (j1939_address_is_unicast(jaddr)) {
+		struct addr_ent *ent;
+
+		ent = &jseg->ents[jaddr];
+		write_lock_bh(&jseg->lock);
+		if (ent->flags & ECUFLAG_STATIC) {
+			ent->flags &= ~ECUFLAG_STATIC;
+			if (!ent->ecu || !(ent->ecu->flags & ECUFLAG_LOCAL))
+				ent->flags &= ~ECUFLAG_LOCAL;
+			ret = 0;
+		} else {
+			ret = -EADDRNOTAVAIL;
+		}
+		write_unlock_bh(&jseg->lock);
+	} else if (jname) {
+		struct j1939_ecu *ecu;
+
+		ecu = j1939_ecu_find_by_name(jname, ifm->ifa_index);
+		if (ecu) {
+			if (ecu->flags & ECUFLAG_LOCAL) {
+				j1939_ecu_unregister(ecu);
+				j1939_ecu_free(ecu);
+			} else {
+				ret = -EREMOTE;
+			}
+		} else {
+			ret = -ENODEV;
+		}
+	}
+	put_j1939_segment(jseg);
+	return ret;
+}
+
+int j1939rtnl_new_addr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+{
+	struct ifaddrmsg *ifm;
+	struct j1939_segment *jseg;
+	uint8_t jaddr = J1939_NO_ADDR;
+	uint64_t jname = J1939_NO_NAME;
+	struct addr_ent *ent;
+	int ret;
+	struct nlattr *nla, *tb[IFA_J1939_MAX];
+
+	if (!net_eq(sock_net(skb->sk), &init_net))
+		return -EINVAL;
+
+	nla = nlmsg_find_attr(nlh, sizeof(*ifm), IFA_LOCAL);
+	if (!nla)
+		return -EINVAL;
+
+	ifm = nlmsg_data(nlh);
+	jseg = j1939_segment_find(ifm->ifa_index);
+	if (!jseg)
+		return -EHOSTDOWN;
+
+	nla_parse_nested(tb, IFA_J1939_MAX-1, nla, j1939_ifa_policy);
+	if (tb[IFA_J1939_ADDR])
+		jaddr = nla_get_u8(tb[IFA_J1939_ADDR]);
+	if (tb[IFA_J1939_NAME])
+		jname = be64_to_cpu(nla_get_u64(tb[IFA_J1939_NAME]));
+
+
+	ret = 0;
+	if (j1939_address_is_unicast(jaddr)) {
+		ent = &jseg->ents[jaddr];
+		write_lock_bh(&jseg->lock);
+		if (ent->flags & ECUFLAG_REMOTE)
+			ret = -EREMOTE;
+		else
+			ent->flags |= ECUFLAG_LOCAL | ECUFLAG_STATIC;
+		write_unlock_bh(&jseg->lock);
+	} else if (jname) {
+		struct j1939_ecu *ecu;
+
+		ecu = j1939_ecu_find_by_name(jname, ifm->ifa_index);
+		if (ecu) {
+			put_j1939_ecu(ecu);
+			ret = -EBUSY;
+		} else {
+			ecu = j1939_ecu_alloc(ifm->ifa_index, jname);
+			if (ecu) {
+				ecu->flags |= ECUFLAG_LOCAL;
+				ret = j1939_ecu_register(ecu);
+			} else
+				ret = -ENOMEM;
+		}
+	}
+	put_j1939_segment(jseg);
+	return ret;
+}
+
+static int j1939rtnl_fill_ifaddr(struct sk_buff *skb, int ifindex,
+		uint8_t addr, uint64_t name, int j1939_flags,
+		u32 pid, u32 seq, int event, unsigned int flags)
+{
+	struct ifaddrmsg *ifm;
+	struct nlmsghdr *nlh;
+	struct nlattr *nla;
+
+	nlh = nlmsg_put(skb, pid, seq, event, sizeof(*ifm), flags);
+	if (nlh == NULL)
+		return -EMSGSIZE;
+
+	ifm = nlmsg_data(nlh);
+	ifm->ifa_family = AF_CAN;
+	ifm->ifa_prefixlen = CAN_J1939;
+	ifm->ifa_flags = name ? 0 : IFA_F_PERMANENT;
+	ifm->ifa_scope = RT_SCOPE_LINK;
+	ifm->ifa_index = ifindex;
+
+	nla = nla_nest_start(skb, IFA_LOCAL);
+	if (j1939_address_is_unicast(addr))
+		NLA_PUT_U8(skb, IFA_J1939_ADDR, addr);
+	if (name)
+		NLA_PUT_U64(skb, IFA_J1939_NAME, cpu_to_be64(name));
+	nla_nest_end(skb, nla);
+
+	return nlmsg_end(skb, nlh);
+
+nla_put_failure:
+	nlmsg_cancel(skb, nlh);
+	return -EMSGSIZE;
+}
+
+int j1939rtnl_dump_addr(struct sk_buff *skb, struct netlink_callback *cb)
+{
+	int ndev, addr, ret;
+	struct net_device *netdev;
+	struct j1939_segment *jseg;
+	struct j1939_ecu *ecu;
+	struct addr_ent *ent;
+	struct list_head *lst;
+
+	if (!net_eq(sock_net(skb->sk), &init_net))
+		return 0;
+
+	ndev = 0;
+	for_each_netdev(&init_net, netdev) {
+		++ndev;
+		if (ndev < cb->args[1])
+			continue;
+		if (netdev->type != ARPHRD_CAN)
+			continue;
+
+		jseg = j1939_segment_find(netdev->ifindex);
+		if (!jseg)
+			continue;
+
+		read_lock_bh(&jseg->lock);
+		for (addr = cb->args[2]; addr < J1939_IDLE_ADDR; ++addr) {
+			ent = &jseg->ents[addr];
+			if (!(ent->flags & ECUFLAG_STATIC))
+				continue;
+			ret = j1939rtnl_fill_ifaddr(skb, netdev->ifindex, addr,
+					0, ent->flags, NETLINK_CB(cb->skb).pid,
+					cb->nlh->nlmsg_seq, RTM_NEWADDR,
+					NLM_F_MULTI);
+			if (ret < 0) {
+				read_unlock_bh(&jseg->lock);
+				goto done;
+			}
+			cb->args[2] = addr + 1;
+		}
+
+		if (addr > J1939_IDLE_ADDR)
+			addr = J1939_IDLE_ADDR;
+		list_for_each(lst, &jseg->ecus) {
+			ecu = list_entry(lst, struct j1939_ecu, list);
+			if (addr++ < cb->args[2])
+				continue;
+			if (!(ecu->flags & ECUFLAG_LOCAL))
+				continue;
+			ret = j1939rtnl_fill_ifaddr(skb, netdev->ifindex,
+					ecu->sa, ecu->name, ecu->flags,
+					NETLINK_CB(cb->skb).pid,
+					cb->nlh->nlmsg_seq, RTM_NEWADDR,
+					NLM_F_MULTI);
+			if (ret < 0) {
+				read_unlock_bh(&jseg->lock);
+				goto done;
+			}
+			cb->args[2] = addr;
+		}
+		read_unlock_bh(&jseg->lock);
+		/* reset first address for device */
+		cb->args[2] = 0;
+	}
+	++ndev;
+done:
+	cb->args[1] = ndev;
+
+	return skb->len;
+}
+
+/*
+ * rtnl_link_ops
+ */
+
+static const struct nla_policy j1939_ifla_policy[IFLA_J1939_MAX] = {
+	[IFLA_J1939_ENABLE] = { .type = NLA_U8, },
+};
+
+static size_t j1939_get_link_af_size(const struct net_device *dev)
+{
+	return nla_policy_len(j1939_ifla_policy, IFLA_J1939_MAX-1);
+}
+
+static int j1939_validate_link_af(const struct net_device *dev,
+				 const struct nlattr *nla)
+{
+	return nla_validate_nested(nla, IFLA_J1939_MAX-1, j1939_ifla_policy);
+}
+
+static int j1939_fill_link_af(struct sk_buff *skb, const struct net_device *dev)
+{
+	struct j1939_segment *jseg;
+
+	if (!dev)
+		return -ENODEV;
+	jseg = j1939_segment_find(dev->ifindex);
+	if (jseg)
+		put_j1939_segment(jseg);
+	NLA_PUT_U8(skb, IFLA_J1939_ENABLE, jseg ? 1 : 0);
+	return 0;
+
+nla_put_failure:
+	return -EMSGSIZE;
+}
+
+static int j1939_set_link_af(struct net_device *dev, const struct nlattr *nla)
+{
+	int ret;
+	struct nlattr *tb[IFLA_J1939_MAX];
+
+	ret = nla_parse_nested(tb, IFLA_J1939_MAX-1, nla, j1939_ifla_policy);
+	if (ret < 0)
+		return ret;
+
+	if (tb[IFLA_J1939_ENABLE]) {
+		if (nla_get_u8(tb[IFLA_J1939_ENABLE]))
+			ret = j1939_segment_attach(dev);
+		else
+			ret = j1939_segment_detach(dev);
+		if (ret < 0)
+			return ret;
+	}
+	return 0;
+}
+
+const struct rtnl_af_ops j1939_rtnl_af_ops = {
+	.family		  = AF_CAN,
+	.fill_link_af	  = j1939_fill_link_af,
+	.get_link_af_size = j1939_get_link_af_size,
+	.validate_link_af = j1939_validate_link_af,
+	.set_link_af	  = j1939_set_link_af,
+};
+
diff --git a/net/can/j1939/socket.c b/net/can/j1939/socket.c
new file mode 100644
index 0000000..c94e3b1
--- /dev/null
+++ b/net/can/j1939/socket.c
@@ -0,0 +1,983 @@
+/*
+ * Copyright (c) 2010-2011 EIA Electronics
+ *
+ * Authors:
+ * Kurt Van Dijck <kurt.van.dijck-/BeEPy95v10@public.gmane.org>
+ * Pieter Beyens <pieter.beyens-/BeEPy95v10@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the version 2 of the GNU General Public License
+ * as published by the Free Software Foundation
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/socket.h>
+#include <linux/list.h>
+#include <linux/if_arp.h>
+#include <net/tcp_states.h>
+
+#include <linux/can/core.h>
+#include <linux/can/j1939.h>
+#include "j1939-priv.h"
+
+struct j1939_sock {
+	struct sock sk; /* must be first to skip with memset */
+	struct list_head list;
+
+	int state;
+	#define JSK_BOUND	BIT(0)
+	#define JSK_CONNECTED	BIT(1)
+	#define PROMISC		BIT(2)
+	#define RECV_OWN	BIT(3)
+
+	struct {
+		name_t src, dst, mask;
+		pgn_t pgn;
+
+		uint8_t sa, da;
+	} addr;
+
+	struct j1939_filter *filters;
+	int nfilters;
+
+	int skb_pending;
+	spinlock_t lock;
+	wait_queue_head_t waitq;
+};
+
+static inline struct j1939_sock *j1939_sk(const struct sock *sk)
+{
+	return container_of(sk, struct j1939_sock, sk);
+}
+
+/* skb_pending issues */
+static inline int j1939_sock_pending_add_first(struct sock *sk)
+{
+	int saved;
+	struct j1939_sock *jsk = j1939_sk(sk);
+
+	spin_lock_bh(&jsk->lock);
+	if (!jsk->skb_pending) {
+		++jsk->skb_pending;
+		saved = 1;
+	} else
+		saved = 0;
+	spin_unlock_bh(&jsk->lock);
+	return saved;
+}
+
+static inline void j1939_sock_pending_add(struct sock *sk)
+{
+	struct j1939_sock *jsk = j1939_sk(sk);
+
+	spin_lock_bh(&jsk->lock);
+	++jsk->skb_pending;
+	spin_unlock_bh(&jsk->lock);
+}
+
+void j1939_sock_pending_del(struct sock *sk)
+{
+	struct j1939_sock *jsk = j1939_sk(sk);
+	int saved;
+
+	spin_lock_bh(&jsk->lock);
+	--jsk->skb_pending;
+	saved = jsk->skb_pending;
+	spin_unlock_bh(&jsk->lock);
+	if (!saved)
+		wake_up(&jsk->waitq);
+}
+
+
+static inline int j1939_no_address(const struct sock *sk)
+{
+	const struct j1939_sock *jsk = j1939_sk(sk);
+	return (jsk->addr.sa == J1939_NO_ADDR) && !jsk->addr.src;
+}
+
+/*
+ * list of sockets
+ */
+static struct {
+	struct mutex lock;
+	struct list_head socks;
+} s;
+
+/* matches skb control buffer (addr) with a j1939 filter */
+static inline int packet_match(const struct j1939_sk_buff_cb *cb,
+		const struct j1939_filter *f, int nfilter)
+{
+	/*
+	 * Filters relying on the addr for static addressing _should_ get
+	 * packets from dynamic addressed ECU's too if they match their SA.
+	 * Sockets using dynamic addressing in their filters should not set it.
+	 */
+	for (; nfilter; ++f, --nfilter) {
+		if ((cb->pgn & f->pgn_mask) != (f->pgn & f->pgn_mask))
+			return 0;
+		if ((cb->src.addr & f->addr_mask) != (f->addr & f->addr_mask))
+			return 0;
+		if ((cb->src.name & f->name_mask) != (f->name & f->name_mask))
+			return 0;
+	}
+	return 1;
+}
+
+/*
+ * callback per socket, called from filter infrastructure
+ */
+static void j1939sk_recv_skb(struct sk_buff *oskb, void *data)
+{
+	struct sk_buff *skb;
+	struct j1939_sock *jsk = (struct j1939_sock *)data;
+	struct j1939_sk_buff_cb *cb = (void *)oskb->cb;
+
+	if (jsk->sk.sk_bound_dev_if && (jsk->sk.sk_bound_dev_if != cb->ifindex))
+		/* this socket does not take packets from this iface */
+		return;
+	if (!(jsk->state & PROMISC)) {
+		if (cb->dst.flags & ECUFLAG_REMOTE)
+			/*
+			 * this msg was destined for an ECU associated
+			 * with this socket
+			 */
+			return;
+		if (jsk->addr.src) {
+			if (cb->dst.name &&
+				(cb->dst.name != jsk->addr.src))
+				/*
+				 * the msg is not destined for the name
+				 * that the socket is bound to
+				 */
+				return;
+		} else if (j1939_address_is_unicast(jsk->addr.sa)) {
+			if (j1939_address_is_unicast(cb->dst.addr) &&
+				(cb->dst.addr != jsk->addr.sa))
+				/*
+				 * the msg is not destined for the name
+				 * that the socket is bound to
+				 */
+				return;
+		}
+	}
+
+	if ((oskb->sk == &jsk->sk) && !(jsk->state & RECV_OWN))
+		/* own message */
+		return;
+
+	if (!packet_match(cb, jsk->filters, jsk->nfilters))
+		return;
+
+	skb = skb_clone(oskb, GFP_ATOMIC);
+	if (!skb) {
+		j1939_warning("skb clone failed\n");
+		return;
+	}
+	cb = (void *)skb->cb;
+	cb->msg_flags &= ~(MSG_DONTROUTE | MSG_CONFIRM);
+	if (oskb->sk)
+		cb->msg_flags |= MSG_DONTROUTE;
+	if (oskb->sk == &jsk->sk)
+		cb->msg_flags |= MSG_CONFIRM;
+
+	skb->sk = &jsk->sk;
+	if (sock_queue_rcv_skb(&jsk->sk, skb) < 0) {
+		kfree_skb(skb);
+		j1939_warning("sock_queue_rcv_skb failed\n");
+	}
+}
+
+static int j1939sk_init(struct sock *sk)
+{
+	struct j1939_sock *jsk = j1939_sk(sk);
+
+	INIT_LIST_HEAD(&jsk->list);
+	spin_lock_init(&jsk->lock);
+	init_waitqueue_head(&jsk->waitq);
+	jsk->sk.sk_priority = j1939_to_sk_priority(6);
+	jsk->sk.sk_reuse = 1; /* per default */
+	jsk->addr.sa = J1939_NO_ADDR;
+	jsk->addr.da = J1939_NO_ADDR;
+	/* per default, mask out the serial number in destinations */
+	jsk->addr.mask = 0xffffffffffe00000ULL;
+
+	return 0;
+}
+
+/*
+ * helper: return <0 for error, >0 for error to notify
+ */
+static int j1939sk_bind_netdev_helper(struct socket *sock)
+{
+	struct j1939_sock *jsk = j1939_sk(sock->sk);
+	int ret;
+	struct net_device *netdev;
+	struct j1939_segment *jseg;
+
+	if (!jsk->sk.sk_bound_dev_if)
+		return 0;
+	ret = 0;
+
+	netdev = dev_get_by_index(&init_net, jsk->sk.sk_bound_dev_if);
+	if (!netdev) {
+		ret = -ENODEV;
+		goto fail_netdev;
+	}
+
+	/* no need to test for CAN device,
+	 * implicitely done by j1939_segment
+	 */
+	jseg = j1939_segment_find(netdev->ifindex);
+	if (!jseg) {
+		ret = -EHOSTDOWN;
+		goto fail_segment;
+	}
+
+	if (!(netdev->flags & IFF_UP)) {
+		sock->sk->sk_err = ENETDOWN;
+		sock->sk->sk_error_report(sock->sk);
+	}
+	put_j1939_segment(jseg);
+fail_segment:
+	dev_put(netdev);
+fail_netdev:
+	return ret;
+}
+
+static int j1939sk_bind(struct socket *sock, struct sockaddr *uaddr, int len)
+{
+	struct sockaddr_can *addr = (struct sockaddr_can *)uaddr;
+	struct j1939_sock *jsk = j1939_sk(sock->sk);
+	struct j1939_ecu *ecu = NULL;
+	int ret, old_state;
+
+	if (len < required_size(can_addr.j1939, *addr))
+		return -EINVAL;
+	if (addr->can_family != AF_CAN)
+		return -EINVAL;
+
+	/* lock s.lock first, to avoid circular lock dependancy */
+	mutex_lock(&s.lock);
+	lock_sock(sock->sk);
+	if (jsk->state & JSK_BOUND) {
+		ret = -EBUSY;
+		if (addr->can_ifindex != jsk->sk.sk_bound_dev_if)
+			goto fail_locked;
+		/*
+		 * do not allow to change addres after first bind(),
+		 * (it would require updating the j1939_ecu list)
+		 * but allow the change SA when using dynaddr,
+		 * and allow to change PGN
+		 */
+		if (!jsk->addr.src ||
+			(jsk->addr.src != addr->can_addr.j1939.name) ||
+			(jsk->addr.pgn != addr->can_addr.j1939.pgn))
+			goto fail_locked;
+		j1939_recv_suspend();
+		/* set to be able to send address claims */
+		jsk->addr.sa = addr->can_addr.j1939.addr;
+		j1939_recv_resume();
+		/* since this socket is bound already, we can skip a lot */
+		release_sock(sock->sk);
+		mutex_unlock(&s.lock);
+		return 0;
+	}
+
+	/* do netdev */
+	if (jsk->sk.sk_bound_dev_if && addr->can_ifindex &&
+			(jsk->sk.sk_bound_dev_if != addr->can_ifindex)) {
+		ret = -EBADR;
+		goto fail_locked;
+	}
+	if (!jsk->sk.sk_bound_dev_if)
+		jsk->sk.sk_bound_dev_if = addr->can_ifindex;
+
+	ret = j1939sk_bind_netdev_helper(sock);
+	if (ret < 0)
+		goto fail_locked;
+
+	/* bind name/addr */
+	if (addr->can_addr.j1939.name) {
+		ecu = j1939_ecu_find_by_name(addr->can_addr.j1939.name,
+				jsk->sk.sk_bound_dev_if);
+		if (!ecu) {
+			ret = -EADDRNOTAVAIL;
+			goto fail_locked;
+		} else if (ecu->flags & ECUFLAG_REMOTE) {
+			ret = -EREMOTE;
+			goto fail_with_ecu;
+		} else if (jsk->sk.sk_bound_dev_if != ecu->ifindex) {
+			ret = -EHOSTUNREACH;
+			goto fail_with_ecu;
+		}
+		jsk->addr.src = ecu->name;
+		jsk->addr.sa = addr->can_addr.j1939.addr;
+	} else if (j1939_address_is_unicast(addr->can_addr.j1939.addr)) {
+		struct j1939_segment *jseg;
+		struct addr_ent *paddr;
+		int flags;
+
+		/* static addressing, netdev is required */
+		if (!jsk->sk.sk_bound_dev_if) {
+			ret = -EINVAL;
+			goto fail_locked;
+		}
+		jseg = j1939_segment_find(jsk->sk.sk_bound_dev_if);
+		if (!jseg) {
+			ret = -ENETUNREACH;
+			goto fail_locked;
+		}
+		paddr = &jseg->ents[addr->can_addr.j1939.addr];
+		ret = 0;
+		read_lock_bh(&jseg->lock);
+		flags = paddr->flags;
+		read_unlock_bh(&jseg->lock);
+		put_j1939_segment(jseg);
+		if (!(flags & ECUFLAG_STATIC)) {
+			ret = -EADDRNOTAVAIL;
+			goto fail_locked;
+		}
+		jsk->addr.sa = addr->can_addr.j1939.addr;
+	} else if (addr->can_addr.j1939.addr == J1939_IDLE_ADDR) {
+		/* static addressing, netdev is required */
+		if (!jsk->sk.sk_bound_dev_if) {
+			ret = -EINVAL;
+			goto fail_locked;
+		}
+		jsk->addr.sa = addr->can_addr.j1939.addr;
+	} else {
+		/* no name, no addr */
+	}
+
+	/* set default transmit pgn/priority */
+	jsk->addr.pgn = addr->can_addr.j1939.pgn;
+
+	old_state = jsk->state;
+	jsk->state |= JSK_BOUND;
+
+	if (!(old_state & (JSK_BOUND | JSK_CONNECTED))) {
+		list_add_tail(&jsk->list, &s.socks);
+		j1939_recv_add(jsk, j1939sk_recv_skb);
+	}
+
+	ret = 0;
+
+fail_with_ecu:
+	if (ecu && !IS_ERR(ecu))
+		put_j1939_ecu(ecu);
+fail_locked:
+	release_sock(sock->sk);
+	mutex_unlock(&s.lock);
+	return ret;
+}
+
+static int j1939sk_connect(struct socket *sock, struct sockaddr *uaddr,
+		int len, int flags)
+{
+	int ret, old_state;
+	struct sockaddr_can *addr = (struct sockaddr_can *)uaddr;
+	struct j1939_sock *jsk = j1939_sk(sock->sk);
+	struct j1939_ecu *ecu;
+	int ifindex;
+
+	if (!uaddr)
+		return -EDESTADDRREQ;
+
+	if (len < required_size(can_addr.j1939, *addr))
+		return -EINVAL;
+	if (addr->can_family != AF_CAN)
+		return -EINVAL;
+
+	mutex_lock(&s.lock);
+	lock_sock(sock->sk);
+	if (jsk->state & JSK_CONNECTED) {
+		ret = -EISCONN;
+		goto fail_locked;
+	}
+
+	ifindex = jsk->sk.sk_bound_dev_if;
+	if (ifindex && addr->can_ifindex && (ifindex != addr->can_ifindex)) {
+		ret = -ECONNREFUSED;
+		goto fail_locked;
+	}
+	if (!ifindex)
+		ifindex = addr->can_ifindex;
+
+	/* lookup destination */
+	if (addr->can_addr.j1939.name) {
+		ecu = j1939_ecu_find_name_masked(addr->can_addr.j1939.name,
+			jsk->addr.mask, ifindex);
+		if (!ecu) {
+			ret = -EADDRNOTAVAIL;
+			goto fail_locked;
+		}
+		if (ifindex && (ifindex != ecu->ifindex)) {
+			ret = -EHOSTUNREACH;
+			goto fail_locked;
+		}
+		ifindex = ecu->ifindex;
+		jsk->addr.dst = ecu->name;
+		jsk->addr.da = ecu->sa;
+		put_j1939_ecu(ecu);
+	} else {
+		/* broadcast */
+		jsk->addr.dst = 0;
+		jsk->addr.da = addr->can_addr.j1939.addr;
+	}
+	/*
+	 * take a default source when not present, so connected sockets
+	 * will stick to the same source ECU
+	 */
+	if (!jsk->addr.src && !j1939_address_is_valid(jsk->addr.sa)) {
+		ecu = j1939_ecu_find_segment_default_tx(ifindex,
+				&jsk->addr.src, &jsk->addr.sa);
+		if (IS_ERR(ecu)) {
+			ret = PTR_ERR(ecu);
+			goto fail_locked;
+		}
+		put_j1939_ecu(ecu);
+	}
+
+	/* start assigning, no problem can occur at this point anymore */
+	jsk->sk.sk_bound_dev_if = ifindex;
+
+	if (!(jsk->state & JSK_BOUND) || !pgn_is_valid(jsk->addr.pgn)) {
+		/*
+		 * bind() takes precedence over connect() for the
+		 * pgn to use ourselve
+		 */
+		jsk->addr.pgn = addr->can_addr.j1939.pgn;
+	}
+
+	old_state = jsk->state;
+	jsk->state |= JSK_CONNECTED;
+
+	if (!(old_state & (JSK_BOUND | JSK_CONNECTED))) {
+		list_add_tail(&jsk->list, &s.socks);
+		j1939_recv_add(jsk, j1939sk_recv_skb);
+	}
+	release_sock(sock->sk);
+	mutex_unlock(&s.lock);
+	return 0;
+
+fail_locked:
+	release_sock(sock->sk);
+	mutex_unlock(&s.lock);
+	return ret;
+}
+
+static void j1939sk_sock2sockaddr_can(struct sockaddr_can *addr,
+		const struct j1939_sock *jsk, int peer)
+{
+	addr->can_family = AF_CAN;
+	addr->can_ifindex = jsk->sk.sk_bound_dev_if;
+	addr->can_addr.j1939.name = peer ? jsk->addr.dst : jsk->addr.src;
+	addr->can_addr.j1939.pgn = jsk->addr.pgn;
+	addr->can_addr.j1939.addr = peer ? jsk->addr.da : jsk->addr.sa;
+}
+
+static int j1939sk_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 j1939_sock *jsk = j1939_sk(sk);
+	int ret = 0;
+
+	lock_sock(sk);
+
+	if (peer && !(jsk->state & JSK_CONNECTED)) {
+		ret = -EADDRNOTAVAIL;
+		goto failure;
+	}
+
+	j1939sk_sock2sockaddr_can(addr, jsk, peer);
+	*len = sizeof(*addr);
+
+failure:
+	release_sock(sk);
+
+	return ret;
+}
+
+static int j1939sk_release(struct socket *sock)
+{
+	struct sock *sk = sock->sk;
+	struct j1939_sock *jsk = j1939_sk(sk);
+
+	j1939_recv_remove(jsk, j1939sk_recv_skb);
+	mutex_lock(&s.lock);
+	list_del_init(&jsk->list);
+	mutex_unlock(&s.lock);
+
+	lock_sock(sk);
+	if (jsk->state & PROMISC)
+		j1939_put_promisc_receiver(jsk->sk.sk_bound_dev_if);
+
+	sock_orphan(sk);
+	sock->sk = NULL;
+
+	release_sock(sk);
+	sock_put(sk);
+
+	return 0;
+}
+
+static int j1939sk_setsockopt_flag(struct j1939_sock *jsk,
+		char __user *optval, unsigned int optlen, int flag)
+{
+	int tmp;
+
+	if (optlen != sizeof(tmp))
+		return -EINVAL;
+	if (copy_from_user(&tmp, optval, optlen))
+		return -EFAULT;
+	lock_sock(&jsk->sk);
+	if (tmp)
+		jsk->state |= flag;
+	else
+		jsk->state &= ~flag;
+	release_sock(&jsk->sk);
+	return tmp;
+}
+
+static int j1939sk_setsockopt(struct socket *sock, int level, int optname,
+		char __user *optval, unsigned int optlen)
+{
+	struct sock *sk = sock->sk;
+	struct j1939_sock *jsk = j1939_sk(sk);
+	int ret = 0, tmp, count;
+	struct j1939_filter *filters, *ofilters;
+
+	if (level != SOL_CAN_J1939)
+		return -EINVAL;
+
+	switch (optname) {
+	case SO_J1939_FILTER:
+		if (optval) {
+			if (optlen % sizeof(*filters) != 0)
+				return -EINVAL;
+			count = optlen / sizeof(*filters);
+			filters = kmalloc(optlen, GFP_KERNEL);
+			if (!filters)
+				return -ENOMEM;
+			if (copy_from_user(filters, optval, optlen)) {
+				kfree(filters);
+				return -EFAULT;
+			}
+		} else {
+			filters = NULL;
+			count = 0;
+		}
+
+		j1939_recv_suspend();
+		ofilters = jsk->filters;
+		jsk->filters = filters;
+		jsk->nfilters = count;
+		j1939_recv_resume();
+		kfree(ofilters);
+		break;
+	case SO_J1939_PROMISC:
+		tmp = jsk->state & PROMISC;
+		ret = j1939sk_setsockopt_flag(jsk, optval, optlen, PROMISC);
+		if (ret && !tmp)
+			j1939_get_promisc_receiver(jsk->sk.sk_bound_dev_if);
+		else if (!ret && tmp)
+			j1939_put_promisc_receiver(jsk->sk.sk_bound_dev_if);
+		ret = 0;
+		break;
+	case SO_J1939_RECV_OWN:
+		j1939sk_setsockopt_flag(jsk, optval, optlen, RECV_OWN);
+		break;
+	case SO_J1939_SEND_PRIO:
+		if (optlen != sizeof(tmp))
+			return -EINVAL;
+		if (copy_from_user(&tmp, optval, optlen))
+			return -EFAULT;
+		if ((tmp < 0) || (tmp > 7))
+			return -EDOM;
+		if ((tmp < 2) && !capable(CAP_NET_ADMIN))
+			return -EPERM;
+		lock_sock(&jsk->sk);
+		jsk->sk.sk_priority = j1939_to_sk_priority(tmp);
+		release_sock(&jsk->sk);
+		break;
+	case SO_J1939_DEST_MASK:
+		lock_sock(&jsk->sk);
+		if (optlen != sizeof(jsk->addr.mask))
+			ret = -EINVAL;
+		else if (jsk->state & JSK_CONNECTED)
+			ret = -EBUSY;
+		else if (copy_from_user(&jsk->addr.mask, optval, optlen))
+			ret = -EFAULT;
+		else
+			ret = 0;
+		release_sock(&jsk->sk);
+		break;
+	default:
+		return -ENOPROTOOPT;
+	}
+
+	return ret;
+}
+
+static int j1939sk_getsockopt(struct socket *sock, int level, int optname,
+		char __user *optval, int __user *optlen)
+{
+	struct sock *sk = sock->sk;
+	struct j1939_sock *jsk = j1939_sk(sk);
+	int ret, ulen;
+	/* set defaults for using 'int' properties */
+	int tmp = 0;
+	int len = sizeof(tmp);
+	void *val = &tmp;
+
+	if (level != SOL_CAN_J1939)
+		return -EINVAL;
+	if (get_user(ulen, optlen))
+		return -EFAULT;
+	if (ulen < 0)
+		return -EINVAL;
+
+	lock_sock(&jsk->sk);
+	switch (optname) {
+	case SO_J1939_PROMISC:
+		tmp = (jsk->state & PROMISC) ? 1 : 0;
+		break;
+	case SO_J1939_RECV_OWN:
+		tmp = (jsk->state & RECV_OWN) ? 1 : 0;
+		break;
+	case SO_J1939_SEND_PRIO:
+		tmp = j1939_prio(jsk->sk.sk_priority);
+		break;
+	case SO_J1939_DEST_MASK:
+		val = &jsk->addr.mask;
+		len = sizeof(jsk->addr.mask);
+		break;
+	default:
+		ret = -ENOPROTOOPT;
+		goto no_copy;
+	}
+
+	/*
+	 * copy to user, based on 'len' & 'val'
+	 * but most sockopt's are 'int' properties, and have 'len' & 'val'
+	 * left unchanged, but instead modified 'tmp'
+	 */
+	if (len > ulen)
+		ret = -EFAULT;
+	else if (put_user(len, optlen))
+		ret = -EFAULT;
+	else if (copy_to_user(optval, val, len))
+		ret = -EFAULT;
+	else
+		ret = 0;
+no_copy:
+	release_sock(&jsk->sk);
+	return ret;
+}
+
+static int j1939sk_recvmsg(struct kiocb *iocb, struct socket *sock,
+			 struct msghdr *msg, size_t size, int flags)
+{
+	struct sock *sk = sock->sk;
+	struct sk_buff *skb;
+	struct j1939_sk_buff_cb *sk_addr;
+	int ret = 0;
+
+	skb = skb_recv_datagram(sk, flags, 0, &ret);
+	if (!skb)
+		return ret;
+
+	if (size < skb->len)
+		msg->msg_flags |= MSG_TRUNC;
+	else
+		size = skb->len;
+
+	ret = memcpy_toiovec(msg->msg_iov, skb->data, size);
+	if (ret < 0)
+		goto failed_with_skb;
+
+	sock_recv_timestamp(msg, sk, skb);
+	sk_addr = (void *)skb->cb;
+
+	if (j1939_address_is_valid(sk_addr->dst.addr))
+		put_cmsg(msg, SOL_CAN_J1939, SCM_J1939_DEST_ADDR,
+				sizeof(sk_addr->dst.addr), &sk_addr->dst.addr);
+
+	if (sk_addr->dst.name)
+		put_cmsg(msg, SOL_CAN_J1939, SCM_J1939_DEST_NAME,
+				sizeof(sk_addr->dst.name), &sk_addr->dst.name);
+
+	put_cmsg(msg, SOL_CAN_J1939, SCM_J1939_PRIO,
+			sizeof(sk_addr->priority), &sk_addr->priority);
+
+	if (msg->msg_name) {
+		struct sockaddr_can *paddr = msg->msg_name;
+
+		msg->msg_namelen = required_size(can_addr.j1939, *paddr);
+		memset(msg->msg_name, 0, msg->msg_namelen);
+		paddr->can_family = AF_CAN;
+		paddr->can_ifindex = sk_addr->ifindex;
+		paddr->can_addr.j1939.name = sk_addr->src.name;
+		paddr->can_addr.j1939.addr = sk_addr->src.addr;
+		paddr->can_addr.j1939.pgn = sk_addr->pgn;
+	}
+
+	skb_free_datagram(sk, skb);
+
+	return size;
+
+failed_with_skb:
+	skb_kill_datagram(sk, skb, flags);
+	return ret;
+}
+
+static int j1939sk_sendmsg(struct kiocb *iocb, struct socket *sock,
+		       struct msghdr *msg, size_t size)
+{
+	struct sock *sk = sock->sk;
+	struct j1939_sock *jsk = j1939_sk(sk);
+	struct j1939_sk_buff_cb *skb_cb;
+	struct sk_buff *skb;
+	struct net_device *dev;
+	struct j1939_ecu *ecu;
+	int ifindex;
+	int ret;
+
+	if (!(jsk->state | JSK_BOUND))
+		return -ENOTCONN;
+
+	if (msg->msg_name && (msg->msg_namelen <
+			required_size(can_addr.j1939, struct sockaddr_can)))
+		return -EINVAL;
+
+	ifindex = jsk->sk.sk_bound_dev_if;
+	if (msg->msg_name) {
+		struct sockaddr_can *addr = msg->msg_name;
+		if (msg->msg_namelen < required_size(can_addr.j1939, *addr))
+			return -EFAULT;
+		if (addr->can_family != AF_CAN)
+			return -EINVAL;
+		if (ifindex && addr->can_ifindex &&
+			(ifindex != addr->can_ifindex))
+			return -ENONET;
+		if (!ifindex)
+			/* take destination intf when intf not yet set */
+			ifindex = addr->can_ifindex;
+	}
+
+	if (!ifindex)
+		return -EDESTADDRREQ;
+	if (j1939_no_address(&jsk->sk)) {
+		lock_sock(&jsk->sk);
+		ecu = j1939_ecu_find_segment_default_tx(
+				jsk->sk.sk_bound_dev_if,
+				&jsk->addr.src, &jsk->addr.sa);
+		release_sock(&jsk->sk);
+		if (IS_ERR(ecu))
+			return PTR_ERR(ecu);
+	}
+
+	dev = dev_get_by_index(&init_net, ifindex);
+	if (!dev)
+		return -ENXIO;
+
+	skb = sock_alloc_send_skb(sk, size,
+			msg->msg_flags & MSG_DONTWAIT, &ret);
+	if (!skb)
+		goto put_dev;
+
+	ret = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
+	if (ret < 0)
+		goto free_skb;
+	skb->dev = dev;
+	skb->sk  = sk;
+
+	BUILD_BUG_ON(sizeof(skb->cb) < sizeof(*skb_cb));
+
+	skb_cb = (void *) skb->cb;
+	memset(skb_cb, 0, sizeof(*skb_cb));
+	skb_cb->msg_flags = msg->msg_flags;
+	skb_cb->ifindex = ifindex;
+	skb_cb->src.name = jsk->addr.src;
+	skb_cb->dst.name = jsk->addr.dst;
+	skb_cb->pgn = jsk->addr.pgn;
+	skb_cb->priority = j1939_prio(jsk->sk.sk_priority);
+	skb_cb->src.addr = jsk->addr.sa;
+	skb_cb->dst.addr = jsk->addr.da;
+
+	if (msg->msg_name) {
+		struct sockaddr_can *addr = msg->msg_name;
+		if (addr->can_addr.j1939.name) {
+			ecu = j1939_ecu_find_name_masked(
+				addr->can_addr.j1939.name, jsk->addr.mask,
+				ifindex);
+			if (!ecu)
+				return -EADDRNOTAVAIL;
+			skb_cb->dst.name = ecu->name;
+			skb_cb->dst.addr = ecu->sa;
+			put_j1939_ecu(ecu);
+		} else {
+			skb_cb->dst.name = 0;
+			skb_cb->dst.addr = addr->can_addr.j1939.addr;
+		}
+		if (pgn_is_valid(addr->can_addr.j1939.pgn))
+			skb_cb->pgn = addr->can_addr.j1939.pgn;
+	}
+
+	if (skb_cb->msg_flags & J1939_MSG_SYNC) {
+		if (skb_cb->msg_flags & MSG_DONTWAIT) {
+			ret = j1939_sock_pending_add_first(&jsk->sk);
+			if (ret > 0)
+				ret = -EAGAIN;
+		} else {
+			ret = wait_event_interruptible(jsk->waitq,
+					j1939_sock_pending_add_first(&jsk->sk));
+		}
+		if (ret < 0)
+			goto free_skb;
+	} else {
+		j1939_sock_pending_add(&jsk->sk);
+	}
+
+	ret = j1939_send(skb, j1939_level_sky);
+	if (ret < 0)
+		goto decrement_pending;
+
+	dev_put(dev);
+	return size;
+
+decrement_pending:
+	j1939_sock_pending_del(&jsk->sk);
+free_skb:
+	kfree_skb(skb);
+put_dev:
+	dev_put(dev);
+	return ret;
+}
+
+/* PROC */
+static int j1939sk_proc_show(struct seq_file *sqf, void *v)
+{
+	struct list_head *lst;
+	struct j1939_sock *jsk;
+	struct net_device *netdev;
+
+	seq_printf(sqf, "iface\tflags\tlocal\tremote\tpgn\tprio\tpending\n");
+	mutex_lock(&s.lock);
+	list_for_each(lst, &s.socks) {
+		jsk = list_entry(lst, struct j1939_sock, list);
+		lock_sock(&jsk->sk);
+		netdev = NULL;
+		if (jsk->sk.sk_bound_dev_if)
+			netdev = dev_get_by_index(&init_net,
+				jsk->sk.sk_bound_dev_if);
+		seq_printf(sqf, "%s\t", netdev ? netdev->name : "-");
+		if (netdev)
+			dev_put(netdev);
+		seq_printf(sqf, "%c%c%c%c\t",
+			(jsk->state & JSK_BOUND) ? 'b' : '-',
+			(jsk->state & JSK_CONNECTED) ? 'c' : '-',
+			(jsk->state & PROMISC) ? 'P' : '-',
+			(jsk->state & RECV_OWN) ? 'o' : '-');
+		if (jsk->addr.src)
+			seq_printf(sqf, "%016llx", (long long)jsk->addr.src);
+		seq_printf(sqf, ",%02x\t", jsk->addr.sa);
+		if (jsk->addr.dst)
+			seq_printf(sqf, "%016llx", (long long)jsk->addr.dst);
+		seq_printf(sqf, "/%016llx", (long long)jsk->addr.mask);
+		seq_printf(sqf, ",%02x\t", jsk->addr.da);
+		seq_printf(sqf, "%05x\t", jsk->addr.pgn);
+		seq_printf(sqf, "%u", j1939_prio(jsk->sk.sk_priority));
+		seq_printf(sqf, "\t%u", jsk->skb_pending);
+
+		release_sock(&jsk->sk);
+		seq_printf(sqf, "\n");
+	}
+	mutex_unlock(&s.lock);
+	return 0;
+}
+
+void j1939sk_netdev_event(int ifindex, int error_code)
+{
+	struct list_head *lst;
+	struct j1939_sock *sock;
+
+	mutex_lock(&s.lock);
+	list_for_each(lst, &s.socks) {
+		sock = list_entry(lst, struct j1939_sock, list);
+		if (sock->sk.sk_bound_dev_if != ifindex)
+			continue;
+		sock->sk.sk_err = error_code;
+		if (!sock_flag(&sock->sk, SOCK_DEAD))
+			sock->sk.sk_error_report(&sock->sk);
+		/* do not remove filters here */
+	}
+	mutex_unlock(&s.lock);
+}
+
+static const struct proto_ops j1939_ops = {
+	.family = PF_CAN,
+	.release = j1939sk_release,
+	.bind = j1939sk_bind,
+	.connect = j1939sk_connect,
+	.socketpair = sock_no_socketpair,
+	.accept = sock_no_accept,
+	.getname = j1939sk_getname,
+	.poll = datagram_poll,
+	.ioctl = can_sock_ioctl,
+	.listen = sock_no_listen,
+	.shutdown = sock_no_shutdown,
+	.setsockopt = j1939sk_setsockopt,
+	.getsockopt = j1939sk_getsockopt,
+	.sendmsg = j1939sk_sendmsg,
+	.recvmsg = j1939sk_recvmsg,
+	.mmap = sock_no_mmap,
+	.sendpage = sock_no_sendpage,
+};
+
+static struct proto j1939_proto __read_mostly = {
+	.name = "CAN_J1939",
+	.owner = THIS_MODULE,
+	.obj_size = sizeof(struct j1939_sock),
+	.init = j1939sk_init,
+};
+
+static const struct can_proto j1939_can_proto = {
+	.type = SOCK_DGRAM,
+	.protocol = CAN_J1939,
+	.ops = &j1939_ops,
+	.prot = &j1939_proto,
+
+	.rtnl_link_ops = &j1939_rtnl_af_ops,
+	.rtnl_new_addr = j1939rtnl_new_addr,
+	.rtnl_del_addr = j1939rtnl_del_addr,
+	.rtnl_dump_addr = j1939rtnl_dump_addr,
+};
+
+__init int j1939sk_module_init(void)
+{
+	int ret;
+
+	INIT_LIST_HEAD(&s.socks);
+	mutex_init(&s.lock);
+
+	ret = can_proto_register(&j1939_can_proto);
+	if (ret < 0)
+		pr_err("can: registration of j1939 protocol failed\n");
+	else
+		j1939_proc_add("sock", j1939sk_proc_show, NULL);
+	return ret;
+}
+
+void j1939sk_module_exit(void)
+{
+	j1939_proc_remove("sock");
+	can_proto_unregister(&j1939_can_proto);
+}
+
+MODULE_ALIAS("can-proto-" __stringify(CAN_J1939));
+
diff --git a/net/can/j1939/transport.c b/net/can/j1939/transport.c
new file mode 100644
index 0000000..5e39c62
--- /dev/null
+++ b/net/can/j1939/transport.c
@@ -0,0 +1,1481 @@
+/*
+ * Copyright (c) 2010-2011 EIA Electronics
+ *
+ * Authors:
+ * Kurt Van Dijck <kurt.van.dijck-/BeEPy95v10@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the version 2 of the GNU General Public License
+ * as published by the Free Software Foundation
+ */
+
+#include <linux/skbuff.h>
+#include <linux/hrtimer.h>
+#include <linux/version.h>
+#include <linux/if_arp.h>
+#include <linux/wait.h>
+#include "j1939-priv.h"
+
+#define REGULAR		0
+#define EXTENDED	1
+
+#define etp_pgn_ctl	0xc800
+#define etp_pgn_dat	0xc700
+#define tp_pgn_ctl	0xec00
+#define tp_pgn_dat	0xeb00
+
+#define  tp_cmd_bam	0x20
+#define  tp_cmd_rts	0x10
+#define  tp_cmd_cts	0x11
+#define  tp_cmd_eof	0x13
+#define  tp_cmd_abort	0xff
+
+#define etp_cmd_rts	0x14
+#define etp_cmd_cts	0x15
+#define etp_cmd_dpo	0x16
+#define etp_cmd_eof	0x17
+#define etp_cmd_abort	0xff
+
+#define ABORT_BUSY	1
+#define ABORT_RESOURCE	2
+#define ABORT_TIMEOUT	3
+#define ABORT_GENERIC	4
+#define ABORT_FAULT	5
+
+#define MAX_TP_PACKET_SIZE	(7*255)
+#define MAX_ETP_PACKET_SIZE	(7*0xffffff)
+
+static int block = 255;
+static int max_packet_size = 1024*100;
+static int retry_ms = 20;
+
+struct session {
+	struct list_head list;
+	atomic_t refs;
+	spinlock_t lock;
+
+	struct j1939_sk_buff_cb *cb; /*
+	 * ifindex, src, dst, pgn define the session block
+	 * the are _never_ modified after insertion in the list
+	 * this decreases locking problems a _lot_
+	 */
+	struct sk_buff *skb;
+
+	/*
+	 * all tx related stuff (last_txcmd, pkt.tx)
+	 * is protected (modified only) with the txtask tasklet
+	 * 'total' & 'block' are never changed,
+	 * last_cmd, last & block are protected by ->lock
+	 * this means that the tx may run after cts is received that should
+	 * have stopped tx, but this time discrepancy is never avoided anyhow
+	 */
+	uint8_t last_cmd, last_txcmd;
+	uint8_t transmission;
+	uint8_t extd;
+	struct {
+		/*
+		 * these do not require 16 bit, they should fit in uint8_t
+		 * but putting in int makes it easier to deal with
+		 */
+		unsigned int total, done, last, tx;
+		unsigned int block; /* for TP */
+		unsigned int dpo; /* for ETP */
+	} pkt;
+	struct hrtimer txtimer, rxtimer;
+	struct tasklet_struct txtask;
+};
+
+static struct j1939tp {
+	spinlock_t lock;
+	struct list_head sessionq;
+	struct list_head extsessionq;
+	struct {
+		struct list_head sessionq;
+		spinlock_t lock;
+		struct work_struct work;
+	} del;
+	wait_queue_head_t wait;
+	struct notifier_block notifier;
+} s;
+
+static struct session *j1939session_new(struct sk_buff *skb);
+static struct session *j1939session_fresh_new(int size,
+		struct j1939_sk_buff_cb *rel_cb, pgn_t pgn);
+
+static inline void fix_cb(struct j1939_sk_buff_cb *cb)
+{
+	cb->msg_flags &= ~J1939_MSG_RESERVED;
+}
+
+static inline struct session *list_to_session(struct list_head *lst)
+{
+	return container_of(lst, struct session, list);
+}
+
+static inline struct list_head *sessionq(int extd)
+{
+	return extd ? &s.extsessionq : &s.sessionq;
+}
+
+static inline void j1939session_destroy(struct session *session)
+{
+	if (session->skb)
+		kfree_skb(session->skb);
+	hrtimer_cancel(&session->rxtimer);
+	hrtimer_cancel(&session->txtimer);
+	tasklet_disable(&session->txtask);
+	kfree(session);
+}
+
+/* clean up work queue */
+static void j1939tp_del_work(struct work_struct *work)
+{
+	struct session *session;
+	int cnt = 0;
+
+	do {
+		session = NULL;
+		spin_lock_bh(&s.del.lock);
+		if (list_empty(&s.del.sessionq)) {
+			spin_unlock_bh(&s.del.lock);
+			break;
+		}
+		session = list_first_entry(&s.del.sessionq,
+				struct session, list);
+		list_del_init(&session->list);
+		spin_unlock_bh(&s.del.lock);
+		j1939session_destroy(session);
+		++cnt;
+	} while (1);
+}
+/* reference counter */
+static inline void get_session(struct session *session)
+{
+	atomic_inc(&session->refs);
+}
+
+static void put_session(struct session *session)
+{
+	BUG_ON(!session);
+	if (atomic_add_return(-1, &session->refs) >= 0)
+		/* not the last one */
+		return;
+	/* it should have been removed from any list long time ago */
+	BUG_ON(!list_empty(&session->list));
+
+	hrtimer_try_to_cancel(&session->rxtimer);
+	hrtimer_try_to_cancel(&session->txtimer);
+	tasklet_disable_nosync(&session->txtask);
+
+	if (in_interrupt()) {
+		spin_lock_bh(&s.del.lock);
+		list_add_tail(&session->list, &s.del.sessionq);
+		spin_unlock_bh(&s.del.lock);
+		schedule_work(&s.del.work);
+	} else {
+		/* destroy session right here */
+		j1939session_destroy(session);
+	}
+}
+
+/* transport status locking */
+static inline void session_lock(struct session *session)
+{
+	get_session(session); /* safety measure */
+	spin_lock_bh(&session->lock);
+}
+
+static inline void session_unlock(struct session *session)
+{
+	spin_unlock_bh(&session->lock);
+	put_session(session);
+}
+
+static inline void sessionlist_lock(void)
+{
+	spin_lock_bh(&s.lock);
+}
+
+static inline void sessionlist_unlock(void)
+{
+	spin_unlock_bh(&s.lock);
+}
+
+/*
+ * see if we are receiver
+ * returns 0 for broadcasts, although we will receive them
+ */
+static inline int j1939tp_im_receiver(const struct j1939_sk_buff_cb *cb)
+{
+	return (cb->dst.flags & ECUFLAG_LOCAL) ? 1 : 0;
+}
+
+/* see if we are sender */
+static inline int j1939tp_im_transmitter(const struct j1939_sk_buff_cb *cb)
+{
+	return (cb->src.flags & ECUFLAG_LOCAL) ? 1 : 0;
+}
+
+/* see if we are involved as either receiver or transmitter */
+/* reverse = -1 means : any direction */
+static int j1939tp_im_involved(const struct j1939_sk_buff_cb *cb, int reverse)
+{
+	if (reverse < 0) {
+		return ((cb->src.flags | cb->dst.flags) & ECUFLAG_LOCAL)
+			? 1 : 0;
+	} else if (reverse) {
+		return j1939tp_im_receiver(cb);
+	} else {
+		return j1939tp_im_transmitter(cb);
+	}
+}
+
+/* extract pgn from flow-ctl message */
+static inline pgn_t j1939xtp_ctl_to_pgn(const uint8_t *dat)
+{
+	pgn_t pgn;
+
+	pgn = (dat[7] << 16) | (dat[6] << 8) | (dat[5] << 0);
+	if (pgn_is_pdu1(pgn))
+		pgn &= 0xffff00;
+	return pgn;
+}
+
+static inline unsigned int j1939tp_ctl_to_size(const uint8_t *dat)
+{
+	return (dat[2] << 8) + (dat[1] << 0);
+}
+static inline unsigned int j1939etp_ctl_to_packet(const uint8_t *dat)
+{
+	return (dat[4] << 16) | (dat[3] << 8) | (dat[2] << 0);
+}
+static inline unsigned int j1939etp_ctl_to_size(const uint8_t *dat)
+{
+	return (dat[4] << 24) | (dat[3] << 16) |
+		(dat[2] << 8) | (dat[1] << 0);
+}
+
+/*
+ * find existing session:
+ * reverse: swap cb's src & dst
+ * there is no problem with matching broadcasts, since
+ * broadcasts (no dst, no da) would never call this
+ * with reverse==1
+ */
+static int j1939tp_match(const struct j1939_sk_buff_cb *a,
+		const struct j1939_sk_buff_cb *b, int reverse)
+{
+	if (a->ifindex != b->ifindex)
+		return 0;
+	if (!reverse) {
+		if (a->src.name) {
+			if (a->src.name != b->src.name)
+				return 0;
+		} else if (a->src.addr != b->src.addr)
+			return 0;
+		if (a->dst.name) {
+			if (a->dst.name != b->dst.name)
+				return 0;
+		} else if (a->dst.addr != b->dst.addr)
+			return 0;
+	} else {
+		if (a->src.name) {
+			if (a->src.name != b->dst.name)
+				return 0;
+		} else if (a->src.addr != b->dst.addr)
+			return 0;
+		if (a->dst.name) {
+			if (a->dst.name != b->src.name)
+				return 0;
+		} else if (a->dst.addr != b->src.addr)
+			return 0;
+	}
+	return 1;
+}
+
+static struct session *_j1939tp_find(struct list_head *root,
+		const struct j1939_sk_buff_cb *cb, int reverse)
+{
+	struct list_head *lst;
+	struct session *session;
+
+	list_for_each(lst, root) {
+		session = list_to_session(lst);
+		get_session(session);
+		if (j1939tp_match(cb, session->cb, reverse))
+			return session;
+		put_session(session);
+	}
+	return NULL;
+}
+
+static struct session *j1939tp_find(struct list_head *root,
+		const struct j1939_sk_buff_cb *cb, int reverse)
+{
+	struct session *session;
+	sessionlist_lock();
+	session = _j1939tp_find(root, cb, reverse);
+	sessionlist_unlock();
+	return session;
+}
+
+static void j1939_skbcb_swap(struct j1939_sk_buff_cb *cb)
+{
+	name_t name;
+	uint8_t addr;
+	int flags;
+
+	name = cb->dst.name;
+	cb->dst.name = cb->src.name;
+	cb->src.name = name;
+
+	addr = cb->dst.addr;
+	cb->dst.addr = cb->src.addr;
+	cb->src.addr = addr;
+
+	flags = cb->dst.flags;
+	cb->dst.flags = cb->src.flags;
+	cb->src.flags = flags;
+}
+/*
+ * TP transmit packet functions
+ *
+ * When PGN >= NO_PGN, take the 'related' pgn
+ */
+static int j1939tp_tx_dat(struct session *related,
+		const uint8_t *dat, int len)
+{
+	int ret;
+	struct sk_buff *skb;
+	struct j1939_sk_buff_cb *skb_cb;
+	uint8_t *skdat;
+
+	skb = dev_alloc_skb(8);
+	if (unlikely(!skb)) {
+		pr_alert("%s: out of memory?\n", __func__);
+		return -ENOMEM;
+	}
+	skb->protocol = related->skb->protocol;
+	skb->pkt_type = related->skb->pkt_type;
+	skb->ip_summed = related->skb->ip_summed;
+	skb->sk	= related->skb->sk;
+
+	skb_cb = (void *)skb->cb;
+	*skb_cb = *(related->cb);
+	fix_cb(skb_cb);
+	/* fix pgn */
+	skb_cb->pgn = related->extd ? etp_pgn_dat : tp_pgn_dat;
+
+	skdat = skb_put(skb, len);
+	memcpy(skdat, dat, len);
+	ret = j1939_send(skb, j1939_level_transport);
+	if (ret < 0)
+		kfree_skb(skb);
+	return ret;
+}
+static int j1939xtp_do_tx_ctl(struct sk_buff *related, int extd,
+		int swap_src_dst, pgn_t pgn, const uint8_t dat[5])
+{
+	int ret;
+	struct sk_buff *skb;
+	struct j1939_sk_buff_cb *skb_cb, *rel_cb;
+	uint8_t *skdat;
+
+	rel_cb = (void *)related->cb;
+	if (!j1939tp_im_involved(rel_cb, swap_src_dst))
+		return 0;
+
+	skb = dev_alloc_skb(8);
+	if (unlikely(!skb)) {
+		pr_alert("%s: out of memory?\n", __func__);
+		return -ENOMEM;
+	}
+	skb->protocol = related->protocol;
+	skb->pkt_type = related->pkt_type;
+	skb->ip_summed = related->ip_summed;
+	skb->sk	= related->sk;
+
+	skb_cb = (void *)skb->cb;
+	*skb_cb = *rel_cb;
+	fix_cb(skb_cb);
+	if (swap_src_dst)
+		j1939_skbcb_swap(skb_cb);
+	/* fix pgn */
+	if (!pgn_is_valid(pgn))
+		/* save related pgn */
+		pgn = rel_cb->pgn;
+	skb_cb->pgn = extd ? etp_pgn_ctl : tp_pgn_ctl;
+
+	skdat = skb_put(skb, 8);
+	memcpy(skdat, dat, 5);
+	skdat[7] = (pgn >> 16) & 0xff;
+	skdat[6] = (pgn >>  8) & 0xff;
+	skdat[5] = (pgn >>  0) & 0xff;
+
+	ret = j1939_send(skb, j1939_level_transport);
+	if (ret)
+		kfree_skb(skb);
+	return ret;
+}
+
+static inline int j1939tp_tx_ctl(struct session *session,
+		int swap_src_dst, const uint8_t dat[8])
+{
+	return j1939xtp_do_tx_ctl(session->skb, session->extd, swap_src_dst,
+			NO_PGN, dat);
+}
+
+static int j1939xtp_tx_abort(struct sk_buff *related, int extd,
+		int swap_src_dst, pgn_t pgn, int err)
+{
+	struct j1939_sk_buff_cb *cb = (void *)related->cb;
+	uint8_t dat[5];
+
+	if (!j1939tp_im_involved(cb, swap_src_dst))
+		return 0;
+
+	memset(dat, 0xff, sizeof(dat));
+	dat[0] = tp_cmd_abort;
+	if (!extd)
+		dat[1] = err ?: ABORT_GENERIC;
+	return j1939xtp_do_tx_ctl(related, extd, swap_src_dst, pgn, dat);
+}
+
+/* timer & scheduler functions */
+static inline void j1939session_schedule_txnow(struct session *session)
+{
+	tasklet_schedule(&session->txtask);
+}
+static enum hrtimer_restart j1939tp_txtimer(struct hrtimer *hrtimer)
+{
+	struct session *session =
+		container_of(hrtimer, struct session, txtimer);
+	j1939session_schedule_txnow(session);
+	return HRTIMER_NORESTART;
+}
+static inline void j1939tp_schedule_txtimer(struct session *session, int msec)
+{
+	hrtimer_start(&session->txtimer,
+			ktime_set(msec / 1000, (msec % 1000)*1000000UL),
+			HRTIMER_MODE_REL);
+}
+static inline void j1939tp_set_rxtimeout(struct session *session, int msec)
+{
+	hrtimer_start(&session->rxtimer,
+			ktime_set(msec / 1000, (msec % 1000)*1000000UL),
+			HRTIMER_MODE_REL);
+}
+
+/*
+ * session completion functions
+ */
+/*
+ * j1939session_drop
+ * removes a session from open session list
+ */
+static inline void j1939session_drop(struct session *session)
+{
+	sessionlist_lock();
+	list_del_init(&session->list);
+	sessionlist_unlock();
+
+	if (session->transmission) {
+		if (session->skb && session->skb->sk)
+			j1939_sock_pending_del(session->skb->sk);
+		wake_up_all(&s.wait);
+	}
+	put_session(session);
+}
+
+static inline void j1939session_completed(struct session *session)
+{
+	j1939_recv(session->skb, j1939_level_transport);
+	j1939session_drop(session);
+}
+
+static void j1939session_cancel(struct session *session, int err)
+{
+	if ((err >= 0) && j1939tp_im_involved(session->cb, -1)) {
+		if (!j1939cb_is_broadcast(session->cb)) {
+			/* do not send aborts on incoming broadcasts */
+			j1939xtp_tx_abort(session->skb, session->extd,
+				!j1939tp_im_transmitter(session->cb),
+				NO_PGN, err);
+		}
+	}
+	j1939session_drop(session);
+}
+
+static enum hrtimer_restart j1939tp_rxtimer(struct hrtimer *hrtimer)
+{
+	struct session *session =
+		container_of(hrtimer, struct session, rxtimer);
+	pr_alert("%s: timeout on %i\n", __func__, session->cb->ifindex);
+	j1939session_cancel(session, ABORT_TIMEOUT);
+	return HRTIMER_NORESTART;
+}
+
+/*
+ * receive packet functions
+ */
+static void _j1939xtp_rx_bad_message(struct sk_buff *skb, int extd)
+{
+	struct j1939_sk_buff_cb *cb = (void *)skb->cb;
+	struct session *session;
+	pgn_t pgn;
+
+	pgn = j1939xtp_ctl_to_pgn(skb->data);
+	session = j1939tp_find(sessionq(extd), cb, 0);
+	if (session /*&& (session->cb->pgn == pgn)*/) {
+		/* do not allow TP control messages on 2 pgn's */
+		j1939session_cancel(session, ABORT_FAULT);
+		put_session(session); /* ~j1939tp_find */
+		return;
+	}
+	j1939xtp_tx_abort(skb, extd, 0, ABORT_FAULT, pgn);
+	if (!session)
+		return;
+	put_session(session); /* ~j1939tp_find */
+}
+
+/* abort packets may come in 2 directions */
+static void j1939xtp_rx_bad_message(struct sk_buff *skb, int extd)
+{
+	struct j1939_sk_buff_cb *cb = (void *)skb->cb;
+
+	pr_info("%s, pgn %05x\n", __func__, j1939xtp_ctl_to_pgn(skb->data));
+	_j1939xtp_rx_bad_message(skb, extd);
+	j1939_skbcb_swap(cb);
+	_j1939xtp_rx_bad_message(skb, extd);
+	/* restore skb */
+	j1939_skbcb_swap(cb);
+	return;
+}
+
+static void _j1939xtp_rx_abort(struct sk_buff *skb, int extd)
+{
+	struct j1939_sk_buff_cb *cb = (void *)skb->cb;
+	struct session *session;
+	pgn_t pgn;
+
+	pgn = j1939xtp_ctl_to_pgn(skb->data);
+	session = j1939tp_find(sessionq(extd), cb, 0);
+	if (!session)
+		return;
+	if (session->transmission && !session->last_txcmd) {
+		/*
+		 * empty block:
+		 * do not drop session when a transmit session did not
+		 * start yet
+		 */
+	} else if (session->cb->pgn == pgn)
+		j1939session_drop(session);
+	/* another PGN had a bad message */
+	/*
+	 * TODO: maybe cancel current connection
+	 * as another pgn was communicated
+	 */
+	put_session(session); /* ~j1939tp_find */
+}
+/* abort packets may come in 2 directions */
+static inline void j1939xtp_rx_abort(struct sk_buff *skb, int extd)
+{
+	struct j1939_sk_buff_cb *cb = (void *)skb->cb;
+
+	pr_info("%s %i, %05x\n", __func__, cb->ifindex, cb->pgn);
+	_j1939xtp_rx_abort(skb, extd);
+	j1939_skbcb_swap(cb);
+	_j1939xtp_rx_abort(skb, extd);
+	/* restore skb */
+	j1939_skbcb_swap(cb);
+	return;
+}
+
+static void j1939xtp_rx_eof(struct sk_buff *skb, int extd)
+{
+	struct j1939_sk_buff_cb *cb = (void *)skb->cb;
+	struct session *session;
+	pgn_t pgn;
+
+	/* end of tx cycle */
+	pgn = j1939xtp_ctl_to_pgn(skb->data);
+	session = j1939tp_find(sessionq(extd), cb, 1);
+	if (!session)
+		/*
+		 * strange, we had EOF on closed connection
+		 * do nothing, as EOF closes the connection anyway
+		 */
+		return;
+
+	if (session->cb->pgn != pgn) {
+		j1939xtp_tx_abort(skb, extd, 1, ABORT_BUSY, pgn);
+		j1939session_cancel(session, ABORT_BUSY);
+	} else {
+		/* transmitted without problems */
+		j1939session_completed(session);
+	}
+	put_session(session); /* ~j1939tp_find */
+}
+
+static void j1939xtp_rx_cts(struct sk_buff *skb, int extd)
+{
+	struct j1939_sk_buff_cb *cb = (void *)skb->cb;
+	struct session *session;
+	pgn_t pgn;
+	unsigned int pkt;
+	const uint8_t *dat;
+
+	dat = skb->data;
+	pgn = j1939xtp_ctl_to_pgn(skb->data);
+	session = j1939tp_find(sessionq(extd), cb, 1);
+	if (!session) {
+		/* 'CTS shall be ignored' */
+		return;
+	}
+	if (session->cb->pgn != pgn) {
+		/* what to do? */
+		j1939xtp_tx_abort(skb, extd, 1, ABORT_BUSY, pgn);
+		j1939session_cancel(session, ABORT_BUSY);
+		put_session(session); /* ~j1939tp_find */
+		return;
+	}
+	session_lock(session);
+	pkt = extd ? j1939etp_ctl_to_packet(dat) : dat[2];
+	if (!dat[0])
+		hrtimer_cancel(&session->txtimer);
+	else if (!pkt)
+		goto bad_fmt;
+	else if (dat[1] > session->pkt.block /* 0xff for etp */)
+		goto bad_fmt;
+	else {
+		/* set packet counters only when not CTS(0) */
+		session->pkt.done = pkt - 1;
+		session->pkt.last = session->pkt.done + dat[1];
+		if (session->pkt.last > session->pkt.total)
+			/* safety measure */
+			session->pkt.last = session->pkt.total;
+		/* TODO: do not set tx here, do it in txtask */
+		session->pkt.tx = session->pkt.done;
+	}
+	session->last_cmd = dat[0];
+	session_unlock(session);
+	if (dat[1]) {
+		j1939tp_set_rxtimeout(session, 1250);
+		if (j1939tp_im_transmitter(session->cb))
+			j1939session_schedule_txnow(session);
+	} else {
+		/* CTS(0) */
+		j1939tp_set_rxtimeout(session, 550);
+	}
+	put_session(session); /* ~j1939tp_find */
+	return;
+bad_fmt:
+	session_unlock(session);
+	j1939session_cancel(session, ABORT_FAULT);
+	put_session(session); /* ~j1939tp_find */
+}
+
+static void j1939xtp_rx_rts(struct sk_buff *skb, int extd)
+{
+	struct j1939_sk_buff_cb *cb = (void *)skb->cb;
+	struct session *session;
+	int len;
+	const uint8_t *dat;
+	pgn_t pgn;
+
+	dat = skb->data;
+	pgn = j1939xtp_ctl_to_pgn(dat);
+
+	if ((tp_cmd_rts == dat[0]) && j1939cb_is_broadcast(cb)) {
+		pr_alert("%s: rts without destination (%i %02x)\n", __func__,
+			cb->ifindex, cb->src.addr);
+		return;
+	}
+	/*
+	 * TODO: abort RTS when a similar
+	 * TP is pending in the other direction
+	 */
+	session = j1939tp_find(sessionq(extd), cb, 0);
+	if (session && !j1939tp_im_transmitter(cb)) {
+		/* RTS on pending connection */
+		j1939session_cancel(session, ABORT_BUSY);
+		if ((pgn != session->cb->pgn) && (tp_cmd_bam != dat[0]))
+			j1939xtp_tx_abort(skb, extd, 1, ABORT_BUSY, pgn);
+		put_session(session); /* ~j1939tp_find */
+		return;
+	} else if (!session && j1939tp_im_transmitter(cb)) {
+		pr_alert("%s: I should tx (%i %02x %02x)\n", __func__,
+			cb->ifindex, cb->src.addr, cb->dst.addr);
+		return;
+	}
+	if (session && (0 != session->last_cmd)) {
+		/* we received a second rts on the same connection */
+		pr_alert("%s: connection exists (%i %02x %02x)\n", __func__,
+				cb->ifindex, cb->src.addr, cb->dst.addr);
+		j1939session_cancel(session, ABORT_BUSY);
+		put_session(session); /* ~j1939tp_find */
+		return;
+	}
+	if (session) {
+		/*
+		 * make sure 'sa' & 'da' are correct !
+		 * They may be 'not filled in yet' for sending
+		 * skb's, since they did not pass the Address Claim ever.
+		 */
+		session->cb->src.addr = cb->src.addr;
+		session->cb->dst.addr = cb->dst.addr;
+	} else {
+		int abort = 0;
+		if (extd) {
+			len = j1939etp_ctl_to_size(dat);
+			if (len > (max_packet_size ?: MAX_ETP_PACKET_SIZE))
+				abort = ABORT_RESOURCE;
+			else if (len <= MAX_TP_PACKET_SIZE)
+				abort = ABORT_FAULT;
+		} else {
+			len = j1939tp_ctl_to_size(dat);
+			if (len > MAX_TP_PACKET_SIZE)
+				abort = ABORT_FAULT;
+			else if (max_packet_size && (len > max_packet_size))
+				abort = ABORT_RESOURCE;
+		}
+		if (abort) {
+			j1939xtp_tx_abort(skb, extd, 1, abort, pgn);
+			return;
+		}
+		session = j1939session_fresh_new(len, cb, pgn);
+		if (!session) {
+			j1939xtp_tx_abort(skb, extd, 1, ABORT_RESOURCE, pgn);
+			return;
+		}
+		session->extd = extd;
+		/* initialize the control buffer: plain copy */
+		session->pkt.total = (len+6)/7;
+		session->pkt.block = 0xff;
+		if (!extd) {
+			if (dat[3] != session->pkt.total)
+				pr_alert("%s: strange total,"
+						" %u != %u\n", __func__,
+						session->pkt.total, dat[3]);
+			session->pkt.total = dat[3];
+			session->pkt.block = dat[4];
+		}
+		session->pkt.done = session->pkt.tx = 0;
+		get_session(session); /* equivalent to j1939tp_find() */
+		sessionlist_lock();
+		list_add_tail(&session->list, sessionq(extd));
+		sessionlist_unlock();
+	}
+	session->last_cmd = dat[0];
+
+	j1939tp_set_rxtimeout(session, 1250);
+
+	if (j1939tp_im_receiver(session->cb)) {
+		if (extd || (tp_cmd_bam != dat[0]))
+			j1939session_schedule_txnow(session);
+	}
+	/*
+	 * as soon as it's inserted, things can go fast
+	 * protect against a long delay
+	 * between spin_unlock & next statement
+	 * so, only release here, at the end
+	 */
+	put_session(session); /* ~j1939tp_find */
+	return;
+}
+
+static void j1939xtp_rx_dpo(struct sk_buff *skb, int extd)
+{
+	struct j1939_sk_buff_cb *cb = (void *)skb->cb;
+	struct session *session;
+	pgn_t pgn;
+	const uint8_t *dat = skb->data;
+
+	pgn = j1939xtp_ctl_to_pgn(dat);
+	session = j1939tp_find(sessionq(extd), cb, 0);
+	if (!session) {
+		pr_info("%s: %s\n", __func__, "no connection found");
+		return;
+	}
+
+	if (session->cb->pgn != pgn) {
+		pr_info("%s: different pgn\n", __func__);
+		j1939xtp_tx_abort(skb, 1, 1, ABORT_BUSY, pgn);
+		j1939session_cancel(session, ABORT_BUSY);
+		put_session(session); /* ~j1939tp_find */
+		return;
+	}
+	/* transmitted without problems */
+	session->pkt.dpo = j1939etp_ctl_to_packet(skb->data);
+	session->last_cmd = dat[0];
+	j1939tp_set_rxtimeout(session, 750);
+	put_session(session); /* ~j1939tp_find */
+}
+
+static void j1939xtp_rx_dat(struct sk_buff *skb, int extd)
+{
+	struct j1939_sk_buff_cb *cb = (void *)skb->cb;
+	struct session *session;
+	const uint8_t *dat;
+	uint8_t *tpdat;
+	int offset;
+	int nbytes;
+	int final;
+	int do_cts_eof;
+	int packet;
+
+	session = j1939tp_find(sessionq(extd), cb, 0);
+	if (!session) {
+		pr_info("%s:%s\n", __func__, "no connection found");
+		return;
+	}
+	dat = skb->data;
+	if (skb->len <= 1)
+		/* makes no sense */
+		goto strange_packet_unlocked;
+
+	session_lock(session);
+
+	switch (session->last_cmd) {
+	case 0xff:
+		break;
+	case etp_cmd_dpo:
+		if (extd)
+			break;
+	case tp_cmd_bam:
+	case tp_cmd_cts:
+		if (!extd)
+			break;
+	default:
+		pr_info("%s: last %02x\n", __func__,
+				session->last_cmd);
+		goto strange_packet;
+	}
+
+	packet = (dat[0]-1+session->pkt.dpo);
+	offset = packet * 7;
+	if ((packet > session->pkt.total) ||
+			(session->pkt.done+1) > session->pkt.total) {
+		pr_info("%s: should have been completed\n", __func__);
+		goto strange_packet;
+	}
+	nbytes = session->skb->len - offset;
+	if (nbytes > 7)
+		nbytes = 7;
+	if ((nbytes <= 0) || ((nbytes + 1) > skb->len)) {
+		pr_info("%s: nbytes %i, len %i\n", __func__, nbytes,
+				skb->len);
+		goto strange_packet;
+	}
+	tpdat = session->skb->data;
+	memcpy(&tpdat[offset], &dat[1], nbytes);
+	if (packet == session->pkt.done)
+		++session->pkt.done;
+
+	if (!extd && j1939cb_is_broadcast(session->cb)) {
+		final = session->pkt.done >= session->pkt.total;
+		do_cts_eof = 0;
+	} else {
+		final = 0; /* never final, an EOF must follow */
+		do_cts_eof = (session->pkt.done >= session->pkt.last);
+	}
+	session_unlock(session);
+	if (final) {
+		j1939session_completed(session);
+	} else if (do_cts_eof) {
+		j1939tp_set_rxtimeout(session, 1250);
+		if (j1939tp_im_receiver(session->cb))
+			j1939session_schedule_txnow(session);
+	} else {
+		j1939tp_set_rxtimeout(session, 250);
+	}
+	session->last_cmd = 0xff;
+	put_session(session); /* ~j1939tp_find */
+	return;
+
+strange_packet:
+	/* unlock session (spinlock) before trying to send */
+	session_unlock(session);
+strange_packet_unlocked:
+	j1939session_cancel(session, ABORT_FAULT);
+	put_session(session); /* ~j1939tp_find */
+}
+
+/*
+ * transmit function
+ */
+static int j1939tp_txnext(struct session *session)
+{
+	uint8_t dat[8];
+	const uint8_t *tpdat;
+	int ret, offset, len, pkt_done, pkt_end;
+	unsigned int pkt;
+
+	memset(dat, 0xff, sizeof(dat));
+	get_session(session); /* do not loose it */
+
+	switch (session->last_cmd) {
+	case 0:
+		if (!j1939tp_im_transmitter(session->cb))
+			break;
+		dat[1] = (session->skb->len >> 0) & 0xff;
+		dat[2] = (session->skb->len >> 8) & 0xff;
+		dat[3] = session->pkt.total;
+		if (session->extd) {
+			dat[0] = etp_cmd_rts;
+			dat[1] = (session->skb->len >>  0) & 0xff;
+			dat[2] = (session->skb->len >>  8) & 0xff;
+			dat[3] = (session->skb->len >> 16) & 0xff;
+			dat[4] = (session->skb->len >> 24) & 0xff;
+		} else if (j1939cb_is_broadcast(session->cb)) {
+			dat[0] = tp_cmd_bam;
+			/* fake cts for broadcast */
+			session->pkt.tx = 0;
+		} else {
+			dat[0] = tp_cmd_rts;
+			dat[4] = dat[3];
+		}
+		if (dat[0] == session->last_txcmd)
+			/* done already */
+			break;
+		ret = j1939tp_tx_ctl(session, 0, dat);
+		if (ret < 0)
+			goto failed;
+		session->last_txcmd = dat[0];
+		/* must lock? */
+		if (tp_cmd_bam == dat[0])
+			j1939tp_schedule_txtimer(session, 50);
+		j1939tp_set_rxtimeout(session, 1250);
+		break;
+	case tp_cmd_rts:
+	case etp_cmd_rts:
+		if (!j1939tp_im_receiver(session->cb))
+			break;
+tx_cts:
+		ret = 0;
+		len = session->pkt.total - session->pkt.done;
+		if (len > 255)
+			len = 255;
+		if (len > session->pkt.block)
+			len = session->pkt.block;
+		if (block && (len > block))
+			len = block;
+
+		if (session->extd) {
+			pkt = session->pkt.done+1;
+			dat[0] = etp_cmd_cts;
+			dat[1] = len;
+			dat[2] = (pkt >>  0) & 0xff;
+			dat[3] = (pkt >>  8) & 0xff;
+			dat[4] = (pkt >> 16) & 0xff;
+		} else {
+			dat[0] = tp_cmd_cts;
+			dat[1] = len;
+			dat[2] = session->pkt.done+1;
+		}
+		if (dat[0] == session->last_txcmd)
+			/* done already */
+			break;
+		ret = j1939tp_tx_ctl(session, 1, dat);
+		if (ret < 0)
+			goto failed;
+		if (len)
+			/* only mark cts done when len is set */
+			session->last_txcmd = dat[0];
+		j1939tp_set_rxtimeout(session, 1250);
+		break;
+	case etp_cmd_cts:
+		if (j1939tp_im_transmitter(session->cb) && session->extd &&
+		    (etp_cmd_dpo != session->last_txcmd)) {
+			/* do dpo */
+			dat[0] = etp_cmd_dpo;
+			session->pkt.dpo = session->pkt.done;
+			pkt = session->pkt.dpo;
+			dat[1] = session->pkt.last - session->pkt.done;
+			dat[2] = (pkt >>  0) & 0xff;
+			dat[3] = (pkt >>  8) & 0xff;
+			dat[4] = (pkt >> 16) & 0xff;
+			ret = j1939tp_tx_ctl(session, 0, dat);
+			if (ret < 0)
+				goto failed;
+			session->last_txcmd = dat[0];
+			j1939tp_set_rxtimeout(session, 1250);
+			session->pkt.tx = session->pkt.done;
+		}
+	case tp_cmd_cts:
+	case 0xff: /* did some data */
+	case etp_cmd_dpo:
+		if ((session->extd || !j1939cb_is_broadcast(session->cb)) &&
+		     j1939tp_im_receiver(session->cb)) {
+			if (session->pkt.done >= session->pkt.total) {
+				if (session->extd) {
+					dat[0] = etp_cmd_eof;
+					dat[1] = session->skb->len >> 0;
+					dat[2] = session->skb->len >> 8;
+					dat[3] = session->skb->len >> 16;
+					dat[4] = session->skb->len >> 24;
+				} else {
+					dat[0] = tp_cmd_eof;
+					dat[1] = session->skb->len;
+					dat[2] = session->skb->len >> 8;
+					dat[3] = session->pkt.total;
+				}
+				if (dat[0] == session->last_txcmd)
+					/* done already */
+					break;
+				ret = j1939tp_tx_ctl(session, 1, dat);
+				if (ret < 0)
+					goto failed;
+				session->last_txcmd = dat[0];
+				j1939tp_set_rxtimeout(session, 1250);
+				/* wait for the EOF packet to come in */
+				break;
+			} else if (session->pkt.done >= session->pkt.last) {
+				session->last_txcmd = 0;
+				goto tx_cts;
+			}
+		}
+	case tp_cmd_bam:
+		if (!j1939tp_im_transmitter(session->cb))
+			break;
+		tpdat = session->skb->data;
+		ret = 0;
+		pkt_done = 0;
+		pkt_end = (!session->extd && j1939cb_is_broadcast(session->cb))
+			? session->pkt.total : session->pkt.last;
+
+		while (session->pkt.tx < pkt_end) {
+			dat[0] = session->pkt.tx - session->pkt.dpo+1;
+			offset = session->pkt.tx * 7;
+			len = session->skb->len - offset;
+			if (len > 7)
+				len = 7;
+			memcpy(&dat[1], &tpdat[offset], len);
+			ret = j1939tp_tx_dat(session, dat, len+1);
+			if (ret < 0)
+				break;
+			session->last_txcmd = 0xff;
+			++pkt_done;
+			++session->pkt.tx;
+			if (j1939cb_is_broadcast(session->cb)) {
+				if (session->pkt.tx < session->pkt.total)
+					j1939tp_schedule_txtimer(session, 50);
+				break;
+			}
+		}
+		if (pkt_done)
+			j1939tp_set_rxtimeout(session, 250);
+		if (ret)
+			goto failed;
+		break;
+	}
+	put_session(session);
+	return 0;
+failed:
+	put_session(session);
+	return ret;
+}
+
+static void j1939tp_txtask(unsigned long val)
+{
+	struct session *session = (void *)val;
+	int ret;
+	ktime_t ktime;
+
+	get_session(session);
+	ret = j1939tp_txnext(session);
+	if (ret < 0) {
+		if (ret == -EADDRNOTAVAIL) {
+			/*
+			 * during address claiming delays, postpone
+			 * the rxtimer too
+			 */
+			ktime = hrtimer_get_remaining(&session->rxtimer);
+			if ((ktime_to_ns(ktime)*NSEC_PER_MSEC) < (retry_ms+20))
+				j1939tp_set_rxtimeout(session, retry_ms+20);
+		}
+		j1939tp_schedule_txtimer(session, retry_ms);
+	}
+	put_session(session);
+}
+
+static inline int j1939tp_tx_initial(struct session *session)
+{
+	int ret;
+
+	get_session(session);
+	while (1) {
+		ret = j1939tp_txnext(session);
+		if (!ret)
+			break;
+		else if (session->cb->msg_flags & MSG_DONTWAIT)
+			break;
+		else if (ret == -EADDRNOTAVAIL) {
+			/* address claim delay */
+			if (signal_pending(current)) {
+				ret = -ERESTARTSYS;
+				break;
+			}
+			msleep(retry_ms);
+		}
+	}
+
+	/* clear MSG_DONTWAIT flag here, it makes no sense from this point on */
+	session->cb->msg_flags &= ~MSG_DONTWAIT;
+
+	put_session(session);
+	return ret;
+}
+
+/* this call is to be used as probe within wait_event_xxx() */
+static int j1939session_insert(struct session *session)
+{
+	struct session *pending;
+
+	sessionlist_lock();
+	pending = _j1939tp_find(sessionq(session->extd), session->cb, 0);
+	if (pending)
+		/* revert the effect of find() */
+		put_session(pending);
+	else
+		list_add_tail(&session->list, sessionq(session->extd));
+	sessionlist_unlock();
+	return pending ? 0 : 1;
+}
+/*
+ * j1939 main intf
+ */
+int j1939_send_transport(struct sk_buff *skb)
+{
+	struct j1939_sk_buff_cb *cb = (void *)skb->cb;
+	struct session *session;
+	int ret;
+
+	if ((tp_pgn_dat == cb->pgn) || (tp_pgn_ctl == cb->pgn) ||
+	    (etp_pgn_dat == cb->pgn) || (etp_pgn_ctl == cb->pgn))
+		/* avoid conflict */
+		return -EDOM;
+	if (skb->len <= 8)
+		return 0;
+	else if (skb->len > (max_packet_size ?: MAX_ETP_PACKET_SIZE))
+		return -EMSGSIZE;
+
+	if (skb->len > MAX_TP_PACKET_SIZE) {
+		if (j1939cb_is_broadcast(cb))
+			return -EDESTADDRREQ;
+	}
+
+	/* prepare new session */
+	session = j1939session_new(skb);
+	if (!session)
+		return -ENOMEM;
+
+	session->extd = (skb->len > MAX_TP_PACKET_SIZE) ? EXTENDED : REGULAR;
+	session->transmission = 1;
+	session->pkt.total = (skb->len + 6)/7;
+	session->pkt.block = session->extd ? 255 :
+		(block ?: session->pkt.total);
+	if (j1939cb_is_broadcast(session->cb))
+		/* set the end-packet for broadcast */
+		session->pkt.last = session->pkt.total;
+
+	/* insert into queue, but avoid collision with pending session */
+	if (session->cb->msg_flags & MSG_DONTWAIT)
+		ret = j1939session_insert(session) ? 0 : -EAGAIN;
+	else
+		ret = wait_event_interruptible(s.wait,
+				j1939session_insert(session));
+	if (ret < 0)
+		goto failed;
+
+	ret = j1939tp_tx_initial(session);
+	if (!ret)
+		/* transmission started */
+		return RESULT_STOP;
+	sessionlist_lock();
+	list_del_init(&session->list);
+	sessionlist_unlock();
+failed:
+	/*
+	 * hide the skb from j1939session_drop, as it would
+	 * kfree_skb, but our caller will kfree_skb(skb) too.
+	 */
+	session->skb = NULL;
+	j1939session_drop(session);
+	return ret;
+}
+
+int j1939_recv_transport(struct sk_buff *skb)
+{
+	struct j1939_sk_buff_cb *cb = (void *)skb->cb;
+	const uint8_t *dat;
+
+	switch (cb->pgn) {
+	case etp_pgn_dat:
+		j1939xtp_rx_dat(skb, EXTENDED);
+		break;
+	case etp_pgn_ctl:
+		if (skb->len < 8) {
+			j1939xtp_rx_bad_message(skb, EXTENDED);
+			break;
+		}
+		dat = skb->data;
+		switch (*dat) {
+		case etp_cmd_rts:
+			j1939xtp_rx_rts(skb, EXTENDED);
+			break;
+		case etp_cmd_cts:
+			j1939xtp_rx_cts(skb, EXTENDED);
+			break;
+		case etp_cmd_dpo:
+			j1939xtp_rx_dpo(skb, EXTENDED);
+			break;
+		case etp_cmd_eof:
+			j1939xtp_rx_eof(skb, EXTENDED);
+			break;
+		case etp_cmd_abort:
+			j1939xtp_rx_abort(skb, EXTENDED);
+			break;
+		default:
+			j1939xtp_rx_bad_message(skb, EXTENDED);
+			break;
+		}
+		break;
+	case tp_pgn_dat:
+		j1939xtp_rx_dat(skb, REGULAR);
+		break;
+	case tp_pgn_ctl:
+		if (skb->len < 8) {
+			j1939xtp_rx_bad_message(skb, REGULAR);
+			break;
+		}
+		dat = skb->data;
+		switch (*dat) {
+		case tp_cmd_bam:
+		case tp_cmd_rts:
+			j1939xtp_rx_rts(skb, REGULAR);
+			break;
+		case tp_cmd_cts:
+			j1939xtp_rx_cts(skb, REGULAR);
+			break;
+		case tp_cmd_eof:
+			j1939xtp_rx_eof(skb, REGULAR);
+			break;
+		case tp_cmd_abort:
+			j1939xtp_rx_abort(skb, REGULAR);
+			break;
+		default:
+			j1939xtp_rx_bad_message(skb, REGULAR);
+			break;
+		}
+		break;
+	default:
+		return 0;
+	}
+	return RESULT_STOP;
+}
+
+static struct session *j1939session_fresh_new(int size,
+		struct j1939_sk_buff_cb *rel_cb, pgn_t pgn)
+{
+	struct sk_buff *skb;
+	struct j1939_sk_buff_cb *cb;
+	struct session *session;
+
+	skb = dev_alloc_skb(size);
+	if (!skb)
+		return NULL;
+	cb = (void *)skb->cb;
+	*cb = *rel_cb;
+	fix_cb(cb);
+	cb->pgn = pgn;
+
+	session = j1939session_new(skb);
+	if (!session) {
+		kfree(skb);
+		return NULL;
+	}
+	/* alloc data area */
+	skb_put(skb, size);
+	return session;
+}
+static struct session *j1939session_new(struct sk_buff *skb)
+{
+	struct session *session;
+
+	session = kzalloc(sizeof(*session), gfp_any());
+	if (!session)
+		return NULL;
+	INIT_LIST_HEAD(&session->list);
+	spin_lock_init(&session->lock);
+	session->skb = skb;
+
+	session->cb = (void *)session->skb->cb;
+	hrtimer_init(&session->txtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	session->txtimer.function = j1939tp_txtimer;
+	hrtimer_init(&session->rxtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	session->rxtimer.function = j1939tp_rxtimer;
+	tasklet_init(&session->txtask, j1939tp_txtask, (unsigned long)session);
+	return session;
+}
+
+static int j1939tp_notifier(struct notifier_block *nb,
+			unsigned long msg, void *data)
+{
+	struct net_device *netdev = (struct net_device *)data;
+	struct session *session;
+	struct list_head *lst, *saved;
+
+	if (!net_eq(dev_net(netdev), &init_net))
+		return NOTIFY_DONE;
+
+	if (netdev->type != ARPHRD_CAN)
+		return NOTIFY_DONE;
+
+	if (msg != NETDEV_UNREGISTER)
+		return NOTIFY_DONE;
+
+	sessionlist_lock();
+	list_for_each_safe(lst, saved, &s.sessionq) {
+		session = list_to_session(lst);
+		if (session->cb->ifindex != netdev->ifindex)
+			continue;
+		list_del_init(&session->list);
+		put_session(session);
+	}
+	list_for_each_safe(lst, saved, &s.extsessionq) {
+		session = list_to_session(lst);
+		if (session->cb->ifindex != netdev->ifindex)
+			continue;
+		list_del_init(&session->list);
+		put_session(session);
+	}
+	sessionlist_unlock();
+	return NOTIFY_DONE;
+}
+
+/* SYSCTL */
+static struct ctl_table_header *j1939tp_table_header;
+
+static int min_block = 1;
+static int max_block = 255;
+static int min_packet = 8;
+static int max_packet = ((2 << 24)-1)*7;
+
+static int min_retry = 5;
+static int max_retry = 5000;
+
+static ctl_table j1939tp_table[] = {
+	{
+		.procname	= "transport_cts_nr_of_frames",
+		.data		= &block,
+		.maxlen		= sizeof(block),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_minmax,
+		.extra1		= &min_block,
+		.extra2		= &max_block,
+	},
+	{
+		.procname	= "transport_max_payload_in_bytes",
+		.data		= &max_packet_size,
+		.maxlen		= sizeof(max_packet_size),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_minmax,
+		.extra1		= &min_packet,
+		.extra2		= &max_packet,
+	},
+	{
+		.procname	= "transport_tx_retry_ms",
+		.data		= &retry_ms,
+		.maxlen		= sizeof(retry_ms),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_minmax,
+		.extra1		= &min_retry,
+		.extra2		= &max_retry,
+	},
+	{ },
+};
+
+static struct ctl_path j1939tp_path[] = {
+	{ .procname = "net", },
+	{ .procname = j1939_procname, },
+	{ }
+};
+
+/* PROC */
+static int j1939tp_proc_show_session(struct seq_file *sqf,
+		struct session *session)
+{
+	seq_printf(sqf, "%i", session->cb->ifindex);
+	if (session->cb->src.name)
+		seq_printf(sqf, "\t%016llx", session->cb->src.name);
+	else
+		seq_printf(sqf, "\t%02x", session->cb->src.addr);
+	if (session->cb->dst.name)
+		seq_printf(sqf, "\t%016llx", session->cb->dst.name);
+	else if (j1939_address_is_unicast(session->cb->dst.addr))
+		seq_printf(sqf, "\t%02x", session->cb->dst.addr);
+	else
+		seq_printf(sqf, "\t-");
+	seq_printf(sqf, "\t%05x\t%u/%u\n", session->cb->pgn,
+			session->pkt.done*7, session->skb->len);
+	return 0;
+}
+
+static int j1939tp_proc_show(struct seq_file *sqf, void *v)
+{
+	struct list_head *lst;
+
+	seq_printf(sqf, "iface\tsrc\tdst\tpgn\tdone/total\n");
+	sessionlist_lock();
+	list_for_each(lst, &s.sessionq)
+		j1939tp_proc_show_session(sqf, list_to_session(lst));
+	list_for_each(lst, &s.extsessionq)
+		j1939tp_proc_show_session(sqf, list_to_session(lst));
+	sessionlist_unlock();
+	return 0;
+}
+
+int __init j1939tp_module_init(void)
+{
+	spin_lock_init(&s.lock);
+	INIT_LIST_HEAD(&s.sessionq);
+	INIT_LIST_HEAD(&s.extsessionq);
+	spin_lock_init(&s.del.lock);
+	INIT_LIST_HEAD(&s.del.sessionq);
+	INIT_WORK(&s.del.work, j1939tp_del_work);
+
+	s.notifier.notifier_call = j1939tp_notifier;
+	register_netdevice_notifier(&s.notifier);
+
+	j1939_proc_add("transport", j1939tp_proc_show, NULL);
+	j1939tp_table_header =
+		register_sysctl_paths(j1939tp_path, j1939tp_table);
+	init_waitqueue_head(&s.wait);
+	return 0;
+}
+
+void j1939tp_module_exit(void)
+{
+	struct session *session;
+
+	wake_up_all(&s.wait);
+
+	unregister_sysctl_table(j1939tp_table_header);
+	unregister_netdevice_notifier(&s.notifier);
+	j1939_proc_remove("transport");
+	sessionlist_lock();
+	while (!list_empty(&s.extsessionq)) {
+		session = list_to_session(s.extsessionq.next);
+		list_del_init(&session->list);
+		put_session(session);
+	}
+	while (!list_empty(&s.sessionq)) {
+		session = list_to_session(s.sessionq.next);
+		list_del_init(&session->list);
+		put_session(session);
+	}
+	sessionlist_unlock();
+	flush_scheduled_work();
+}
+

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [RFC v3 5/6] j1939: add documentation and MAINTAINERS
       [not found] ` <20110314132004.GA333-MxZ6Iy/zr/UdbCeoMzGj59i2O/JbrIOy@public.gmane.org>
                     ` (3 preceding siblings ...)
  2011-03-14 13:56   ` [RFC v3 4/6] j1939: initial import of SAE J1939 Kurt Van Dijck
@ 2011-03-14 13:59   ` Kurt Van Dijck
       [not found]     ` <20110314135917.GF333-MxZ6Iy/zr/UdbCeoMzGj59i2O/JbrIOy@public.gmane.org>
  2011-03-14 14:05   ` [RFC v3 6/6] iproute2: add CAN and J1939 rtnetlink support Kurt Van Dijck
  2011-03-15  9:23   ` [RFC v3 0/6] CAN: add SAE J1939 protocol Kurt Van Dijck
  6 siblings, 1 reply; 30+ messages in thread
From: Kurt Van Dijck @ 2011-03-14 13:59 UTC (permalink / raw)
  To: socketcan-core-0fE9KPoRgkgATYTw5x5z8w, netdev-u79uwXL29TY76Z2rM5mHXA

This patch adds the documentation and MAINTAINERS.
This is seperated from 4/6 for size constraints
on berlios' SocketCAN mailing list.

Signed-off-by: Kurt Van Dijck <kurt.van.dijck-/BeEPy95v10@public.gmane.org>
---
diff --git a/Documentation/networking/j1939.txt b/Documentation/networking/j1939.txt
new file mode 100644
index 0000000..690e0a0
--- /dev/null
+++ b/Documentation/networking/j1939.txt
@@ -0,0 +1,532 @@
+============================================================================
+
+j1939.txt
+
+Readme file for the J1939 Protocol
+
+This file contains
+
+  1 Overview / What is j1939
+    1.1 specifications used
+
+  2 Motivation
+
+  3 J1939 concepts
+    3.1 socket type
+    3.2 addressing
+    3.3 priority
+    3.4 PGN
+    3.5 filtering
+    3.6 destinations with dynamic address
+
+  4 How to use J1939
+    4.1 rtnetlink interface
+    4.2 API calls
+        4.2.1 Message flags during sendmsg
+    4.3 dynamic addressing
+
+  5 socket options
+    5.1 SO_J1939_FILTER
+    5.2 SO_J1939_PROMISC
+    5.3 SO_J1939_RECV_OWN
+    5.4 SO_J1939_RECV_DEST
+    5.5 SO_J1939_RECV_PRIO
+    5.6 SO_J1939_SEND_PRIO
+    5.7 SO_J1939_DEST_MASK
+
+  6 can-j1939 procfs interface
+    6.1 /proc/net/can-j1939/ecu
+    6.2 /proc/net/can-j1939/filter
+    6.3 /proc/net/can-j1939/sock
+    6.4 /proc/net/can-j1939/transport
+
+  7 can-j1939 SYSCTL
+    7.1 /proc/sys/net/can-j1939/transport_max_payload_in_bytes
+    7.2 /proc/sys/net/can-j1939/transport_cts_nr_of_frames
+    7.3 /proc/sys/net/can-j1939/transport_tx_retry_ms
+
+  8 Credits
+
+============================================================================
+
+1. Introduction
+--------------------------------
+
+  SAE J1939 defines a higher layer protocol on CAN. It implements a more
+  sophisticated addressing scheme and extends the maximum packet size above
+  8 bytes. Several derived specifications exists, which differ from the
+  original j1939 on the application level, like MilCAN, NMEA2000 and
+  especially ISO-11783 (ISOBUS). This last one specifies the so-called ETP
+  (Extended Transport Protocol) which is has been included in this
+  implementation. This inclusion results in a maximum packet size of
+  ((2^24)-1)*7 bytes
+
+
+1.1 specifications used
+
+  SAE J1939-21 : data link layer
+  SAE J1939-81 : network management
+  ISO 11783-6  : Virtual Terminal (Extended Transport Protocol)
+
+
+2. Motivation
+--------------------------------
+
+  Given the fact there's something like SocketCAN with an API similar to BSD
+  sockets, we found some reasons to justify a kernel implementation for the
+  addressing and transport methods used by J1939.
+
+  * addressing:
+    When a process on an ECU communicates via j1939, it should not necessarily
+    know its source address. Although at least 1 process per ECU should know
+    the source address. Other processes should be able to reuse that address.
+    This way, address parameters for different processes cooperating for the
+    same ECU, are not duplicated.
+    This way of working is closely related to the unix concept where programs
+    do just 1 thing, and do it well.
+
+  * dynamic addressing:
+    Address Claiming in J1939 is time critical. Furthermore data transport
+    should be handled properly during the address negotiation. Putting these
+    functionality in the kernel eliminates this functionality as a requirement
+    for _every_ userspace process that communicates via J1939. This results in
+    a consistent J1939 bus with proper addressing.
+
+  * transport:
+    Both TP & ETP reuse some PGN's to relay big packets over them. Different
+    processes may thus use the same TP & ETP PGN's without actually knowing it.
+    The individual TP & ETP sessions _must_ be serialized (synchronised)
+    between different processes. The kernel solves this problem properly, and
+    eliminates the serialisation (synchronisation) as a requirement for
+    _every_ userspace process that communicates via J1939.
+
+  J1939 defines some other features (relaying, gateway, Fast Packet transport,
+  ...). In-kernel code for these would not contribute to protocol stability.
+  Therefore, these parts are left to userspace.
+
+  The j1939 sockets operate on CAN network devices (see SocketCAN). Any j1939
+  userspace library operating on CAN raw sockets will still operate properly.
+  Since such library does not communicate with the in-kernel implementation,
+  care must be taken that these 2 do not interfere. In practice, this means
+  they cannot share ECU addresses. A single ECU (or virtual ECU) address is
+  used by the library exclusively, or by the in-kernel system exclusively.
+
+
+3. J1939 concepts
+--------------------------------
+
+3.1 PGN
+
+  The PGN (Parameter Group Number) is a number to identify a packet. The PGN
+  is composed as follows:
+   1 bit  : Reserved Bit
+   1 bit  : Data Page
+   8 bits : PF (PDU Format)
+   8 bits : PS (PDU Specific)
+
+  In J1939-21, distinction is made between PDU1 Format (where PF < 240) and
+  PDU2 Format (where PF >= 240). Furthermore, when using PDU2 Format, the
+  PS-field contains a so-called Group Extension, which is part of the PGN.
+  When using PDU2 Format, the Group Extension is set in the PS-field.
+
+  On the other hand, when using PDU1 Format, the PS-field contains a so-called
+  Destination Address, which is _not_ part of the PGN. When communicating a
+  PGN from userspace to kernel (or visa versa) and PDU2 Format is used, the
+  PS-field of the PGN shall be set to zero. The Destination Address shall be
+  set elsewhere.
+
+  Regarding PGN mapping to 29-bit CAN identifier, the Destination Address
+  shall be get/set from/to the apropriate bits of the identifier by the kernel.
+
+
+3.2 addressing
+
+  Both static and dynamic addressing methods can be used.
+
+  For static addresses, no extra checks are made by the kernel, and provided
+  addresses are considered right. This responsibility is for the OEM or system
+  integrator.
+
+  For dynamic addressing, so-called Address Claiming, extra support is forseen
+  in the kernel. In J1939 any ECU is known by it's 64-bit NAME. At the moment
+  of succesfull address claim, the kernel keeps track of both NAME and source
+  address being claimed. This serves as a base for filter schemes. By default,
+  packets with a destination that is not locally, will be rejected soon after
+  reception.
+
+  Mixed mode packets (from a static to a dynamic address or vice versa) are
+  allowed. The BSD sockets define seperate API calls for getting/setting the
+  local & remote address and are applicable for J1939 sockets.
+
+
+3.3 Filtering
+
+  Similar to SocketCAN, j1939 defines filters per socket that a user can set
+  in order to receive a subset of the j1939 traffic. Filtering can base on
+  * SA
+  * NAME
+  * PGN
+
+  There is a semantic difference with SocketCAN with regard to filtering.
+  When multiple filters are in place for a single socket, and a packet comes
+  in that matches several of those filters, the packet is only received once
+  for that socket.
+  The rationale behind this difference originates in the filter capabilities.
+  Where SocketCAN filters on only 1 orthogonal (can id), J1939 can filter
+  on 3 orthogonal properties (sa, name, pgn).
+
+  When a filter on the SA is set, j1939 traffic with a matching SA, but with
+  its NAME set (aka having claimed SA successfully) will match, although
+  the filter would not match its NAME.
+
+  Filtering on priority is _not_ supported.
+
+
+4. How to use J1939
+--------------------------------
+
+4.1 rtnetlink interface
+
+  Per default j1939 is not active. Specifying can_ifindex != 0 in bind(2)
+  or connect(2) needs an active j1939 on that interface. You must have done
+  $ ip link set canX j1939 on
+  on that interface.
+
+  $ ip link set canX j1939 down
+  disables j1939 on canX.
+
+  Assigning addresses is done via
+  $ ip addr add dev canX j1939 0xXX
+  statically or
+  $ ip addr add dev canX j1939 name 0xXX
+  dynamically. In the latter case, address claiming must take place
+  before other traffic can leave.
+
+  Removing addresses is done similarly via
+  $ ip addr del dev canX j1939 0xXX
+  $ ip addr del dev canX j1939 name 0xXX
+
+  A static address cannot be assigned together with a 64bit name.
+
+4.2 API calls
+
+  Like TCP/IP and CAN, you first need to open a socket for communicating over a
+  CAN network. To use j1939, include <include/linux/j1939.h>. From there,
+  <include/linux/can.h> will be included too.
+  To open a socket, you would write
+
+    s = socket(PF_CAN, SOCK_DGRAM, CAN_J1939);
+
+  J1939 does use SOCK_DGRAM sockets. In the j1939 specification, connections are
+  mentioned in the context of transport protocol sessions. These still deliver
+  packets to the other end (using several CAN packets).
+  SOCK_STREAM is never appropriate.
+
+  After the successful creation of the socket, you would normally use the
+  bind(2) and/or connect(2) system call to bind the socket to a CAN interface
+  (which is different from TCP/IP due to different addressing) After binding
+  and/or connecting the socket, you can read(2) and write(2) from/to the socket
+  or use send(2), sendto(2), sendmsg(2) and the recv* counterpart operations on
+  the socket as usual. There are also J1939 specific socket options described
+  below.
+
+  In order to send data, a bind(2) must have succeeded. bind(2) assigns a local
+  address to a socket. For this to succeed, you can only choose addresses
+  that have been assigned earlier (see 4.1). When an empty address is assigned
+  (ie. SA=0xff && name=0), a default is taken for the device that is bound to.
+
+  Different from CAN is that the payload data is just the data that get send,
+  without it's header info. The header info is derived from the sockaddr
+  supplied to bind(2), connect(2), sendto(2) and recvfrom(2). A write(2) with
+  size 4 will result in a packet with 4 bytes.
+
+  The sockaddr structure has extensions for use with j1939 as specified below:
+      struct sockaddr_can {
+         sa_family_t can_family;
+         int         can_ifindex;
+         union {
+            struct {
+               __u64 name;
+               __u32 pgn;
+               __u8  addr;
+            } j1939;
+         } can_addr;
+      }
+
+  can_family & can_ifindex serve the same purpose as for other SocketCAN sockets.
+
+  can_addr.j1939.pgn specifies the PGN (max 0x3ffff). Individual bits are
+  specified above.
+
+  can_addr.j1939.name contains the 64-bit J1939 NAME.
+
+  can_addr.j1939.addr contains the source address.
+
+  When sending data, the source address is applied as follows: If
+  can_addr.j1939.name != 0 the NAME is looked up by the kernel and the
+  corresponding Source Address is used. If can_addr.j1939.name == 0,
+  can_addr.j1939.addr is used.
+
+  After a bind(2), the local address is assigned, i.e. the source address.
+  After a connect(2), the remote address is assigned, i.e. the destination
+  address.
+
+  Both write(2) and send(2) will send a packet with local address from bind,
+  remote address from connect(2). When the address was not set, a broadcast is
+  sent. The PGN is used from bind(2) or overruled with sendto(2), which will
+  override the destination address when valid, and the PGN when valid.
+
+  Both read(2) and recv(2) will receive packets matching the sockets filters.
+  recvfrom(2) will receive these packets with originator's address.
+
+  When creating a socket, reasonable defaults have been set. Some options can be
+  modified with setsockopt(2) & getsockopt(2).
+
+4.2.1 Message flags during sendmsg
+
+  send(2), sendto(2) and sendmsg(2) take a 'flags' argument. J1939 interpretes
+  these flags during outgoing traffic:
+
+  * MSG_DONTWAIT determines nonblocking operation. When a packet must wait for
+    any reason, -EAGAIN is returned.
+
+  * MSG_SYN
+    Packets flagged with MSG_SYN will wait for all pending packets on a socket
+    to be sent before trying to send. This means that if a socket just started
+    a Transport Protocol session, a packet with MSG_SYN will wait for that
+    session to complete before proceeding.
+    Traffic without MSG_SYN (on that very same socket) will still continue.
+
+4.3 Dynamic Addressing
+
+  Distinction has to be made in and using the claimed address and doing an
+  address claim. To use an already claimed address, one has to fill in the
+  j1939.name member and provide it to bind(2). If the name had claimed an
+  address earlier, all further PGN's being sent will use that address. And the
+  j1939.addr member will be ignored.
+
+  An exception on this is pgn 0x0ee00. This is the "Address Claim/Cannot Claim
+  Address" message and when the kernel will use the j1939.addr member for that
+  pgn if necessary.
+
+  To claim an address, bind(2) with:
+  j1939.pgn  set to 0x0ee00
+  j1939.addr set to the desired Source Address.
+  j1939.name set to the NAME you want the Source Address to claim to.
+
+  Afterwards do a write(2) with data set to the NAME (Little Endian). If the
+  NAME provided, does not match the j1939.name provided to bind(2), EPROTO
+  will be returned. One might use sendto(2) also to send the Addres Claim. In
+  that case, the j1939.addr member must be set to the broadcast address (255)
+  and the j1939.pgn must be set to 0x0ee00. If This combination is not given,
+  EPROTO is returned.
+
+  If no-one else contest the address claim within 250ms after transmission, the
+  kernel marks the NAME-SA assignment as valid. The valid assignment will be
+  kept, among other valid NAME-SA assignments. From that point, any socket
+  bound to the NAME can send packets.
+
+  If another ECU claims the address, the kernel will mark the NAME-SA expired.
+  No socket bound to the NAME can send packets (other than address claims).
+  To claim another address, some socket bound to NAME, must bind(2) again,
+  but with only j1939.addr changed to the new SA, and must then send a
+  valid address claim packet. This restarts the state machine in the kernel
+  (and any other participant on the bus) for this NAME.
+
+
+5 Socket Options
+--------------------------------
+
+  j1939 sockets have some options that are configurable via setsockopt(2).
+  Each of those options is initialized with a reasonable default.
+
+
+5.1 SO_J1939_FILTER
+
+  As mentioned above, J1939 supports filtering in both NAME, Source Address
+  and PGN. All members must match.
+
+   struct j1939_filter filter = {
+      .name         = ...
+      .name_mask   = ...
+      .addr         = ...
+      .addr_mask   = ...
+      .pgn         = ...
+      .pgn_mask   = ...
+   }
+
+    setsockopt(s, SOL_CAN_J1939, SO_J1939_FILTER, &filter, sizeof(filter));
+
+
+5.2 SO_J1939_PROMISC
+
+  When set, j1939 will receive all packets, not just those with a destination
+  on the local system.
+  default off.
+
+    int promisc = 1; /* 0 = disabled (default), 1 = enabled */
+
+    setsockopt(s, SOL_CAN_J1939, SO_J1939_PROMISC, &promisc, sizeof(promisc));
+
+
+5.3 SO_J1939_RECV_OWN
+
+  All the sent j1939 packets are looped back in the system.
+  The reception of the j1939 packets on the same socket that was
+  sending the j1939 packet is assumed to be unwanted and therefore
+  disabled by default. This default behaviour may be changed on
+  demand:
+
+    int recv_own_msgs = 1; /* 0 = disabled (default), 1 = enabled */
+
+    setsockopt(s, SOL_CAN_J1939, SO_J1939_RECV_OWN,
+               &recv_own_msgs, sizeof(recv_own_msgs));
+
+
+5.4 SO_J1939_RECV_DEST
+
+  Received j1939 packets that make their way up to the socket, had a destination
+  address matching the socket's local address. This can have several reasons:
+  - broadcast packet.
+  - destination spec matches the local address
+  - destination spec matches _a_ local address on the system, and the socket
+    had no local address defined.
+  - SO_J1939_PROMISC was set
+  If the user is interested in the original destination spec, SO_J1939_RECV_DEST
+  can be changed to 1 to receive the destination spec with each packet.
+  The destination is attached to the msghdr in the recvmsg(2) call.
+  It can be extracted using cmsg(3) macros, with
+  cmsg_level == SOL_J1939 && cmsg_type == SCM_J1939_DEST.
+  the returned data is a struct sockaddr_can, with the regular j1939 fields
+  stuffed. Mind that PGN is the same as the PGN in sockaddr after recvfrom.
+
+
+5.5 SO_J1939_RECV_PRIO
+
+  As stated earlier, the priority field is stripped very soon. In order to
+  allow retreiving the packet's priority, SO_J1939_RECV_PRIO can be set to 1.
+
+  As a result, an extra int will be attached during recvmsg(2), similar
+  as in SO_J1939_RECV_DEST, but with cmsg_type == SCM_J1939_PRIO
+
+6.6 SO_J1939_SEND_PRIO
+
+  To set the priority field for outgoing packets, the SO_J1939_SEND_PRIO can
+  be changed. This int field specifies the priority that will be used.
+  j1939 defines a priority between 0 and 7 inclusive,
+  with 7 the lowest priority.
+  Per default, the priority is set to 6 (conforming J1939).
+  This priority socket option operates on the same value that is modified
+  with
+
+    setsockopt(s, SOL_SOCKET, SO_PRIORITY, &pri, sizeof(pri))
+
+  socketoption, with a difference that SOL_SOCKET/SO_PRIORITY is defined with
+  0 the lowest priority. SOL_CAN_J1939/SO_J1939_SEND_PRIO inverts this value
+  for you.
+
+5.7 SO_J1939_DEST_MASK
+
+  When a destination is specified by its name (and thus using dynamic addressing),
+  and such name should be unique amongst the world, it may be hard to predict the
+  name of eg. a gearbox controller on the bus, although its type and manufacturer
+  are know. This is because the serial number is part of the name.
+  To simplify specifying a destination, a per-socket destination mask is provided
+  that is activated whenever a destination name is wanted. Any bits cleared in
+  this mask are ignored during the lookup. As a result, more than 1 ECU may match
+  this name/mask pair. In all cases, the first match is used.
+  The API is thus capable of specifying a name for eg. the gearbox controller,
+  without knowing its serial number.
+  This mask can mask out any part in the name. Note there's only 1 mask per socket.
+
+  this mask is default set to mask the serial number.
+
+  when can_addr.j1939.name is used for destination in outgoing packets
+  (see bind(2), sendto(2)), the exact name is often not known due to serial
+  numbers in it.
+  Therefore, SO_J1939_DEST_MASK sets an uint64_t mask that will be used
+  for resolving these names. Only the bits set to 1 in the mask will be
+  evaluated for find the destination name.
+  Per default, the mask is set to mask out the serial number
+  (0xffffffffffe00000ULL)
+
+  to mask out only the manufacturer code (bits 21-31), do
+
+    uint64_t mask = 0xffffffff001fffffULL;
+
+    setsockopt(s, SOL_CAN_J1939, SO_J1939_DEST_MASK, &mask, sizeof(mask));
+
+
+6. /proc/net/can-j1939 Interface.
+--------------------------------
+
+  Files giving you a view on the in-kernel operation of J1939 are located at:
+  /proc/net/j1939.
+
+6.1 /proc/net/can-j1939/ecu
+
+  This file gives an overview of the known ECU's to the kernel.
+  - iface : network interface they operate on.
+  - SA : current address.
+  - name : 64bit NAME
+  - flags : 'L' = local, 'R' = remote
+
+6.2 /proc/net/can-j1939/filter
+
+6.3 /proc/net/can-j1939/sock
+
+  This file gives a list of all j1939 sockets currently open.
+  - iface : network interface
+  - flags :
+    'b' : bound
+    'c' : connected
+    'P' : PROMISC
+    'o' : RECV_OWN
+    'd' : RECV_DEST
+    'p' : RECV_PRIO
+  - local: [NAME],SA
+  - remote: [NAME]/MASK,DA
+  - pgn : PGN
+  - prio : priority
+  - pending : # packets pending (see MSG_SYN on 4.2.1)
+
+6.4 /proc/net/can-j1939/transport
+
+  This file shows a list of pending transport sessions
+  - iface
+  - src : XX (addr) or XXXXXXXXXXXXXXXX (name)
+  - dst : XX or XXXXXXXXXXXXXXXX or '-' (broadcast)
+  - pgn :
+  - done/total : current # transferred bytes / total
+
+
+7. /proc/sys/net/can-j1939 - SYSCTL
+--------------------------------
+
+  Via these sysctl files, some parameters of the j1939 module can be tuned.
+
+7.1 /proc/sys/net/can-j1939/transport_max_payload_in_bytes [int]
+
+  Is the maximum packet size to accept on both transmit & receive side.
+  Bigger packets will be rejected (local sender), aborted (local receiver)
+  or ignored (broadcasts & remote recievers in PROMISC).
+
+7.2 /proc/sys/net/can-j1939/transport_cts_nr_frames [int]
+
+  Controls the number of packets to allow between consecutive CTS frames
+  (default 255).
+  This number is communicated within the CTS frame from receiver to transmitter.
+  Setting this has effect on received transport sessions only.
+
+7.3 /proc/sys/net/can-j1939/transport_tx_retry_ms [int]
+
+  Controls how many time to wait before retrying to send an individual TP
+  flow or data packet after transmission failure (default 20).
+
+
+8. Credits
+--------------------------------
+
+  Kurt Van Dijck (j1939 core, transport protocol, API)
+  Pieter Beyens (j1939 core, address claiming)
+
diff --git a/MAINTAINERS b/MAINTAINERS
index 75760e7..a7d7c17 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1631,6 +1631,14 @@ F:	include/linux/can/error.h
 F:	include/linux/can/netlink.h
 F:	include/linux/can/platform/
 
+CAN-J1939 NETWORK LAYER
+M:	Kurt Van Dijck <kurt.van.dijck-/BeEPy95v10@public.gmane.org>
+L:	socketcan-core-0fE9KPoRgkgATYTw5x5z8w@public.gmane.org
+L:	netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
+S:	Maintained
+F:	net/can/j1939/
+F:	include/linux/can/j1939.h
+
 CELL BROADBAND ENGINE ARCHITECTURE
 M:	Arnd Bergmann <arnd-r2nGTMty4D4@public.gmane.org>
 L:	linuxppc-dev-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [RFC v3 6/6] iproute2: add CAN and J1939 rtnetlink support
       [not found] ` <20110314132004.GA333-MxZ6Iy/zr/UdbCeoMzGj59i2O/JbrIOy@public.gmane.org>
                     ` (4 preceding siblings ...)
  2011-03-14 13:59   ` [RFC v3 5/6] j1939: add documentation and MAINTAINERS Kurt Van Dijck
@ 2011-03-14 14:05   ` Kurt Van Dijck
  2011-03-15  9:23   ` [RFC v3 0/6] CAN: add SAE J1939 protocol Kurt Van Dijck
  6 siblings, 0 replies; 30+ messages in thread
From: Kurt Van Dijck @ 2011-03-14 14:05 UTC (permalink / raw)
  To: socketcan-core-0fE9KPoRgkgATYTw5x5z8w, netdev-u79uwXL29TY76Z2rM5mHXA

Add iproute2 support for CAN and J1939 rtnetlink.

Signed-off-by: Kurt Van Dijck <kurt.van.dijck-/BeEPy95v10@public.gmane.org>
---
diff --git a/Makefile b/Makefile
index c03d74c..efd06de 100644
--- a/Makefile
+++ b/Makefile
@@ -27,9 +27,12 @@ ADDLIB+=dnet_ntop.o dnet_pton.o
 #options for ipx
 ADDLIB+=ipx_ntop.o ipx_pton.o
 
+#options for j1939
+ADDLIB+=j1939.o
+
 CC = gcc
 HOSTCC = gcc
-CCOPTS = -D_GNU_SOURCE -O2 -Wstrict-prototypes -Wall
+CCOPTS = -D_GNU_SOURCE -Wstrict-prototypes -Wall
 CFLAGS = $(CCOPTS) -I../include $(DEFINES)
 YACCFLAGS = -d -t -v
 
diff --git a/include/linux/can.h b/include/linux/can.h
new file mode 100644
index 0000000..9c2523c
--- /dev/null
+++ b/include/linux/can.h
@@ -0,0 +1,129 @@
+/*
+ * linux/can.h
+ *
+ * Definitions for CAN network layer (socket addr / CAN frame / CAN filter)
+ *
+ * Authors: Oliver Hartkopp <oliver.hartkopp-l29pVbxQd1IUtdQbppsyvg@public.gmane.org>
+ *          Urs Thuermann   <urs.thuermann-l29pVbxQd1IUtdQbppsyvg@public.gmane.org>
+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research
+ * All rights reserved.
+ *
+ * Send feedback to <socketcan-users-0fE9KPoRgkgATYTw5x5z8w@public.gmane.org>
+ *
+ */
+
+#ifndef CAN_H
+#define CAN_H
+
+#include <linux/types.h>
+#include <linux/socket.h>
+
+/* 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 */
+
+/*
+ * Controller Area Network Identifier structure
+ *
+ * bit 0-28	: CAN identifier (11/29 bit)
+ * bit 29	: error frame flag (0 = data frame, 1 = error frame)
+ * bit 30	: remote transmission request flag (1 = rtr frame)
+ * bit 31	: frame format flag (0 = standard 11 bit, 1 = extended 29 bit)
+ */
+typedef __u32 canid_t;
+
+/*
+ * Controller Area Network Error Frame Mask structure
+ *
+ * bit 0-28	: error class mask (see include/linux/can/error.h)
+ * bit 29-31	: set to zero
+ */
+typedef __u32 can_err_mask_t;
+
+/**
+ * struct can_frame - basic CAN frame structure
+ * @can_id:  the CAN ID of the frame and CAN_*_FLAG flags, see above.
+ * @can_dlc: the data length field of the CAN frame
+ * @data:    the CAN frame payload.
+ */
+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_J1939	7 /* SAE J1939 */
+#define CAN_NPROTO	8
+
+#define SOL_CAN_BASE 100
+
+/**
+ * struct sockaddr_can - the sockaddr structure for CAN sockets
+ * @can_family:  address family number AF_CAN.
+ * @can_ifindex: CAN network interface index.
+ * @can_addr:    protocol specific address information
+ */
+struct sockaddr_can {
+	sa_family_t can_family;
+	int         can_ifindex;
+	union {
+		/* transport protocol class address information (e.g. ISOTP) */
+		struct { canid_t rx_id, tx_id; } tp;
+
+		/* J1939 address information */
+		struct {
+			/* 8 byte name when using dynamic addressing */
+			__u64 name;
+			/*
+			 * pgn:
+			 * 8bit: PS in PDU2 case, else 0
+			 * 8bit: PF
+			 * 1bit: DP
+			 * 1bit: reserved
+			 */
+			__u32 pgn;
+
+			/* 1byte address */
+			__u8 addr;
+		} j1939;
+
+		/* reserved for future CAN protocols address information */
+	} can_addr;
+};
+
+/**
+ * struct can_filter - CAN ID based filter in can_register().
+ * @can_id:   relevant bits of CAN ID which are not masked out.
+ * @can_mask: CAN mask (see description)
+ *
+ * Description:
+ * A filter matches, when
+ *
+ *          <received_can_id> & mask == can_id & mask
+ *
+ * The filter can be inverted (CAN_INV_FILTER bit set in can_id) or it can
+ * filter for error frames (CAN_ERR_FLAG bit set in mask).
+ */
+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 --git a/include/linux/can/j1939.h b/include/linux/can/j1939.h
new file mode 100644
index 0000000..fa62562
--- /dev/null
+++ b/include/linux/can/j1939.h
@@ -0,0 +1,93 @@
+/*
+ * j1939.h
+ *
+ */
+
+#ifndef _J1939_H_
+#define _J1939_H_
+
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/can.h>
+
+#define J1939_NO_ADDR	0xff
+#define J1939_NO_NAME	0
+#define J1939_NO_PGN	0x7ffff
+/*
+ * J1939 Parameter Group Number
+ *
+ * bit 0-7	: PDU Specific (PS)
+ * bit 8-15	: PDU Format (PF)
+ * bit 16	: Data Page (DP)
+ * bit 17	: Reserved (R)
+ * bit 19-31	: set to zero
+ */
+typedef __u32 pgn_t;
+
+/*
+ * J1939 Priority
+ *
+ * bit 0-2	: Priority (P)
+ * bit 3-7	: set to zero
+ */
+typedef __u8 priority_t;
+
+/*
+ * J1939 NAME
+ *
+ * bit 0-20	: Identity Number
+ * bit 21-31	: Manufacturer Code
+ * bit 32-34	: ECU Instance
+ * bit 35-39	: Function Instance
+ * bit 40-47	: Function
+ * bit 48	: Reserved
+ * bit 49-55	: Vehicle System
+ * bit 56-59	: Vehicle System Instance
+ * bit 60-62	: Industry Group
+ * bit 63	: Arbitrary Address Capable
+ */
+typedef __u64 name_t;
+
+/*
+ * J1939 socket options
+ */
+#define SOL_CAN_J1939 (SOL_CAN_BASE + CAN_J1939)
+enum {
+	SO_J1939_FILTER = 1,	/* set filters */
+	SO_J1939_PROMISC = 2,	/* set/clr promiscuous mode */
+	SO_J1939_RECV_OWN = 3,
+	SO_J1939_RECV_DEST = 4, /* set/clr attach dest control message */
+	SO_J1939_RECV_PRIO = 5,
+	SO_J1939_SEND_PRIO = 6,
+	SO_J1939_DEST_MASK = 7, /* mask names in connect() & sendto() */
+};
+
+#define SCM_J1939_DEST SO_J1939_RECV_DEST
+#define SCM_J1939_PRIO SO_J1939_RECV_PRIO
+
+struct j1939_filter {
+	name_t name;
+	name_t name_mask;
+	__u8 addr;
+	__u8 addr_mask;
+	pgn_t pgn;
+	pgn_t pgn_mask;
+};
+
+/*
+ * RTNETLINK
+ */
+enum {
+	IFLA_J1939_UNSPEC,
+	IFLA_J1939_ENABLE,
+	IFLA_J1939_MAX,
+};
+
+enum {
+	IFA_J1939_UNSPEC,
+	IFA_J1939_ADDR,
+	IFA_J1939_NAME,
+	IFA_J1939_MAX,
+};
+
+#endif /* _J1939_H_ */
diff --git a/include/utils.h b/include/utils.h
index 3da6998..b6344d5 100644
--- a/include/utils.h
+++ b/include/utils.h
@@ -95,8 +95,15 @@ extern __u8* hexstring_a2n(const char *str, __u8 *buf, int blen);
 
 extern const char *format_host(int af, int len, const void *addr,
 			       char *buf, int buflen);
-extern const char *rt_addr_n2a(int af, int len, const void *addr,
+/* 'address with protocol' n2a */
+extern const char *rt_addrpr_n2a(int af, int protocol, int len, const void *addr,
 			       char *buf, int buflen);
+static inline const char *rt_addr_n2a(int af, int len, const void *addr,
+			       char *buf, int buflen)
+{
+	return rt_addrpr_n2a(af, 0, len, addr, buf, buflen);
+
+}
 
 void missarg(const char *) __attribute__((noreturn));
 void invarg(const char *, const char *) __attribute__((noreturn));
@@ -111,6 +118,16 @@ int dnet_pton(int af, const char *src, void *addr);
 const char *ipx_ntop(int af, const void *addr, char *str, size_t len);
 int ipx_pton(int af, const char *src, void *addr);
 
+/* j1939 */
+extern const char *j1939_ntop(int af, const void *addr, size_t vlen,
+		char *str, size_t len);
+extern const char *j1939_link_attrtop(struct rtattr *nla);
+
+extern int j1939_addr_args(int argc, char *argv[],
+		struct nlmsghdr *msg, int msg_size);
+extern int j1939_link_args(int argc, char *argv[],
+		struct nlmsghdr *msg, int msg_size);
+
 extern int __iproute2_hz_internal;
 extern int __get_hz(void);
 
diff --git a/ip/ip.c b/ip/ip.c
index b127d57..50fcb1c 100644
--- a/ip/ip.c
+++ b/ip/ip.c
@@ -46,7 +46,7 @@ static void usage(void)
 "where  OBJECT := { link | addr | addrlabel | route | rule | neigh | ntable |\n"
 "                   tunnel | tuntap | maddr | mroute | mrule | monitor | xfrm }\n"
 "       OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[esolve] |\n"
-"                    -f[amily] { inet | inet6 | ipx | dnet | link } |\n"
+"                    -f[amily] { inet | inet6 | ipx | dnet | link  | can} |\n"
 "                    -l[oops] { maximum-addr-flush-attempts } |\n"
 "                    -o[neline] | -t[imestamp] | -b[atch] [filename] |\n"
 "                    -rc[vbuf] [size]}\n");
@@ -181,6 +181,8 @@ int main(int argc, char **argv)
 				preferred_family = AF_PACKET;
 			else if (strcmp(argv[1], "ipx") == 0)
 				preferred_family = AF_IPX;
+			else if (strcmp(argv[1], "can") == 0)
+				preferred_family = AF_CAN;
 			else if (strcmp(argv[1], "help") == 0)
 				usage();
 			else
diff --git a/ip/ipaddress.c b/ip/ipaddress.c
index a775ecd..09db9fd 100644
--- a/ip/ipaddress.c
+++ b/ip/ipaddress.c
@@ -27,6 +27,7 @@
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/sockios.h>
+#include <linux/can.h>
 
 #include "rt_names.h"
 #include "utils.h"
@@ -68,6 +69,8 @@ static void usage(void)
 	fprintf(stderr, "IFADDR := PREFIX | ADDR peer PREFIX\n");
 	fprintf(stderr, "          [ broadcast ADDR ] [ anycast ADDR ]\n");
 	fprintf(stderr, "          [ label STRING ] [ scope SCOPE-ID ]\n");
+	fprintf(stderr, "          | j1939 J1939IFADDR\n");
+	fprintf(stderr, "          \n");
 	fprintf(stderr, "SCOPE-ID := [ host | link | global | NUMBER ]\n");
 	fprintf(stderr, "FLAG-LIST := [ FLAG-LIST ] FLAG\n");
 	fprintf(stderr, "FLAG  := [ permanent | dynamic | secondary | primary |\n");
@@ -77,6 +80,10 @@ static void usage(void)
 	fprintf(stderr, "CONFFLAG  := [ home | nodad ]\n");
 	fprintf(stderr, "LIFETIME := [ valid_lft LFT ] [ preferred_lft LFT ]\n");
 	fprintf(stderr, "LFT := forever | SECONDS\n");
+	fprintf(stderr, "          \n");
+	fprintf(stderr, "J1939IFADDR := [SA] [ name NODENAME ]\n");
+	fprintf(stderr, "SA := U8\n");
+	fprintf(stderr, "NODENAME := U64\n");
 
 	exit(-1);
 }
@@ -421,6 +428,19 @@ int print_linkinfo(const struct sockaddr_nl *who,
 	}
 
 	fprintf(fp, "\n");
+
+	if (do_link && tb[IFLA_AF_SPEC]) {
+		struct rtattr *af[AF_MAX];
+
+		parse_rtattr_nested(af, AF_MAX, tb[IFLA_AF_SPEC]);
+		if (af[AF_CAN]) {
+			struct rtattr *prot[CAN_NPROTO];
+
+			parse_rtattr_nested(prot, CAN_NPROTO, af[AF_CAN]);
+			if (prot[CAN_J1939])
+				fprintf(fp, "    %s\n", j1939_link_attrtop(prot[CAN_J1939]));
+		}
+	}
 	fflush(fp);
 	return 0;
 }
@@ -445,6 +465,13 @@ static int set_lifetime(unsigned int *lifetime, char *argv)
 	return 0;
 }
 
+static const int af_use_prefix[AF_MAX] = {
+	[AF_INET] = 1,
+	[AF_INET6] = 1,
+	[AF_DECnet] = 1,
+	[AF_IPX] = 1,
+};
+
 int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n,
 		   void *arg)
 {
@@ -452,6 +479,7 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n,
 	struct ifaddrmsg *ifa = NLMSG_DATA(n);
 	int len = n->nlmsg_len;
 	int deprecated = 0;
+	int protocol = 0;
 	/* Use local copy of ifa_flags to not interfere with filtering code */
 	unsigned int ifa_flags;
 	struct rtattr * rta_tb[IFA_MAX+1];
@@ -471,10 +499,12 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n,
 
 	parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(ifa), n->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));
 
-	if (!rta_tb[IFA_LOCAL])
-		rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS];
-	if (!rta_tb[IFA_ADDRESS])
-		rta_tb[IFA_ADDRESS] = rta_tb[IFA_LOCAL];
+	if (af_use_prefix[ifa->ifa_family]) {
+		if (!rta_tb[IFA_LOCAL])
+			rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS];
+		if (!rta_tb[IFA_ADDRESS])
+			rta_tb[IFA_ADDRESS] = rta_tb[IFA_LOCAL];
+	}
 
 	if (filter.ifindex && filter.ifindex != ifa->ifa_index)
 		return 0;
@@ -536,38 +566,64 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n,
 		fprintf(fp, "    dnet ");
 	else if (ifa->ifa_family == AF_IPX)
 		fprintf(fp, "     ipx ");
+	else if (ifa->ifa_family == AF_CAN) {
+		/* ifa->ifa_prefixlen is abused for protocol number */
+		const char *sprotocol;
+		char num[16];
+
+		/* 1st: set protocol, as this is rather tricky */
+		protocol = ifa->ifa_prefixlen;
+
+		/* 2nd: set label */
+		switch (protocol) {
+		case CAN_J1939:
+			sprotocol = "j1939";
+			break;
+		default:
+			sprintf(num, "%i", ifa->ifa_prefixlen);
+			sprotocol = num;
+			break;
+		}
+		fprintf(fp, "    can-%s ", sprotocol);
+	}
 	else
 		fprintf(fp, "    family %d ", ifa->ifa_family);
 
 	if (rta_tb[IFA_LOCAL]) {
-		fprintf(fp, "%s", rt_addr_n2a(ifa->ifa_family,
+		fprintf(fp, "%s", rt_addrpr_n2a(ifa->ifa_family, protocol,
 					      RTA_PAYLOAD(rta_tb[IFA_LOCAL]),
 					      RTA_DATA(rta_tb[IFA_LOCAL]),
 					      abuf, sizeof(abuf)));
 
 		if (rta_tb[IFA_ADDRESS] == NULL ||
 		    memcmp(RTA_DATA(rta_tb[IFA_ADDRESS]), RTA_DATA(rta_tb[IFA_LOCAL]), 4) == 0) {
-			fprintf(fp, "/%d ", ifa->ifa_prefixlen);
 		} else {
-			fprintf(fp, " peer %s/%d ",
-				rt_addr_n2a(ifa->ifa_family,
+			fprintf(fp, " peer %s",
+				rt_addrpr_n2a(ifa->ifa_family, protocol,
 					    RTA_PAYLOAD(rta_tb[IFA_ADDRESS]),
 					    RTA_DATA(rta_tb[IFA_ADDRESS]),
-					    abuf, sizeof(abuf)),
-				ifa->ifa_prefixlen);
+					    abuf, sizeof(abuf)));
 		}
+		if (af_use_prefix[ifa->ifa_family])
+			fprintf(fp, "/%d", ifa->ifa_prefixlen);
+		fprintf(fp, " ");
+	} else if (rta_tb[IFA_ADDRESS]) {
+		fprintf(fp, "peer %s ", rt_addrpr_n2a(ifa->ifa_family, protocol,
+					RTA_PAYLOAD(rta_tb[IFA_ADDRESS]),
+					RTA_DATA(rta_tb[IFA_ADDRESS]),
+					abuf, sizeof(abuf)));
 	}
 
 	if (rta_tb[IFA_BROADCAST]) {
 		fprintf(fp, "brd %s ",
-			rt_addr_n2a(ifa->ifa_family,
+			rt_addrpr_n2a(ifa->ifa_family, protocol,
 				    RTA_PAYLOAD(rta_tb[IFA_BROADCAST]),
 				    RTA_DATA(rta_tb[IFA_BROADCAST]),
 				    abuf, sizeof(abuf)));
 	}
 	if (rta_tb[IFA_ANYCAST]) {
 		fprintf(fp, "any %s ",
-			rt_addr_n2a(ifa->ifa_family,
+			rt_addrpr_n2a(ifa->ifa_family, protocol,
 				    RTA_PAYLOAD(rta_tb[IFA_ANYCAST]),
 				    RTA_DATA(rta_tb[IFA_ANYCAST]),
 				    abuf, sizeof(abuf)));
@@ -1091,12 +1147,18 @@ static int ipaddr_modify(int cmd, int flags, int argc, char **argv)
 			req.ifa.ifa_flags |= IFA_F_HOMEADDRESS;
 		} else if (strcmp(*argv, "nodad") == 0) {
 			req.ifa.ifa_flags |= IFA_F_NODAD;
+		} else if (matches(*argv, "j1939") == 0) {
+			int ret;
+
+			ret = j1939_addr_args(argc, argv, &req.n, sizeof(req));
+			if (ret < 0)
+				return ret;
+			argc -= ret;
+			argv += ret;
 		} else {
 			if (strcmp(*argv, "local") == 0) {
 				NEXT_ARG();
 			}
-			if (matches(*argv, "help") == 0)
-				usage();
 			if (local_len)
 				duparg2("local", *argv);
 			lcl_arg = *argv;
@@ -1202,8 +1264,9 @@ int do_ipaddr(int argc, char **argv)
 		return ipaddr_list_or_flush(argc-1, argv+1, 0);
 	if (matches(*argv, "flush") == 0)
 		return ipaddr_list_or_flush(argc-1, argv+1, 1);
-	if (matches(*argv, "help") == 0)
+	if (matches(*argv, "help") == 0) {
 		usage();
+	}
 	fprintf(stderr, "Command \"%s\" is unknown, try \"ip addr help\".\n", *argv);
 	exit(-1);
 }
diff --git a/ip/iplink.c b/ip/iplink.c
index cb2c4f5..06fc34c 100644
--- a/ip/iplink.c
+++ b/ip/iplink.c
@@ -27,6 +27,7 @@
 #include <string.h>
 #include <sys/ioctl.h>
 #include <linux/sockios.h>
+#include <linux/can.h>
 
 #include "rt_names.h"
 #include "utils.h"
@@ -71,6 +72,7 @@ void iplink_usage(void)
 	fprintf(stderr, "	                  [ vf NUM [ mac LLADDR ]\n");
 	fprintf(stderr, "				   [ vlan VLANID [ qos VLAN-QOS ] ]\n");
 	fprintf(stderr, "				   [ rate TXRATE ] ] \n");
+	fprintf(stderr, "			  [ j1939 { on | off } ]\n");
 	fprintf(stderr, "       ip link show [ DEVICE ]\n");
 
 	if (iplink_have_newlink()) {
@@ -383,6 +385,12 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
 				  *argv, strlen(*argv));
 			argc--; argv++;
 			break;
+		} else if (matches(*argv, "j1939") == 0) {
+			ret = j1939_link_args(argc, argv, &req->n, sizeof(*req));
+			if (ret < 0)
+				return ret;
+			argc -= ret;
+			argv += ret;
 		} else {
 			if (strcmp(*argv, "dev") == 0) {
 				NEXT_ARG();
diff --git a/lib/j1939.c b/lib/j1939.c
new file mode 100644
index 0000000..157a8ce
--- /dev/null
+++ b/lib/j1939.c
@@ -0,0 +1,153 @@
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <endian.h>
+#include <linux/can/j1939.h>
+
+#include "utils.h"
+
+#ifndef htobe64
+# if __BYTE_ORDER == __LITTLE_ENDIAN
+#  define htobe64(x) __bswap_64 (x)
+#  define htole64(x) (x)
+#  define be64toh(x) __bswap_64 (x)
+#  define le64toh(x) (x)
+# else
+#  define htobe64(x) (x)
+#  define htole64(x) __bswap_64 (x)
+#  define be64toh(x) (x)
+#  define le64toh(x) __bswap_64 (x)
+# endif
+#endif
+/*
+ * print J1939 name
+ * for use from rt_addr_n2a
+ */
+const char *j1939_ntop(int af, const void *vaddr, size_t vlen,
+		char *str, size_t len)
+{
+	struct rtattr *tb[IFA_J1939_MAX];
+	int strdone = 0;
+
+	/* cast vaddr to non-const pointer */
+	parse_rtattr(tb, IFA_J1939_MAX-1, (void *)vaddr, vlen);
+	if (tb[IFA_J1939_ADDR]) {
+		strdone += sprintf(&str[strdone], "0x%02x",
+				*(uint8_t *)RTA_DATA(tb[IFA_J1939_ADDR]));
+		if (tb[IFA_J1939_NAME])
+			str[strdone++] = ' ';
+	}
+	if (tb[IFA_J1939_NAME])
+		strdone += sprintf(&str[strdone], "name %016llx",
+				(unsigned long long)be64toh(*(uint64_t *)RTA_DATA(tb[IFA_J1939_NAME])));
+	errno = 0;
+	return str;
+}
+
+/*
+ * fill an ifaddr message from program arguments
+ */
+int j1939_addr_args(int argc, char *argv[], struct nlmsghdr *msg, int msg_size)
+{
+	int saved_argc = argc;
+	struct ifaddrmsg *ifa = (void *)&msg[1];
+	struct rtattr *local;
+
+	if (ifa->ifa_family == AF_UNSPEC)
+		ifa->ifa_family = AF_CAN;
+	else {
+		fprintf(stderr, "j1939 only allowed for AF_CAN\n");
+		return -1;
+	}
+	if (!ifa->ifa_prefixlen)
+		ifa->ifa_prefixlen = CAN_J1939;
+	else {
+		fprintf(stderr, "CAN protocol %i already specified",
+				ifa->ifa_prefixlen);
+		return -1;
+	}
+	NEXT_ARG();
+	/* j1939 SA & NAME never need to be specified together */
+	if (matches(*argv, "name") == 0) {
+		uint64_t name;
+
+		NEXT_ARG();
+		name = htobe64(strtoull(*argv, 0, 16));
+		if (!name) {
+			fprintf(stderr, "0 name is not valid\n");
+			return -1;
+		}
+		local = addattr_nest(msg, msg_size, IFA_LOCAL);
+		addattr_l(msg, msg_size, IFA_J1939_NAME, &name, sizeof(name));
+		addattr_nest_end(msg, local);
+	} else {
+		unsigned int laddr;
+		uint8_t addr;
+
+		addr = laddr = strtoul(*argv, 0, 0);
+		if (laddr >= 0xfe) {
+			fprintf(stderr, "address '%s' not valid\n", *argv);
+			return -1;
+		}
+		local = addattr_nest(msg, msg_size, IFA_LOCAL);
+		addattr_l(msg, msg_size, IFA_J1939_ADDR, &addr, sizeof(addr));
+		addattr_nest_end(msg, local);
+	}
+
+	return saved_argc - argc;
+}
+
+/*
+ * fill an link_af message from program arguments
+ */
+int j1939_link_args(int argc, char *argv[], struct nlmsghdr *msg, int msg_size)
+{
+	int saved_argc = argc;
+	struct rtattr *afspec, *can, *j1939;
+	uint8_t enable;
+
+	NEXT_ARG();
+	if (strcmp(*argv, "on") == 0) {
+		enable = 1;
+	} else if (strcmp(*argv, "off") == 0) {
+		enable = 0;
+	} else {
+		enable = 1;
+		/* revert arguments */
+		++argc;
+		--argv;
+	}
+
+	afspec = addattr_nest(msg, msg_size, IFLA_AF_SPEC);
+	can = addattr_nest(msg, msg_size, AF_CAN);
+	j1939 = addattr_nest(msg, msg_size, CAN_J1939);
+	addattr_l(msg, msg_size, IFLA_J1939_ENABLE, &enable, sizeof(enable));
+	addattr_nest_end(msg, j1939);
+	addattr_nest_end(msg, can);
+	addattr_nest_end(msg, afspec);
+
+	return saved_argc - argc;
+}
+
+/*
+ * process the returned IFLA_AF_SPEC/AF_CAN/CAN_J1939 attribute
+ */
+const char *j1939_link_attrtop(struct rtattr *nla)
+{
+	static char str[32];
+	int pos;
+	struct rtattr *tb[IFLA_J1939_MAX];
+
+	pos = 0;
+	str[0] = 0;
+	parse_rtattr_nested(tb, IFLA_J1939_MAX-1, nla);
+	if (tb[IFLA_J1939_ENABLE]) {
+		uint8_t *u8ptr;
+
+		u8ptr = RTA_DATA(tb[IFLA_J1939_ENABLE]);
+		pos += sprintf(&str[pos], "j1939 %s", *u8ptr ? "on" : "off");
+	}
+	return str;
+}
+
diff --git a/lib/utils.c b/lib/utils.c
index a60d884..02dda80 100644
--- a/lib/utils.c
+++ b/lib/utils.c
@@ -25,6 +25,7 @@
 #include <linux/pkt_sched.h>
 #include <time.h>
 #include <sys/time.h>
+#include <linux/can.h>
 
 
 #include "utils.h"
@@ -513,7 +514,8 @@ int __get_user_hz(void)
 	return sysconf(_SC_CLK_TCK);
 }
 
-const char *rt_addr_n2a(int af, int len, const void *addr, char *buf, int buflen)
+const char *rt_addrpr_n2a(int af, int protocol, int len, const void *addr,
+		char *buf, int buflen)
 {
 	switch (af) {
 	case AF_INET:
@@ -527,6 +529,11 @@ const char *rt_addr_n2a(int af, int len, const void *addr, char *buf, int buflen
 		memcpy(dna.a_addr, addr, 2);
 		return dnet_ntop(af, &dna, buf, buflen);
 	}
+	case AF_CAN:
+		switch (protocol) {
+		case CAN_J1939:
+			return j1939_ntop(af, addr, len, buf, buflen);
+		}
 	default:
 		return "???";
 	}
diff --git a/man/man8/ip.8 b/man/man8/ip.8
index 8d55fa9..d17e06a 100644
--- a/man/man8/ip.8
+++ b/man/man8/ip.8
@@ -23,7 +23,7 @@ ip \- show / manipulate routing, devices, policy routing and tunnels
 \fB\-s\fR[\fItatistics\fR] |
 \fB\-r\fR[\fIesolve\fR] |
 \fB\-f\fR[\fIamily\fR] {
-.BR inet " | " inet6 " | " ipx " | " dnet " | " link " } | "
+.BR inet " | " inet6 " | " ipx " | " dnet " | " link " | " can " } | "
 \fB\-o\fR[\fIneline\fR] }
 
 .ti -8
@@ -95,7 +95,9 @@ ip \- show / manipulate routing, devices, policy routing and tunnels
 .B qos
 .IR VLAN-QOS " ] ] ["
 .B rate
-.IR TXRATE " ]"
+.IR TXRATE " ] |"
+.br
+.BR j1939 " { " on " | " off " }"
 
 .ti -8
 .B ip link show
@@ -126,7 +128,9 @@ ip \- show / manipulate routing, devices, policy routing and tunnels
 .B  label
 .IR STRING " ] [ "
 .B  scope
-.IR SCOPE-ID " ]"
+.IR SCOPE-ID " ] | "
+.B  j1939
+.IR IFADDRJ1939 " ] "
 
 .ti -8
 .IR SCOPE-ID " := "
@@ -142,6 +146,15 @@ ip \- show / manipulate routing, devices, policy routing and tunnels
 tentative " | " deprecated " | " dadfailed " | " temporary " ]"
 
 .ti -8
+.IR J1939IFADDR " := [ " SA " ] [ "
+.B  name
+.IR " NODENAME " ]
+.br
+.IR SA " := " U8
+.br
+.IR NODENAME " := " U64
+
+.ti -8
 .BR "ip addrlabel" " { " add " | " del " } " prefix
 .BR PREFIX " [ "
 .B dev
@@ -1038,6 +1051,11 @@ Setting this parameter to 0 disables rate limiting. The
 parameter must be specified.
 .in -8
 
+.TP
+.BR "j1939 on " or "j1939 off"
+Enable or disable SAE J1939 on the device. This will only
+work when the device is a CAN device.
+
 .PP
 .B Warning:
 If multiple parameter changes are requested,

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* Re: [RFC v3 3/6] can: make struct proto const
  2011-03-14 13:47   ` [RFC v3 3/6] can: make struct proto const Kurt Van Dijck
@ 2011-03-14 14:09     ` Eric Dumazet
  2011-03-14 15:02       ` Kurt Van Dijck
  0 siblings, 1 reply; 30+ messages in thread
From: Eric Dumazet @ 2011-03-14 14:09 UTC (permalink / raw)
  To: Kurt Van Dijck; +Cc: socketcan-core, netdev

Le lundi 14 mars 2011 à 14:47 +0100, Kurt Van Dijck a écrit :
> can_ioctl is the only reason for struct proto to be non-const.
> script/check-patch.pl suggests struct proto be const.
> This patch performs the necessary change.
> 
> Signed-off-by: Kurt Van Dijck <kurt.van.dijck@eia.be>
> ---
> diff --git a/include/linux/can/core.h b/include/linux/can/core.h
> index 430c446..0767cc6 100644
> --- a/include/linux/can/core.h
> +++ b/include/linux/can/core.h
> @@ -39,7 +39,7 @@
>  struct can_proto {
>  	int              type;
>  	int              protocol;
> -	struct proto_ops *ops;
> +	const struct proto_ops *ops;
>  	struct proto     *prot;
>  
>  	const struct rtnl_af_ops *rtnl_link_ops;
> @@ -78,6 +78,8 @@ struct rtgencanmsg {
>  
>  extern int  can_proto_register(const struct can_proto *cp);
>  extern void can_proto_unregister(const struct can_proto *cp);
> +extern int can_sock_ioctl(struct socket *sock, unsigned int cmd,
> +		unsigned long arg);
>  
>  extern int  can_rx_register(struct net_device *dev, canid_t can_id,
>  			    canid_t mask,
> diff --git a/net/can/af_can.c b/net/can/af_can.c
> index db59c6e..c1f8c05 100644
> --- a/net/can/af_can.c
> +++ b/net/can/af_can.c
> @@ -139,7 +139,7 @@ static inline void can_put_proto(const struct can_proto *cp)
>   * af_can socket functions
>   */
>  
> -static int can_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
> +int can_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
>  {
>  	struct sock *sk = sock->sk;
>  
> @@ -152,6 +152,7 @@ static int can_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
>  		return -ENOIOCTLCMD;
>  	}
>  }
> +EXPORT_SYMBOL(can_sock_ioctl);
>  
>  static void can_sock_destruct(struct sock *sk)
>  {
> @@ -720,10 +721,6 @@ int can_proto_register(const struct can_proto *cp)
>  		err = -EBUSY;
>  	} else {
>  		proto_tab[proto] = cp;
> -
> -		/* use generic ioctl function if not defined by module */
> -		if (!cp->ops->ioctl)
> -			cp->ops->ioctl = can_ioctl;

Hmm, you actually fixed a race / bug, since we installed in proto_tab[]
a pointer to a not yet initted ops structure.

I suggest you change patch title and changelog to properly describe the
bug fix.




^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC v3 1/6] can: extend sockaddr_can to include j1939 members
  2011-03-14 13:24   ` [RFC v3 1/6] can: extend sockaddr_can to include j1939 members Kurt Van Dijck
@ 2011-03-14 14:15     ` Eric Dumazet
  2011-03-14 14:53       ` Kurt Van Dijck
  0 siblings, 1 reply; 30+ messages in thread
From: Eric Dumazet @ 2011-03-14 14:15 UTC (permalink / raw)
  To: Kurt Van Dijck; +Cc: socketcan-core, netdev

Le lundi 14 mars 2011 à 14:24 +0100, Kurt Van Dijck a écrit :

> +/*
> + * required_size
> + * macro to find the minimum size of a struct
> + * that includes a requested member
> + */
> +#define required_size(member, struct_type) \
> +	(offsetof(typeof(struct_type), member) + \
> +	 sizeof(((typeof(struct_type) *)(0))->member))
> +

Hmm, most similar macros reverse arguments.

(For example : offsetof())

What about

#define required_size(TYPE, MEMBER) ...




^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC v3 1/6] can: extend sockaddr_can to include j1939 members
  2011-03-14 14:15     ` Eric Dumazet
@ 2011-03-14 14:53       ` Kurt Van Dijck
  0 siblings, 0 replies; 30+ messages in thread
From: Kurt Van Dijck @ 2011-03-14 14:53 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: socketcan-core-0fE9KPoRgkgATYTw5x5z8w, netdev-u79uwXL29TY76Z2rM5mHXA

On Mon, Mar 14, 2011 at 03:15:00PM +0100, Eric Dumazet wrote:
> > +/*
> > + * required_size
> > + * macro to find the minimum size of a struct
> > + * that includes a requested member
> > + */
> > +#define required_size(member, struct_type) \
> > +	(offsetof(typeof(struct_type), member) + \
> > +	 sizeof(((typeof(struct_type) *)(0))->member))
> > +
> 
> Hmm, most similar macros reverse arguments.
> 
> (For example : offsetof())
I had 'list_entry' in mind.
> 
> What about
> 
> #define required_size(TYPE, MEMBER) ...
I'm not against that ...
If I receive no complaint for that, I can alter this in the next series.
> 
> 
Thanks,
Kurt

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC v3 3/6] can: make struct proto const
  2011-03-14 14:09     ` Eric Dumazet
@ 2011-03-14 15:02       ` Kurt Van Dijck
  2011-03-14 16:42         ` Eric Dumazet
  0 siblings, 1 reply; 30+ messages in thread
From: Kurt Van Dijck @ 2011-03-14 15:02 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: socketcan-core-0fE9KPoRgkgATYTw5x5z8w, netdev-u79uwXL29TY76Z2rM5mHXA

On Mon, Mar 14, 2011 at 03:09:15PM +0100, Eric Dumazet wrote:
> Le lundi 14 mars 2011 à 14:47 +0100, Kurt Van Dijck a écrit :
> > can_ioctl is the only reason for struct proto to be non-const.
> > script/check-patch.pl suggests struct proto be const.
> > This patch performs the necessary change.
> > 
> >  static void can_sock_destruct(struct sock *sk)
> >  {
> > @@ -720,10 +721,6 @@ int can_proto_register(const struct can_proto *cp)
> >  		err = -EBUSY;
> >  	} else {
> >  		proto_tab[proto] = cp;
> > -
> > -		/* use generic ioctl function if not defined by module */
> > -		if (!cp->ops->ioctl)
> > -			cp->ops->ioctl = can_ioctl;
> 
> Hmm, you actually fixed a race / bug, since we installed in proto_tab[]
> a pointer to a not yet initted ops structure.
I see your point.
The reason I modified this was, as described, checkpatch.pl was complaining.
Anyway, this sequence was protected by a spinlock 'proto_tab_lock'.
I don't think it was a race.

Did I miss something?
Kurt
_______________________________________________
Socketcan-core mailing list
Socketcan-core@lists.berlios.de
https://lists.berlios.de/mailman/listinfo/socketcan-core

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC v3 3/6] can: make struct proto const
  2011-03-14 15:02       ` Kurt Van Dijck
@ 2011-03-14 16:42         ` Eric Dumazet
  2011-03-14 17:17           ` Kurt Van Dijck
  0 siblings, 1 reply; 30+ messages in thread
From: Eric Dumazet @ 2011-03-14 16:42 UTC (permalink / raw)
  To: Kurt Van Dijck; +Cc: socketcan-core, netdev

Le lundi 14 mars 2011 à 16:02 +0100, Kurt Van Dijck a écrit :

> I see your point.
> The reason I modified this was, as described, checkpatch.pl was complaining.
> Anyway, this sequence was protected by a spinlock 'proto_tab_lock'.
> I don't think it was a race.
> 
> Did I miss something?

As soon as proto_tab[proto] = cp; is done, another thread on another cpu
can read the pointer and follow it.

Hmm, I missed can_create() also uses the spinlock protection, so you're
probably right.

It seems a bit overkill :(
phonet uses RCU for example.



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC v3 3/6] can: make struct proto const
  2011-03-14 16:42         ` Eric Dumazet
@ 2011-03-14 17:17           ` Kurt Van Dijck
  2011-03-15 21:28             ` Oliver Hartkopp
  0 siblings, 1 reply; 30+ messages in thread
From: Kurt Van Dijck @ 2011-03-14 17:17 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: socketcan-core-0fE9KPoRgkgATYTw5x5z8w, netdev-u79uwXL29TY76Z2rM5mHXA

On Mon, Mar 14, 2011 at 05:42:23PM +0100, Eric Dumazet wrote:
> Le lundi 14 mars 2011 à 16:02 +0100, Kurt Van Dijck a écrit :
> 
> > I see your point.
> > The reason I modified this was, as described, checkpatch.pl was complaining.
> > Anyway, this sequence was protected by a spinlock 'proto_tab_lock'.
> > I don't think it was a race.
> > 
> > Did I miss something?
> 
> As soon as proto_tab[proto] = cp; is done, another thread on another cpu
> can read the pointer and follow it.
> 
> Hmm, I missed can_create() also uses the spinlock protection, so you're
> probably right.
> 
> It seems a bit overkill :(
> phonet uses RCU for example.
I'll keep that in mind.
Switching CAN protos to RCU is far beyond to goal of this patch :-)

Thanks,
Kurt
_______________________________________________
Socketcan-core mailing list
Socketcan-core@lists.berlios.de
https://lists.berlios.de/mailman/listinfo/socketcan-core

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC v3 0/6] CAN: add SAE J1939 protocol
       [not found] ` <20110314132004.GA333-MxZ6Iy/zr/UdbCeoMzGj59i2O/JbrIOy@public.gmane.org>
                     ` (5 preceding siblings ...)
  2011-03-14 14:05   ` [RFC v3 6/6] iproute2: add CAN and J1939 rtnetlink support Kurt Van Dijck
@ 2011-03-15  9:23   ` Kurt Van Dijck
  6 siblings, 0 replies; 30+ messages in thread
From: Kurt Van Dijck @ 2011-03-15  9:23 UTC (permalink / raw)
  To: socketcan-core-0fE9KPoRgkgATYTw5x5z8w, netdev-u79uwXL29TY76Z2rM5mHXA

On Mon, Mar 14, 2011 at 02:20:04PM +0100, Kurt Van Dijck wrote:
> 
> This series adds SAE J1939 support to the current net-next-2.6.
> For the rtnetlink operations to work, a 2.6.38-rc1 is required.
> 
> 1/6: can: extend sockaddr_can to include j1939 members
> 2/6: can: add rtnetlink support
> 3/6: can: make struct proto const
> 4/6: j1939: initial import of SAE J1939
> 5/6: j1939: add documentation & MAINTAINERS
> 6/6: iproute2: use CAN & J1939
> 
> Still a lot of things probably need explanation...

I had not mentioned the major differences with v2
(which went to berlios SocketCAN mailing list only).

* replace magic constants with macro's
* use a static protocol stack, not a dynamic one.
* remove feature that have limited use and are
  difficult to explain.
* renamed some structure types to increase code readability. 
* block on transport sessions until CAN frame is queued.

* fix bugs.

Kurt

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC v3 3/6] can: make struct proto const
  2011-03-14 17:17           ` Kurt Van Dijck
@ 2011-03-15 21:28             ` Oliver Hartkopp
       [not found]               ` <4D7FD9ED.1080004-fJ+pQTUTwRTk1uMJSBkQmQ@public.gmane.org>
  2011-03-15 22:19               ` Eric Dumazet
  0 siblings, 2 replies; 30+ messages in thread
From: Oliver Hartkopp @ 2011-03-15 21:28 UTC (permalink / raw)
  To: Kurt Van Dijck, Eric Dumazet; +Cc: socketcan-core, netdev

On 14.03.2011 18:17, Kurt Van Dijck wrote:
> On Mon, Mar 14, 2011 at 05:42:23PM +0100, Eric Dumazet wrote:
>> Le lundi 14 mars 2011 à 16:02 +0100, Kurt Van Dijck a écrit :
>>
>>> I see your point.
>>> The reason I modified this was, as described, checkpatch.pl was complaining.
>>> Anyway, this sequence was protected by a spinlock 'proto_tab_lock'.
>>> I don't think it was a race.
>>>
>>> Did I miss something?
>>
>> As soon as proto_tab[proto] = cp; is done, another thread on another cpu
>> can read the pointer and follow it.
>>
>> Hmm, I missed can_create() also uses the spinlock protection, so you're
>> probably right.
>>
>> It seems a bit overkill :(
>> phonet uses RCU for example.

Hello Eric,

the RCU code in phonet is worth to consider. But loading and removing of
protocols is far away from being a hot path ... what would be the advantages
to move to RCU here?

> I'll keep that in mind.
> Switching CAN protos to RCU is far beyond to goal of this patch :-)

Anyway making the struct proto a const (and set the default defines in the CAN
protocols) is a nice cleanup. Let's wait for the feedback about the RCU from
Eric ... then this patch could be put into mainline independently from the
j1939 protocol.

Thanks,
Oliver

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC v3 3/6] can: make struct proto const
       [not found]               ` <4D7FD9ED.1080004-fJ+pQTUTwRTk1uMJSBkQmQ@public.gmane.org>
@ 2011-03-15 22:12                 ` Kurt Van Dijck
  0 siblings, 0 replies; 30+ messages in thread
From: Kurt Van Dijck @ 2011-03-15 22:12 UTC (permalink / raw)
  To: Oliver Hartkopp
  Cc: socketcan-core-0fE9KPoRgkgATYTw5x5z8w,
	netdev-u79uwXL29TY76Z2rM5mHXA, Eric Dumazet

On Tue, Mar 15, 2011 at 10:28:13PM +0100, Oliver Hartkopp wrote:
> On 14.03.2011 18:17, Kurt Van Dijck wrote:
> > On Mon, Mar 14, 2011 at 05:42:23PM +0100, Eric Dumazet wrote:
> >> Le lundi 14 mars 2011 à 16:02 +0100, Kurt Van Dijck a écrit :
> >>
> >>> I see your point.
> >>> The reason I modified this was, as described, checkpatch.pl was complaining.
> >>> Anyway, this sequence was protected by a spinlock 'proto_tab_lock'.
> >>> I don't think it was a race.
> >>>
> >>> Did I miss something?
> >>
> >> As soon as proto_tab[proto] = cp; is done, another thread on another cpu
> >> can read the pointer and follow it.
> >>
> >> Hmm, I missed can_create() also uses the spinlock protection, so you're
> >> probably right.
> >>
> >> It seems a bit overkill :(
> >> phonet uses RCU for example.
> 
> Hello Eric,
> 
> the RCU code in phonet is worth to consider. But loading and removing of
> protocols is far away from being a hot path ... what would be the advantages
> to move to RCU here?
Does RCU avoid a spinlock?

> 
> > I'll keep that in mind.
> > Switching CAN protos to RCU is far beyond to goal of this patch :-)
> 
> Anyway making the struct proto a const (and set the default defines in the CAN
> protocols) is a nice cleanup. Let's wait for the feedback about the RCU from
> Eric ... then this patch could be put into mainline independently from the
> j1939 protocol.
ack.

Kurt
_______________________________________________
Socketcan-core mailing list
Socketcan-core@lists.berlios.de
https://lists.berlios.de/mailman/listinfo/socketcan-core

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC v3 3/6] can: make struct proto const
  2011-03-15 21:28             ` Oliver Hartkopp
       [not found]               ` <4D7FD9ED.1080004-fJ+pQTUTwRTk1uMJSBkQmQ@public.gmane.org>
@ 2011-03-15 22:19               ` Eric Dumazet
  1 sibling, 0 replies; 30+ messages in thread
From: Eric Dumazet @ 2011-03-15 22:19 UTC (permalink / raw)
  To: Oliver Hartkopp; +Cc: Kurt Van Dijck, socketcan-core, netdev

Le mardi 15 mars 2011 à 22:28 +0100, Oliver Hartkopp a écrit :

> Hello Eric,
> 
> the RCU code in phonet is worth to consider. But loading and removing of
> protocols is far away from being a hot path ... what would be the advantages
> to move to RCU here?
> 

can_create() could avoid taking the spinlock.

I have no idea if its a critical path, I guess not.



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC v3 5/6] j1939: add documentation and MAINTAINERS
       [not found]     ` <20110314135917.GF333-MxZ6Iy/zr/UdbCeoMzGj59i2O/JbrIOy@public.gmane.org>
@ 2011-03-20 15:56       ` Oliver Hartkopp
       [not found]         ` <4D8623BE.2080807-fJ+pQTUTwRTk1uMJSBkQmQ@public.gmane.org>
  0 siblings, 1 reply; 30+ messages in thread
From: Oliver Hartkopp @ 2011-03-20 15:56 UTC (permalink / raw)
  To: Kurt Van Dijck
  Cc: socketcan-core-0fE9KPoRgkgATYTw5x5z8w, netdev-u79uwXL29TY76Z2rM5mHXA

On 14.03.2011 14:59, Kurt Van Dijck wrote:
> This patch adds the documentation and MAINTAINERS.

Hello Kurt,

even after our F2F-discussion on the Embedded World i'm still not convinced,
why it should be a good idea to handle all the address claiming process inside
the kernel.

Besides the fact, that other j1939 implementation are *completely* implemented
in userspace (and can cope with the time restrictions), i do not see why you
put the address claiming into the kernel and not only the transport layer stuff.

The address claiming can be compared to something like DHCP or DNS in the
internet protocol world, that are both handled and implemented in userspace
apps or userspace libraries.

E.g. these bits from the documentation look like you are starting some kind of
'addressing service' daemon:

> +4.1 rtnetlink interface
> +
> +  Per default j1939 is not active. Specifying can_ifindex != 0 in bind(2)
> +  or connect(2) needs an active j1939 on that interface. You must have done
> +  $ ip link set canX j1939 on
> +  on that interface.
> +
> +  $ ip link set canX j1939 down
> +  disables j1939 on canX.

You are activating the 'addressing service' on specific CAN interfaces.

Then you suggest to attach static and/or dynamic addresses to the interface.

> +  Assigning addresses is done via
> +  $ ip addr add dev canX j1939 0xXX
> +  statically or
> +  $ ip addr add dev canX j1939 name 0xXX
> +  dynamically. In the latter case, address claiming must take place
> +  before other traffic can leave.

like you would have using DHCP/DNS (adapted for j1939) ...

> +  Removing addresses is done similarly via
> +  $ ip addr del dev canX j1939 0xXX
> +  $ ip addr del dev canX j1939 name 0xXX
> +
> +  A static address cannot be assigned together with a 64bit name.

Ah. You provide two kernel interfaces instead of handling the address claiming
in userspace and provide only one simple (static) interface to the kernel.

This artifact brings this fact out again:

> +  can_addr.j1939.name contains the 64-bit J1939 NAME.
> +
> +  can_addr.j1939.addr contains the source address.
> +
> +  When sending data, the source address is applied as follows: If
> +  can_addr.j1939.name != 0 the NAME is looked up by the kernel and the
> +  corresponding Source Address is used. If can_addr.j1939.name == 0,
> +  can_addr.j1939.addr is used.

Yes. You are providing two programming interfaces to the kernel that can be
used exclusive-OR only.

As other j1939 implementations implement the address claiming in userspace
too, there's no necessity to implement this inside the kernel. DHCP and DNS
can also lead to address changes and some 'new j1939 addressing daemon' could
be implemented in a way that allows to tell registered j1939 apps address
changes in a fast way (trigger/signal/select/whatever). I don't know how much
of the 4838 lines of code from your RFC can be removed - but i assume it would
vastly reduce the complexity of your posted j1939 implementation.

If you would implement only the j1939 transport layer stuff (using static
addressing) together with some userspace 'address claiming' daemon and/or
library (compared to DNS) this would make more sense to me. Especially it
makes the kernel API clear and simple(!). As a side-effect this would remove
the need for a separate system-wide configuration which would need to be added
with your suggested netlink extensions in af_can.c, iproute2 and the other
adaptions to the current code to extend the sockaddr_can in size.

I know you're a fan of j1939 address claiming inside the kernel but IMO this
does not fit other networking addressing concepts inside the kernel and messes
up the kernel API for j1939, sigh.

If it makes sense to you, i would offer my help to implement the address
claiming daemon based on CAN_RAW and CAN_BCM ... 8-)

Anyway: Thanks for you contribution!

Oliver

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC v3 5/6] j1939: add documentation and MAINTAINERS
       [not found]         ` <4D8623BE.2080807-fJ+pQTUTwRTk1uMJSBkQmQ@public.gmane.org>
@ 2011-03-25 13:55           ` Kurt Van Dijck
  2011-03-29 14:29           ` SAE J1939: update Kurt Van Dijck
  2011-04-13  4:49           ` [RFC v3 5/6] j1939: rename NAME to UUID? Kurt Van Dijck
  2 siblings, 0 replies; 30+ messages in thread
From: Kurt Van Dijck @ 2011-03-25 13:55 UTC (permalink / raw)
  To: Oliver Hartkopp
  Cc: socketcan-core-0fE9KPoRgkgATYTw5x5z8w, netdev-u79uwXL29TY76Z2rM5mHXA

On Sun, Mar 20, 2011 at 04:56:46PM +0100, Oliver Hartkopp wrote:
> On 14.03.2011 14:59, Kurt Van Dijck wrote:
> 
> Hello Kurt,
hello Oliver :-)
> 
> even after our F2F-discussion on the Embedded World i'm still not convinced,
ok

Are you aware of the fact that, since your experience with dynamic addressing
is limited, ignoring this completely will leave you yet with a working,
operational J1939 stack?
When address claiming is not in place, just work with the static addresses. It'll
work. The addition of address claiming in kernel just looses you a few
cpu clock cycles.

At least,  that's the intention of the API.
The patches I sent have proven to have some faults yet. I'm again working on an
update.

> why it should be a good idea to handle all the address claiming process inside
> the kernel.
IMO, it's a good idea to have the kernel support the address claiming process.
Why:
* IMO, J1939 implicitely puts address claiming below Transport protocol.
  As such, you can't really put Transport protocol in kernel & address claim
  in userspace.
* In kernel, an ECU can 'atomically' switch addresses,
  AND have pending transport sessions (in kernel) use the new address.
* in kernel, a sendto() can be held (block) during address claim delays (not yet
  implemented).
* In kernel, you can let userspace participate on a J1939 bus _correctly_
  in an imperative way, rather than the volutary userspace library setups.

The above are arguments to minimize the required overhead in userspace for
supporting address claiming.

I don't want the kernel to handle _all_ the address claiming.
Why:
* address claiming _is_ a policy related thing. I don't put policies
  in kernel. I learned that as soon that a policy is implemented, our customer
  wants it different.
  But our customer should _not_ try modifying the non-policy related part of
  address claiming.

Think of this scenario: we put only transport sessions in kernel.
So, you instruct the kernel to send few kB on j1939 bus, from (A)0x80.
What will happen when (B)0x80 kicks (A) from its 0x80 using address claiming.
(A) will use (eg.) 0x82.  But your transport session is still pending,
and using 0x80 ==>> illegal.

My implementation lets the kernel follow the address claiming traffic, that was
initiated from userspace, so it can handle this situation correctly.

Also note that this is the smallest example to make the point. More elaborated and
complex examples exist.

The important thing, IMO, is how this is controlled from userspace. Yes, you
can instruct the kernel to do magic trickery then, but my implementation
uses the regular API's for this. I just accepted the fact that the 64bit name
is the real reference to indicate an ECU. So I put that in the sockaddr_can too.
> 
> Besides the fact, that other j1939 implementation are *completely* implemented
> in userspace (and can cope with the time restrictions),
They probably do, on a voluntary basis.

When spread across different processes cooperating to the same ECU,
they have no means to guarantee anything. So, every application should
carefully respect the guidelines for the userspace library.
And after that is accomplished, do they take care of the following scenario:
Process A sends a PGN regularly
Process B deals with address claims.
When process B emits a new address, process A should _not_ send new PGN's for
250msec. That is the 'time restriction'
However, their interprocess communication will race with the in-kernel CAN queue's.
So, A may emit PGN's after the address claim, but before the 'address notification'
I don't see a proper way to deal with it.
> i do not see why you
> put the address claiming into the kernel and not only the transport layer stuff.
see above.
> 
> The address claiming can be compared to something like DHCP or DNS in the
> internet protocol world, that are both handled and implemented in userspace
> apps or userspace libraries.
Yes and no.
Yes: DHCP also deals with 'dynamic addresses'. The policies applied there could
be used for J1939 too.
No: DHCP operates in a master-slave way, J1939 does not.
DHCP does not handle conflicts, since the master should not give conflicting leases.
J1939 must deal with conflicts.

A proper comparison on IP would be to eliminate the DHCP server, and let each
client 'just use an IP', and when another ethernet card happens to have chosen
the exact same IP, the winner is decided (on both ends) based on the MAC address.
This would introduce loads of problems in IP too.
The atomic operation & conflict handling are kernel parts IMHO.

another comparison would be ARP, where each node holds its own table, carefully
built from passing network traffic.

The 64bit 'name' is not a name as in DNS, it's a unique ID.
> 
> E.g. these bits from the documentation look like you are starting some kind of
> 'addressing service' daemon:
Yep, to implement the 'address choosing' policy.
I'm still testing all J1939 requirements here, but when this is ready, I feel
I will need to publish such program.
> 
> > +4.1 rtnetlink interface
> > +
> > +  Per default j1939 is not active. Specifying can_ifindex != 0 in bind(2)
> > +  or connect(2) needs an active j1939 on that interface. You must have done
> > +  $ ip link set canX j1939 on
> > +  on that interface.
> > +
> > +  $ ip link set canX j1939 down
> > +  disables j1939 on canX.
> 
> You are activating the 'addressing service' on specific CAN interfaces.
Since no autoprobing of protocols is possible on CAN (in contrast to Ethernet).
> 
> Then you suggest to attach static and/or dynamic addresses to the interface.
Correction: you assign a static address, or a 'name' for use with dynamic addressing.
the name for dynamic addressing is not a 'dynamic address'.
> 
> > +  Assigning addresses is done via
> > +  $ ip addr add dev canX j1939 0xXX
> > +  statically or
> > +  $ ip addr add dev canX j1939 name 0xXX
> > +  dynamically. In the latter case, address claiming must take place
> > +  before other traffic can leave.
> 
> like you would have using DHCP/DNS (adapted for j1939) ...
The userspace part for address claiming (in fact, the right CAN frames should appear
to fullfill the address claiming requirements) can then bind to the name, and claim
addresses for it. The kernel will reccognize those, and act upon them. The kernel
will at no point initiate an address claim.
> 
> > +  Removing addresses is done similarly via
> > +  $ ip addr del dev canX j1939 0xXX
> > +  $ ip addr del dev canX j1939 name 0xXX
> > +
> > +  A static address cannot be assigned together with a 64bit name.
> 
> Ah. You provide two kernel interfaces
Yep, because there are two distinct use cases to address.
With dynamic addressing, the 8bit address is just a temporary placeholder, which may
change in the future. This makes a bad discriminator to differentiate between hosts.
therefore, to specify a host to the kernel (as source or destination), the 8bit
address is irrelevant at that point in time.
Therefore, the kernel _needs_ knowledge of the 64bit name, just to provide a
decent interface to userspace for source/destination identification.

> instead of handling the address claiming
> in userspace and provide only one simple (static) interface to the kernel.
And this is no option IMO.
Just above, I indicated that the kernel needs the 64bit name. Pairing with the 8bit
address in userspace only will:
* add a serious amount of userspace code & userspace timing requirements.
* create a complex library/IPC API.
* not solve the case for pending transport sessions.
* still unspecified how the kernel should treat messages that have specified
  a 64bit destination name with different 8bit destination address.
IMO, doing these things in userspace are unnecessarily complicated.

> 
> This artifact brings this fact out again:
> 
> > +  can_addr.j1939.name contains the 64-bit J1939 NAME.
> > +
> > +  can_addr.j1939.addr contains the source address.
> > +
> > +  When sending data, the source address is applied as follows: If
> > +  can_addr.j1939.name != 0 the NAME is looked up by the kernel and the
> > +  corresponding Source Address is used. If can_addr.j1939.name == 0,
> > +  can_addr.j1939.addr is used.
> 
> Yes. You are providing two programming interfaces to the kernel that can be
> used exclusive-OR only.
ack.
> 
> As other j1939 implementations implement the address claiming in userspace
> too, there's no necessity to implement this inside the kernel. DHCP and DNS
> can also lead to address changes and some 'new j1939 addressing daemon' could
> be implemented in a way that allows to tell registered j1939 apps address
> changes in a fast way (trigger/signal/select/whatever). I don't know how much
This is like saying: the race condition could be improved. But it's still there, isn't it?
> of the 4838 lines of code from your RFC can be removed - but i assume it would
+/- 700
which will move to every userspace application, and they'd still not be correct.
> vastly reduce the complexity of your posted j1939 implementation.
> 
> If you would implement only the j1939 transport layer stuff (using static
> addressing) together with some userspace 'address claiming' daemon and/or
> library (compared to DNS) this would make more sense to me. Especially it
> makes the kernel API clear and simple(!).
and crippled.
Being clear and simple is no justification for introducing race conditions!
> As a side-effect this would remove
> the need for a separate system-wide configuration
Why is that a problem. I look at it as a powerfull administrative tool.
The fact that J1939 is the first CAN protocol with a 'real' addressing scheme
seems a major problem.
> which would need to be added
> with your suggested netlink extensions in af_can.c, iproute2
It works, and IMO fits in the policies.
> and the other adaptions to the current code to extend the sockaddr_can in size.
Sooner or later, when CAN protocols are added, the sockaddr_can will grow.
Not letting this grow is equivalent of saying that no CAN protocols will be added.

This fits in the current policies. why do BSD socket functions invented
the af_family & socklen_t stuff. Because they faced this problem before.
Putting J1939 inside AF_CAN implies handling this kind of stuff. And I handled it.
I haven't recompiled my old can tools for ages now, but they still work.
> 
> I know you're a fan of j1939 address claiming inside the kernel
I'm no fan. I only respect the fact that it's the only right place.
> but IMO this does not fit other networking addressing concepts inside the kernel
IPv6 automatic router detection?
At least, I disagree.
> and messes up the kernel API for j1939, sigh.
I don't think my proposed API is a mess. It my way of addressing existing problems.
The fact that some userspace library for tons of dollars does not solve my problem
is IMO no reason to make the same fault.
> 
> If it makes sense to you, i would offer my help to implement the address
> claiming daemon based on CAN_RAW and CAN_BCM ... 8-)
Thanks for the offer.
I have no clue yet how to do the necessary IPC in a way that userspace would
be easy to work with _UNDER ALL CIRCUMSTANCES_ (sorry for the capitals).
> 
> Anyway: Thanks for you contribution!
Thanks for looking at the API.
For what it's worth, since the discussion started, I also think the API has improved
a lot. Thanks for that!

Kurt
> 
> Oliver

^ permalink raw reply	[flat|nested] 30+ messages in thread

* SAE J1939: update
       [not found]         ` <4D8623BE.2080807-fJ+pQTUTwRTk1uMJSBkQmQ@public.gmane.org>
  2011-03-25 13:55           ` Kurt Van Dijck
@ 2011-03-29 14:29           ` Kurt Van Dijck
  2011-03-29 19:41             ` Oliver Hartkopp
  2011-04-13  4:49           ` [RFC v3 5/6] j1939: rename NAME to UUID? Kurt Van Dijck
  2 siblings, 1 reply; 30+ messages in thread
From: Kurt Van Dijck @ 2011-03-29 14:29 UTC (permalink / raw)
  To: Oliver Hartkopp
  Cc: socketcan-core-0fE9KPoRgkgATYTw5x5z8w, netdev-u79uwXL29TY76Z2rM5mHXA

Oliver,

Some progress:

I dropped the state-machine for the address claiming. This makes it less
confusing I hope.

I dropped SO_J1939_DEST_MASK. This could be done in userspace by
accessing a procfs file, or additional rtnetlink ...
Lookup up remote ecu's is not strictly necessary in kernel.
I have no idea yet how such library would look like.

Can userspace tools be attached to the socketCAN subversion can-utils, or
would a seperate dir be necessary?

I'd say 'suggestions are welcome' but I know you'd suggest to remove
address claiming..

Kurt

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: SAE J1939: update
  2011-03-29 14:29           ` SAE J1939: update Kurt Van Dijck
@ 2011-03-29 19:41             ` Oliver Hartkopp
  0 siblings, 0 replies; 30+ messages in thread
From: Oliver Hartkopp @ 2011-03-29 19:41 UTC (permalink / raw)
  To: Kurt Van Dijck; +Cc: socketcan-core, netdev

On 29.03.2011 16:29, Kurt Van Dijck wrote:
> Oliver,
> 
> Some progress:
> 
> I dropped the state-machine for the address claiming. This makes it less
> confusing I hope.

Thanks.

> I dropped SO_J1939_DEST_MASK. This could be done in userspace by
> accessing a procfs file, or additional rtnetlink ...
> Lookup up remote ecu's is not strictly necessary in kernel.
> I have no idea yet how such library would look like.

I'll check that with my colleague Urs, who knows very good, which concepts and
'mechanics' are commonly used for such kind of requirements.

> Can userspace tools be attached to the socketCAN subversion can-utils, or
> would a seperate dir be necessary?

I assume about 3-4 tools (like an AC-daemon, some dump or sniffer tool and a
library with some header file) to emerge in can-utils then, which should be
ok. There could also be some test-programms or src-samples that could be
placed in trunk/test .

> I'd say 'suggestions are welcome' but I know you'd suggest to remove
> address claiming..

I'm really very interested in having the address claiming - just somewhere in
userspace :-)

But of course it might become an ambitious target to support the address
claiming with an appropriate infrastructure to help users to fulfill their
needs without getting confused.

Thanks & best regards,
Oliver

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC v3 5/6] j1939: rename NAME to UUID?
       [not found]         ` <4D8623BE.2080807-fJ+pQTUTwRTk1uMJSBkQmQ@public.gmane.org>
  2011-03-25 13:55           ` Kurt Van Dijck
  2011-03-29 14:29           ` SAE J1939: update Kurt Van Dijck
@ 2011-04-13  4:49           ` Kurt Van Dijck
       [not found]             ` <20110413044928.GA289-ozGf4kBk5synFtIcQ8t7k3L8HoS0Hn3T@public.gmane.org>
  2 siblings, 1 reply; 30+ messages in thread
From: Kurt Van Dijck @ 2011-04-13  4:49 UTC (permalink / raw)
  To: Oliver Hartkopp
  Cc: socketcan-core-0fE9KPoRgkgATYTw5x5z8w, netdev-u79uwXL29TY76Z2rM5mHXA

Oliver et.al.,

On Sun, Mar 20, 2011 at 04:56:46PM +0100, Oliver Hartkopp wrote:
> On 14.03.2011 14:59, Kurt Van Dijck wrote:
> 
> Then you suggest to attach static and/or dynamic addresses to the interface.
> 
> > +  Assigning addresses is done via
> > +  $ ip addr add dev canX j1939 0xXX
> > +  statically or
> > +  $ ip addr add dev canX j1939 name 0xXX
> > +  dynamically. In the latter case, address claiming must take place
> > +  before other traffic can leave.
> 
> like you would have using DHCP/DNS (adapted for j1939) ...
> 
I suspect the confustion with DHCP/DNS comes free with the used terminology.

Specifications talk about a 64bit NAME, where is actually is a 64bit UUID.
Calling this number a UUID may clarify things, but leaves the spec in the
terminology.

one would then do:
$ ip addr add dev canX j1939 uuid XXXX

Would that be a good way to progress?

Kurt

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC v3 5/6] j1939: rename NAME to UUID?
       [not found]             ` <20110413044928.GA289-ozGf4kBk5synFtIcQ8t7k3L8HoS0Hn3T@public.gmane.org>
@ 2011-04-15 17:57               ` Oliver Hartkopp
       [not found]                 ` <4DA88705.5040203-fJ+pQTUTwRTk1uMJSBkQmQ@public.gmane.org>
  0 siblings, 1 reply; 30+ messages in thread
From: Oliver Hartkopp @ 2011-04-15 17:57 UTC (permalink / raw)
  To: Kurt Van Dijck
  Cc: socketcan-core-0fE9KPoRgkgATYTw5x5z8w, netdev-u79uwXL29TY76Z2rM5mHXA

On 13.04.2011 06:49, Kurt Van Dijck wrote:
> Oliver et.al.,
> 
> On Sun, Mar 20, 2011 at 04:56:46PM +0100, Oliver Hartkopp wrote:
>> On 14.03.2011 14:59, Kurt Van Dijck wrote:
>>
>> Then you suggest to attach static and/or dynamic addresses to the interface.
>>
>>> +  Assigning addresses is done via
>>> +  $ ip addr add dev canX j1939 0xXX
>>> +  statically or
>>> +  $ ip addr add dev canX j1939 name 0xXX
>>> +  dynamically. In the latter case, address claiming must take place
>>> +  before other traffic can leave.
>>
>> like you would have using DHCP/DNS (adapted for j1939) ...
>>
> I suspect the confustion with DHCP/DNS comes free with the used terminology.
> 
> Specifications talk about a 64bit NAME, where is actually is a 64bit UUID.
> Calling this number a UUID may clarify things, but leaves the spec in the
> terminology.
> 
> one would then do:
> $ ip addr add dev canX j1939 uuid XXXX
> 
> Would that be a good way to progress?

Hello Kurt,

i don't know if it helps - at least for j1939 users - to rename the NAME for
j1939 address claiming to UUID which is usually 128 bit long an has a pretty
different understanding than the J1939 NAME which stands for

   1. Arbitrary address bit
   2. Industry group, length 3 bits
   3. Vehicle system instance, length 4 bits
   4. Vehicle system, length 7 bits
   5. Reserved bit
   6. Function, length 8 bits
   7. Function instance, length 5 bits
   8. ECU instance, length 3 bits
   9. Manufacturer code, length 11 bits
  10. Identity number, length 21 bits

(from http://www.kvaser.com/en/about-can/higher-layer-protocols/36.html)

This is not comparable to the ideas from RFC 4122 ...

Thinking about the approach to implement the j1939 address claiming (AC) in
userspace, i discovered two ways which could both be hidden inside some
easy-to-use helper functions:

1. implement a thread (e.g. within a library) which opens a CAN_RAW socket on
a specific CAN-interface and takes care of the AC procedure and monitors
ongoing AC procedures on the bus. In this case every j1939 application
requiring AC internally would monitor all the AC handling on itself (which
should be no general problem - written only once).

2. create j1939ac daemon(s) using PF_UNIX-sockets to be named e.g.
j1939ac_can0, j1939ac_can1, etc. - these daemons take care for all AC
requirements of the host it is running on. The PF_UNIX-sockets are used in
SOCK_DGRAM mode and only the j1939 processes that need AC can then register
their NAME by sending a request datagram, and get back the j1939-address once
it is claimed (and all the updates on changes). As the j1939ac daemons are
running on the same host as the j1939 application processes, optional the
process' PID could be provided to the daemon during the registering process,
so that the daemon can send a signal to a signal handler of the application
process (if you would like to omit the select() syscall to handle both the
j1939 and PF_UNIX sockets).

->   <Req><Name="A3B5667799332242" PID="12345">
<-   <Resp><ACState="claimed" Name="A3B5667799332242" Address="1B">
(some time)
<-   <Resp><ACState="changed" Name="A3B5667799332242" Address="1C">

This is a sketch that could be put into simple C-structs that are sent via the
PF_UNIX DGRAM socket.

In all suggested cases (using a thread, daemon with/without signal) the AC
procedure can be managed in userspace without real pain. But especially with
less pain than putting the AC process into kernelspace and provide your
suggested socket API with bind/connect/... in very different manners.

Regards,
Oliver

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC v3 5/6] j1939: rename NAME to UUID?
       [not found]                 ` <4DA88705.5040203-fJ+pQTUTwRTk1uMJSBkQmQ@public.gmane.org>
@ 2011-04-20  7:10                   ` Kurt Van Dijck
  2011-04-20  7:24                   ` Kurt Van Dijck
  1 sibling, 0 replies; 30+ messages in thread
From: Kurt Van Dijck @ 2011-04-20  7:10 UTC (permalink / raw)
  To: Oliver Hartkopp
  Cc: socketcan-core-0fE9KPoRgkgATYTw5x5z8w, netdev-u79uwXL29TY76Z2rM5mHXA

On Fri, Apr 15, 2011 at 07:57:25PM +0200, Oliver Hartkopp wrote:
> On 13.04.2011 06:49, Kurt Van Dijck wrote:
> > Oliver et.al.,
> > 
> > On Sun, Mar 20, 2011 at 04:56:46PM +0100, Oliver Hartkopp wrote:
> >> On 14.03.2011 14:59, Kurt Van Dijck wrote:
> >>
> >> Then you suggest to attach static and/or dynamic addresses to the interface.
> >>
> >>> +  Assigning addresses is done via
> >>> +  $ ip addr add dev canX j1939 0xXX
> >>> +  statically or
> >>> +  $ ip addr add dev canX j1939 name 0xXX
> >>> +  dynamically. In the latter case, address claiming must take place
> >>> +  before other traffic can leave.
> >>
> >> like you would have using DHCP/DNS (adapted for j1939) ...
> >>
> > I suspect the confustion with DHCP/DNS comes free with the used terminology.
> > 
> > Specifications talk about a 64bit NAME, where is actually is a 64bit UUID.
> > Calling this number a UUID may clarify things, but leaves the spec in the
> > terminology.
> > 
> > one would then do:
> > $ ip addr add dev canX j1939 uuid XXXX
> > 
> > Would that be a good way to progress?
> 
> Hello Kurt,
> 
> i don't know if it helps - at least for j1939 users - to rename the NAME for
> j1939 address claiming to UUID which is usually 128 bit long an has a pretty
> different understanding than the J1939 NAME which stands for
> 
>    1. Arbitrary address bit
>    2. Industry group, length 3 bits
>    3. Vehicle system instance, length 4 bits
>    4. Vehicle system, length 7 bits
>    5. Reserved bit
>    6. Function, length 8 bits
>    7. Function instance, length 5 bits
>    8. ECU instance, length 3 bits
>    9. Manufacturer code, length 11 bits
>   10. Identity number, length 21 bits
> 
> (from http://www.kvaser.com/en/about-can/higher-layer-protocols/36.html)
> 
> This is not comparable to the ideas from RFC 4122 ...

please note that for address claiming, this interpretation should not be used
as such, and the whole 64bit NAME is regarded as a 'Unique Number' :-)

I was not aware of RFC 4122 :-)

Never mind this idea, I'll stick to 'NAME' as that is what j1939 users
are used to. I wanted to avoid people thinking on DNS, but I should not
introduce other misunderstandings.

Kurt

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC v3 5/6] j1939: rename NAME to UUID?
       [not found]                 ` <4DA88705.5040203-fJ+pQTUTwRTk1uMJSBkQmQ@public.gmane.org>
  2011-04-20  7:10                   ` Kurt Van Dijck
@ 2011-04-20  7:24                   ` Kurt Van Dijck
       [not found]                     ` <20110420072439.GB332-ozGf4kBk5synFtIcQ8t7k3L8HoS0Hn3T@public.gmane.org>
  1 sibling, 1 reply; 30+ messages in thread
From: Kurt Van Dijck @ 2011-04-20  7:24 UTC (permalink / raw)
  To: Oliver Hartkopp
  Cc: socketcan-core-0fE9KPoRgkgATYTw5x5z8w, netdev-u79uwXL29TY76Z2rM5mHXA

On Fri, Apr 15, 2011 at 07:57:25PM +0200, Oliver Hartkopp wrote:
> On 13.04.2011 06:49, Kurt Van Dijck wrote:
> > Oliver et.al.,
> 
> Thinking about the approach to implement the j1939 address claiming (AC) in
> userspace, i discovered two ways which could both be hidden inside some
> easy-to-use helper functions:
> 
> 1. implement a thread (e.g. within a library) which opens a CAN_RAW socket on
> a specific CAN-interface and takes care of the AC procedure and monitors
> ongoing AC procedures on the bus. In this case every j1939 application
> requiring AC internally would monitor all the AC handling on itself (which
> should be no general problem - written only once).
> 
> 2. create j1939ac daemon(s) using PF_UNIX-sockets to be named e.g.
> j1939ac_can0, j1939ac_can1, etc. - these daemons take care for all AC
> requirements of the host it is running on. The PF_UNIX-sockets are used in
> SOCK_DGRAM mode and only the j1939 processes that need AC can then register
> their NAME by sending a request datagram, and get back the j1939-address once
> it is claimed (and all the updates on changes). As the j1939ac daemons are
> running on the same host as the j1939 application processes, optional the
> process' PID could be provided to the daemon during the registering process,
> so that the daemon can send a signal to a signal handler of the application
> process (if you would like to omit the select() syscall to handle both the
> j1939 and PF_UNIX sockets).
> 
> ->   <Req><Name="A3B5667799332242" PID="12345">
> <-   <Resp><ACState="claimed" Name="A3B5667799332242" Address="1B">
> (some time)
> <-   <Resp><ACState="changed" Name="A3B5667799332242" Address="1C">
> 
> This is a sketch that could be put into simple C-structs that are sent via the
> PF_UNIX DGRAM socket.
> 
> In all suggested cases (using a thread, daemon with/without signal) the AC
> procedure can be managed in userspace without real pain.
I seriously doubt this statement.
define 'real pain'.
> But especially with
> less pain than putting the AC process into kernelspace and provide your
> suggested socket API with bind/connect/... in very different manners.
* You're only counting LOC in kernel, and not in userspace.
* The constructs you present create some kind of infrastructure. You will
  need a torough documentation of the 'good practice' since that's crucial
  to the correct operation of the stack. Did you ever consider the impact
  on the userspace application side.
  Remember that userspace programs should be easy to write.
  I found your proposals impact application development very hard.


I still think my passive support in kernel performs better and gives an
easier API to get things done with.

I have it all operating, both embedded and on dual-core 64bit system.
I need to git pull the latest updates, and I'll send a revised patchset
tomorrow.

Kind regards,
Kurt

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC v3 5/6] j1939: rename NAME to UUID?
       [not found]                     ` <20110420072439.GB332-ozGf4kBk5synFtIcQ8t7k3L8HoS0Hn3T@public.gmane.org>
@ 2011-04-20 10:59                       ` Oliver Hartkopp
       [not found]                         ` <4DAEBC94.5020009-fJ+pQTUTwRTk1uMJSBkQmQ@public.gmane.org>
  2011-04-22 14:18                       ` Kurt Van Dijck
  1 sibling, 1 reply; 30+ messages in thread
From: Oliver Hartkopp @ 2011-04-20 10:59 UTC (permalink / raw)
  To: Kurt Van Dijck
  Cc: socketcan-core-0fE9KPoRgkgATYTw5x5z8w, netdev-u79uwXL29TY76Z2rM5mHXA

On 20.04.2011 09:24, Kurt Van Dijck wrote:
> On Fri, Apr 15, 2011 at 07:57:25PM +0200, Oliver Hartkopp wrote:
>> On 13.04.2011 06:49, Kurt Van Dijck wrote:
>>> Oliver et.al.,
>>
>> Thinking about the approach to implement the j1939 address claiming (AC) in
>> userspace, i discovered two ways which could both be hidden inside some
>> easy-to-use helper functions:
>>
>> 1. implement a thread (e.g. within a library) which opens a CAN_RAW socket on
>> a specific CAN-interface and takes care of the AC procedure and monitors
>> ongoing AC procedures on the bus. In this case every j1939 application
>> requiring AC internally would monitor all the AC handling on itself (which
>> should be no general problem - written only once).
>>
>> 2. create j1939ac daemon(s) using PF_UNIX-sockets to be named e.g.
>> j1939ac_can0, j1939ac_can1, etc. - these daemons take care for all AC
>> requirements of the host it is running on. The PF_UNIX-sockets are used in
>> SOCK_DGRAM mode and only the j1939 processes that need AC can then register
>> their NAME by sending a request datagram, and get back the j1939-address once
>> it is claimed (and all the updates on changes). As the j1939ac daemons are
>> running on the same host as the j1939 application processes, optional the
>> process' PID could be provided to the daemon during the registering process,
>> so that the daemon can send a signal to a signal handler of the application
>> process (if you would like to omit the select() syscall to handle both the
>> j1939 and PF_UNIX sockets).
>>
>> ->   <Req><Name="A3B5667799332242" PID="12345">
>> <-   <Resp><ACState="claimed" Name="A3B5667799332242" Address="1B">
>> (some time)
>> <-   <Resp><ACState="changed" Name="A3B5667799332242" Address="1C">
>>
>> This is a sketch that could be put into simple C-structs that are sent via the
>> PF_UNIX DGRAM socket.
>>
>> In all suggested cases (using a thread, daemon with/without signal) the AC
>> procedure can be managed in userspace without real pain.
> I seriously doubt this statement.
> define 'real pain'.

The same pain as writing a DNS or DHCP daemon which is doing a similar job ...

>> But especially with
>> less pain than putting the AC process into kernelspace and provide your
>> suggested socket API with bind/connect/... in very different manners.
> * You're only counting LOC in kernel, and not in userspace.

Yes! Things that can be left out of the kernel, should be implemented and
maintained in userspace - at least to reduce complexity and potential security
issues.

> * The constructs you present create some kind of infrastructure. You will
>   need a torough documentation of the 'good practice' since that's crucial
>   to the correct operation of the stack. Did you ever consider the impact
>   on the userspace application side.

Yes.

>   Remember that userspace programs should be easy to write.
>   I found your proposals impact application development very hard.

define 'very hard' ;-)

> I still think my passive support in kernel performs better and gives an
> easier API to get things done with.

Kurt, the problem for me is, that you constantly state that your approach is
the best. For me it is not.

The major issue in your implementation is the lack of the possibility to
simulate several j1939 ECUs on one Linux host talking to each other via
virtual CAN busses to create a complete j1939 network. And so far you did not
address this request.

There are several j1939 implementations that are running (or can be made
running) completely in userspace using raw-sockets. Obviously many people are
convenient with these implementations.

I'm fine to place the j1939 data transfer part (supporting the segmented
transfer of long j1939 PDUs) into the kernel - but not all the address
claiming and the binding of j1939 addresses to network interfaces that also
kills the requested feature of simulating a complete j1939 network.

As an amicable approach i would suggest to proceed in two steps:

1. post and mainline the j1939 bits that deal with the data transfer only
   - no address claiming / j1939 name handling
   - no binding of j1939 addresses to CAN network devices
   - no extensions in the current af_can.c
   - etc.

2. discuss the implementation of the (optional) j1939 address claiming

For me this approach makes sense for j1939 newbies and also experienced j1939
users that may become interested in the Linux mainline implementation.

Then - discussing with a larger number of potential and real j1939 users - we
should face the address claiming and its possible implementation options.

Best regards,
Oliver

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC v3 5/6] j1939: rename NAME to UUID?
       [not found]                         ` <4DAEBC94.5020009-fJ+pQTUTwRTk1uMJSBkQmQ@public.gmane.org>
@ 2011-04-21  6:54                           ` Kurt Van Dijck
  0 siblings, 0 replies; 30+ messages in thread
From: Kurt Van Dijck @ 2011-04-21  6:54 UTC (permalink / raw)
  To: Oliver Hartkopp
  Cc: socketcan-core-0fE9KPoRgkgATYTw5x5z8w, netdev-u79uwXL29TY76Z2rM5mHXA

> 
> Kurt, the problem for me is, that you constantly state that your approach is
> the best. For me it is not.
no userspace counterpart can handle transient conditions like kernel can...
> 
> The major issue in your implementation is the lack of the possibility to
> simulate several j1939 ECUs on one Linux host talking to each other via
> virtual CAN busses to create a complete j1939 network. And so far you did not
> address this request.
Oliver,
I tried to explain already several times that this stack _IS_ capable
of having several j1939 ECU's on one linux host, talking to any CAN bus, virtual
or physical.
I agree that if this was not the case, your arguments would have been valid.

The major improvement (IMHO) of my in-kernel j1939 stack is that several
applications can also contribute to the same ECU, without protocol violations.

side note: this is not even a matter introduced with address claiming :-0
> 

ever done this?
$ ip addr add 192.168.0.1/24 dev eth0
$ ip addr add 192.168.1.1/24 dev eth0

Likewise I do now:
$ ip addr add j1939 0x20 dev can0
$ ip addr add j1939 0x21 dev can0

I see no problem there.

With address claiming:
$ ip addr add j1939 name 0123456789ABCDE0 dev can0
$ ip addr add j1939 name 0123456789ABCDE1 dev can0
and my daemon to choose addresses (posted later today on can-utils)

$ jacd --range 0x20-0x30 0123456789ABCDE0 can0
$ jacd --range 0x20-0x30 0123456789ABCDE1 can0

No, no typos here. both ECU's will resolve conflicts on CAN, on the same host!
The second will ECU will finally get 0x21, _as should be_ per J1939.

Oliver,
The way I understand your request, this addressed that. What did I miss up to here?

I skipped a lot of your original email since the issue addressed here seems to
be source of misunderstanding.

Kind regards,
Kurt

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC v3 5/6] j1939: rename NAME to UUID?
       [not found]                     ` <20110420072439.GB332-ozGf4kBk5synFtIcQ8t7k3L8HoS0Hn3T@public.gmane.org>
  2011-04-20 10:59                       ` Oliver Hartkopp
@ 2011-04-22 14:18                       ` Kurt Van Dijck
       [not found]                         ` <20110422141832.GB334-ozGf4kBk5synFtIcQ8t7k3L8HoS0Hn3T@public.gmane.org>
  1 sibling, 1 reply; 30+ messages in thread
From: Kurt Van Dijck @ 2011-04-22 14:18 UTC (permalink / raw)
  To: Oliver Hartkopp, socketcan-core-0fE9KPoRgkgATYTw5x5z8w,
	netdev-u79uwXL29TY76Z2rM5mHXA

On Wed, Apr 20, 2011 at 09:24:39AM +0200, Kurt Van Dijck wrote:
> I need to git pull the latest updates, and I'll send a revised patchset
> tomorrow.
Oliver,

I did not forget, but something came in between. next week for sure.

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC v3 5/6] j1939: rename NAME to UUID?
       [not found]                         ` <20110422141832.GB334-ozGf4kBk5synFtIcQ8t7k3L8HoS0Hn3T@public.gmane.org>
@ 2011-04-22 15:14                           ` Oliver Hartkopp
       [not found]                             ` <4DB19B46.4000306-fJ+pQTUTwRTk1uMJSBkQmQ@public.gmane.org>
  0 siblings, 1 reply; 30+ messages in thread
From: Oliver Hartkopp @ 2011-04-22 15:14 UTC (permalink / raw)
  To: Kurt Van Dijck
  Cc: socketcan-core-0fE9KPoRgkgATYTw5x5z8w, netdev-u79uwXL29TY76Z2rM5mHXA

On 22.04.2011 16:18, Kurt Van Dijck wrote:
> On Wed, Apr 20, 2011 at 09:24:39AM +0200, Kurt Van Dijck wrote:
>> I need to git pull the latest updates, and I'll send a revised patchset
>> tomorrow.
> Oliver,
> 
> I did not forget, but something came in between. next week for sure.

Oh, no problem.

I'm constantly working on my reply to your latest answer 8-)

BTW: Do you have any sample code that shows, how the sending (and receiving)
of the same BAM message would look like in the static and in the
address-claimed case?? I'm not really able to extract this information from
your posted documentation.

I would like to know

- what has to be configured before (from the user and the admin)
- how does the application source code look like in the requested four cases

I think we're a bit stuck in the discussion of the 'easy to use' socket API
without having real-world examples.

Thanks,
Oliver

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC v3 5/6] j1939: rename NAME to UUID?
       [not found]                             ` <4DB19B46.4000306-fJ+pQTUTwRTk1uMJSBkQmQ@public.gmane.org>
@ 2011-04-23  5:51                               ` Kurt Van Dijck
  0 siblings, 0 replies; 30+ messages in thread
From: Kurt Van Dijck @ 2011-04-23  5:51 UTC (permalink / raw)
  To: Oliver Hartkopp
  Cc: socketcan-core-0fE9KPoRgkgATYTw5x5z8w, netdev-u79uwXL29TY76Z2rM5mHXA

On Fri, Apr 22, 2011 at 05:14:14PM +0200, Oliver Hartkopp wrote:
> On 22.04.2011 16:18, Kurt Van Dijck wrote:
> > On Wed, Apr 20, 2011 at 09:24:39AM +0200, Kurt Van Dijck wrote:
> >> I need to git pull the latest updates, and I'll send a revised patchset
> >> tomorrow.
> > Oliver,
> > 
> > I did not forget, but something came in between. next week for sure.
> 
> Oh, no problem.
> 
> I'm constantly working on my reply to your latest answer 8-)
> 
> BTW: Do you have any sample code that shows, how the sending (and receiving)
> of the same BAM message would look like in the static and in the
> address-claimed case?? I'm not really able to extract this information from
> your posted documentation.
> 
> I would like to know
> 
> - what has to be configured before (from the user and the admin)
> - how does the application source code look like in the requested four cases
> 
> I think we're a bit stuck in the discussion of the 'easy to use' socket API
> without having real-world examples.
ack.

Since I think I got the stack stable now (and some LOC dropped), I agree that
'simple' real-world examples may document a lot.

> 
> Thanks,
> Oliver
Kurt

^ permalink raw reply	[flat|nested] 30+ messages in thread

end of thread, other threads:[~2011-04-23  5:51 UTC | newest]

Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-03-14 13:20 [RFC v3 0/6] CAN: add SAE J1939 protocol Kurt Van Dijck
     [not found] ` <20110314132004.GA333-MxZ6Iy/zr/UdbCeoMzGj59i2O/JbrIOy@public.gmane.org>
2011-03-14 13:24   ` [RFC v3 1/6] can: extend sockaddr_can to include j1939 members Kurt Van Dijck
2011-03-14 14:15     ` Eric Dumazet
2011-03-14 14:53       ` Kurt Van Dijck
2011-03-14 13:26   ` [RFC v3 2/6] can: add rtnetlink support Kurt Van Dijck
2011-03-14 13:47   ` [RFC v3 3/6] can: make struct proto const Kurt Van Dijck
2011-03-14 14:09     ` Eric Dumazet
2011-03-14 15:02       ` Kurt Van Dijck
2011-03-14 16:42         ` Eric Dumazet
2011-03-14 17:17           ` Kurt Van Dijck
2011-03-15 21:28             ` Oliver Hartkopp
     [not found]               ` <4D7FD9ED.1080004-fJ+pQTUTwRTk1uMJSBkQmQ@public.gmane.org>
2011-03-15 22:12                 ` Kurt Van Dijck
2011-03-15 22:19               ` Eric Dumazet
2011-03-14 13:56   ` [RFC v3 4/6] j1939: initial import of SAE J1939 Kurt Van Dijck
2011-03-14 13:59   ` [RFC v3 5/6] j1939: add documentation and MAINTAINERS Kurt Van Dijck
     [not found]     ` <20110314135917.GF333-MxZ6Iy/zr/UdbCeoMzGj59i2O/JbrIOy@public.gmane.org>
2011-03-20 15:56       ` Oliver Hartkopp
     [not found]         ` <4D8623BE.2080807-fJ+pQTUTwRTk1uMJSBkQmQ@public.gmane.org>
2011-03-25 13:55           ` Kurt Van Dijck
2011-03-29 14:29           ` SAE J1939: update Kurt Van Dijck
2011-03-29 19:41             ` Oliver Hartkopp
2011-04-13  4:49           ` [RFC v3 5/6] j1939: rename NAME to UUID? Kurt Van Dijck
     [not found]             ` <20110413044928.GA289-ozGf4kBk5synFtIcQ8t7k3L8HoS0Hn3T@public.gmane.org>
2011-04-15 17:57               ` Oliver Hartkopp
     [not found]                 ` <4DA88705.5040203-fJ+pQTUTwRTk1uMJSBkQmQ@public.gmane.org>
2011-04-20  7:10                   ` Kurt Van Dijck
2011-04-20  7:24                   ` Kurt Van Dijck
     [not found]                     ` <20110420072439.GB332-ozGf4kBk5synFtIcQ8t7k3L8HoS0Hn3T@public.gmane.org>
2011-04-20 10:59                       ` Oliver Hartkopp
     [not found]                         ` <4DAEBC94.5020009-fJ+pQTUTwRTk1uMJSBkQmQ@public.gmane.org>
2011-04-21  6:54                           ` Kurt Van Dijck
2011-04-22 14:18                       ` Kurt Van Dijck
     [not found]                         ` <20110422141832.GB334-ozGf4kBk5synFtIcQ8t7k3L8HoS0Hn3T@public.gmane.org>
2011-04-22 15:14                           ` Oliver Hartkopp
     [not found]                             ` <4DB19B46.4000306-fJ+pQTUTwRTk1uMJSBkQmQ@public.gmane.org>
2011-04-23  5:51                               ` Kurt Van Dijck
2011-03-14 14:05   ` [RFC v3 6/6] iproute2: add CAN and J1939 rtnetlink support Kurt Van Dijck
2011-03-15  9:23   ` [RFC v3 0/6] CAN: add SAE J1939 protocol Kurt Van Dijck

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).