diff options
Diffstat (limited to 'net/can/af_can.c')
| -rw-r--r-- | net/can/af_can.c | 299 | 
1 files changed, 193 insertions, 106 deletions
diff --git a/net/can/af_can.c b/net/can/af_can.c index 702be5a2c95..ce82337521f 100644 --- a/net/can/af_can.c +++ b/net/can/af_can.c @@ -38,11 +38,10 @@   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH   * DAMAGE.   * - * Send feedback to <socketcan-users@lists.berlios.de> - *   */  #include <linux/module.h> +#include <linux/stddef.h>  #include <linux/init.h>  #include <linux/kmod.h>  #include <linux/slab.h> @@ -58,12 +57,14 @@  #include <linux/skbuff.h>  #include <linux/can.h>  #include <linux/can/core.h> +#include <linux/can/skb.h> +#include <linux/ratelimit.h>  #include <net/net_namespace.h>  #include <net/sock.h>  #include "af_can.h" -static __initdata const char banner[] = KERN_INFO +static __initconst const char banner[] = KERN_INFO  	"can: controller area network core (" CAN_VERSION_STRING ")\n";  MODULE_DESCRIPTION("Controller Area Network PF_CAN core"); @@ -84,8 +85,8 @@ 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 DEFINE_SPINLOCK(proto_tab_lock); +static const struct can_proto *proto_tab[CAN_NPROTO] __read_mostly; +static DEFINE_MUTEX(proto_tab_lock);  struct timer_list can_stattimer;   /* timer for statistics update */  struct s_stats    can_stats;       /* packet statistics */ @@ -95,7 +96,7 @@ struct s_pstats   can_pstats;      /* receive list statistics */   * af_can socket functions   */ -static int can_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) +int can_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)  {  	struct sock *sk = sock->sk; @@ -108,17 +109,36 @@ static int can_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)  		return -ENOIOCTLCMD;  	}  } +EXPORT_SYMBOL(can_ioctl);  static void can_sock_destruct(struct sock *sk)  {  	skb_queue_purge(&sk->sk_receive_queue);  } +static const struct can_proto *can_get_proto(int protocol) +{ +	const struct can_proto *cp; + +	rcu_read_lock(); +	cp = rcu_dereference(proto_tab[protocol]); +	if (cp && !try_module_get(cp->prot->owner)) +		cp = NULL; +	rcu_read_unlock(); + +	return cp; +} + +static inline void can_put_proto(const struct can_proto *cp) +{ +	module_put(cp->prot->owner); +} +  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; @@ -129,9 +149,12 @@ static int can_create(struct net *net, struct socket *sock, int protocol,  	if (!net_eq(net, &init_net))  		return -EAFNOSUPPORT; +	cp = can_get_proto(protocol); +  #ifdef CONFIG_MODULES -	/* try to load protocol module kernel is modular */ -	if (!proto_tab[protocol]) { +	if (!cp) { +		/* try to load protocol module if kernel is modular */ +  		err = request_module("can-proto-%d", protocol);  		/* @@ -139,25 +162,21 @@ static int can_create(struct net *net, struct socket *sock, int protocol,  		 * return the error code immediately.  Below we will  		 * return -EPROTONOSUPPORT  		 */ -		if (err && printk_ratelimit()) -			printk(KERN_ERR "can: request_module " +		if (err) +			printk_ratelimited(KERN_ERR "can: request_module "  			       "(can-proto-%d) failed.\n", protocol); + +		cp = can_get_proto(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); -  	/* check for available protocol and correct usage */  	if (!cp)  		return -EPROTONOSUPPORT;  	if (cp->type != sock->type) { -		err = -EPROTONOSUPPORT; +		err = -EPROTOTYPE;  		goto errout;  	} @@ -182,7 +201,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;  } @@ -203,30 +222,46 @@ static int can_create(struct net *net, struct socket *sock, int protocol,   *  -ENOBUFS on full driver queue (see net_xmit_errno())   *  -ENOMEM when local loopback failed at calling skb_clone()   *  -EPERM when trying to send on a non-CAN interface + *  -EMSGSIZE CAN frame size is bigger than CAN interface MTU   *  -EINVAL when the skb->data does not contain a valid CAN frame   */  int can_send(struct sk_buff *skb, int loop)  {  	struct sk_buff *newskb = NULL; -	struct can_frame *cf = (struct can_frame *)skb->data; -	int err; +	struct canfd_frame *cfd = (struct canfd_frame *)skb->data; +	int err = -EINVAL; + +	if (skb->len == CAN_MTU) { +		skb->protocol = htons(ETH_P_CAN); +		if (unlikely(cfd->len > CAN_MAX_DLEN)) +			goto inval_skb; +	} else if (skb->len == CANFD_MTU) { +		skb->protocol = htons(ETH_P_CANFD); +		if (unlikely(cfd->len > CANFD_MAX_DLEN)) +			goto inval_skb; +	} else +		goto inval_skb; -	if (skb->len != sizeof(struct can_frame) || cf->can_dlc > 8) { -		kfree_skb(skb); -		return -EINVAL; +	/* +	 * Make sure the CAN frame can pass the selected CAN netdevice. +	 * As structs can_frame and canfd_frame are similar, we can provide +	 * CAN FD frames to legacy CAN drivers as long as the length is <= 8 +	 */ +	if (unlikely(skb->len > skb->dev->mtu && cfd->len > CAN_MAX_DLEN)) { +		err = -EMSGSIZE; +		goto inval_skb;  	} -	if (skb->dev->type != ARPHRD_CAN) { -		kfree_skb(skb); -		return -EPERM; +	if (unlikely(skb->dev->type != ARPHRD_CAN)) { +		err = -EPERM; +		goto inval_skb;  	} -	if (!(skb->dev->flags & IFF_UP)) { -		kfree_skb(skb); -		return -ENETDOWN; +	if (unlikely(!(skb->dev->flags & IFF_UP))) { +		err = -ENETDOWN; +		goto inval_skb;  	} -	skb->protocol = htons(ETH_P_CAN);  	skb_reset_network_header(skb);  	skb_reset_transport_header(skb); @@ -256,7 +291,7 @@ int can_send(struct sk_buff *skb, int loop)  				return -ENOMEM;  			} -			newskb->sk = skb->sk; +			can_skb_set_owner(newskb, skb->sk);  			newskb->ip_summed = CHECKSUM_UNNECESSARY;  			newskb->pkt_type = PACKET_BROADCAST;  		} @@ -283,6 +318,10 @@ int can_send(struct sk_buff *skb, int loop)  	can_stats.tx_frames_delta++;  	return 0; + +inval_skb: +	kfree_skb(skb); +	return err;  }  EXPORT_SYMBOL(can_send); @@ -299,6 +338,29 @@ static struct dev_rcv_lists *find_dev_rcv_lists(struct net_device *dev)  }  /** + * effhash - hash function for 29 bit CAN identifier reduction + * @can_id: 29 bit CAN identifier + * + * Description: + *  To reduce the linear traversal in one linked list of _single_ EFF CAN + *  frame subscriptions the 29 bit identifier is mapped to 10 bits. + *  (see CAN_EFF_RCV_HASH_BITS definition) + * + * Return: + *  Hash value from 0x000 - 0x3FF ( enforced by CAN_EFF_RCV_HASH_BITS mask ) + */ +static unsigned int effhash(canid_t can_id) +{ +	unsigned int hash; + +	hash = can_id; +	hash ^= can_id >> CAN_EFF_RCV_HASH_BITS; +	hash ^= can_id >> (2 * CAN_EFF_RCV_HASH_BITS); + +	return hash & ((1 << CAN_EFF_RCV_HASH_BITS) - 1); +} + +/**   * find_rcv_list - determine optimal filterlist inside device filter struct   * @can_id: pointer to CAN identifier of a given can_filter   * @mask: pointer to CAN mask of a given can_filter @@ -317,8 +379,8 @@ static struct dev_rcv_lists *find_dev_rcv_lists(struct net_device *dev)   *  relevant bits for the filter.   *   *  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). For error frames - *  there is a special filterlist and a special rx path filter handling. + *  filter for error messages (CAN_ERR_FLAG bit set in mask). For error msg + *  frames there is a special filterlist and a special rx path filter handling.   *   * Return:   *  Pointer to optimal filterlist for the given can_id/mask pair. @@ -330,7 +392,7 @@ static struct hlist_head *find_rcv_list(canid_t *can_id, canid_t *mask,  {  	canid_t inv = *can_id & CAN_INV_FILTER; /* save flag before masking */ -	/* filter for error frames in extra filterlist */ +	/* filter for error message frames in extra filterlist */  	if (*mask & CAN_ERR_FLAG) {  		/* clear CAN_ERR_FLAG in filter entry */  		*mask &= CAN_ERR_MASK; @@ -361,10 +423,8 @@ static struct hlist_head *find_rcv_list(canid_t *can_id, canid_t *mask,  	    !(*can_id & CAN_RTR_FLAG)) {  		if (*can_id & CAN_EFF_FLAG) { -			if (*mask == (CAN_EFF_MASK | CAN_EFF_RTR_FLAGS)) { -				/* RFC: a future use-case for hash-tables? */ -				return &d->rx[RX_EFF]; -			} +			if (*mask == (CAN_EFF_MASK | CAN_EFF_RTR_FLAGS)) +				return &d->rx_eff[effhash(*can_id)];  		} else {  			if (*mask == (CAN_SFF_MASK | CAN_EFF_RTR_FLAGS))  				return &d->rx_sff[*can_id]; @@ -382,7 +442,7 @@ static struct hlist_head *find_rcv_list(canid_t *can_id, canid_t *mask,   * @mask: CAN mask (see description)   * @func: callback function on filter match   * @data: returned parameter for callback function - * @ident: string for calling module indentification + * @ident: string for calling module identification   *   * Description:   *  Invokes the callback function with the received sk_buff and the given @@ -391,7 +451,7 @@ static struct hlist_head *find_rcv_list(canid_t *can_id, canid_t *mask,   *          <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). + *  filter for error message frames (CAN_ERR_FLAG bit set in mask).   *   *  The provided pointer to the sk_buff is guaranteed to be valid as long as   *  the callback function is running. The callback function must *not* free @@ -478,7 +538,6 @@ void can_rx_unregister(struct net_device *dev, canid_t can_id, canid_t mask,  {  	struct receiver *r = NULL;  	struct hlist_head *rl; -	struct hlist_node *next;  	struct dev_rcv_lists *d;  	if (dev && dev->type != ARPHRD_CAN) @@ -488,7 +547,7 @@ void can_rx_unregister(struct net_device *dev, canid_t can_id, canid_t mask,  	d = find_dev_rcv_lists(dev);  	if (!d) { -		printk(KERN_ERR "BUG: receive list not found for " +		pr_err("BUG: receive list not found for "  		       "dev %s, id %03X, mask %03X\n",  		       DNAME(dev), can_id, mask);  		goto out; @@ -502,23 +561,20 @@ void can_rx_unregister(struct net_device *dev, canid_t can_id, canid_t mask,  	 * been registered before.  	 */ -	hlist_for_each_entry_rcu(r, next, rl, list) { +	hlist_for_each_entry_rcu(r, rl, list) {  		if (r->can_id == can_id && r->mask == mask &&  		    r->func == func && r->data == data)  			break;  	}  	/* -	 * Check for bugs in CAN protocol implementations: -	 * If no matching list item was found, the list cursor variable next -	 * will be NULL, while r will point to the last item of the list. +	 * Check for bugs in CAN protocol implementations using af_can.c: +	 * 'r' will be NULL if no matching list item was found for removal.  	 */ -	if (!next) { -		printk(KERN_ERR "BUG: receive list entry not found for " -		       "dev %s, id %03X, mask %03X\n", -		       DNAME(dev), can_id, mask); -		r = NULL; +	if (!r) { +		WARN(1, "BUG: receive list entry not found for dev %s, " +		     "id %03X, mask %03X\n", DNAME(dev), can_id, mask);  		goto out;  	} @@ -552,7 +608,6 @@ static inline void deliver(struct sk_buff *skb, struct receiver *r)  static int can_rcv_filter(struct dev_rcv_lists *d, struct sk_buff *skb)  {  	struct receiver *r; -	struct hlist_node *n;  	int matches = 0;  	struct can_frame *cf = (struct can_frame *)skb->data;  	canid_t can_id = cf->can_id; @@ -561,8 +616,8 @@ static int can_rcv_filter(struct dev_rcv_lists *d, struct sk_buff *skb)  		return 0;  	if (can_id & CAN_ERR_FLAG) { -		/* check for error frame entries only */ -		hlist_for_each_entry_rcu(r, n, &d->rx[RX_ERR], list) { +		/* check for error message frame entries only */ +		hlist_for_each_entry_rcu(r, &d->rx[RX_ERR], list) {  			if (can_id & r->mask) {  				deliver(skb, r);  				matches++; @@ -572,13 +627,13 @@ static int can_rcv_filter(struct dev_rcv_lists *d, struct sk_buff *skb)  	}  	/* check for unfiltered entries */ -	hlist_for_each_entry_rcu(r, n, &d->rx[RX_ALL], list) { +	hlist_for_each_entry_rcu(r, &d->rx[RX_ALL], list) {  		deliver(skb, r);  		matches++;  	}  	/* check for can_id/mask entries */ -	hlist_for_each_entry_rcu(r, n, &d->rx[RX_FIL], list) { +	hlist_for_each_entry_rcu(r, &d->rx[RX_FIL], list) {  		if ((can_id & r->mask) == r->can_id) {  			deliver(skb, r);  			matches++; @@ -586,7 +641,7 @@ static int can_rcv_filter(struct dev_rcv_lists *d, struct sk_buff *skb)  	}  	/* check for inverted can_id/mask entries */ -	hlist_for_each_entry_rcu(r, n, &d->rx[RX_INV], list) { +	hlist_for_each_entry_rcu(r, &d->rx[RX_INV], list) {  		if ((can_id & r->mask) != r->can_id) {  			deliver(skb, r);  			matches++; @@ -598,7 +653,7 @@ static int can_rcv_filter(struct dev_rcv_lists *d, struct sk_buff *skb)  		return matches;  	if (can_id & CAN_EFF_FLAG) { -		hlist_for_each_entry_rcu(r, n, &d->rx[RX_EFF], list) { +		hlist_for_each_entry_rcu(r, &d->rx_eff[effhash(can_id)], list) {  			if (r->can_id == can_id) {  				deliver(skb, r);  				matches++; @@ -606,7 +661,7 @@ static int can_rcv_filter(struct dev_rcv_lists *d, struct sk_buff *skb)  		}  	} else {  		can_id &= CAN_SFF_MASK; -		hlist_for_each_entry_rcu(r, n, &d->rx_sff[can_id], list) { +		hlist_for_each_entry_rcu(r, &d->rx_sff[can_id], list) {  			deliver(skb, r);  			matches++;  		} @@ -615,24 +670,11 @@ static int can_rcv_filter(struct dev_rcv_lists *d, struct sk_buff *skb)  	return matches;  } -static int can_rcv(struct sk_buff *skb, struct net_device *dev, -		   struct packet_type *pt, struct net_device *orig_dev) +static void can_receive(struct sk_buff *skb, struct net_device *dev)  {  	struct dev_rcv_lists *d; -	struct can_frame *cf = (struct can_frame *)skb->data;  	int matches; -	if (!net_eq(dev_net(dev), &init_net)) -		goto drop; - -	if (WARN_ONCE(dev->type != ARPHRD_CAN || -		      skb->len != sizeof(struct can_frame) || -		      cf->can_dlc > 8, -		      "PF_CAN: dropped non conform skbuf: " -		      "dev type %d, len %d, can_dlc %d\n", -		      dev->type, skb->len, cf->can_dlc)) -		goto drop; -  	/* update statistics */  	can_stats.rx_frames++;  	can_stats.rx_frames_delta++; @@ -656,7 +698,49 @@ static int can_rcv(struct sk_buff *skb, struct net_device *dev,  		can_stats.matches++;  		can_stats.matches_delta++;  	} +} + +static int can_rcv(struct sk_buff *skb, struct net_device *dev, +		   struct packet_type *pt, struct net_device *orig_dev) +{ +	struct canfd_frame *cfd = (struct canfd_frame *)skb->data; + +	if (unlikely(!net_eq(dev_net(dev), &init_net))) +		goto drop; +	if (WARN_ONCE(dev->type != ARPHRD_CAN || +		      skb->len != CAN_MTU || +		      cfd->len > CAN_MAX_DLEN, +		      "PF_CAN: dropped non conform CAN skbuf: " +		      "dev type %d, len %d, datalen %d\n", +		      dev->type, skb->len, cfd->len)) +		goto drop; + +	can_receive(skb, dev); +	return NET_RX_SUCCESS; + +drop: +	kfree_skb(skb); +	return NET_RX_DROP; +} + +static int canfd_rcv(struct sk_buff *skb, struct net_device *dev, +		   struct packet_type *pt, struct net_device *orig_dev) +{ +	struct canfd_frame *cfd = (struct canfd_frame *)skb->data; + +	if (unlikely(!net_eq(dev_net(dev), &init_net))) +		goto drop; + +	if (WARN_ONCE(dev->type != ARPHRD_CAN || +		      skb->len != CANFD_MTU || +		      cfd->len > CANFD_MAX_DLEN, +		      "PF_CAN: dropped non conform CAN FD skbuf: " +		      "dev type %d, len %d, datalen %d\n", +		      dev->type, skb->len, cfd->len)) +		goto drop; + +	can_receive(skb, dev);  	return NET_RX_SUCCESS;  drop: @@ -678,14 +762,13 @@ 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;  	if (proto < 0 || proto >= CAN_NPROTO) { -		printk(KERN_ERR "can: protocol number %d out of range\n", -		       proto); +		pr_err("can: protocol number %d out of range\n", proto);  		return -EINVAL;  	} @@ -693,19 +776,15 @@ int can_proto_register(struct can_proto *cp)  	if (err < 0)  		return err; -	spin_lock(&proto_tab_lock); +	mutex_lock(&proto_tab_lock); +  	if (proto_tab[proto]) { -		printk(KERN_ERR "can: protocol %d already registered\n", -		       proto); +		pr_err("can: protocol %d already registered\n", proto);  		err = -EBUSY; -	} else { -		proto_tab[proto] = cp; +	} else +		RCU_INIT_POINTER(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); +	mutex_unlock(&proto_tab_lock);  	if (err < 0)  		proto_unregister(cp->prot); @@ -718,17 +797,16 @@ 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; -	spin_lock(&proto_tab_lock); -	if (!proto_tab[proto]) { -		printk(KERN_ERR "BUG: can: protocol %d is not registered\n", -		       proto); -	} -	proto_tab[proto] = NULL; -	spin_unlock(&proto_tab_lock); +	mutex_lock(&proto_tab_lock); +	BUG_ON(proto_tab[proto] != cp); +	RCU_INIT_POINTER(proto_tab[proto], NULL); +	mutex_unlock(&proto_tab_lock); + +	synchronize_rcu();  	proto_unregister(cp->prot);  } @@ -738,9 +816,9 @@ EXPORT_SYMBOL(can_proto_unregister);   * af_can notifier to create/remove CAN netdevice specific structs   */  static int can_notifier(struct notifier_block *nb, unsigned long msg, -			void *data) +			void *ptr)  { -	struct net_device *dev = (struct net_device *)data; +	struct net_device *dev = netdev_notifier_info_to_dev(ptr);  	struct dev_rcv_lists *d;  	if (!net_eq(dev_net(dev), &init_net)) @@ -755,11 +833,8 @@ static int can_notifier(struct notifier_block *nb, unsigned long msg,  		/* create new dev_rcv_lists for this device */  		d = kzalloc(sizeof(*d), GFP_KERNEL); -		if (!d) { -			printk(KERN_ERR -			       "can: allocation of receive list failed\n"); +		if (!d)  			return NOTIFY_DONE; -		}  		BUG_ON(dev->ml_priv);  		dev->ml_priv = d; @@ -777,8 +852,8 @@ static int can_notifier(struct notifier_block *nb, unsigned long msg,  				dev->ml_priv = NULL;  			}  		} else -			printk(KERN_ERR "can: notifier: receive list not " -			       "found for dev %s\n", dev->name); +			pr_err("can: notifier: receive list not found for dev " +			       "%s\n", dev->name);  		spin_unlock(&can_rcvlists_lock); @@ -794,10 +869,14 @@ static int can_notifier(struct notifier_block *nb, unsigned long msg,  static struct packet_type can_packet __read_mostly = {  	.type = cpu_to_be16(ETH_P_CAN), -	.dev  = NULL,  	.func = can_rcv,  }; +static struct packet_type canfd_packet __read_mostly = { +	.type = cpu_to_be16(ETH_P_CANFD), +	.func = canfd_rcv, +}; +  static const struct net_proto_family can_family_ops = {  	.family = PF_CAN,  	.create = can_create, @@ -811,6 +890,12 @@ static struct notifier_block can_netdev_notifier __read_mostly = {  static __init int can_init(void)  { +	/* check for correct padding to be able to use the structs similarly */ +	BUILD_BUG_ON(offsetof(struct can_frame, can_dlc) != +		     offsetof(struct canfd_frame, len) || +		     offsetof(struct can_frame, data) != +		     offsetof(struct canfd_frame, data)); +  	printk(banner);  	memset(&can_rx_alldev_list, 0, sizeof(can_rx_alldev_list)); @@ -833,6 +918,7 @@ static __init int can_init(void)  	sock_register(&can_family_ops);  	register_netdevice_notifier(&can_netdev_notifier);  	dev_add_pack(&can_packet); +	dev_add_pack(&canfd_packet);  	return 0;  } @@ -842,11 +928,12 @@ static __exit void can_exit(void)  	struct net_device *dev;  	if (stats_timer) -		del_timer(&can_stattimer); +		del_timer_sync(&can_stattimer);  	can_remove_proc();  	/* protocol unregister */ +	dev_remove_pack(&canfd_packet);  	dev_remove_pack(&can_packet);  	unregister_netdevice_notifier(&can_netdev_notifier);  	sock_unregister(PF_CAN); @@ -854,7 +941,7 @@ static __exit void can_exit(void)  	/* remove created dev_rcv_lists from still registered CAN devices */  	rcu_read_lock();  	for_each_netdev_rcu(&init_net, dev) { -		if (dev->type == ARPHRD_CAN && dev->ml_priv){ +		if (dev->type == ARPHRD_CAN && dev->ml_priv) {  			struct dev_rcv_lists *d = dev->ml_priv;  | 
