diff options
Diffstat (limited to 'net/ipv4/devinet.c')
-rw-r--r-- | net/ipv4/devinet.c | 97 |
1 files changed, 94 insertions, 3 deletions
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index dc94b0316b78..748cb5b337bd 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c | |||
@@ -1256,6 +1256,87 @@ 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_rtnl(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_rtnl(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_validate_link_af(const struct net_device *dev, | ||
1293 | const struct nlattr *nla) | ||
1294 | { | ||
1295 | struct nlattr *a, *tb[IFLA_INET_MAX+1]; | ||
1296 | int err, rem; | ||
1297 | |||
1298 | if (dev && !__in_dev_get_rtnl(dev)) | ||
1299 | return -EAFNOSUPPORT; | ||
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 | return 0; | ||
1318 | } | ||
1319 | |||
1320 | static int inet_set_link_af(struct net_device *dev, const struct nlattr *nla) | ||
1321 | { | ||
1322 | struct in_device *in_dev = __in_dev_get_rtnl(dev); | ||
1323 | struct nlattr *a, *tb[IFLA_INET_MAX+1]; | ||
1324 | int rem; | ||
1325 | |||
1326 | if (!in_dev) | ||
1327 | return -EAFNOSUPPORT; | ||
1328 | |||
1329 | if (nla_parse_nested(tb, IFLA_INET_MAX, nla, NULL) < 0) | ||
1330 | BUG(); | ||
1331 | |||
1332 | if (tb[IFLA_INET_CONF]) { | ||
1333 | nla_for_each_nested(a, tb[IFLA_INET_CONF], rem) | ||
1334 | ipv4_devconf_set(in_dev, nla_type(a), nla_get_u32(a)); | ||
1335 | } | ||
1336 | |||
1337 | return 0; | ||
1338 | } | ||
1339 | |||
1259 | #ifdef CONFIG_SYSCTL | 1340 | #ifdef CONFIG_SYSCTL |
1260 | 1341 | ||
1261 | static void devinet_copy_dflt_conf(struct net *net, int i) | 1342 | static void devinet_copy_dflt_conf(struct net *net, int i) |
@@ -1349,9 +1430,9 @@ static int devinet_sysctl_forward(ctl_table *ctl, int write, | |||
1349 | return ret; | 1430 | return ret; |
1350 | } | 1431 | } |
1351 | 1432 | ||
1352 | int ipv4_doint_and_flush(ctl_table *ctl, int write, | 1433 | static int ipv4_doint_and_flush(ctl_table *ctl, int write, |
1353 | void __user *buffer, | 1434 | void __user *buffer, |
1354 | size_t *lenp, loff_t *ppos) | 1435 | size_t *lenp, loff_t *ppos) |
1355 | { | 1436 | { |
1356 | int *valp = ctl->data; | 1437 | int *valp = ctl->data; |
1357 | int val = *valp; | 1438 | int val = *valp; |
@@ -1619,6 +1700,14 @@ static __net_initdata struct pernet_operations devinet_ops = { | |||
1619 | .exit = devinet_exit_net, | 1700 | .exit = devinet_exit_net, |
1620 | }; | 1701 | }; |
1621 | 1702 | ||
1703 | static struct rtnl_af_ops inet_af_ops = { | ||
1704 | .family = AF_INET, | ||
1705 | .fill_link_af = inet_fill_link_af, | ||
1706 | .get_link_af_size = inet_get_link_af_size, | ||
1707 | .validate_link_af = inet_validate_link_af, | ||
1708 | .set_link_af = inet_set_link_af, | ||
1709 | }; | ||
1710 | |||
1622 | void __init devinet_init(void) | 1711 | void __init devinet_init(void) |
1623 | { | 1712 | { |
1624 | register_pernet_subsys(&devinet_ops); | 1713 | register_pernet_subsys(&devinet_ops); |
@@ -1626,6 +1715,8 @@ void __init devinet_init(void) | |||
1626 | register_gifconf(PF_INET, inet_gifconf); | 1715 | register_gifconf(PF_INET, inet_gifconf); |
1627 | register_netdevice_notifier(&ip_netdev_notifier); | 1716 | register_netdevice_notifier(&ip_netdev_notifier); |
1628 | 1717 | ||
1718 | rtnl_af_register(&inet_af_ops); | ||
1719 | |||
1629 | rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL); | 1720 | rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL); |
1630 | rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL); | 1721 | rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL); |
1631 | rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr); | 1722 | rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr); |