• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6.36/net/bridge/
1/* Modified by Broadcom Corp. Portions Copyright (c) Broadcom Corp, 2012. */
2/*
3 *	Forwarding database
4 *	Linux ethernet bridge
5 *
6 *	Authors:
7 *	Lennert Buytenhek		<buytenh@gnu.org>
8 *
9 *	This program is free software; you can redistribute it and/or
10 *	modify it under the terms of the GNU General Public License
11 *	as published by the Free Software Foundation; either version
12 *	2 of the License, or (at your option) any later version.
13 */
14
15#include <linux/kernel.h>
16#include <linux/init.h>
17#include <linux/rculist.h>
18#include <linux/spinlock.h>
19#include <linux/times.h>
20#include <linux/netdevice.h>
21#include <linux/etherdevice.h>
22#include <linux/jhash.h>
23#include <linux/random.h>
24#include <linux/slab.h>
25#include <asm/atomic.h>
26#include <asm/unaligned.h>
27#include "br_private.h"
28#ifdef HNDCTF
29#include <linux/if.h>
30#include <linux/if_vlan.h>
31#include <linux/if_ether.h>
32#include <net/arp.h>
33#include <typedefs.h>
34#include <osl.h>
35#include <ctf/hndctf.h>
36#else
37#define BCMFASTPATH_HOST
38#endif	/* HNDCTF */
39
40#ifdef HNDCTF
41static void
42br_brc_init(ctf_brc_t *brc, unsigned char *ea, struct net_device *rxdev, unsigned char *sip)
43{
44	memset(brc, 0, sizeof(ctf_brc_t));
45
46	memcpy(brc->dhost.octet, ea, ETH_ALEN);
47
48        if (rxdev->priv_flags & IFF_802_1Q_VLAN) {
49		brc->txifp = (void *)vlan_dev_real_dev(rxdev);
50		brc->vid = vlan_dev_vlan_id(rxdev);
51		brc->action = ((vlan_dev_vlan_flags(rxdev) & 1) ?
52		                     CTF_ACTION_TAG : CTF_ACTION_UNTAG);
53	} else {
54		brc->txifp = (void *)rxdev;
55		brc->action = CTF_ACTION_UNTAG;
56	}
57
58	if (sip)
59		memcpy(&brc->ip, sip, IPV4_ADDR_LEN);
60
61#ifdef DEBUG
62	printk("mac %02x:%02x:%02x:%02x:%02x:%02x\n",
63	       brc->dhost.octet[0], brc->dhost.octet[1],
64	       brc->dhost.octet[2], brc->dhost.octet[3],
65	       brc->dhost.octet[4], brc->dhost.octet[5]);
66	printk("vid: %d action %x\n", brc->vid, brc->action);
67	printk("txif: %s\n", ((struct net_device *)brc->txifp)->name);
68#endif
69
70	return;
71}
72
73/*
74 * Add bridge cache entry.
75 */
76void
77br_brc_add(unsigned char *ea, struct net_device *rxdev, struct sk_buff *skb)
78{
79	ctf_brc_t brc_entry, *brcp;
80	struct ethhdr *eth;
81	struct arphdr *arp;
82	unsigned char *arp_ptr = NULL;
83
84	/* Add brc entry only if packet is received on ctf
85	 * enabled interface
86	 */
87	if (!ctf_isenabled(kcih, ((rxdev->priv_flags & IFF_802_1Q_VLAN) ?
88	                   vlan_dev_real_dev(rxdev) : rxdev)))
89		return;
90
91	if (skb) {
92		/* Only handle ARP Reply */
93		eth = (struct ethhdr *)skb_mac_header(skb);
94		if (eth->h_proto == htons(ETHER_TYPE_ARP)) {
95			arp = (struct arphdr *)skb_network_header(skb);
96			if (arp->ar_hrd == htons(ARPHRD_ETHER) &&
97			    arp->ar_pro == htons(ETH_P_IP) &&
98			    arp->ar_op == htons(ARPOP_REPLY)) {
99			    /* Extract source ip fields */
100				arp_ptr = (unsigned char *)(arp+1);
101				arp_ptr += skb->dev->addr_len;
102			}
103		}
104	}
105
106	br_brc_init(&brc_entry, ea, rxdev, arp_ptr);
107
108#ifdef DEBUG
109	printk("%s: Adding brc entry\n", __FUNCTION__);
110#endif
111
112	/* Add the bridge cache entry */
113	if ((brcp = ctf_brc_lkup(kcih, ea)) == NULL)
114		ctf_brc_add(kcih, &brc_entry);
115	else {
116		ctf_brc_release(kcih, brcp);
117		ctf_brc_update(kcih, &brc_entry);
118	}
119
120	return;
121}
122
123#endif /* HNDCTF */
124
125static struct kmem_cache *br_fdb_cache __read_mostly;
126static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
127		      const unsigned char *addr);
128
129static u32 fdb_salt __read_mostly;
130
131int __init br_fdb_init(void)
132{
133	br_fdb_cache = kmem_cache_create("bridge_fdb_cache",
134					 sizeof(struct net_bridge_fdb_entry),
135					 0,
136					 SLAB_HWCACHE_ALIGN, NULL);
137	if (!br_fdb_cache)
138		return -ENOMEM;
139
140	get_random_bytes(&fdb_salt, sizeof(fdb_salt));
141	return 0;
142}
143
144void br_fdb_fini(void)
145{
146	kmem_cache_destroy(br_fdb_cache);
147}
148
149
150/* if topology_changing then use forward_delay (default 15 sec)
151 * otherwise keep longer (default 5 minutes)
152 */
153static inline unsigned long hold_time(const struct net_bridge *br)
154{
155	return br->topology_change ? br->forward_delay : br->ageing_time;
156}
157
158static inline int has_expired(const struct net_bridge *br,
159				  const struct net_bridge_fdb_entry *fdb)
160{
161	return !fdb->is_static &&
162		time_before_eq(fdb->ageing_timer + hold_time(br), jiffies);
163}
164
165static inline int br_mac_hash(const unsigned char *mac)
166{
167	/* use 1 byte of OUI cnd 3 bytes of NIC */
168	u32 key = get_unaligned((u32 *)(mac + 2));
169	return jhash_1word(key, fdb_salt) & (BR_HASH_SIZE - 1);
170}
171
172static void fdb_rcu_free(struct rcu_head *head)
173{
174	struct net_bridge_fdb_entry *ent
175		= container_of(head, struct net_bridge_fdb_entry, rcu);
176	kmem_cache_free(br_fdb_cache, ent);
177}
178
179static inline void fdb_delete(struct net_bridge_fdb_entry *f)
180{
181	hlist_del_rcu(&f->hlist);
182
183#ifdef HNDCTF
184	/* Delete the corresponding brc entry when it expires
185	 * or deleted by user.
186	 */
187	ctf_brc_delete(kcih, f->addr.addr);
188#endif /* HNDCTF */
189
190	call_rcu(&f->rcu, fdb_rcu_free);
191}
192
193void br_fdb_changeaddr(struct net_bridge_port *p, const unsigned char *newaddr)
194{
195	struct net_bridge *br = p->br;
196	int i;
197
198	spin_lock_bh(&br->hash_lock);
199
200	/* Search all chains since old address/hash is unknown */
201	for (i = 0; i < BR_HASH_SIZE; i++) {
202		struct hlist_node *h;
203		hlist_for_each(h, &br->hash[i]) {
204			struct net_bridge_fdb_entry *f;
205
206			f = hlist_entry(h, struct net_bridge_fdb_entry, hlist);
207			if (f->dst == p && f->is_local) {
208				/* maybe another port has same hw addr? */
209				struct net_bridge_port *op;
210				list_for_each_entry(op, &br->port_list, list) {
211					if (op != p &&
212					    !compare_ether_addr(op->dev->dev_addr,
213								f->addr.addr)) {
214						f->dst = op;
215						goto insert;
216					}
217				}
218
219				/* delete old one */
220				fdb_delete(f);
221				goto insert;
222			}
223		}
224	}
225 insert:
226	/* insert new address,  may fail if invalid address or dup. */
227	fdb_insert(br, p, newaddr);
228
229	spin_unlock_bh(&br->hash_lock);
230}
231
232void br_fdb_cleanup(unsigned long _data)
233{
234	struct net_bridge *br = (struct net_bridge *)_data;
235	unsigned long delay = hold_time(br);
236	unsigned long next_timer = jiffies + br->ageing_time;
237	int i;
238
239	spin_lock_bh(&br->hash_lock);
240	for (i = 0; i < BR_HASH_SIZE; i++) {
241		struct net_bridge_fdb_entry *f;
242		struct hlist_node *h, *n;
243
244		hlist_for_each_entry_safe(f, h, n, &br->hash[i], hlist) {
245			unsigned long this_timer;
246			if (f->is_static)
247				continue;
248			this_timer = f->ageing_timer + delay;
249			if (time_before_eq(this_timer, jiffies)) {
250#ifdef HNDCTF
251				ctf_brc_t *brcp;
252
253				/* Before expiring the fdb entry check the brc
254				 * live counter to make sure there are no frames
255				 * on this connection for timeout period.
256				 */
257				brcp = ctf_brc_lkup(kcih, f->addr.addr);
258				if (brcp != NULL) {
259					uint32 arpip = 0;
260
261					if (brcp->live > 0) {
262						brcp->live = 0;
263						brcp->hitting = 0;
264						ctf_brc_release(kcih, brcp);
265						f->ageing_timer = jiffies;
266						continue;
267					} else if (brcp->hitting > 0) {
268						/* When bridge deletes a CTF hitting cache entry,
269						/* we use DHCP "probes" (ARP Request) to trigger
270						 * the CTF fast path restoration.
271						 */
272						brcp->hitting = 0;
273						if (brcp->ip != 0)
274							arpip = brcp->ip;
275					}
276					ctf_brc_release(kcih, brcp);
277					if (arpip != 0)
278						arp_send(ARPOP_REQUEST, ETH_P_ARP,
279							arpip, br->dev, 0, NULL,
280							NULL, NULL);
281				}
282#endif /* HNDCTF */
283				fdb_delete(f);
284			} else if (time_before(this_timer, next_timer))
285				next_timer = this_timer;
286		}
287	}
288	spin_unlock_bh(&br->hash_lock);
289
290	mod_timer(&br->gc_timer, round_jiffies_up(next_timer));
291}
292
293/* Completely flush all dynamic entries in forwarding database.*/
294void br_fdb_flush(struct net_bridge *br)
295{
296	int i;
297
298	spin_lock_bh(&br->hash_lock);
299	for (i = 0; i < BR_HASH_SIZE; i++) {
300		struct net_bridge_fdb_entry *f;
301		struct hlist_node *h, *n;
302		hlist_for_each_entry_safe(f, h, n, &br->hash[i], hlist) {
303			if (!f->is_static)
304				fdb_delete(f);
305		}
306	}
307	spin_unlock_bh(&br->hash_lock);
308}
309
310/* Flush all entries refering to a specific port.
311 * if do_all is set also flush static entries
312 */
313void br_fdb_delete_by_port(struct net_bridge *br,
314			   const struct net_bridge_port *p,
315			   int do_all)
316{
317	int i;
318
319	spin_lock_bh(&br->hash_lock);
320	for (i = 0; i < BR_HASH_SIZE; i++) {
321		struct hlist_node *h, *g;
322
323		hlist_for_each_safe(h, g, &br->hash[i]) {
324			struct net_bridge_fdb_entry *f
325				= hlist_entry(h, struct net_bridge_fdb_entry, hlist);
326			if (f->dst != p)
327				continue;
328
329			if (f->is_static && !do_all)
330				continue;
331			/*
332			 * if multiple ports all have the same device address
333			 * then when one port is deleted, assign
334			 * the local entry to other port
335			 */
336			if (f->is_local) {
337				struct net_bridge_port *op;
338				list_for_each_entry(op, &br->port_list, list) {
339					if (op != p &&
340					    !compare_ether_addr(op->dev->dev_addr,
341								f->addr.addr)) {
342						f->dst = op;
343						goto skip_delete;
344					}
345				}
346			}
347
348			fdb_delete(f);
349		skip_delete: ;
350		}
351	}
352	spin_unlock_bh(&br->hash_lock);
353}
354
355/* No locking or refcounting, assumes caller has rcu_read_lock */
356struct net_bridge_fdb_entry * BCMFASTPATH_HOST __br_fdb_get(struct net_bridge *br,
357					  const unsigned char *addr)
358{
359	struct hlist_node *h;
360	struct net_bridge_fdb_entry *fdb;
361
362	hlist_for_each_entry_rcu(fdb, h, &br->hash[br_mac_hash(addr)], hlist) {
363		if (!compare_ether_addr(fdb->addr.addr, addr)) {
364			if (unlikely(has_expired(br, fdb)))
365				break;
366			return fdb;
367		}
368	}
369
370	return NULL;
371}
372
373#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
374/* Interface used by ATM LANE hook to test
375 * if an addr is on some other bridge port */
376int br_fdb_test_addr(struct net_device *dev, unsigned char *addr)
377{
378	struct net_bridge_fdb_entry *fdb;
379	int ret;
380
381	if (!br_port_exists(dev))
382		return 0;
383
384	rcu_read_lock();
385	fdb = __br_fdb_get(br_port_get_rcu(dev)->br, addr);
386	ret = fdb && fdb->dst->dev != dev &&
387		fdb->dst->state == BR_STATE_FORWARDING;
388	rcu_read_unlock();
389
390	return ret;
391}
392#endif /* CONFIG_ATM_LANE */
393
394/*
395 * Fill buffer with forwarding table records in
396 * the API format.
397 */
398int br_fdb_fillbuf(struct net_bridge *br, void *buf,
399		   unsigned long maxnum, unsigned long skip)
400{
401	struct __fdb_entry *fe = buf;
402	int i, num = 0;
403	struct hlist_node *h;
404	struct net_bridge_fdb_entry *f;
405
406	memset(buf, 0, maxnum*sizeof(struct __fdb_entry));
407
408	rcu_read_lock();
409	for (i = 0; i < BR_HASH_SIZE; i++) {
410		hlist_for_each_entry_rcu(f, h, &br->hash[i], hlist) {
411			if (num >= maxnum)
412				goto out;
413
414			if (has_expired(br, f))
415				continue;
416
417			if (skip) {
418				--skip;
419				continue;
420			}
421
422			/* convert from internal format to API */
423			memcpy(fe->mac_addr, f->addr.addr, ETH_ALEN);
424
425			/* due to ABI compat need to split into hi/lo */
426			fe->port_no = f->dst->port_no;
427			fe->port_hi = f->dst->port_no >> 8;
428
429			fe->is_local = f->is_local;
430			if (!f->is_static)
431				fe->ageing_timer_value = jiffies_to_clock_t(jiffies - f->ageing_timer);
432			++fe;
433			++num;
434		}
435	}
436
437 out:
438	rcu_read_unlock();
439
440	return num;
441}
442
443static inline struct net_bridge_fdb_entry *fdb_find(struct hlist_head *head,
444						    const unsigned char *addr)
445{
446	struct hlist_node *h;
447	struct net_bridge_fdb_entry *fdb;
448
449	hlist_for_each_entry_rcu(fdb, h, head, hlist) {
450		if (!compare_ether_addr(fdb->addr.addr, addr))
451			return fdb;
452	}
453	return NULL;
454}
455
456#ifdef HNDCTF
457static struct net_bridge_fdb_entry *fdb_create(struct hlist_head *head,
458					       struct net_bridge_port *source,
459					       const unsigned char *addr,
460					       int is_local,
461					       struct sk_buff *skb)
462#else
463static struct net_bridge_fdb_entry *fdb_create(struct hlist_head *head,
464					       struct net_bridge_port *source,
465					       const unsigned char *addr,
466					       int is_local)
467#endif
468{
469	struct net_bridge_fdb_entry *fdb;
470
471	fdb = kmem_cache_alloc(br_fdb_cache, GFP_ATOMIC);
472	if (fdb) {
473		memcpy(fdb->addr.addr, addr, ETH_ALEN);
474		hlist_add_head_rcu(&fdb->hlist, head);
475
476		fdb->dst = source;
477		fdb->is_local = is_local;
478		fdb->is_static = is_local;
479		fdb->ageing_timer = jiffies;
480
481		/* Add bridge cache entry for non local hosts */
482#ifdef HNDCTF
483		if (!is_local && (source->state == BR_STATE_FORWARDING))
484			br_brc_add((unsigned char *)addr, source->dev, skb);
485#endif /* HNDCTF */
486	}
487	return fdb;
488}
489
490static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
491		  const unsigned char *addr)
492{
493	struct hlist_head *head = &br->hash[br_mac_hash(addr)];
494	struct net_bridge_fdb_entry *fdb;
495
496	if (!is_valid_ether_addr(addr))
497		return -EINVAL;
498
499	fdb = fdb_find(head, addr);
500	if (fdb) {
501		/* it is okay to have multiple ports with same
502		 * address, just use the first one.
503		 */
504		if (fdb->is_local)
505			return 0;
506		br_warn(br, "adding interface %s with same address "
507		       "as a received packet\n",
508		       source->dev->name);
509		fdb_delete(fdb);
510	}
511
512#ifdef HNDCTF
513	if (!fdb_create(head, source, addr, 1, NULL))
514#else
515	if (!fdb_create(head, source, addr, 1))
516#endif
517		return -ENOMEM;
518
519	return 0;
520}
521
522int br_fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
523		  const unsigned char *addr)
524{
525	int ret;
526
527	spin_lock_bh(&br->hash_lock);
528	ret = fdb_insert(br, source, addr);
529	spin_unlock_bh(&br->hash_lock);
530	return ret;
531}
532
533#ifdef HNDCTF
534void BCMFASTPATH_HOST br_fdb_update(struct net_bridge *br, struct net_bridge_port *source,
535		   const unsigned char *addr, struct sk_buff *skb)
536#else
537void BCMFASTPATH_HOST br_fdb_update(struct net_bridge *br, struct net_bridge_port *source,
538		   const unsigned char *addr)
539#endif
540{
541	struct hlist_head *head = &br->hash[br_mac_hash(addr)];
542	struct net_bridge_fdb_entry *fdb;
543
544	/* some users want to always flood. */
545	if (hold_time(br) == 0)
546		return;
547
548	/* ignore packets unless we are using this port */
549	if (!(source->state == BR_STATE_LEARNING ||
550	      source->state == BR_STATE_FORWARDING))
551		return;
552
553	fdb = fdb_find(head, addr);
554	if (likely(fdb)) {
555		/* attempt to update an entry for a local interface */
556		if (unlikely(fdb->is_local)) {
557			if (net_ratelimit())
558				br_debug(br, "received packet on %s with "
559					"own address as source address\n",
560					source->dev->name);
561		} else {
562			/* fastpath: update of existing entry */
563#ifdef HNDCTF
564			/* Add the entry if the addr is new, or
565			 * update the brc entry incase the host moved from
566			 * one bridge to another or to a different port under
567			 * the same bridge.
568			 */
569			if (source->state == BR_STATE_FORWARDING)
570				br_brc_add((unsigned char *)addr, source->dev, skb);
571#endif /* HNDCTF */
572
573			fdb->dst = source;
574			fdb->ageing_timer = jiffies;
575		}
576	} else {
577		spin_lock(&br->hash_lock);
578		if (!fdb_find(head, addr))
579#ifdef HNDCTF
580			fdb_create(head, source, addr, 0, skb);
581#else
582			fdb_create(head, source, addr, 0);
583#endif
584		/* else  we lose race and someone else inserts
585		 * it first, don't bother updating
586		 */
587		spin_unlock(&br->hash_lock);
588	}
589}
590