--- zzzz-none-000/linux-2.6.28.10/net/bridge/br_fdb.c 2009-05-02 18:54:43.000000000 +0000 +++ puma5-6360-529/linux-2.6.28.10/net/bridge/br_fdb.c 2010-10-01 08:25:34.000000000 +0000 @@ -10,6 +10,24 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ +/*---------------------------------------------------------------------------- +// Copyright 2007, Texas Instruments Incorporated +// +// This program has been modified from its original operation by Texas Instruments +// to do the following: +// +// 1. HIL Event generation to support TI Packet Processor +// +// THIS MODIFIED SOFTWARE AND DOCUMENTATION ARE PROVIDED +// "AS IS," AND TEXAS INSTRUMENTS MAKES NO REPRESENTATIONS +// OR WARRENTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY +// PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE OR +// DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY PATENTS, +// COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. +// +// These changes are covered as per original license +//-----------------------------------------------------------------------------*/ #include #include @@ -18,12 +36,23 @@ #include #include #include +#include #include #include #include #include #include "br_private.h" +#if defined(CONFIG_IFX_PPA_API) || defined(CONFIG_IFX_PPA_API_MODULE) +#include +#endif + +#if defined(CONFIG_FUSIV_KERNEL_AP_2_AP) || defined(CONFIG_FUSIV_KERNEL_AP_2_AP_MODULE) +void (*ap2apBridgeFlowDelete_ptr)(void *) = NULL; +int (*Isap2apBridgeTraffic_ptr)(void *) = NULL; +short (*apAddBridgePortNewHWaddr_ptr)( struct net_bridge_port* p) = NULL; +#endif + static struct kmem_cache *br_fdb_cache __read_mostly; static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source, const unsigned char *addr); @@ -113,6 +142,13 @@ /* insert new address, may fail if invalid address or dup. */ fdb_insert(br, p, newaddr); +#if defined(CONFIG_FUSIV_KERNEL_AP_2_AP) || defined(CONFIG_FUSIV_KERNEL_AP_2_AP_MODULE) + if(apAddBridgePortNewHWaddr_ptr != NULL) + { + (*apAddBridgePortNewHWaddr_ptr)(p); + } +#endif + spin_unlock_bh(&br->hash_lock); } @@ -130,12 +166,48 @@ hlist_for_each_entry_safe(f, h, n, &br->hash[i], hlist) { unsigned long this_timer; +#if defined(CONFIG_FUSIV_KERNEL_AP_2_AP) || defined(CONFIG_FUSIV_KERNEL_AP_2_AP_MODULE) + if(Isap2apBridgeTraffic_ptr != NULL) + { + if (!(*Isap2apBridgeTraffic_ptr)((void *)f)) + continue; + } else + printk("\n ap2ap module must required\n"); +#endif +#if defined(CONFIG_IFX_PPA_API) || defined(CONFIG_IFX_PPA_API_MODULE) + if ( ppa_hook_bridge_entry_hit_time_fn != NULL && !f->is_local ) + { + uint32_t last_hit_time; + + if ( ppa_hook_bridge_entry_hit_time_fn(f->addr.addr, &last_hit_time) == IFX_PPA_HIT ) + f->ageing_timer = last_hit_time * HZ; + } +#endif + if (f->is_static) continue; this_timer = f->ageing_timer + delay; - if (time_before_eq(this_timer, jiffies)) - fdb_delete(f); - else if (time_before(this_timer, next_timer)) + if (time_before_eq(this_timer, jiffies)) { + + /* Generate a HIL Packet Processor event + * indicating that the FDB entry is being deleted. + * Notifications are sent only for non-local FDB + * entries as local traffic is not accelerated + * through PP. */ + if(!f->is_local) + ti_hil_pp_event(TI_BRIDGE_FDB_DELETED, (void*)f); + +#ifdef CONFIG_TI_PACKET_PROCESSOR + /* Check if the PP has a session alive for this FDB + * entry + * ACTIVE - DONT delete the FDB entry. + * NOT ACTIVE - Delete the FDB entry. */ + if (!(f->ti_pp_fdb_status & TI_PP_FDB_ACTIVE)) + fdb_delete(f); +#else + fdb_delete(f); +#endif + } else if (time_before(this_timer, next_timer)) next_timer = this_timer; } } @@ -208,6 +280,29 @@ spin_unlock_bh(&br->hash_lock); } +void br_fdb_delete_by_mac_if_local_without_port(struct net_bridge *br, unsigned char *addr) +{ + int i; + + spin_lock_bh(&br->hash_lock); + for (i = 0; i < BR_HASH_SIZE; i++) { + struct hlist_node *h, *g; + + hlist_for_each_safe(h, g, &br->hash[i]) { + struct net_bridge_fdb_entry *f + = hlist_entry(h, struct net_bridge_fdb_entry, hlist); + if (0 == f->dst && f->is_local && !compare_ether_addr(f->addr.addr, addr)) { + fdb_delete(f); + goto end; + } + } + } +end: + spin_unlock_bh(&br->hash_lock); +} + + + /* No locking or refcounting, assumes caller has no preempt (rcu_read_lock) */ struct net_bridge_fdb_entry *__br_fdb_get(struct net_bridge *br, const unsigned char *addr) @@ -250,8 +345,20 @@ /* Set entry up for deletion with RCU */ void br_fdb_put(struct net_bridge_fdb_entry *ent) { - if (atomic_dec_and_test(&ent->use_count)) - call_rcu(&ent->rcu, fdb_rcu_free); + if (atomic_dec_and_test(&ent->use_count)) { +#if defined(CONFIG_FUSIV_KERNEL_AP_2_AP) || defined(CONFIG_FUSIV_KERNEL_AP_2_AP_MODULE) + if(ap2apBridgeFlowDelete_ptr != NULL) + { + (*ap2apBridgeFlowDelete_ptr)((void *)ent); + } else + printk("\nbr_fdb_put: ap2ap_lkm not initialized properly...\n"); +#endif +#if defined(CONFIG_IFX_PPA_API) || defined(CONFIG_IFX_PPA_API_MODULE) + if ( ppa_hook_bridge_entry_delete_fn != NULL ) + ppa_hook_bridge_entry_delete_fn(ent->addr.addr, 0); +#endif + call_rcu(&ent->rcu, fdb_rcu_free); + } } /* @@ -277,6 +384,10 @@ if (has_expired(br, f)) continue; + if(!f->dst) { + continue; + } + if (skip) { --skip; continue; @@ -325,14 +436,32 @@ fdb = kmem_cache_alloc(br_fdb_cache, GFP_ATOMIC); if (fdb) { +#if defined(CONFIG_FUSIV_KERNEL_AP_2_AP) || defined(CONFIG_FUSIV_KERNEL_AP_2_AP_MODULE) + memset(fdb, 0, sizeof(*fdb)); +#endif memcpy(fdb->addr.addr, addr, ETH_ALEN); atomic_set(&fdb->use_count, 1); hlist_add_head_rcu(&fdb->hlist, head); - fdb->dst = source; + fdb->dst = source; /* AVM: note that source may be 0 if is_local */ fdb->is_local = is_local; fdb->is_static = is_local; fdb->ageing_timer = jiffies; + +#ifdef CONFIG_TI_PACKET_PROCESSOR + /* Initialize the Status flag to INACTIVE by default. If + * the event TI_BRIDGE_FDB_CREATED is indeed handled, then + * this flag must be set to TI_PP_FDB_ACTIVE so that it + * can be synced up with PP when FDB entry expires in the + * bridge. If the status flag is not set active, it is assumed + * that the TI_BRIDGE_FDB_* events are not handled and thus + * bridge takes complete control over the fdb entry deletion */ + fdb->ti_pp_fdb_status = TI_PP_FDB_INACTIVE; +#endif + + /* Indicate to the HIL layer that a non-local FDB entry has been created. */ + if (!fdb->is_local) + ti_hil_pp_event(TI_BRIDGE_FDB_CREATED, (void *)fdb); } return fdb; } @@ -356,13 +485,12 @@ printk(KERN_WARNING "%s adding interface with same address " "as a received packet\n", - source->dev->name); + source ? source->dev->name : ""); fdb_delete(fdb); } if (!fdb_create(head, source, addr, 1)) return -ENOMEM; - return 0; } @@ -404,14 +532,38 @@ /* fastpath: update of existing entry */ fdb->dst = source; fdb->ageing_timer = jiffies; + + /* Indicate to the HIL layer that an FDB entry has been updated. */ + ti_hil_pp_event(TI_BRIDGE_FDB_CREATED, (void *)fdb); } } else { spin_lock(&br->hash_lock); - if (!fdb_find(head, addr)) + if (!fdb_find(head, addr)){ fdb_create(head, source, addr, 0); +#if defined(CONFIG_IFX_PPA_API) || defined(CONFIG_IFX_PPA_API_MODULE) + if ( ppa_hook_bridge_entry_add_fn != NULL && source->dev ) + ppa_hook_bridge_entry_add_fn((unsigned char *)addr, source->dev, 0); +#endif + } /* else we lose race and someone else inserts * it first, don't bother updating */ spin_unlock(&br->hash_lock); } } + +EXPORT_SYMBOL(br_mac_hash); +EXPORT_SYMBOL(br_fdb_update); +EXPORT_SYMBOL(br_fdb_get); +#if defined(CONFIG_FUSIV_KERNEL_AP_2_AP) || defined(CONFIG_FUSIV_KERNEL_AP_2_AP_MODULE) +EXPORT_SYMBOL(ap2apBridgeFlowDelete_ptr); +EXPORT_SYMBOL(Isap2apBridgeTraffic_ptr); +EXPORT_SYMBOL(fdb_delete); +EXPORT_SYMBOL(apAddBridgePortNewHWaddr_ptr); +#endif + +#if defined(CONFIG_IFX_PPA_API_MODULE) +EXPORT_SYMBOL(br_fdb_put); +EXPORT_SYMBOL(br_fdb_get); +EXPORT_SYMBOL(br_dev_xmit); +#endif