初始化
static __init int can_init(void)
{
printk(banner);
// 创建接收者高速缓存
rcv_cache = kmem_cache_create("can_receiver", sizeof(struct receiver), 0, 0, NULL);
if (!rcv_cache)
return -ENOMEM;
/*
* Insert can_rx_alldev_list for reception on all devices.
* This struct is zero initialized which is correct for the
* embedded hlist heads, the dev pointer, and the entries counter.
*/
spin_lock(&can_rcvlists_lock);
hlist_add_head_rcu(&can_rx_alldev_list.list, &can_rx_dev_list);
spin_unlock(&can_rcvlists_lock);
// 统计定时器
if (stats_timer) {
/* the statistics are updated every second (timer triggered) */
setup_timer(&can_stattimer, can_stat_update, 0);
mod_timer(&can_stattimer, round_jiffies(jiffies + HZ));
} else
can_stattimer.function = NULL;
// 初始化proc文件节点
can_init_proc();
// 向系统注册PF_CAN协议族
sock_register(&can_family_ops);
// 监听CAN类型网络设备的注册&去注册
register_netdevice_notifier(&can_netdev_notifier);
// 向网络设备接口层注册接收ETH_P_CAN类型的数据包
dev_add_pack(&can_packet);
return 0;
}
module_init(can_init);
PF_CAN接口
static struct net_proto_family can_family_ops __read_mostly = {
.family = PF_CAN,
.create = can_create,
.owner = THIS_MODULE,
};
当用户态程序调用socket()创建PF_CAN协议族的套接字时,将会调用到can_create()。
socket创建接口: can_create()
/* 当前版本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_NPROTO 7
/* table of registered CAN protocols */
static struct can_proto *proto_tab[CAN_NPROTO] __read_mostly;
static DEFINE_SPINLOCK(proto_tab_lock);
static int can_create(struct net *net, struct socket *sock, int protocol)
{
struct sock *sk;
struct can_proto *cp;
int err = 0;
sock->state = SS_UNCONNECTED;
if (protocol < 0 || protocol >= CAN_NPROTO)
return -EINVAL;
if (net != &init_net)
return -EAFNOSUPPORT;
#ifdef CONFIG_MODULES
// 动态加载协议模块
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);
/* check for available protocol and correct usage */
if (!cp)
return -EPROTONOSUPPORT;
if (cp->type != sock->type) {
err = -EPROTONOSUPPORT;
goto errout;
}
if (cp->capability >= 0 && !capable(cp->capability)) {
err = -EPERM;
goto errout;
}
// 其它socket接口实现由具体的协议来提供
sock->ops = cp->ops;
// 分配sock对象
sk = sk_alloc(net, PF_CAN, GFP_KERNEL, cp->prot);
if (!sk) {
err = -ENOMEM;
goto errout;
}
sock_init_data(sock, sk); // 初始化sock对象的通用字段
sk->sk_destruct = can_sock_destruct;
// 调用协议相关初始化接口
if (sk->sk_prot->init)
err = sk->sk_prot->init(sk);
if (err) {
/* release sk on errors */
sock_orphan(sk);
sock_put(sk);
}
errout:
module_put(cp->prot->owner);
return err;
}
可见,CAN核心本身的设计是协议无关的,具体支持什么类型的协议可以有外部扩展,CAN核心提供了can_proto_register()/can_proto_unregister()接口来让外部模块注册支持的协议。
协议注册: can_proto_register()
/**
* can_proto_register - register CAN transport protocol
* @cp: pointer to CAN protocol structure
*
* Return:
* 0 on success
* -EINVAL invalid (out of range) protocol number
* -EBUSY protocol already in use
* -ENOBUF if proto_register() fails
*/
int can_proto_register(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);
return -EINVAL;
}
// 向系统注册该协议
err = proto_register(cp->prot, 0);
if (err < 0)
return err;
// 将协议保存到全局数组proto_table[]中
spin_lock(&proto_tab_lock);
if (proto_tab[proto]) {
printk(KERN_ERR "can: protocol %d already registered\n",
proto);
err = -EBUSY;
} else {
proto_tab[proto] = cp;
// 注意这里,如果协议未提供ioctl()接口,替换为通用的ioctl接口,该接口提供了时间戳功能
if (!cp->ops->ioctl)
cp->ops->ioctl = can_ioctl;
}
spin_unlock(&proto_tab_lock);
if (err < 0)
proto_unregister(cp->prot);
return err;
}