文章目录
数据结构
sock对象raw_sock
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)));
};
/*
* A raw socket has a list of can_filters attached to it, each receiving
* the CAN frames matching that filter. If the filter list is empty,
* no CAN frames will be received by the socket. The default after
* opening the socket, is to have one filter which receives all frames.
* The filter list is allocated dynamically with the exception of the
* list containing only one item. This common case is optimized by
* storing the single filter in dfilter, to avoid using dynamic memory.
*/
struct raw_sock {
struct sock sk;
int bound; // 标识是否执行过bind()
int ifindex; // 记录bind()的网络设备索引
struct notifier_block notifier;
int loopback; // 标识是否让发送的数据帧环回
int recv_own_msgs; // 1:可接收本端发送报文;0:拒绝接收本端发送报文
int count; /* number of active filters */
struct can_filter dfilter; /* default/single filter */
/* pointer to filter(s),如果只有1个filter,那么filter会只想dfilter */
struct can_filter *filter;
can_err_mask_t err_mask;
};
PF_CAN协议族地址: sockaddr_can
和IP协议族类似,CAN协议族对应的地址为socket地址为sockaddr_can。
/**
* 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;
/* reserved for future CAN protocols address information */
} can_addr;
};
初始化
// 后面重点关注bind()、setsockopt()、getsockopt()、sendmsg()、recvmsg()的实现
static struct proto_ops raw_ops __read_mostly = {
.family = PF_CAN,
.release = raw_release,
.bind = raw_bind,
.connect = sock_no_connect,
.socketpair = sock_no_socketpair,
.accept = sock_no_accept,
.getname = raw_getname, // 只支持获取本端地址信息
.poll = datagram_poll,
.ioctl = NULL, /* use can_ioctl() from af_can.c */
.listen = sock_no_listen,
.shutdown = sock_no_shutdown,
.setsockopt = raw_setsockopt,
.getsockopt = raw_getsockopt,
.sendmsg = raw_sendmsg,
.recvmsg = raw_recvmsg,
.mmap = sock_no_mmap,
.sendpage = sock_no_sendpage,
};
static struct proto raw_proto __read_mostly = {
.name = "CAN_RAW",
.owner = THIS_MODULE,
// 真实的sock对象
.obj_size = sizeof(struct raw_sock),
// socket创建时,由CAN核心调用该协议相关初始化函数初始化sock结构
.init = raw_init,
};
// 用户态需要使用socket(PF_CAN, SOCK_RAW, CAN_RAW)创建RAW类型套接字
static struct can_proto raw_can_proto __read_mostly = {
.type = SOCK_RAW,
.protocol = CAN_RAW,
.capability = -1,
.ops = &raw_ops,
.prot = &raw_proto,
};
static __init int raw_module_init(void)
{
int err;
printk(banner);
// 向CAN核心注册RAW类型的协议
err = can_proto_register(&raw_can_proto);
if (err < 0)
printk(KERN_ERR "can: registration of raw protocol failed\n");
return err;
}
module_init(raw_module_init);
raw_sock初始化: raw_init()
static int raw_init(struct sock *sk)
{
struct raw_sock *ro = raw_sk(sk);
ro->bound = 0;
ro->ifindex = 0;
/* set default filter to single entry dfilter */
ro->dfilter.can_id = 0;
ro->dfilter.can_mask = MASK_ALL;
ro->filter = &ro->dfilter;
ro->count = 1;
/* set default loopback behaviour */
ro->loopback = 1;
ro->recv_own_msgs = 0;
// 监听了网络设备的去注册和down事件,主要是做一些清理性的工作,这里不再展开
ro->notifier.notifier_call = raw_notifier;
register_netdevice_notifier(&ro->notifier);
return 0;
}
socket接口实现
绑定: raw_bind()
static int raw_bind(struct socket *sock, struct sockaddr *uaddr, int len)
{
struct sockaddr_can *addr = (struct sockaddr_can *)uaddr;
struct sock *sk = sock->sk;
struct raw_sock *ro = raw_sk(sk);
int ifindex;
int err = 0;
int notify_enetdown = 0;
// 地址长度校验
if (len < sizeof(*addr))
return -EINVAL;
lock_sock(sk);
// 重复绑定
if (ro->bound && addr->can_ifindex == ro->ifindex)
goto out;
if (addr->can_ifindex) { // 要绑定到指定的网络设备
struct net_device *dev;
dev = dev_get_by_index(&init_net, addr->can_ifindex);
if (!dev) {
err = -ENODEV;
goto out;
}
// 要绑定的网络设备必须是CAN类型
if (dev->type != ARPHRD_CAN) {
dev_put(dev);
err = -ENODEV;
goto out;
}
// 如果当前网络设备没有UP,会主动向用户态报告一次错误
if (!(dev->flags & IFF_UP))
notify_enetdown = 1;
// 记录绑定网络设备索引并设置过滤器
ifindex = dev->ifindex;
err = raw_enable_allfilters(dev, sk);
dev_put(dev);
} else {
// 记录绑定网络设备索引=0并设置过滤器
ifindex = 0;
err = raw_enable_allfilters(NULL, sk);
}
if (!err) {
if (ro->bound) {
// 去注册旧的过滤器
if (ro->ifindex) {
struct net_device *dev;
dev = dev_get_by_index(&init_net, ro->ifindex);
if (dev) {
raw_disable_allfilters(dev, sk);
dev_put(dev);
}
} else
raw_disable_allfilters(NULL, sk);
}
// 记录绑定信息
ro->ifindex = ifindex;
ro->bound = 1;
}
out:
release_sock(sk);
if (notify_enetdown) {
sk->sk_err = ENETDOWN;
if (!sock_flag(sk, SOCK_DEAD))
sk->sk_error_report(sk);
}
return err;
}
bind()过程最重要的就是设置过滤器,然后将绑定信息更新到raw_sock的ifindex和bound字段中。
使能过滤器: raw_enable_allfilters()
static int raw_enable_filters(struct net_device *dev, struct sock *sk,
struct can_filter *filter, int count)
{
int err = 0;
int i;
// 遍历当前已设置的过滤器,分别向CAN核心注册接收者
for (i = 0; i < count; i++) {
err = can_rx_register(dev, filter[i].can_id, filter[i].can_mask, raw_rcv, sk, "raw");
// 错误回滚
if (err) {
/* clean up successfully registered filters */
while (--i >= 0)
can_rx_unregister(dev, filter[i].can_id, filter[i].can_mask, raw_rcv, sk);
break;
}
}
return err;
}
static int raw_enable_errfilter(struct net_device *dev, struct sock *sk,
can_err_mask_t err_mask)
{
int err = 0;
// 注册错误接收者
if (err_mask)
err = can_rx_register(dev, 0, err_mask | CAN_ERR_FLAG, raw_rcv, sk, "raw");
return err;
}
static int raw_enable_allfilters(struct net_device *dev, struct sock *sk)
{
struct raw_sock *ro = raw_sk(sk);
int err;
// 分别设置filter和err filter
err = raw_enable_filters(dev, sk, ro->filter, ro->count);
if (!err) {
err = raw_enable_errfilter(dev, sk, ro->err_mask);
if (err)
raw_disable_filters(dev, sk, ro->filter, ro->count);
}
return err;
}
从filter的使能实现上看,如果要实现bind()过程中能够设置有效的filter,那么必须提前将filter参数设置到内核,从socket接口实现上看,只有setsockopt()可以胜任这一工作了。
设置socket选项: raw_setsockopt()
static int raw_setsockopt(struct socket *sock, int level, int optname,
char __user *optval, int optlen)
{
struct sock *sk = sock->sk;
struct raw_sock *ro = raw_sk(sk);
struct can_filter *filter = NULL; /* dyn. alloc'ed filters */
struct can_filter sfilter; /* single filter */
struct net_device *dev = NULL;
can_err_mask_t err_mask = 0;
int count = 0;
int err = 0;
// 常规参数校验
if (level != SOL_CAN_RAW)
return -EINVAL;
if (optlen < 0)
return -EINVAL;
switch (optname) {
case CAN_RAW_FILTER: // 配置filter
// 可一次配置多个filter,单个filter保存到sfilter中,多个filter保存到堆区
if (optlen % sizeof(struct can_filter) != 0)
return -EINVAL;
count = optlen / sizeof(struct can_filter);
if (count > 1) {
/* filter does not fit into dfilter => alloc space */
filter = kmalloc(optlen, GFP_KERNEL);
if (!filter)
return -ENOMEM;
if (copy_from_user(filter, optval, optlen)) {
kfree(filter);
return -EFAULT;
}
} else if (count == 1) {
if (copy_from_user(&sfilter, optval, optlen))
return -EFAULT;
}
lock_sock(sk);
// 如果之前已经绑定过,那么先移除旧的filter
if (ro->bound && ro->ifindex)
dev = dev_get_by_index(&init_net, ro->ifindex);
if (ro->bound) {
/* (try to) register the new filters */
if (count == 1)
err = raw_enable_filters(dev, sk, &sfilter, 1);
else
err = raw_enable_filters(dev, sk, filter, count);
if (err) {
if (count > 1)
kfree(filter);
goto out_fil;
}
/* remove old filter registrations */
raw_disable_filters(dev, sk, ro->filter, ro->count);
}
/* remove old filter space */
if (ro->count > 1)
kfree(ro->filter);
// 将新的filter关联到socket
if (count == 1) {
/* copy filter data for single filter */
ro->dfilter = sfilter;
filter = &ro->dfilter;
}
ro->filter = filter;
ro->count = count;
out_fil:
if (dev)
dev_put(dev);
release_sock(sk);
break;
case CAN_RAW_ERR_FILTER: // 配置错误filter
// 配置的是err_mask
if (optlen != sizeof(err_mask))
return -EINVAL;
if (copy_from_user(&err_mask, optval, optlen))
return -EFAULT;
err_mask &= CAN_ERR_MASK;
lock_sock(sk);
// 如果之前绑定过,先移除旧的err_mask
if (ro->bound && ro->ifindex)
dev = dev_get_by_index(&init_net, ro->ifindex);
if (ro->bound) {
/* (try to) register the new err_mask */
err = raw_enable_errfilter(dev, sk, err_mask);
if (err)
goto out_err;
/* remove old err_mask registration */
raw_disable_errfilter(dev, sk, ro->err_mask);
}
// 保存新的err_mask
ro->err_mask = err_mask;
out_err:
if (dev)
dev_put(dev);
release_sock(sk);
break;
case CAN_RAW_LOOPBACK: // 配置loopback
if (optlen != sizeof(ro->loopback))
return -EINVAL;
if (copy_from_user(&ro->loopback, optval, optlen))
return -EFAULT;
break;
case CAN_RAW_RECV_OWN_MSGS: // 配置是否接收自身发送报文
if (optlen != sizeof(ro->recv_own_msgs))
return -EINVAL;
if (copy_from_user(&ro->recv_own_msgs, optval, optlen))
return -EFAULT;
break;
default:
return -ENOPROTOOPT;
}
return err;
}
getsockopt()的实现raw_getsockopt()与raw_setsockopt()是一一对应的,这里不再展开。
发送数据: raw_sendmsg()
static int raw_sendmsg(struct kiocb *iocb, struct socket *sock,
struct msghdr *msg, size_t size)
{
struct sock *sk = sock->sk;
struct raw_sock *ro = raw_sk(sk);
struct sk_buff *skb;
struct net_device *dev;
int ifindex;
int err;
// 出口设备必须指定,要么提前bind(),要么通过sendmsg()调用指定,二者优先使用sendmsg()的参数
if (msg->msg_name) {
struct sockaddr_can *addr = (struct sockaddr_can *)msg->msg_name;
if (addr->can_family != AF_CAN)
return -EINVAL;
ifindex = addr->can_ifindex;
} else
ifindex = ro->ifindex;
// 发送数据长度校验,每次只能发送一个CAN帧
if (size != sizeof(struct can_frame))
return -EINVAL;
// 出口网络设备有效性校验
dev = dev_get_by_index(&init_net, ifindex);
if (!dev)
return -ENXIO;
// 构造skb,并将要发送的数据填充到skb中
skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err);
if (!skb)
goto put_dev;
err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
if (err < 0)
goto free_skb;
// 绑定出口设备信息到skb
skb->dev = dev;
skb->sk = sk;
// 调用CAN核心接口发送CAN帧
err = can_send(skb, ro->loopback);
dev_put(dev);
if (err)
goto send_failed;
return size;
free_skb:
kfree_skb(skb);
put_dev:
dev_put(dev);
send_failed:
return err;
}
接收数据: raw_recvmsg()
static int raw_recvmsg(struct kiocb *iocb, struct socket *sock,
struct msghdr *msg, size_t size, int flags)
{
struct sock *sk = sock->sk;
struct sk_buff *skb;
int err = 0;
int noblock;
noblock = flags & MSG_DONTWAIT;
flags &= ~MSG_DONTWAIT;
// 调用通用的接收接口,该接口可能会阻塞
skb = skb_recv_datagram(sk, flags, noblock, &err);
if (!skb)
return err;
// 拷贝数据
if (size < skb->len)
msg->msg_flags |= MSG_TRUNC;
else
size = skb->len;
err = memcpy_toiovec(msg->msg_iov, skb->data, size);
if (err < 0) {
skb_free_datagram(sk, skb);
return err;
}
// 更新sock对象的接收时间戳,因此SIOCGSTAMP选项才可以获取到数据
sock_recv_timestamp(msg, sk, skb);
// 拷贝接收网络设备地址
if (msg->msg_name) {
msg->msg_namelen = sizeof(struct sockaddr_can);
memcpy(msg->msg_name, skb->cb, msg->msg_namelen);
}
// 释放skb
skb_free_datagram(sk, skb);
return size;
}
raw_recvmsg()仅仅是从sock对象的接收队列中取数据,往队列中放数据是由CAN核心调用raw_rcv()完成的,该函数在使能过滤器时通过can_rx_register()注册给了CAN核心。
raw_rcv()
// data指针指向所属sock对象
static void raw_rcv(struct sk_buff *skb, void *data)
{
struct sock *sk = (struct sock *)data;
struct raw_sock *ro = raw_sk(sk);
struct sockaddr_can *addr;
// 如果没有打开接收自身发送报文开关,则忽略自身的报文
if (!ro->recv_own_msgs && skb->sk == sk)
return;
/* clone the given skb to be able to enqueue it into the rcv queue */
skb = skb_clone(skb, GFP_ATOMIC);
if (!skb)
return;
/*
* Put the datagram to the queue so that raw_recvmsg() can
* get it from there. We need to pass the interface index to
* raw_recvmsg(). We pass a whole struct sockaddr_can in skb->cb
* containing the interface index.
*/
// skb->cb设置为入口网络设备的地址
BUILD_BUG_ON(sizeof(skb->cb) < sizeof(struct sockaddr_can));
addr = (struct sockaddr_can *)skb->cb;
memset(addr, 0, sizeof(*addr));
addr->can_family = AF_CAN;
addr->can_ifindex = skb->dev->ifindex;
// 将skb放入sock对象的接收队列
if (sock_queue_rcv_skb(sk, skb) < 0)
kfree_skb(skb);
}