aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/rtnetlink.h12
-rw-r--r--net/core/rtnetlink.c29
-rw-r--r--net/ipv4/devinet.c26
-rw-r--r--net/ipv6/addrconf.c6
4 files changed, 53 insertions, 20 deletions
diff --git a/include/net/rtnetlink.h b/include/net/rtnetlink.h
index 35be0bbcd7da..4093ca78cf60 100644
--- a/include/net/rtnetlink.h
+++ b/include/net/rtnetlink.h
@@ -92,8 +92,10 @@ extern void rtnl_link_unregister(struct rtnl_link_ops *ops);
92 * specific netlink attributes. 92 * specific netlink attributes.
93 * @get_link_af_size: Function to calculate size of address family specific 93 * @get_link_af_size: Function to calculate size of address family specific
94 * netlink attributes exlusive the container attribute. 94 * netlink attributes exlusive the container attribute.
95 * @parse_link_af: Function to parse a IFLA_AF_SPEC attribute and modify 95 * @validate_link_af: Validate a IFLA_AF_SPEC attribute, must check attr
96 * net_device accordingly. 96 * for invalid configuration settings.
97 * @set_link_af: Function to parse a IFLA_AF_SPEC attribute and modify
98 * net_device accordingly.
97 */ 99 */
98struct rtnl_af_ops { 100struct rtnl_af_ops {
99 struct list_head list; 101 struct list_head list;
@@ -103,8 +105,10 @@ struct rtnl_af_ops {
103 const struct net_device *dev); 105 const struct net_device *dev);
104 size_t (*get_link_af_size)(const struct net_device *dev); 106 size_t (*get_link_af_size)(const struct net_device *dev);
105 107
106 int (*parse_link_af)(struct net_device *dev, 108 int (*validate_link_af)(const struct net_device *dev,
107 const struct nlattr *attr); 109 const struct nlattr *attr);
110 int (*set_link_af)(struct net_device *dev,
111 const struct nlattr *attr);
108}; 112};
109 113
110extern int __rtnl_af_register(struct rtnl_af_ops *ops); 114extern int __rtnl_af_register(struct rtnl_af_ops *ops);
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index bf69e5871b1a..750db57f3bb3 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -1107,6 +1107,28 @@ static int validate_linkmsg(struct net_device *dev, struct nlattr *tb[])
1107 return -EINVAL; 1107 return -EINVAL;
1108 } 1108 }
1109 1109
1110 if (tb[IFLA_AF_SPEC]) {
1111 struct nlattr *af;
1112 int rem, err;
1113
1114 nla_for_each_nested(af, tb[IFLA_AF_SPEC], rem) {
1115 const struct rtnl_af_ops *af_ops;
1116
1117 if (!(af_ops = rtnl_af_lookup(nla_type(af))))
1118 return -EAFNOSUPPORT;
1119
1120 if (!af_ops->set_link_af)
1121 return -EOPNOTSUPP;
1122
1123 if (af_ops->validate_link_af) {
1124 err = af_ops->validate_link_af(dev,
1125 tb[IFLA_AF_SPEC]);
1126 if (err < 0)
1127 return err;
1128 }
1129 }
1130 }
1131
1110 return 0; 1132 return 0;
1111} 1133}
1112 1134
@@ -1356,12 +1378,9 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
1356 const struct rtnl_af_ops *af_ops; 1378 const struct rtnl_af_ops *af_ops;
1357 1379
1358 if (!(af_ops = rtnl_af_lookup(nla_type(af)))) 1380 if (!(af_ops = rtnl_af_lookup(nla_type(af))))
1359 continue; 1381 BUG();
1360
1361 if (!af_ops->parse_link_af)
1362 continue;
1363 1382
1364 err = af_ops->parse_link_af(dev, af); 1383 err = af_ops->set_link_af(dev, af);
1365 if (err < 0) 1384 if (err < 0)
1366 goto errout; 1385 goto errout;
1367 1386
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 71afc26c2df8..d9f71bae45c4 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -1289,14 +1289,14 @@ static const struct nla_policy inet_af_policy[IFLA_INET_MAX+1] = {
1289 [IFLA_INET_CONF] = { .type = NLA_NESTED }, 1289 [IFLA_INET_CONF] = { .type = NLA_NESTED },
1290}; 1290};
1291 1291
1292static int inet_parse_link_af(struct net_device *dev, const struct nlattr *nla) 1292static int inet_validate_link_af(const struct net_device *dev,
1293 const struct nlattr *nla)
1293{ 1294{
1294 struct in_device *in_dev = __in_dev_get_rcu(dev);
1295 struct nlattr *a, *tb[IFLA_INET_MAX+1]; 1295 struct nlattr *a, *tb[IFLA_INET_MAX+1];
1296 int err, rem; 1296 int err, rem;
1297 1297
1298 if (!in_dev) 1298 if (dev && !__in_dev_get_rcu(dev))
1299 return -EOPNOTSUPP; 1299 return -EAFNOSUPPORT;
1300 1300
1301 err = nla_parse_nested(tb, IFLA_INET_MAX, nla, inet_af_policy); 1301 err = nla_parse_nested(tb, IFLA_INET_MAX, nla, inet_af_policy);
1302 if (err < 0) 1302 if (err < 0)
@@ -1314,6 +1314,21 @@ static int inet_parse_link_af(struct net_device *dev, const struct nlattr *nla)
1314 } 1314 }
1315 } 1315 }
1316 1316
1317 return 0;
1318}
1319
1320static int inet_set_link_af(struct net_device *dev, const struct nlattr *nla)
1321{
1322 struct in_device *in_dev = __in_dev_get_rcu(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
1317 if (tb[IFLA_INET_CONF]) { 1332 if (tb[IFLA_INET_CONF]) {
1318 nla_for_each_nested(a, tb[IFLA_INET_CONF], rem) 1333 nla_for_each_nested(a, tb[IFLA_INET_CONF], rem)
1319 ipv4_devconf_set(in_dev, nla_type(a), nla_get_u32(a)); 1334 ipv4_devconf_set(in_dev, nla_type(a), nla_get_u32(a));
@@ -1689,7 +1704,8 @@ static struct rtnl_af_ops inet_af_ops = {
1689 .family = AF_INET, 1704 .family = AF_INET,
1690 .fill_link_af = inet_fill_link_af, 1705 .fill_link_af = inet_fill_link_af,
1691 .get_link_af_size = inet_get_link_af_size, 1706 .get_link_af_size = inet_get_link_af_size,
1692 .parse_link_af = inet_parse_link_af, 1707 .validate_link_af = inet_validate_link_af,
1708 .set_link_af = inet_set_link_af,
1693}; 1709};
1694 1710
1695void __init devinet_init(void) 1711void __init devinet_init(void)
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 4cf760598c2a..1023ad0d2b15 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -3956,11 +3956,6 @@ static int inet6_fill_link_af(struct sk_buff *skb, const struct net_device *dev)
3956 return 0; 3956 return 0;
3957} 3957}
3958 3958
3959static int inet6_parse_link_af(struct net_device *dev, const struct nlattr *nla)
3960{
3961 return -EOPNOTSUPP;
3962}
3963
3964static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, 3959static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev,
3965 u32 pid, u32 seq, int event, unsigned int flags) 3960 u32 pid, u32 seq, int event, unsigned int flags)
3966{ 3961{
@@ -4670,7 +4665,6 @@ static struct rtnl_af_ops inet6_ops = {
4670 .family = AF_INET6, 4665 .family = AF_INET6,
4671 .fill_link_af = inet6_fill_link_af, 4666 .fill_link_af = inet6_fill_link_af,
4672 .get_link_af_size = inet6_get_link_af_size, 4667 .get_link_af_size = inet6_get_link_af_size,
4673 .parse_link_af = inet6_parse_link_af,
4674}; 4668};
4675 4669
4676/* 4670/*