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