diff options
-rw-r--r-- | include/net/rtnetlink.h | 12 | ||||
-rw-r--r-- | net/core/rtnetlink.c | 29 | ||||
-rw-r--r-- | net/ipv4/devinet.c | 26 | ||||
-rw-r--r-- | net/ipv6/addrconf.c | 6 |
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 | */ |
98 | struct rtnl_af_ops { | 100 | struct 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 | ||
110 | extern int __rtnl_af_register(struct rtnl_af_ops *ops); | 114 | extern 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 | ||
1292 | static int inet_parse_link_af(struct net_device *dev, const struct nlattr *nla) | 1292 | static 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 | |||
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_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 | ||
1695 | void __init devinet_init(void) | 1711 | void __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 | ||
3959 | static int inet6_parse_link_af(struct net_device *dev, const struct nlattr *nla) | ||
3960 | { | ||
3961 | return -EOPNOTSUPP; | ||
3962 | } | ||
3963 | |||
3964 | static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, | 3959 | static 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 | /* |