> +static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
> +{
> +     struct rtnl_link_ops *ops;
> +     struct net_device *dev;
> +     struct ifinfomsg *ifm;
> +     char name[MODULE_NAME_LEN];
> +     char ifname[IFNAMSIZ];
> +     struct nlattr *tb[IFLA_MAX+1];
> +     struct nlattr *linkinfo[IFLA_INFO_MAX+1];
> +     int err;
> +
> +     err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy);
> +     if (err < 0)
> +             return err;
> +
> +     if (tb[IFLA_IFNAME])
> +             nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ);
> +     else
> +             ifname[0] = '\0';
> +
> +     ifm = nlmsg_data(nlh);
> +     if (ifm->ifi_index > 0)
> +             dev = __dev_get_by_index(ifm->ifi_index);
> +     else if (ifname[0])
> +             dev = __dev_get_by_name(ifname);
> +     else
> +             dev = NULL;
> +
> +     if (tb[IFLA_LINKINFO]) {
> +             err = nla_parse_nested(linkinfo, IFLA_INFO_MAX,
> +                                    tb[IFLA_LINKINFO], ifla_info_policy);
> +             if (err < 0)
> +                     return err;
> +     } else
> +             memset(linkinfo, 0, sizeof(linkinfo));
> +
> +     if (linkinfo[IFLA_INFO_NAME]) {
> +             nla_strlcpy(name, linkinfo[IFLA_INFO_NAME], sizeof(name));
> +             ops = rtnl_link_ops_get(name);

Ugh.  Shouldn't we have the request_module logic here?
Otherwise it looks like we can skip the validate method and 
have other weird interactions.


> +     } else {
> +             name[0] = '\0';
> +             ops = NULL;
> +     }
> +
> +     if (1) {
> +             struct nlattr *attr[ops ? ops->maxtype + 1 : 0], **data = NULL;
> +
> +             if (ops) {
> +                     if (ops->maxtype && linkinfo[IFLA_INFO_DATA]) {
> +                             err = nla_parse_nested(attr, ops->maxtype,
> + linkinfo[IFLA_INFO_DATA],
> +                                                    ops->policy);
> +                             if (err < 0)
> +                                     return err;
> +                             data = attr;
> +                     }
> +                     if (ops->validate) {
> +                             err = ops->validate(tb, data);
> +                             if (err < 0)
> +                                     return err;
> +                     }
> +             }
> +
> +             if (dev) {
> +                     int modified = 0;
> +
> +                     if (nlh->nlmsg_flags & NLM_F_EXCL)
> +                             return -EEXIST;
> +                     if (nlh->nlmsg_flags & NLM_F_REPLACE)
> +                             return -EOPNOTSUPP;
> +
> +                     if (linkinfo[IFLA_INFO_DATA]) {
> +                             if (!ops || ops != dev->rtnl_link_ops ||
> +                                 !ops->changelink)
> +                                     return -EOPNOTSUPP;
> +
> +                             err = ops->changelink(dev, tb, data);
> +                             if (err < 0)
> +                                     return err;
> +                             modified = 1;
> +                     }
> +
> +                     return do_setlink(dev, ifm, tb, ifname, modified);
> +             }
> +
> +             if (!(nlh->nlmsg_flags & NLM_F_CREATE))
> +                     return -ENODEV;
> +
> +             if (ifm->ifi_index)
> +                     return -EINVAL;
> +             if (tb[IFLA_ADDRESS] || tb[IFLA_BROADCAST] || tb[IFLA_MAP])
> +                     return -EOPNOTSUPP;
> +
> +#ifdef CONFIG_KMOD
> +             if (!ops && name[0]) {
> +                     /* race condition: device may be created while rtnl is
> +                      * unlocked, final register_netdevice will catch it.
> +                      */
> +                     __rtnl_unlock();
> +                     request_module("rtnl-link-%s", name);
> +                     rtnl_lock();
> +                     ops = rtnl_link_ops_get(name);
> +             }
> +#endif
> +             if (!ops)
> +                     return -EOPNOTSUPP;

> +
> +             if (!ifname[0])
> +                     snprintf(ifname, IFNAMSIZ, "%s%%d", ops->name);
> +             dev = alloc_netdev(ops->priv_size, ifname, ops->setup);
> +             if (!dev)
> +                     return -ENOMEM;
> +
> +             if (strchr(dev->name, '%')) {
> +                     err = dev_alloc_name(dev, dev->name);
> +                     if (err < 0)
> +                             goto err_free;
> +             }
> +             dev->rtnl_link_ops = ops;
> +
> +             if (tb[IFLA_MTU])
> +                     dev->mtu = nla_get_u32(tb[IFLA_MTU]);
> +             if (tb[IFLA_TXQLEN])
> +                     dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]);
> +             if (tb[IFLA_WEIGHT])
> +                     dev->weight = nla_get_u32(tb[IFLA_WEIGHT]);
> +             if (tb[IFLA_OPERSTATE])
> +                     set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE]));
> +             if (tb[IFLA_LINKMODE])
> +                     dev->link_mode = nla_get_u8(tb[IFLA_LINKMODE]);
> +
> +             err = ops->newlink(dev, tb, data);
> +err_free:
> +             if (err < 0)
> +                     free_netdev(dev);
> +             return err;
> +     }
> +}
> +

Eric
-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to