aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/rtnetlink.h4
-rw-r--r--net/core/rtnetlink.c83
2 files changed, 57 insertions, 30 deletions
diff --git a/include/net/rtnetlink.h b/include/net/rtnetlink.h
index 3861c05cdf0f..8218288ab7ee 100644
--- a/include/net/rtnetlink.h
+++ b/include/net/rtnetlink.h
@@ -78,6 +78,10 @@ extern void __rtnl_link_unregister(struct rtnl_link_ops *ops);
78extern int rtnl_link_register(struct rtnl_link_ops *ops); 78extern int rtnl_link_register(struct rtnl_link_ops *ops);
79extern void rtnl_link_unregister(struct rtnl_link_ops *ops); 79extern void rtnl_link_unregister(struct rtnl_link_ops *ops);
80 80
81extern struct net_device *rtnl_create_link(char *ifname,
82 const struct rtnl_link_ops *ops, struct nlattr *tb[]);
83extern const struct nla_policy ifla_policy[IFLA_MAX+1];
84
81#define MODULE_ALIAS_RTNL_LINK(kind) MODULE_ALIAS("rtnl-link-" kind) 85#define MODULE_ALIAS_RTNL_LINK(kind) MODULE_ALIAS("rtnl-link-" kind)
82 86
83#endif 87#endif
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 2b0b6fac6cef..dca9e80ba574 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -713,7 +713,7 @@ cont:
713 return skb->len; 713 return skb->len;
714} 714}
715 715
716static const struct nla_policy ifla_policy[IFLA_MAX+1] = { 716const struct nla_policy ifla_policy[IFLA_MAX+1] = {
717 [IFLA_IFNAME] = { .type = NLA_STRING, .len = IFNAMSIZ-1 }, 717 [IFLA_IFNAME] = { .type = NLA_STRING, .len = IFNAMSIZ-1 },
718 [IFLA_ADDRESS] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN }, 718 [IFLA_ADDRESS] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
719 [IFLA_BROADCAST] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN }, 719 [IFLA_BROADCAST] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
@@ -937,6 +937,48 @@ static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
937 return 0; 937 return 0;
938} 938}
939 939
940struct net_device *rtnl_create_link(char *ifname,
941 const struct rtnl_link_ops *ops, struct nlattr *tb[])
942{
943 int err;
944 struct net_device *dev;
945
946 err = -ENOMEM;
947 dev = alloc_netdev(ops->priv_size, ifname, ops->setup);
948 if (!dev)
949 goto err;
950
951 if (strchr(dev->name, '%')) {
952 err = dev_alloc_name(dev, dev->name);
953 if (err < 0)
954 goto err_free;
955 }
956
957 dev->rtnl_link_ops = ops;
958
959 if (tb[IFLA_MTU])
960 dev->mtu = nla_get_u32(tb[IFLA_MTU]);
961 if (tb[IFLA_ADDRESS])
962 memcpy(dev->dev_addr, nla_data(tb[IFLA_ADDRESS]),
963 nla_len(tb[IFLA_ADDRESS]));
964 if (tb[IFLA_BROADCAST])
965 memcpy(dev->broadcast, nla_data(tb[IFLA_BROADCAST]),
966 nla_len(tb[IFLA_BROADCAST]));
967 if (tb[IFLA_TXQLEN])
968 dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]);
969 if (tb[IFLA_OPERSTATE])
970 set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE]));
971 if (tb[IFLA_LINKMODE])
972 dev->link_mode = nla_get_u8(tb[IFLA_LINKMODE]);
973
974 return dev;
975
976err_free:
977 free_netdev(dev);
978err:
979 return ERR_PTR(err);
980}
981
940static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) 982static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
941{ 983{
942 const struct rtnl_link_ops *ops; 984 const struct rtnl_link_ops *ops;
@@ -1049,38 +1091,17 @@ replay:
1049 1091
1050 if (!ifname[0]) 1092 if (!ifname[0])
1051 snprintf(ifname, IFNAMSIZ, "%s%%d", ops->kind); 1093 snprintf(ifname, IFNAMSIZ, "%s%%d", ops->kind);
1052 dev = alloc_netdev(ops->priv_size, ifname, ops->setup); 1094
1053 if (!dev) 1095 dev = rtnl_create_link(ifname, ops, tb);
1054 return -ENOMEM; 1096
1055 1097 if (IS_ERR(dev))
1056 if (strchr(dev->name, '%')) { 1098 err = PTR_ERR(dev);
1057 err = dev_alloc_name(dev, dev->name); 1099 else if (ops->newlink)
1058 if (err < 0)
1059 goto err_free;
1060 }
1061 dev->rtnl_link_ops = ops;
1062
1063 if (tb[IFLA_MTU])
1064 dev->mtu = nla_get_u32(tb[IFLA_MTU]);
1065 if (tb[IFLA_ADDRESS])
1066 memcpy(dev->dev_addr, nla_data(tb[IFLA_ADDRESS]),
1067 nla_len(tb[IFLA_ADDRESS]));
1068 if (tb[IFLA_BROADCAST])
1069 memcpy(dev->broadcast, nla_data(tb[IFLA_BROADCAST]),
1070 nla_len(tb[IFLA_BROADCAST]));
1071 if (tb[IFLA_TXQLEN])
1072 dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]);
1073 if (tb[IFLA_OPERSTATE])
1074 set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE]));
1075 if (tb[IFLA_LINKMODE])
1076 dev->link_mode = nla_get_u8(tb[IFLA_LINKMODE]);
1077
1078 if (ops->newlink)
1079 err = ops->newlink(dev, tb, data); 1100 err = ops->newlink(dev, tb, data);
1080 else 1101 else
1081 err = register_netdevice(dev); 1102 err = register_netdevice(dev);
1082err_free: 1103
1083 if (err < 0) 1104 if (err < 0 && !IS_ERR(dev))
1084 free_netdev(dev); 1105 free_netdev(dev);
1085 return err; 1106 return err;
1086 } 1107 }
@@ -1329,3 +1350,5 @@ EXPORT_SYMBOL(rtnl_unlock);
1329EXPORT_SYMBOL(rtnl_unicast); 1350EXPORT_SYMBOL(rtnl_unicast);
1330EXPORT_SYMBOL(rtnl_notify); 1351EXPORT_SYMBOL(rtnl_notify);
1331EXPORT_SYMBOL(rtnl_set_sk_err); 1352EXPORT_SYMBOL(rtnl_set_sk_err);
1353EXPORT_SYMBOL(rtnl_create_link);
1354EXPORT_SYMBOL(ifla_policy);