diff options
Diffstat (limited to 'net/can/af_can.c')
| -rw-r--r-- | net/can/af_can.c | 36 | 
1 files changed, 29 insertions, 7 deletions
diff --git a/net/can/af_can.c b/net/can/af_can.c index 3ab8dd2e128..ce82337521f 100644 --- a/net/can/af_can.c +++ b/net/can/af_can.c @@ -57,6 +57,7 @@  #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> @@ -290,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;  		} @@ -337,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 @@ -399,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]; @@ -420,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 @@ -631,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, &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++;  | 
