数据结构
CAN数据接收链表dev_rcv_lists
CAN核心为每个CAN类型网络设备都关联一个该链表对象(表头为can_rx_dev_list),用于保存所有对该CAN网络设备数据感兴趣的接收者。
enum { RX_ERR, RX_ALL, RX_FIL, RX_INV, RX_EFF, RX_MAX };
struct dev_rcv_lists {
struct hlist_node list;
struct rcu_head rcu;
struct net_device *dev;
struct hlist_head rx[RX_MAX];
struct hlist_head rx_sff[0x800];
int remove_on_zero_entries;
int entries;
};
CAN数据接收者receiver
struct receiver {
struct hlist_node list;
struct rcu_head rcu;
canid_t can_id;
canid_t mask;
unsigned long matches;
void (*func)(struct sk_buff *, void *);
void *data;
char *ident;
};
CAN帧结构
#define CAN_EFF_FLAG 0x80000000U
#define CAN_RTR_FLAG 0x40000000U
#define CAN_ERR_FLAG 0x20000000U
#define CAN_SFF_MASK 0x000007FFU
#define CAN_EFF_MASK 0x1FFFFFFFU
#define CAN_ERR_MASK 0x1FFFFFFFU
typedef __u32 canid_t;
struct can_frame {
canid_t can_id;
__u8 can_dlc;
__u8 data[8] __attribute__((aligned(8)));
};
对于canid_t的使用主要是在接收过滤器设置和数据接收两个流程中,这里linux做的是比较混乱的,bit0~bit28没有疑问,对应的就是CAN帧中的标识符字段,但是高3bit的使用需要分情况梳理。
接收过滤器设置(can_id和mask两个参数):
- mask参数中这是bit29(CAN_ERR_FLAG)代表要监听错误帧;
- can_id参数中设置bit29(CAN_INV_FILTER)代表匹配结果要取反;
- mask的bit0~bit28都为0,表示不做过滤全匹配;
接收流程
接收者列表维护
CAN核心仅仅对接收到的CAN帧进行分发,分发过程就是围绕上面提到的can_rx_dev_list链表进行的。
在模块初始化时,CAN核心向网络设备管理层注册了notifier,对应的接收函数为can_notifier()。
static int can_notifier(struct notifier_block *nb, unsigned long msg, void *data)
{
struct net_device *dev = (struct net_device *)data;
struct dev_rcv_lists *d;
if (!net_eq(dev_net(dev), &init_net))
return NOTIFY_DONE;
if (dev->type != ARPHRD_CAN)
return NOTIFY_DONE;
switch (msg) {
case NETDEV_REGISTER:
d = kzalloc(sizeof(*d), GFP_KERNEL);
if (!d) {
printk(KERN_ERR
"can: allocation of receive list failed\n");
return NOTIFY_DONE;
}
d->dev = dev;
spin_lock(&can_rcvlists_lock);
hlist_add_head_rcu(&d->list, &can_rx_dev_list);
spin_unlock(&can_rcvlists_lock);
break;
case NETDEV_UNREGISTER:
spin_lock(&can_rcvlists_lock);
d = find_dev_rcv_lists(dev);
if (d) {
if (d->entries) {
d->remove_on_zero_entries = 1;
d = NULL;
} else
hlist_del_rcu(&d->list);
} else
printk(KERN_ERR "can: notifier: receive list not "
"found for dev %s\n", dev->name);
spin_unlock(&can_rcvlists_lock);
if (d)
call_rcu(&d->rcu, can_rx_delete_device);
break;
}
return NOTIFY_DONE;
}
CAN核心为每个CAN类型的网络设备都维护了一个dev_rcv_lists链表对象。有了链表对象,需要向链表对象中注册接收者才能完成数据包的分发,注册接口为can_rx_register(),当然对应的也有can_rx_unregister()接口。
int can_rx_register(struct net_device *dev, canid_t can_id, canid_t mask,
void (*func)(struct sk_buff *, void *), void *data, char *ident)
{
struct receiver *r;
struct hlist_head *rl;
struct dev_rcv_lists *d;
int err = 0;
r = kmem_cache_alloc(rcv_cache, GFP_KERNEL);
if (!r)
return -ENOMEM;
spin_lock(&can_rcvlists_lock);
d = find_dev_rcv_lists(dev);
if (d) {
rl = find_rcv_list(&can_id, &mask, d);
r->can_id = can_id;
r->mask = mask;
r->matches = 0;
r->func = func;
r->data = data;
r->ident = ident;
hlist_add_head_rcu(&r->list, rl);
d->entries++;
can_pstats.rcv_entries++;
if (can_pstats.rcv_entries_max < can_pstats.rcv_entries)
can_pstats.rcv_entries_max = can_pstats.rcv_entries;
} else {
kmem_cache_free(rcv_cache, r);
err = -ENODEV;
}
spin_unlock(&can_rcvlists_lock);
return err;
}
find_rcv_list()
static struct hlist_head *find_rcv_list(canid_t *can_id, canid_t *mask,
struct dev_rcv_lists *d)
{
canid_t inv = *can_id & CAN_INV_FILTER;
if (*mask & CAN_ERR_FLAG) {
*mask &= CAN_ERR_MASK;
return &d->rx[RX_ERR];
}
#define CAN_EFF_RTR_FLAGS (CAN_EFF_FLAG | CAN_RTR_FLAG)
if ((*mask & CAN_EFF_FLAG) && !(*can_id & CAN_EFF_FLAG))
*mask &= (CAN_SFF_MASK | CAN_EFF_RTR_FLAGS);
*can_id &= *mask;
if (inv)
return &d->rx[RX_INV];
if (!(*mask))
return &d->rx[RX_ALL];
if (((*mask & CAN_EFF_RTR_FLAGS) == CAN_EFF_RTR_FLAGS) && !(*can_id & CAN_RTR_FLAG)) {
if (*can_id & CAN_EFF_FLAG) {
if (*mask == (CAN_EFF_MASK | CAN_EFF_RTR_FLAGS)) {
return &d->rx[RX_EFF];
}
} else {
if (*mask == (CAN_SFF_MASK | CAN_EFF_RTR_FLAGS))
return &d->rx_sff[*can_id];
}
}
return &d->rx[RX_FIL];
}
CAN核心收到数据can_rcv()
在模块初始化时,CAN核心向网络设备接口层注册了数据包接收接口can_rcv()。can_rcv()就是根据网络设备找到其对应的dev_rcv_lists链表,然后根据匹配规则,将skb分发给接收者。
static struct packet_type can_packet __read_mostly = {
.type = __constant_htons(ETH_P_CAN),
.dev = NULL,
.func = can_rcv,
};
static int can_rcv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *pt, struct net_device *orig_dev)
{
struct dev_rcv_lists *d;
struct can_frame *cf = (struct can_frame *)skb->data;
int matches;
if (dev->type != ARPHRD_CAN || !net_eq(dev_net(dev), &init_net)) {
kfree_skb(skb);
return 0;
}
BUG_ON(skb->len != sizeof(struct can_frame) || cf->can_dlc > 8);
can_stats.rx_frames++;
can_stats.rx_frames_delta++;
rcu_read_lock();
matches = can_rcv_filter(&can_rx_alldev_list, skb);
d = find_dev_rcv_lists(dev);
if (d)
matches += can_rcv_filter(d, skb);
rcu_read_unlock();
kfree_skb(skb);
if (matches > 0) {
can_stats.matches++;
can_stats.matches_delta++;
}
return 0;
}
CAN核心分发接收数据: can_rcv_filter()
static inline void deliver(struct sk_buff *skb, struct receiver *r)
{
r->func(skb, r->data);
r->matches++;
}
static int can_rcv_filter(struct dev_rcv_lists *d, struct sk_buff *skb)
{
struct receiver *r;
struct hlist_node *n;
int matches = 0;
struct can_frame *cf = (struct can_frame *)skb->data;
canid_t can_id = cf->can_id;
if (d->entries == 0)
return 0;
if (can_id & CAN_ERR_FLAG) {
hlist_for_each_entry_rcu(r, n, &d->rx[RX_ERR], list) {
if (can_id & r->mask) {
deliver(skb, r);
matches++;
}
}
return matches;
}
hlist_for_each_entry_rcu(r, n, &d->rx[RX_ALL], list) {
deliver(skb, r);
matches++;
}
hlist_for_each_entry_rcu(r, n, &d->rx[RX_FIL], list) {
if ((can_id & r->mask) == r->can_id) {
deliver(skb, r);
matches++;
}
}
hlist_for_each_entry_rcu(r, n, &d->rx[RX_INV], list) {
if ((can_id & r->mask) != r->can_id) {
deliver(skb, r);
matches++;
}
}
if (can_id & CAN_RTR_FLAG)
return matches;
if (can_id & CAN_EFF_FLAG) {
hlist_for_each_entry_rcu(r, n, &d->rx[RX_EFF], list) {
if (r->can_id == can_id) {
deliver(skb, r);
matches++;
}
}
} else {
can_id &= CAN_SFF_MASK;
hlist_for_each_entry_rcu(r, n, &d->rx_sff[can_id], list) {
deliver(skb, r);
matches++;
}
}
return matches;
}
至此数据就交给了BCM等传输协议了。
发送流程
上层协议组织好CAN帧后,调用CAN核心的can_send()将数据包发送出去。
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;
if (skb->len != sizeof(struct can_frame) || cf->can_dlc > 8) {
kfree_skb(skb);
return -EINVAL;
}
if (skb->dev->type != ARPHRD_CAN) {
kfree_skb(skb);
return -EPERM;
}
if (!(skb->dev->flags & IFF_UP)) {
kfree_skb(skb);
return -ENETDOWN;
}
skb->protocol = htons(ETH_P_CAN);
skb_reset_network_header(skb);
skb_reset_transport_header(skb);
if (loop) {
skb->pkt_type = PACKET_LOOPBACK;
if (!(skb->dev->flags & IFF_ECHO)) {
newskb = skb_clone(skb, GFP_ATOMIC);
if (!newskb) {
kfree_skb(skb);
return -ENOMEM;
}
newskb->sk = skb->sk;
newskb->ip_summed = CHECKSUM_UNNECESSARY;
newskb->pkt_type = PACKET_BROADCAST;
}
} else {
skb->pkt_type = PACKET_HOST;
}
err = dev_queue_xmit(skb);
if (err > 0)
err = net_xmit_errno(err);
if (err) {
if (newskb)
kfree_skb(newskb);
return err;
}
if (newskb)
netif_rx(newskb);
can_stats.tx_frames++;
can_stats.tx_frames_delta++;
return 0;
}
|