aboutsummaryrefslogtreecommitdiffstats
path: root/net/bridge/br_fdb.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/bridge/br_fdb.c')
-rw-r--r--net/bridge/br_fdb.c266
1 files changed, 143 insertions, 123 deletions
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index d9576e6de2b..68def3b7fb4 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -28,8 +28,7 @@
28static struct kmem_cache *br_fdb_cache __read_mostly; 28static struct kmem_cache *br_fdb_cache __read_mostly;
29static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source, 29static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
30 const unsigned char *addr); 30 const unsigned char *addr);
31static void fdb_notify(struct net_bridge *br, 31static void fdb_notify(const struct net_bridge_fdb_entry *, int);
32 const struct net_bridge_fdb_entry *, int);
33 32
34static u32 fdb_salt __read_mostly; 33static u32 fdb_salt __read_mostly;
35 34
@@ -81,10 +80,10 @@ static void fdb_rcu_free(struct rcu_head *head)
81 kmem_cache_free(br_fdb_cache, ent); 80 kmem_cache_free(br_fdb_cache, ent);
82} 81}
83 82
84static void fdb_delete(struct net_bridge *br, struct net_bridge_fdb_entry *f) 83static inline void fdb_delete(struct net_bridge_fdb_entry *f)
85{ 84{
85 fdb_notify(f, RTM_DELNEIGH);
86 hlist_del_rcu(&f->hlist); 86 hlist_del_rcu(&f->hlist);
87 fdb_notify(br, f, RTM_DELNEIGH);
88 call_rcu(&f->rcu, fdb_rcu_free); 87 call_rcu(&f->rcu, fdb_rcu_free);
89} 88}
90 89
@@ -107,15 +106,15 @@ void br_fdb_changeaddr(struct net_bridge_port *p, const unsigned char *newaddr)
107 struct net_bridge_port *op; 106 struct net_bridge_port *op;
108 list_for_each_entry(op, &br->port_list, list) { 107 list_for_each_entry(op, &br->port_list, list) {
109 if (op != p && 108 if (op != p &&
110 ether_addr_equal(op->dev->dev_addr, 109 !compare_ether_addr(op->dev->dev_addr,
111 f->addr.addr)) { 110 f->addr.addr)) {
112 f->dst = op; 111 f->dst = op;
113 goto insert; 112 goto insert;
114 } 113 }
115 } 114 }
116 115
117 /* delete old one */ 116 /* delete old one */
118 fdb_delete(br, f); 117 fdb_delete(f);
119 goto insert; 118 goto insert;
120 } 119 }
121 } 120 }
@@ -127,18 +126,6 @@ void br_fdb_changeaddr(struct net_bridge_port *p, const unsigned char *newaddr)
127 spin_unlock_bh(&br->hash_lock); 126 spin_unlock_bh(&br->hash_lock);
128} 127}
129 128
130void br_fdb_change_mac_address(struct net_bridge *br, const u8 *newaddr)
131{
132 struct net_bridge_fdb_entry *f;
133
134 /* If old entry was unassociated with any port, then delete it. */
135 f = __br_fdb_get(br, br->dev->dev_addr);
136 if (f && f->is_local && !f->dst)
137 fdb_delete(br, f);
138
139 fdb_insert(br, NULL, newaddr);
140}
141
142void br_fdb_cleanup(unsigned long _data) 129void br_fdb_cleanup(unsigned long _data)
143{ 130{
144 struct net_bridge *br = (struct net_bridge *)_data; 131 struct net_bridge *br = (struct net_bridge *)_data;
@@ -146,7 +133,7 @@ void br_fdb_cleanup(unsigned long _data)
146 unsigned long next_timer = jiffies + br->ageing_time; 133 unsigned long next_timer = jiffies + br->ageing_time;
147 int i; 134 int i;
148 135
149 spin_lock(&br->hash_lock); 136 spin_lock_bh(&br->hash_lock);
150 for (i = 0; i < BR_HASH_SIZE; i++) { 137 for (i = 0; i < BR_HASH_SIZE; i++) {
151 struct net_bridge_fdb_entry *f; 138 struct net_bridge_fdb_entry *f;
152 struct hlist_node *h, *n; 139 struct hlist_node *h, *n;
@@ -157,12 +144,12 @@ void br_fdb_cleanup(unsigned long _data)
157 continue; 144 continue;
158 this_timer = f->updated + delay; 145 this_timer = f->updated + delay;
159 if (time_before_eq(this_timer, jiffies)) 146 if (time_before_eq(this_timer, jiffies))
160 fdb_delete(br, f); 147 fdb_delete(f);
161 else if (time_before(this_timer, next_timer)) 148 else if (time_before(this_timer, next_timer))
162 next_timer = this_timer; 149 next_timer = this_timer;
163 } 150 }
164 } 151 }
165 spin_unlock(&br->hash_lock); 152 spin_unlock_bh(&br->hash_lock);
166 153
167 mod_timer(&br->gc_timer, round_jiffies_up(next_timer)); 154 mod_timer(&br->gc_timer, round_jiffies_up(next_timer));
168} 155}
@@ -178,7 +165,7 @@ void br_fdb_flush(struct net_bridge *br)
178 struct hlist_node *h, *n; 165 struct hlist_node *h, *n;
179 hlist_for_each_entry_safe(f, h, n, &br->hash[i], hlist) { 166 hlist_for_each_entry_safe(f, h, n, &br->hash[i], hlist) {
180 if (!f->is_static) 167 if (!f->is_static)
181 fdb_delete(br, f); 168 fdb_delete(f);
182 } 169 }
183 } 170 }
184 spin_unlock_bh(&br->hash_lock); 171 spin_unlock_bh(&br->hash_lock);
@@ -214,15 +201,15 @@ void br_fdb_delete_by_port(struct net_bridge *br,
214 struct net_bridge_port *op; 201 struct net_bridge_port *op;
215 list_for_each_entry(op, &br->port_list, list) { 202 list_for_each_entry(op, &br->port_list, list) {
216 if (op != p && 203 if (op != p &&
217 ether_addr_equal(op->dev->dev_addr, 204 !compare_ether_addr(op->dev->dev_addr,
218 f->addr.addr)) { 205 f->addr.addr)) {
219 f->dst = op; 206 f->dst = op;
220 goto skip_delete; 207 goto skip_delete;
221 } 208 }
222 } 209 }
223 } 210 }
224 211
225 fdb_delete(br, f); 212 fdb_delete(f);
226 skip_delete: ; 213 skip_delete: ;
227 } 214 }
228 } 215 }
@@ -237,7 +224,7 @@ struct net_bridge_fdb_entry *__br_fdb_get(struct net_bridge *br,
237 struct net_bridge_fdb_entry *fdb; 224 struct net_bridge_fdb_entry *fdb;
238 225
239 hlist_for_each_entry_rcu(fdb, h, &br->hash[br_mac_hash(addr)], hlist) { 226 hlist_for_each_entry_rcu(fdb, h, &br->hash[br_mac_hash(addr)], hlist) {
240 if (ether_addr_equal(fdb->addr.addr, addr)) { 227 if (!compare_ether_addr(fdb->addr.addr, addr)) {
241 if (unlikely(has_expired(br, fdb))) 228 if (unlikely(has_expired(br, fdb)))
242 break; 229 break;
243 return fdb; 230 return fdb;
@@ -247,7 +234,7 @@ struct net_bridge_fdb_entry *__br_fdb_get(struct net_bridge *br,
247 return NULL; 234 return NULL;
248} 235}
249 236
250#if IS_ENABLED(CONFIG_ATM_LANE) 237#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
251/* Interface used by ATM LANE hook to test 238/* Interface used by ATM LANE hook to test
252 * if an addr is on some other bridge port */ 239 * if an addr is on some other bridge port */
253int br_fdb_test_addr(struct net_device *dev, unsigned char *addr) 240int br_fdb_test_addr(struct net_device *dev, unsigned char *addr)
@@ -262,7 +249,7 @@ int br_fdb_test_addr(struct net_device *dev, unsigned char *addr)
262 ret = 0; 249 ret = 0;
263 else { 250 else {
264 fdb = __br_fdb_get(port->br, addr); 251 fdb = __br_fdb_get(port->br, addr);
265 ret = fdb && fdb->dst && fdb->dst->dev != dev && 252 ret = fdb && fdb->dst->dev != dev &&
266 fdb->dst->state == BR_STATE_FORWARDING; 253 fdb->dst->state == BR_STATE_FORWARDING;
267 } 254 }
268 rcu_read_unlock(); 255 rcu_read_unlock();
@@ -294,10 +281,6 @@ int br_fdb_fillbuf(struct net_bridge *br, void *buf,
294 if (has_expired(br, f)) 281 if (has_expired(br, f))
295 continue; 282 continue;
296 283
297 /* ignore pseudo entry for local MAC address */
298 if (!f->dst)
299 continue;
300
301 if (skip) { 284 if (skip) {
302 --skip; 285 --skip;
303 continue; 286 continue;
@@ -312,7 +295,7 @@ int br_fdb_fillbuf(struct net_bridge *br, void *buf,
312 295
313 fe->is_local = f->is_local; 296 fe->is_local = f->is_local;
314 if (!f->is_static) 297 if (!f->is_static)
315 fe->ageing_timer_value = jiffies_delta_to_clock_t(jiffies - f->updated); 298 fe->ageing_timer_value = jiffies_to_clock_t(jiffies - f->updated);
316 ++fe; 299 ++fe;
317 ++num; 300 ++num;
318 } 301 }
@@ -331,7 +314,7 @@ static struct net_bridge_fdb_entry *fdb_find(struct hlist_head *head,
331 struct net_bridge_fdb_entry *fdb; 314 struct net_bridge_fdb_entry *fdb;
332 315
333 hlist_for_each_entry(fdb, h, head, hlist) { 316 hlist_for_each_entry(fdb, h, head, hlist) {
334 if (ether_addr_equal(fdb->addr.addr, addr)) 317 if (!compare_ether_addr(fdb->addr.addr, addr))
335 return fdb; 318 return fdb;
336 } 319 }
337 return NULL; 320 return NULL;
@@ -344,7 +327,7 @@ static struct net_bridge_fdb_entry *fdb_find_rcu(struct hlist_head *head,
344 struct net_bridge_fdb_entry *fdb; 327 struct net_bridge_fdb_entry *fdb;
345 328
346 hlist_for_each_entry_rcu(fdb, h, head, hlist) { 329 hlist_for_each_entry_rcu(fdb, h, head, hlist) {
347 if (ether_addr_equal(fdb->addr.addr, addr)) 330 if (!compare_ether_addr(fdb->addr.addr, addr))
348 return fdb; 331 return fdb;
349 } 332 }
350 return NULL; 333 return NULL;
@@ -364,6 +347,7 @@ static struct net_bridge_fdb_entry *fdb_create(struct hlist_head *head,
364 fdb->is_static = 0; 347 fdb->is_static = 0;
365 fdb->updated = fdb->used = jiffies; 348 fdb->updated = fdb->used = jiffies;
366 hlist_add_head_rcu(&fdb->hlist, head); 349 hlist_add_head_rcu(&fdb->hlist, head);
350 fdb_notify(fdb, RTM_NEWNEIGH);
367 } 351 }
368 return fdb; 352 return fdb;
369} 353}
@@ -387,7 +371,7 @@ static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
387 br_warn(br, "adding interface %s with same address " 371 br_warn(br, "adding interface %s with same address "
388 "as a received packet\n", 372 "as a received packet\n",
389 source->dev->name); 373 source->dev->name);
390 fdb_delete(br, fdb); 374 fdb_delete(fdb);
391 } 375 }
392 376
393 fdb = fdb_create(head, source, addr); 377 fdb = fdb_create(head, source, addr);
@@ -395,7 +379,6 @@ static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
395 return -ENOMEM; 379 return -ENOMEM;
396 380
397 fdb->is_local = fdb->is_static = 1; 381 fdb->is_local = fdb->is_static = 1;
398 fdb_notify(br, fdb, RTM_NEWNEIGH);
399 return 0; 382 return 0;
400} 383}
401 384
@@ -441,11 +424,9 @@ void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source,
441 } 424 }
442 } else { 425 } else {
443 spin_lock(&br->hash_lock); 426 spin_lock(&br->hash_lock);
444 if (likely(!fdb_find(head, addr))) { 427 if (likely(!fdb_find(head, addr)))
445 fdb = fdb_create(head, source, addr); 428 fdb_create(head, source, addr);
446 if (fdb) 429
447 fdb_notify(br, fdb, RTM_NEWNEIGH);
448 }
449 /* else we lose race and someone else inserts 430 /* else we lose race and someone else inserts
450 * it first, don't bother updating 431 * it first, don't bother updating
451 */ 432 */
@@ -465,36 +446,37 @@ static int fdb_to_nud(const struct net_bridge_fdb_entry *fdb)
465 return NUD_REACHABLE; 446 return NUD_REACHABLE;
466} 447}
467 448
468static int fdb_fill_info(struct sk_buff *skb, const struct net_bridge *br, 449static int fdb_fill_info(struct sk_buff *skb,
469 const struct net_bridge_fdb_entry *fdb, 450 const struct net_bridge_fdb_entry *fdb,
470 u32 portid, u32 seq, int type, unsigned int flags) 451 u32 pid, u32 seq, int type, unsigned int flags)
471{ 452{
472 unsigned long now = jiffies; 453 unsigned long now = jiffies;
473 struct nda_cacheinfo ci; 454 struct nda_cacheinfo ci;
474 struct nlmsghdr *nlh; 455 struct nlmsghdr *nlh;
475 struct ndmsg *ndm; 456 struct ndmsg *ndm;
476 457
477 nlh = nlmsg_put(skb, portid, seq, type, sizeof(*ndm), flags); 458 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags);
478 if (nlh == NULL) 459 if (nlh == NULL)
479 return -EMSGSIZE; 460 return -EMSGSIZE;
480 461
462
481 ndm = nlmsg_data(nlh); 463 ndm = nlmsg_data(nlh);
482 ndm->ndm_family = AF_BRIDGE; 464 ndm->ndm_family = AF_BRIDGE;
483 ndm->ndm_pad1 = 0; 465 ndm->ndm_pad1 = 0;
484 ndm->ndm_pad2 = 0; 466 ndm->ndm_pad2 = 0;
485 ndm->ndm_flags = 0; 467 ndm->ndm_flags = 0;
486 ndm->ndm_type = 0; 468 ndm->ndm_type = 0;
487 ndm->ndm_ifindex = fdb->dst ? fdb->dst->dev->ifindex : br->dev->ifindex; 469 ndm->ndm_ifindex = fdb->dst->dev->ifindex;
488 ndm->ndm_state = fdb_to_nud(fdb); 470 ndm->ndm_state = fdb_to_nud(fdb);
489 471
490 if (nla_put(skb, NDA_LLADDR, ETH_ALEN, &fdb->addr)) 472 NLA_PUT(skb, NDA_LLADDR, ETH_ALEN, &fdb->addr);
491 goto nla_put_failure; 473
492 ci.ndm_used = jiffies_to_clock_t(now - fdb->used); 474 ci.ndm_used = jiffies_to_clock_t(now - fdb->used);
493 ci.ndm_confirmed = 0; 475 ci.ndm_confirmed = 0;
494 ci.ndm_updated = jiffies_to_clock_t(now - fdb->updated); 476 ci.ndm_updated = jiffies_to_clock_t(now - fdb->updated);
495 ci.ndm_refcnt = 0; 477 ci.ndm_refcnt = 0;
496 if (nla_put(skb, NDA_CACHEINFO, sizeof(ci), &ci)) 478 NLA_PUT(skb, NDA_CACHEINFO, sizeof(ci), &ci);
497 goto nla_put_failure; 479
498 return nlmsg_end(skb, nlh); 480 return nlmsg_end(skb, nlh);
499 481
500nla_put_failure: 482nla_put_failure:
@@ -509,10 +491,9 @@ static inline size_t fdb_nlmsg_size(void)
509 + nla_total_size(sizeof(struct nda_cacheinfo)); 491 + nla_total_size(sizeof(struct nda_cacheinfo));
510} 492}
511 493
512static void fdb_notify(struct net_bridge *br, 494static void fdb_notify(const struct net_bridge_fdb_entry *fdb, int type)
513 const struct net_bridge_fdb_entry *fdb, int type)
514{ 495{
515 struct net *net = dev_net(br->dev); 496 struct net *net = dev_net(fdb->dst->dev);
516 struct sk_buff *skb; 497 struct sk_buff *skb;
517 int err = -ENOBUFS; 498 int err = -ENOBUFS;
518 499
@@ -520,7 +501,7 @@ static void fdb_notify(struct net_bridge *br,
520 if (skb == NULL) 501 if (skb == NULL)
521 goto errout; 502 goto errout;
522 503
523 err = fdb_fill_info(skb, br, fdb, 0, 0, type, 0); 504 err = fdb_fill_info(skb, fdb, 0, 0, type, 0);
524 if (err < 0) { 505 if (err < 0) {
525 /* -EMSGSIZE implies BUG in fdb_nlmsg_size() */ 506 /* -EMSGSIZE implies BUG in fdb_nlmsg_size() */
526 WARN_ON(err == -EMSGSIZE); 507 WARN_ON(err == -EMSGSIZE);
@@ -535,88 +516,105 @@ errout:
535} 516}
536 517
537/* Dump information about entries, in response to GETNEIGH */ 518/* Dump information about entries, in response to GETNEIGH */
538int br_fdb_dump(struct sk_buff *skb, 519int br_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb)
539 struct netlink_callback *cb,
540 struct net_device *dev,
541 int idx)
542{ 520{
543 struct net_bridge *br = netdev_priv(dev); 521 struct net *net = sock_net(skb->sk);
544 int i; 522 struct net_device *dev;
523 int idx = 0;
524
525 rcu_read_lock();
526 for_each_netdev_rcu(net, dev) {
527 struct net_bridge *br = netdev_priv(dev);
528 int i;
545 529
546 if (!(dev->priv_flags & IFF_EBRIDGE)) 530 if (!(dev->priv_flags & IFF_EBRIDGE))
547 goto out; 531 continue;
548 532
549 for (i = 0; i < BR_HASH_SIZE; i++) { 533 for (i = 0; i < BR_HASH_SIZE; i++) {
550 struct hlist_node *h; 534 struct hlist_node *h;
551 struct net_bridge_fdb_entry *f; 535 struct net_bridge_fdb_entry *f;
552 536
553 hlist_for_each_entry_rcu(f, h, &br->hash[i], hlist) { 537 hlist_for_each_entry_rcu(f, h, &br->hash[i], hlist) {
554 if (idx < cb->args[0]) 538 if (idx < cb->args[0])
555 goto skip; 539 goto skip;
556 540
557 if (fdb_fill_info(skb, br, f, 541 if (fdb_fill_info(skb, f,
558 NETLINK_CB(cb->skb).portid, 542 NETLINK_CB(cb->skb).pid,
559 cb->nlh->nlmsg_seq, 543 cb->nlh->nlmsg_seq,
560 RTM_NEWNEIGH, 544 RTM_NEWNEIGH,
561 NLM_F_MULTI) < 0) 545 NLM_F_MULTI) < 0)
562 break; 546 break;
563skip: 547skip:
564 ++idx; 548 ++idx;
549 }
565 } 550 }
566 } 551 }
552 rcu_read_unlock();
553
554 cb->args[0] = idx;
567 555
568out: 556 return skb->len;
569 return idx;
570} 557}
571 558
572/* Update (create or replace) forwarding database entry */ 559/* Create new static fdb entry */
573static int fdb_add_entry(struct net_bridge_port *source, const __u8 *addr, 560static int fdb_add_entry(struct net_bridge_port *source, const __u8 *addr,
574 __u16 state, __u16 flags) 561 __u16 state)
575{ 562{
576 struct net_bridge *br = source->br; 563 struct net_bridge *br = source->br;
577 struct hlist_head *head = &br->hash[br_mac_hash(addr)]; 564 struct hlist_head *head = &br->hash[br_mac_hash(addr)];
578 struct net_bridge_fdb_entry *fdb; 565 struct net_bridge_fdb_entry *fdb;
579 566
580 fdb = fdb_find(head, addr); 567 fdb = fdb_find(head, addr);
581 if (fdb == NULL) { 568 if (fdb)
582 if (!(flags & NLM_F_CREATE)) 569 return -EEXIST;
583 return -ENOENT;
584
585 fdb = fdb_create(head, source, addr);
586 if (!fdb)
587 return -ENOMEM;
588 fdb_notify(br, fdb, RTM_NEWNEIGH);
589 } else {
590 if (flags & NLM_F_EXCL)
591 return -EEXIST;
592 }
593 570
594 if (fdb_to_nud(fdb) != state) { 571 fdb = fdb_create(head, source, addr);
595 if (state & NUD_PERMANENT) 572 if (!fdb)
596 fdb->is_local = fdb->is_static = 1; 573 return -ENOMEM;
597 else if (state & NUD_NOARP) {
598 fdb->is_local = 0;
599 fdb->is_static = 1;
600 } else
601 fdb->is_local = fdb->is_static = 0;
602
603 fdb->updated = fdb->used = jiffies;
604 fdb_notify(br, fdb, RTM_NEWNEIGH);
605 }
606 574
575 if (state & NUD_PERMANENT)
576 fdb->is_local = fdb->is_static = 1;
577 else if (state & NUD_NOARP)
578 fdb->is_static = 1;
607 return 0; 579 return 0;
608} 580}
609 581
610/* Add new permanent fdb entry with RTM_NEWNEIGH */ 582/* Add new permanent fdb entry with RTM_NEWNEIGH */
611int br_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], 583int br_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
612 struct net_device *dev,
613 const unsigned char *addr, u16 nlh_flags)
614{ 584{
585 struct net *net = sock_net(skb->sk);
586 struct ndmsg *ndm;
587 struct nlattr *tb[NDA_MAX+1];
588 struct net_device *dev;
615 struct net_bridge_port *p; 589 struct net_bridge_port *p;
616 int err = 0; 590 const __u8 *addr;
591 int err;
617 592
618 if (!(ndm->ndm_state & (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE))) { 593 ASSERT_RTNL();
619 pr_info("bridge: RTM_NEWNEIGH with invalid state %#x\n", ndm->ndm_state); 594 err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL);
595 if (err < 0)
596 return err;
597
598 ndm = nlmsg_data(nlh);
599 if (ndm->ndm_ifindex == 0) {
600 pr_info("bridge: RTM_NEWNEIGH with invalid ifindex\n");
601 return -EINVAL;
602 }
603
604 dev = __dev_get_by_index(net, ndm->ndm_ifindex);
605 if (dev == NULL) {
606 pr_info("bridge: RTM_NEWNEIGH with unknown ifindex\n");
607 return -ENODEV;
608 }
609
610 if (!tb[NDA_LLADDR] || nla_len(tb[NDA_LLADDR]) != ETH_ALEN) {
611 pr_info("bridge: RTM_NEWNEIGH with invalid address\n");
612 return -EINVAL;
613 }
614
615 addr = nla_data(tb[NDA_LLADDR]);
616 if (!is_valid_ether_addr(addr)) {
617 pr_info("bridge: RTM_NEWNEIGH with invalid ether address\n");
620 return -EINVAL; 618 return -EINVAL;
621 } 619 }
622 620
@@ -627,15 +625,9 @@ int br_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
627 return -EINVAL; 625 return -EINVAL;
628 } 626 }
629 627
630 if (ndm->ndm_flags & NTF_USE) { 628 spin_lock_bh(&p->br->hash_lock);
631 rcu_read_lock(); 629 err = fdb_add_entry(p, addr, ndm->ndm_state);
632 br_fdb_update(p->br, p, addr); 630 spin_unlock_bh(&p->br->hash_lock);
633 rcu_read_unlock();
634 } else {
635 spin_lock_bh(&p->br->hash_lock);
636 err = fdb_add_entry(p, addr, ndm->ndm_state, nlh_flags);
637 spin_unlock_bh(&p->br->hash_lock);
638 }
639 631
640 return err; 632 return err;
641} 633}
@@ -650,17 +642,45 @@ static int fdb_delete_by_addr(struct net_bridge_port *p, const u8 *addr)
650 if (!fdb) 642 if (!fdb)
651 return -ENOENT; 643 return -ENOENT;
652 644
653 fdb_delete(p->br, fdb); 645 fdb_delete(fdb);
654 return 0; 646 return 0;
655} 647}
656 648
657/* Remove neighbor entry with RTM_DELNEIGH */ 649/* Remove neighbor entry with RTM_DELNEIGH */
658int br_fdb_delete(struct ndmsg *ndm, struct net_device *dev, 650int br_fdb_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
659 const unsigned char *addr)
660{ 651{
652 struct net *net = sock_net(skb->sk);
653 struct ndmsg *ndm;
661 struct net_bridge_port *p; 654 struct net_bridge_port *p;
655 struct nlattr *llattr;
656 const __u8 *addr;
657 struct net_device *dev;
662 int err; 658 int err;
663 659
660 ASSERT_RTNL();
661 if (nlmsg_len(nlh) < sizeof(*ndm))
662 return -EINVAL;
663
664 ndm = nlmsg_data(nlh);
665 if (ndm->ndm_ifindex == 0) {
666 pr_info("bridge: RTM_DELNEIGH with invalid ifindex\n");
667 return -EINVAL;
668 }
669
670 dev = __dev_get_by_index(net, ndm->ndm_ifindex);
671 if (dev == NULL) {
672 pr_info("bridge: RTM_DELNEIGH with unknown ifindex\n");
673 return -ENODEV;
674 }
675
676 llattr = nlmsg_find_attr(nlh, sizeof(*ndm), NDA_LLADDR);
677 if (llattr == NULL || nla_len(llattr) != ETH_ALEN) {
678 pr_info("bridge: RTM_DELNEIGH with invalid address\n");
679 return -EINVAL;
680 }
681
682 addr = nla_data(llattr);
683
664 p = br_port_get_rtnl(dev); 684 p = br_port_get_rtnl(dev);
665 if (p == NULL) { 685 if (p == NULL) {
666 pr_info("bridge: RTM_DELNEIGH %s not a bridge port\n", 686 pr_info("bridge: RTM_DELNEIGH %s not a bridge port\n",