diff options
Diffstat (limited to 'net/bridge/br_netlink.c')
-rw-r--r-- | net/bridge/br_netlink.c | 60 |
1 files changed, 52 insertions, 8 deletions
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index f8bf4c7f842c..ffb0dc4cc0e8 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c | |||
@@ -12,9 +12,11 @@ | |||
12 | 12 | ||
13 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
14 | #include <linux/slab.h> | 14 | #include <linux/slab.h> |
15 | #include <linux/etherdevice.h> | ||
15 | #include <net/rtnetlink.h> | 16 | #include <net/rtnetlink.h> |
16 | #include <net/net_namespace.h> | 17 | #include <net/net_namespace.h> |
17 | #include <net/sock.h> | 18 | #include <net/sock.h> |
19 | |||
18 | #include "br_private.h" | 20 | #include "br_private.h" |
19 | 21 | ||
20 | static inline size_t br_nlmsg_size(void) | 22 | static inline size_t br_nlmsg_size(void) |
@@ -118,8 +120,9 @@ static int br_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) | |||
118 | int idx; | 120 | int idx; |
119 | 121 | ||
120 | idx = 0; | 122 | idx = 0; |
121 | for_each_netdev(net, dev) { | 123 | rcu_read_lock(); |
122 | struct net_bridge_port *port = br_port_get_rtnl(dev); | 124 | for_each_netdev_rcu(net, dev) { |
125 | struct net_bridge_port *port = br_port_get_rcu(dev); | ||
123 | 126 | ||
124 | /* not a bridge port */ | 127 | /* not a bridge port */ |
125 | if (!port || idx < cb->args[0]) | 128 | if (!port || idx < cb->args[0]) |
@@ -133,7 +136,7 @@ static int br_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) | |||
133 | skip: | 136 | skip: |
134 | ++idx; | 137 | ++idx; |
135 | } | 138 | } |
136 | 139 | rcu_read_unlock(); | |
137 | cb->args[0] = idx; | 140 | cb->args[0] = idx; |
138 | 141 | ||
139 | return skb->len; | 142 | return skb->len; |
@@ -188,20 +191,61 @@ static int br_rtm_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
188 | return 0; | 191 | return 0; |
189 | } | 192 | } |
190 | 193 | ||
194 | static int br_validate(struct nlattr *tb[], struct nlattr *data[]) | ||
195 | { | ||
196 | if (tb[IFLA_ADDRESS]) { | ||
197 | if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) | ||
198 | return -EINVAL; | ||
199 | if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) | ||
200 | return -EADDRNOTAVAIL; | ||
201 | } | ||
202 | |||
203 | return 0; | ||
204 | } | ||
205 | |||
206 | static struct rtnl_link_ops br_link_ops __read_mostly = { | ||
207 | .kind = "bridge", | ||
208 | .priv_size = sizeof(struct net_bridge), | ||
209 | .setup = br_dev_setup, | ||
210 | .validate = br_validate, | ||
211 | }; | ||
191 | 212 | ||
192 | int __init br_netlink_init(void) | 213 | int __init br_netlink_init(void) |
193 | { | 214 | { |
194 | if (__rtnl_register(PF_BRIDGE, RTM_GETLINK, NULL, br_dump_ifinfo)) | 215 | int err; |
195 | return -ENOBUFS; | ||
196 | 216 | ||
197 | /* Only the first call to __rtnl_register can fail */ | 217 | err = rtnl_link_register(&br_link_ops); |
198 | __rtnl_register(PF_BRIDGE, RTM_SETLINK, br_rtm_setlink, NULL); | 218 | if (err < 0) |
219 | goto err1; | ||
220 | |||
221 | err = __rtnl_register(PF_BRIDGE, RTM_GETLINK, NULL, br_dump_ifinfo); | ||
222 | if (err) | ||
223 | goto err2; | ||
224 | err = __rtnl_register(PF_BRIDGE, RTM_SETLINK, br_rtm_setlink, NULL); | ||
225 | if (err) | ||
226 | goto err3; | ||
227 | err = __rtnl_register(PF_BRIDGE, RTM_NEWNEIGH, br_fdb_add, NULL); | ||
228 | if (err) | ||
229 | goto err3; | ||
230 | err = __rtnl_register(PF_BRIDGE, RTM_DELNEIGH, br_fdb_delete, NULL); | ||
231 | if (err) | ||
232 | goto err3; | ||
233 | err = __rtnl_register(PF_BRIDGE, RTM_GETNEIGH, NULL, br_fdb_dump); | ||
234 | if (err) | ||
235 | goto err3; | ||
199 | 236 | ||
200 | return 0; | 237 | return 0; |
238 | |||
239 | err3: | ||
240 | rtnl_unregister_all(PF_BRIDGE); | ||
241 | err2: | ||
242 | rtnl_link_unregister(&br_link_ops); | ||
243 | err1: | ||
244 | return err; | ||
201 | } | 245 | } |
202 | 246 | ||
203 | void __exit br_netlink_fini(void) | 247 | void __exit br_netlink_fini(void) |
204 | { | 248 | { |
249 | rtnl_link_unregister(&br_link_ops); | ||
205 | rtnl_unregister_all(PF_BRIDGE); | 250 | rtnl_unregister_all(PF_BRIDGE); |
206 | } | 251 | } |
207 | |||