diff options
-rw-r--r-- | include/linux/if_link.h | 8 | ||||
-rw-r--r-- | net/ipv4/devinet.c | 75 |
2 files changed, 83 insertions, 0 deletions
diff --git a/include/linux/if_link.h b/include/linux/if_link.h index 443d04a66a79..2e02e4d7b11e 100644 --- a/include/linux/if_link.h +++ b/include/linux/if_link.h | |||
@@ -147,6 +147,14 @@ enum { | |||
147 | #define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg)) | 147 | #define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg)) |
148 | #endif | 148 | #endif |
149 | 149 | ||
150 | enum { | ||
151 | IFLA_INET_UNSPEC, | ||
152 | IFLA_INET_CONF, | ||
153 | __IFLA_INET_MAX, | ||
154 | }; | ||
155 | |||
156 | #define IFLA_INET_MAX (__IFLA_INET_MAX - 1) | ||
157 | |||
150 | /* ifi_flags. | 158 | /* ifi_flags. |
151 | 159 | ||
152 | IFF_* flags. | 160 | IFF_* flags. |
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index dc94b0316b78..71afc26c2df8 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c | |||
@@ -1256,6 +1256,72 @@ errout: | |||
1256 | rtnl_set_sk_err(net, RTNLGRP_IPV4_IFADDR, err); | 1256 | rtnl_set_sk_err(net, RTNLGRP_IPV4_IFADDR, err); |
1257 | } | 1257 | } |
1258 | 1258 | ||
1259 | static size_t inet_get_link_af_size(const struct net_device *dev) | ||
1260 | { | ||
1261 | struct in_device *in_dev = __in_dev_get_rcu(dev); | ||
1262 | |||
1263 | if (!in_dev) | ||
1264 | return 0; | ||
1265 | |||
1266 | return nla_total_size(IPV4_DEVCONF_MAX * 4); /* IFLA_INET_CONF */ | ||
1267 | } | ||
1268 | |||
1269 | static int inet_fill_link_af(struct sk_buff *skb, const struct net_device *dev) | ||
1270 | { | ||
1271 | struct in_device *in_dev = __in_dev_get_rcu(dev); | ||
1272 | struct nlattr *nla; | ||
1273 | int i; | ||
1274 | |||
1275 | if (!in_dev) | ||
1276 | return -ENODATA; | ||
1277 | |||
1278 | nla = nla_reserve(skb, IFLA_INET_CONF, IPV4_DEVCONF_MAX * 4); | ||
1279 | if (nla == NULL) | ||
1280 | return -EMSGSIZE; | ||
1281 | |||
1282 | for (i = 0; i < IPV4_DEVCONF_MAX; i++) | ||
1283 | ((u32 *) nla_data(nla))[i] = in_dev->cnf.data[i]; | ||
1284 | |||
1285 | return 0; | ||
1286 | } | ||
1287 | |||
1288 | static const struct nla_policy inet_af_policy[IFLA_INET_MAX+1] = { | ||
1289 | [IFLA_INET_CONF] = { .type = NLA_NESTED }, | ||
1290 | }; | ||
1291 | |||
1292 | static int inet_parse_link_af(struct net_device *dev, const struct nlattr *nla) | ||
1293 | { | ||
1294 | struct in_device *in_dev = __in_dev_get_rcu(dev); | ||
1295 | struct nlattr *a, *tb[IFLA_INET_MAX+1]; | ||
1296 | int err, rem; | ||
1297 | |||
1298 | if (!in_dev) | ||
1299 | return -EOPNOTSUPP; | ||
1300 | |||
1301 | err = nla_parse_nested(tb, IFLA_INET_MAX, nla, inet_af_policy); | ||
1302 | if (err < 0) | ||
1303 | return err; | ||
1304 | |||
1305 | if (tb[IFLA_INET_CONF]) { | ||
1306 | nla_for_each_nested(a, tb[IFLA_INET_CONF], rem) { | ||
1307 | int cfgid = nla_type(a); | ||
1308 | |||
1309 | if (nla_len(a) < 4) | ||
1310 | return -EINVAL; | ||
1311 | |||
1312 | if (cfgid <= 0 || cfgid > IPV4_DEVCONF_MAX) | ||
1313 | return -EINVAL; | ||
1314 | } | ||
1315 | } | ||
1316 | |||
1317 | if (tb[IFLA_INET_CONF]) { | ||
1318 | nla_for_each_nested(a, tb[IFLA_INET_CONF], rem) | ||
1319 | ipv4_devconf_set(in_dev, nla_type(a), nla_get_u32(a)); | ||
1320 | } | ||
1321 | |||
1322 | return 0; | ||
1323 | } | ||
1324 | |||
1259 | #ifdef CONFIG_SYSCTL | 1325 | #ifdef CONFIG_SYSCTL |
1260 | 1326 | ||
1261 | static void devinet_copy_dflt_conf(struct net *net, int i) | 1327 | static void devinet_copy_dflt_conf(struct net *net, int i) |
@@ -1619,6 +1685,13 @@ static __net_initdata struct pernet_operations devinet_ops = { | |||
1619 | .exit = devinet_exit_net, | 1685 | .exit = devinet_exit_net, |
1620 | }; | 1686 | }; |
1621 | 1687 | ||
1688 | static struct rtnl_af_ops inet_af_ops = { | ||
1689 | .family = AF_INET, | ||
1690 | .fill_link_af = inet_fill_link_af, | ||
1691 | .get_link_af_size = inet_get_link_af_size, | ||
1692 | .parse_link_af = inet_parse_link_af, | ||
1693 | }; | ||
1694 | |||
1622 | void __init devinet_init(void) | 1695 | void __init devinet_init(void) |
1623 | { | 1696 | { |
1624 | register_pernet_subsys(&devinet_ops); | 1697 | register_pernet_subsys(&devinet_ops); |
@@ -1626,6 +1699,8 @@ void __init devinet_init(void) | |||
1626 | register_gifconf(PF_INET, inet_gifconf); | 1699 | register_gifconf(PF_INET, inet_gifconf); |
1627 | register_netdevice_notifier(&ip_netdev_notifier); | 1700 | register_netdevice_notifier(&ip_netdev_notifier); |
1628 | 1701 | ||
1702 | rtnl_af_register(&inet_af_ops); | ||
1703 | |||
1629 | rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL); | 1704 | rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL); |
1630 | rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL); | 1705 | rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL); |
1631 | rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr); | 1706 | rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr); |