Linux内核实践 - 如何添加网络协议[二]:实现
|
而设备的初始化应该发生在创建设备时,也就是向网络注册它时,也就是register_brcm_dev(),注册一个新设备, 需要知道它的下层设备real_dev以及唯一标识brcm设备的brcm_port。首先确定该设备没有被创建,然后用alloc_netdev_mq创建 新设备new_dev,然后设置相关属性,特别是它的私有属性brcm_dev_info(new_dev),然后添加它到brcm_group_hash中,最后发 生真正的注册register_netdevice()。
static int register_brcm_dev(struct
net_device *real_dev, u16 brcm_port)
{
struct net_device *new_dev;
struct net *net = dev_net(real_dev);
struct brcm_group *grp;
char name[IFNAMSIZ];
int err;
if(brcm_port >= BRCM_PORT_MASK)
return -ERANGE;
// exist yet
if (find_brcm_dev(real_dev, brcm_port) != NULL)
return -EEXIST;
snprintf(name, IFNAMSIZ, "brcm%i", brcm_port);
new_dev = alloc_netdev_mq(sizeof(struct brcm_dev_info), name,
brcm_setup, 1);
if (new_dev == NULL)
return -ENOBUFS;
new_dev->real_num_tx_queues = real_dev->real_num_tx_queues;
dev_net_set(new_dev, net);
new_dev->mtu = real_dev->mtu;
brcm_dev_info(new_dev)->brcm_port = brcm_port;
brcm_dev_info(new_dev)->real_dev = real_dev;
brcm_dev_info(new_dev)->dent = NULL;
//new_dev->rtnl_link_ops = &brcm_link_ops;
grp = brcm_find_group(real_dev);
if (!grp)
grp = brcm_group_alloc(real_dev);
err = register_netdevice(new_dev);
if (err < 0)
goto out_free_newdev;
/* Account for reference in struct vlan_dev_info */
dev_hold(real_dev);
brcm_group_set_device(grp, brcm_port, new_dev);
return 0;
out_free_newdev:
free_netdev(new_dev);
return err;
}
ioctl 由于brcm设备可以存在多个,并且和下层设备不是固定的对应关系,因此它的创 建应该可以人为控制,因此通过ioctl由用户进行创建。这里只为brcm提供了两种操作-添加与删除。一种设备添加一定是与下层 设备成关系的,因此添加时需要手动指明这种下层设备,然后通过__dev_get_by_name()从网络空间中找到这种设备,就可以调 用register_brcm_dev()来完成注册了。而设备的删除则是直接删除,直接删除unregister_brcm_dev()。
static int brcm_ioctl_handler(struct net *net, void __user *arg)
{
int err;
struct brcm_ioctl_args args;
struct net_device *dev = NULL;
if (copy_from_user(&args, arg, sizeof(struct brcm_ioctl_args)))
return -EFAULT;
/* Null terminate this sucker, just in case. */
args.device1[23] = 0;
args.u.device2[23] = 0;
rtnl_lock();
switch (args.cmd) {
case ADD_BRCM_CMD:
case DEL_BRCM_CMD:
err = -ENODEV;
dev = __dev_get_by_name(net, args.device1);
if (!dev)
goto out;
err = -EINVAL;
if (args.cmd != ADD_BRCM_CMD && !is_brcm_dev(dev))
goto out;
}
switch (args.cmd) {
case ADD_BRCM_CMD:
err = -EPERM;
if (!capable(CAP_NET_ADMIN))
break;
err = register_brcm_dev(dev, args.u.port);
break;
case DEL_BRCM_CMD:
err = -EPERM;
if (!capable(CAP_NET_ADMIN))
break;
unregister_brcm_dev(dev, NULL);
err = 0;
break;
default:
err = -EOPNOTSUPP;
break;
}
out:
rtnl_unlock();
return err;
} (编辑:宣城站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |


