diff options
Diffstat (limited to 'target/linux/realtek/files/drivers/net/rtl819x/l2Driver/rtl865x_fdb.c')
-rw-r--r-- | target/linux/realtek/files/drivers/net/rtl819x/l2Driver/rtl865x_fdb.c | 2022 |
1 files changed, 2022 insertions, 0 deletions
diff --git a/target/linux/realtek/files/drivers/net/rtl819x/l2Driver/rtl865x_fdb.c b/target/linux/realtek/files/drivers/net/rtl819x/l2Driver/rtl865x_fdb.c new file mode 100644 index 000000000..264dcc06e --- /dev/null +++ b/target/linux/realtek/files/drivers/net/rtl819x/l2Driver/rtl865x_fdb.c @@ -0,0 +1,2022 @@ +/* @doc RTL_LAYEREDDRV_API + + @module rtl865x_fdb.c - RTL865x Home gateway controller Layered driver API documentation | + This document explains the API interface of the table driver module. Functions with rtl865x prefix + are external functions. + @normal Hyking Liu (Hyking_liu@realsil.com.cn) <date> + + Copyright <cp>2008 Realtek<tm> Semiconductor Cooperation, All Rights Reserved. + + @head3 List of Symbols | + Here is a list of all functions and variables in this module. + + @index | RTL_LAYEREDDRV_API +*/ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> + +#include <net/rtl/rtl_types.h> +#include <net/rtl/rtl_glue.h> +#include <net/rtl/rtl865x_fdb_api.h> +#include "AsicDriver/asicRegs.h" +//#include <common/rtl8651_aclLocal.h> +#ifdef CONFIG_RTL_LAYERED_ASIC_DRIVER +//#include <net/rtl/rtl_queue.h> +#include "AsicDriver/rtl865x_asicCom.h" +#include "AsicDriver/rtl865x_asicL2.h" +#else +#include <AsicDriver/rtl865xC_tblAsicDrv.h> +#include <AsicDriver/rtl8651_tblAsicDrv.h> +#include "rtl8651_tblDrvPatch.h" +#endif + +#include <net/rtl/rtl865x_netif.h> +#include "common/rtl865x_eventMgr.h" +#include "common/mbuf.h" +#include "rtl865x_fdb.h" +#include "common/rtl_errno.h" + +#if defined(CONFIG_RTL865X_LANPORT_RESTRICTION) +lan_restrict_info lan_restrict_tbl[LAN_RESTRICT_PORT_NUMBER]; +#endif + +struct rtl865x_L2Tables sw_FDB_Table; +int32 arpAgingTime = 450; +ether_addr_t cpu_mac = { {0x00, 0x00, 0x0a, 0x00, 0x00, 0x0f} }; +rtl865x_tblAsicDrv_l2Param_t tmpL2buff; + +static RTL_DECLARE_MUTEX(l2_sem); +int32 _rtl865x_fdb_alloc(void) +{ + int32 index = 0; + memset( &sw_FDB_Table, 0, sizeof( sw_FDB_Table ) ); + #ifdef __KERNEL__ + TBL_MEM_ALLOC(sw_FDB_Table.filterDB, rtl865x_filterDbTable_t, RTL865x_FDB_NUMBER); + #else + sw_FDB_Table.filterDB = (rtl865x_filterDbTable_t *)malloc(RTL865x_FDB_NUMBER * sizeof(rtl865x_filterDbTable_t)); + #endif + {//Initial free filter database entry + rtl865x_filterDbTableEntry_t * tempFilterDb = NULL; + #ifdef __KERNEL__ + TBL_MEM_ALLOC(tempFilterDb, rtl865x_filterDbTableEntry_t, RTL8651_L2TBL_ROW); + #else + #endif + SLIST_INIT(&sw_FDB_Table.freefdbList.filterDBentry); + for(index=0; index<RTL8651_L2TBL_ROW; index++) + SLIST_INSERT_HEAD(&sw_FDB_Table.freefdbList.filterDBentry, &tempFilterDb[index], nextFDB); + } + + return SUCCESS; + +} + +int32 rtl865x_getReserveMacAddr(ether_addr_t *macAddr) +{ + memcpy( macAddr, &cpu_mac, sizeof(ether_addr_t)); + return SUCCESS; +} + +int32 _rtl865x_layer2_patch(void) +{ + + int32 retval = 0; + ether_addr_t mac = { {0xff, 0xff, 0xff, 0xff, 0xff, 0xff} }; + uint32 portmask=RTL_WANPORT_MASK|RTL_LANPORT_MASK; + + retval = _rtl865x_addFilterDatabaseEntry(RTL865x_L2_TYPEII, RTL_LAN_FID, &mac, FDB_TYPE_TRAPCPU, portmask, TRUE, FALSE); +#if defined (CONFIG_RTL_IVL_SUPPORT) + retval = _rtl865x_addFilterDatabaseEntry(RTL865x_L2_TYPEII, RTL_WAN_FID, &mac, FDB_TYPE_TRAPCPU, portmask, TRUE, FALSE); +#endif + + retval = _rtl865x_addFilterDatabaseEntry(RTL865x_L2_TYPEII, RTL_LAN_FID, &cpu_mac, FDB_TYPE_TRAPCPU, 0, TRUE, FALSE); +#if defined (CONFIG_RTL_IVL_SUPPORT) + retval = _rtl865x_addFilterDatabaseEntry(RTL865x_L2_TYPEII, RTL_WAN_FID, &cpu_mac, FDB_TYPE_TRAPCPU, 0, TRUE, FALSE); +#endif + assert(retval == SUCCESS); + + return SUCCESS; +} + +int32 _rtl865x_fdb_collect(void) +{ + int32 index = 0; + int32 index1 = 0; + + rtl865x_filterDbTable_t *filterDbPtr; + rtl865x_filterDbTableEntry_t * tempFilterDbPtr; + for(index=0,filterDbPtr=&sw_FDB_Table.filterDB[0]; index<RTL865x_FDB_NUMBER; index++,filterDbPtr++) { + for(index1=0; index1<RTL8651_L2TBL_ROW; index1++) + while(SLIST_FIRST(&(filterDbPtr->database[index1]))) { + tempFilterDbPtr = SLIST_FIRST(&(filterDbPtr->database[index1])); + SLIST_REMOVE_HEAD(&(filterDbPtr->database[index1]), nextFDB); + SLIST_INSERT_HEAD(&sw_FDB_Table.freefdbList.filterDBentry, tempFilterDbPtr, nextFDB); + } + } + + return SUCCESS; + +} + +int32 _rtl865x_fdb_init(void) +{ + int32 index, index1; + /*Initial Filter database*/ + rtl865x_filterDbTable_t *fdb_t = &sw_FDB_Table.filterDB[0]; + for(index=0; index<RTL865x_FDB_NUMBER; index++, fdb_t++) { + for(index1=0; index1<RTL8651_L2TBL_ROW; index1++) + SLIST_INIT(&(fdb_t->database[index1])); + fdb_t->valid = 1; + } + + return SUCCESS; +} + +int32 _rtl865x_clearHWL2Table(void) +{ + int i, j; + + for (i = 0; i < RTL8651_L2TBL_ROW; i++) + for (j = 0; j < RTL8651_L2TBL_COLUMN; j++) + { + rtl8651_delAsicL2Table(i, j); + } + + return SUCCESS; +} + +int32 rtl865x_layer2_init(void) +{ + + _rtl865x_fdb_alloc(); + + _rtl865x_fdb_init(); + + _rtl865x_layer2_patch(); + + return SUCCESS; +} + +int32 rtl865x_layer2_reinit(void) +{ + _rtl865x_clearHWL2Table(); + + _rtl865x_fdb_collect(); + + //_rtl865x_fdb_alloc(); + + _rtl865x_fdb_init(); + + _rtl865x_layer2_patch(); + + return SUCCESS; +} + + uint32 rtl865x_getHWL2Index(ether_addr_t * macAddr, uint16 fid) + { + return (rtl8651_filterDbIndex(macAddr, fid)); + } + +int32 rtl865x_setHWL2Table(uint32 row, uint32 column, rtl865x_tblAsicDrv_l2Param_t *l2p) +{ + return (rtl8651_setAsicL2Table(row, column, l2p)); +} + +int32 rtl865x_getHWL2Table(uint32 row, uint32 column, rtl865x_tblAsicDrv_l2Param_t *l2p) +{ + return rtl8651_getAsicL2Table(row, column, l2p); +} + +int32 rtl865x_refleshHWL2Table(ether_addr_t * macAddr, uint32 flags,uint16 fid) +{ + + rtl865x_tblAsicDrv_l2Param_t L2temp, *L2buff; + uint32 rowIdx, col_num; + uint32 colIdx = 0; + uint32 found = FALSE; + + L2buff = &L2temp; + memset(L2buff, 0, sizeof(rtl865x_tblAsicDrv_l2Param_t)); + rowIdx = rtl8651_filterDbIndex(macAddr, fid); + + for(colIdx=0; colIdx<RTL8651_L2TBL_COLUMN; colIdx++) { + if ((rtl8651_getAsicL2Table(rowIdx, colIdx, L2buff))!=SUCCESS || + memcmp(&(L2buff->macAddr), macAddr, 6)!= 0) + continue; + + if (((flags&FDB_STATIC) && L2buff->isStatic) || + ((flags&FDB_DYNAMIC) && !L2buff->isStatic)) { + assert(colIdx); + col_num = colIdx; + found = TRUE; + break; + } + } + + if (found == TRUE) + { + L2buff->ageSec = 450; + rtl8651_setAsicL2Table(rowIdx, colIdx, L2buff); + return SUCCESS; + } + else + { + return FAILED; + } +} + +int32 rtl_get_hw_fdb_age(uint32 fid,ether_addr_t *mac, uint32 flags) +{ + uint32 rowIdx; + uint32 colIdx = 0; + int32 retval = 0; + rtl865x_tblAsicDrv_l2Param_t L2buff; + + memset(&L2buff,0,sizeof(rtl865x_tblAsicDrv_l2Param_t)); + + rowIdx = rtl8651_filterDbIndex(mac, fid); + + for(colIdx=0; colIdx<RTL8651_L2TBL_COLUMN; colIdx++) + { + retval = rtl8651_getAsicL2Table(rowIdx, colIdx, &L2buff); + + if (retval !=SUCCESS || + memcmp(&(L2buff.macAddr), mac, 6)!= 0) + continue; + if (((flags&FDB_DYNAMIC) && !L2buff.isStatic)||((flags&FDB_STATIC) && L2buff.isStatic)) + { + retval = L2buff.ageSec; + break; + } + + } + + return retval; +} + +int32 rtl865x_Lookup_fdb_entry(uint32 fid, ether_addr_t *mac, uint32 flags, uint32 *col_num, rtl865x_tblAsicDrv_l2Param_t *L2buff) +{ + uint32 rowIdx; + uint32 colIdx; + int32 retval; + + rowIdx = rtl8651_filterDbIndex(mac, fid); + colIdx = 0; + + for(colIdx=0; colIdx<RTL8651_L2TBL_COLUMN; colIdx++) + { + retval = rtl8651_getAsicL2Table(rowIdx, colIdx, L2buff); + + if (retval !=SUCCESS || + memcmp(&(L2buff->macAddr), mac, 6)!= 0) + continue; + if (((flags&FDB_STATIC) && L2buff->isStatic) || + ((flags&FDB_DYNAMIC) && !L2buff->isStatic)) { + assert(colIdx); + *col_num = colIdx; + return SUCCESS; + } + + } + return FAILED; +} + +/* +@func enum RTL_RESULT | rtl865x_addFdbEntry | Add an MAC address, said Filter Database Entry +@parm uint32 | fid | The filter database index (valid: 0~3) +@parm ether_addr_t * | mac | The MAC address to be added +@parm uint32 | portmask | The portmask of this MAC address belongs to +@parm uint32 | type | fdb entry type +@rvalue SUCCESS | Add success +@rvalue FAILED | General failure +@comm + Add a Filter Database Entry to L2 Table(1024-Entry) +@devnote + (under construction) +*/ +int32 rtl865x_addFilterDatabaseEntry( uint32 fid, ether_addr_t * mac, uint32 portmask, uint32 type ) +{ + int32 retval; + unsigned long flags; + if (type != FDB_TYPE_FWD && type != FDB_TYPE_SRCBLK && type != FDB_TYPE_TRAPCPU) + return RTL_EINVALIDINPUT; /* Invalid parameter */ + + if (fid >= RTL865x_FDB_NUMBER) + return RTL_EINVALIDINPUT; + if (mac == (ether_addr_t *)NULL) + return RTL_EINVALIDINPUT; + if (sw_FDB_Table.filterDB[fid].valid == 0) + return RTL_EINVALIDFID; + /*l2 lock*/ + //rtl_down_interruptible(&l2_sem); + local_irq_save(flags); +#ifdef CONFIG_RTL865X_LANPORT_RESTRICTION + retval = _rtl865x_addFilterDatabaseEntry(RTL865x_L2_TYPEII, fid, mac, type, portmask, TRUE, FALSE); +#else + retval = _rtl865x_addFilterDatabaseEntry(RTL865x_L2_TYPEII, fid, mac, type, portmask, FALSE, FALSE); +#endif + /*l2 unlock*/ + //rtl_up(&l2_sem); + local_irq_restore(flags); + return retval; +} + +int32 rtl865x_addFilterDatabaseEntryExtension( uint16 fid, rtl865x_filterDbTableEntry_t * L2entry) +{ + int32 retval; + unsigned long flags; + if (L2entry->process != FDB_TYPE_FWD && L2entry->process != FDB_TYPE_SRCBLK && L2entry->process != FDB_TYPE_TRAPCPU) + return RTL_EINVALIDINPUT; /* Invalid parameter */ + + if (fid >= RTL865x_FDB_NUMBER) + return RTL_EINVALIDINPUT; + if (&(L2entry->macAddr) == (ether_addr_t *)NULL) + return RTL_EINVALIDINPUT; + if (sw_FDB_Table.filterDB[fid].valid == 0) + return RTL_EINVALIDFID; + /*l2 lock*/ + //rtl_down_interruptible(&l2_sem); + local_irq_save(flags); + retval = _rtl865x_addFilterDatabaseEntry( L2entry->l2type, + fid, + &(L2entry->macAddr), + L2entry->process, + L2entry->memberPortMask, + L2entry->auth, + L2entry->SrcBlk); + + /*l2 unlock*/ + //rtl_up(&l2_sem); + local_irq_restore(flags); + return retval; +} + + +#if 0 +int32 rtl865x_addFilterDatabaseEntry( uint32 fid, ether_addr_t * mac, uint32 portmask, uint32 type , uint32 isStatic) +{ + int32 retval; + + if (type != FDB_TYPE_FWD && type != FDB_TYPE_SRCBLK && type != FDB_TYPE_TRAPCPU) + return RTL_EINVALIDINPUT; /* Invalid parameter */ + + if (fid >= RTL865x_FDB_NUMBER) + return RTL_EINVALIDINPUT; + if (mac == (ether_addr_t *)NULL) + return RTL_EINVALIDINPUT; + if (sw_FDB_Table.filterDB[fid].valid == 0) + return RTL_EINVALIDFID; + /*l2 lock*/ + +#ifdef RTL865XC_LAN_PORT_NUM_RESTRIT + retval = _rtl865x_addFilterDatabaseEntry(isStatic == TRUE? RTL865x_L2_TYPEII:RTL865x_L2_TYPEI, fid, mac, type, portmask, TRUE, FALSE); +#else + retval = _rtl865x_addFilterDatabaseEntry(isStatic == TRUE? RTL865x_L2_TYPEII:RTL865x_L2_TYPEI, fid, mac, type, portmask, FALSE, FALSE); + +#endif + /*l2 unlock*/ + + + return retval; +} +#endif + + +int32 _rtl865x_removeFilterDatabaseEntry(uint16 fid, ether_addr_t * mac, uint32 rowIdx) +{ + rtl865x_filterDbTable_t *fdb_t = &sw_FDB_Table.filterDB[fid]; + rtl865x_filterDbTableEntry_t * l2entry_t ; + + if (SLIST_FIRST(&(fdb_t->database[rowIdx]))) + { + SLIST_FOREACH(l2entry_t, &(fdb_t->database[rowIdx]), nextFDB) + { + if (memcmp(&(l2entry_t->macAddr), mac, 6)== 0) + { + SLIST_REMOVE( + &(fdb_t->database[rowIdx]), + l2entry_t, + rtl865x_filterDbTableEntry_s, + nextFDB + ); + SLIST_INSERT_HEAD(&sw_FDB_Table.freefdbList.filterDBentry, l2entry_t, nextFDB); + + rtl865x_raiseEvent(EVENT_DEL_FDB, (void *)(l2entry_t)); + + return SUCCESS; + } + } + } + + return FAILED; +} + +int32 rtl865x_lookup_FilterDatabaseEntry(uint16 fid, ether_addr_t * mac, rtl865x_filterDbTableEntry_t *l2_entry) +{ + rtl865x_filterDbTable_t *fdb_t = &sw_FDB_Table.filterDB[fid]; + rtl865x_filterDbTableEntry_t * l2entry_t ; + uint32 rowIdx; + + rowIdx = rtl8651_filterDbIndex(mac, fid); + + if (SLIST_FIRST(&(fdb_t->database[rowIdx]))) + { + SLIST_FOREACH(l2entry_t, &(fdb_t->database[rowIdx]), nextFDB) + { + if (memcmp(&(l2entry_t->macAddr), mac, 6)== 0) + { + l2_entry->asicPos = l2entry_t->asicPos; + l2_entry->auth = l2entry_t->auth; + l2_entry->l2type = l2entry_t->l2type; + l2_entry->linkId = l2entry_t->linkId; + l2_entry->memberPortMask = l2entry_t->memberPortMask; + l2_entry->nhFlag = l2entry_t->nhFlag; + l2_entry->process = l2entry_t->process; + l2_entry->SrcBlk = l2entry_t->SrcBlk; + l2_entry->vid = l2entry_t->vid; + return SUCCESS; + } + } + } + + memset(l2_entry, 0, sizeof(rtl865x_filterDbTableEntry_t)); + return FAILED; +} + +int32 _rtl865x_addFilterDatabaseEntry(uint16 l2Type, uint16 fid, ether_addr_t * macAddr, uint32 type, uint32 portMask, uint8 auth, uint8 SrcBlk) +{ + uint32 rowIdx = 0; + uint32 colIdx = 0; + uint32 col_num = 0; + uint32 col_tmp = 0; + uint16 tmp_age = 0xffff; + int32 found = FALSE; + int32 flag = FALSE; + int32 nexthp_flag = FALSE; + int32 isStatic = FALSE; + int32 toCpu = FALSE; + rtl865x_filterDbTableEntry_t * l2entry_t = NULL; + rtl865x_filterDbTableEntry_t *tmpL2; + rtl865x_filterDbTable_t *fdb_t = &sw_FDB_Table.filterDB[fid]; + rtl865x_tblAsicDrv_l2Param_t l2entry_tmp,*L2buff; + int32 retval = 0; + + L2buff = &l2entry_tmp; + memset(L2buff,0,sizeof(rtl865x_tblAsicDrv_l2Param_t)); + rowIdx = rtl8651_filterDbIndex(macAddr, fid); + for(colIdx=0; colIdx<RTL8651_L2TBL_COLUMN; colIdx++) + { + retval = rtl8651_getAsicL2Table(rowIdx, colIdx, L2buff); + if ((retval)==SUCCESS) + { + /*check whether mac address has been learned to HW or not*/ + if (memcmp(&(L2buff->macAddr), macAddr, 6)== 0) + { + /*the entry has been auto learned*/ + if (L2buff->memberPortMask==portMask) + { + /*the entry has been auto learned */ + found = TRUE; + col_tmp = colIdx; + } + else + /*portmask is different , it should be overwrited*/ + { + found = FALSE; + flag = TRUE; + } + break; + } + /*no matched entry, try get minimum aging time L2 Asic entry*/ + if (tmp_age> L2buff->ageSec) + { + tmp_age = L2buff->ageSec; + col_num = colIdx; + } + } + else + { + /*there is still empty l2 asic entry*/ + flag = TRUE; + break; + } + } + + switch(l2Type) { + case RTL865x_L2_TYPEI: + nexthp_flag = FALSE;isStatic = FALSE; + break; + case RTL865x_L2_TYPEII: + nexthp_flag = TRUE; isStatic = TRUE; + break; + case RTL865x_L2_TYPEIII: + nexthp_flag = FALSE;isStatic = TRUE; + break; + default: assert(0); + } + + switch(type) { + case FDB_TYPE_FWD: + toCpu = FALSE; + break; + case FDB_TYPE_DSTBLK: + toCpu = FALSE; + break; + case FDB_TYPE_SRCBLK: + toCpu = FALSE; + break; + case FDB_TYPE_TRAPCPU: + toCpu = TRUE; + break; + default: assert(0); + } + + if (found == FALSE) + { +#if 0 + /*no empty entry, overwrite the biggest aging time asic l2 entry*/ + if(flag == FALSE) + { + /*delete the biggest aging time software entry*/ + rtl8651_getAsicL2Table(rowIdx, col_num, L2buff); + _rtl865x_removeFilterDatabaseEntry(fid, &(L2buff->macAddr), rowIdx); + + /*overwrite asic entry*/ + rtl8651_setAsicL2Table_Patch( + rowIdx, + col_num, + macAddr, + toCpu, + SrcBlk, + portMask, + arpAgingTime, + isStatic, + nexthp_flag, + fid, + auth); + col_tmp = col_num; + } + else +#endif + /*portmask is different , so it should overwrite the original asic entry. Or there is empty entry, set it to asic*/ + if(flag == TRUE) + { + rtl8651_setAsicL2Table_Patch( + rowIdx, + colIdx, + macAddr, + toCpu, + SrcBlk, + portMask, + arpAgingTime, + isStatic, + nexthp_flag, + fid, + auth); + col_tmp = colIdx; + } + } + /*find the same asic entry, should update the aging time*/ + else + { + rtl8651_setAsicL2Table_Patch( + rowIdx, + col_tmp, + macAddr, + toCpu, + SrcBlk, + portMask, + arpAgingTime, + isStatic, + nexthp_flag, + fid, + auth); + } + +/* + colIdx=0; + + tmpL2 = SLIST_FIRST(&(fdb_t->database[rowIdx])); + tmpL2->nextFDB.sle_next = NULL; + + for(colIdx=0; colIdx<RTL8651_L2TBL_COLUMN; colIdx++) + { + if ((rtl8651_getAsicL2Table(rowIdx, colIdx, L2buff))==SUCCESS) + { + l2entry_t->asicPos =colIdx; + l2entry_t->auth = L2buff->auth; + l2entry_t->configToAsic = 0; + l2entry_t->memberPortMask = L2buff->memberPortMask; + l2entry_t->SrcBlk = L2buff->srcBlk; + memcpy(&l2entry_t->macAddr, &L2buff->macAddr, sizeof(ether_addr_t)); + + tmpL2->nextFDB.sle_next = l2entry_t; + l2entry_t->nextFDB.sle_next = NULL; + tmpL2 = l2entry_t; + } + } +*/ + + if (SLIST_FIRST(&sw_FDB_Table.freefdbList.filterDBentry) == NULL) + return RTL_ENOFREEBUFFER; + + /*config the SW l2 entry */ + l2entry_t = SLIST_FIRST(&sw_FDB_Table.freefdbList.filterDBentry); + SLIST_REMOVE_HEAD(&sw_FDB_Table.freefdbList.filterDBentry, nextFDB); + + l2entry_t->asicPos =col_tmp; + l2entry_t->auth = auth; + l2entry_t->configToAsic = 0; + l2entry_t->memberPortMask = portMask; + l2entry_t->l2type = l2Type; + l2entry_t->nhFlag = nexthp_flag; + + l2entry_t->SrcBlk = FALSE; + memcpy(&l2entry_t->macAddr, macAddr, sizeof(ether_addr_t)); + switch(type) { + case FDB_TYPE_FWD: + l2entry_t->process = FDB_TYPE_FWD; + l2entry_t->memberPortMask = portMask; + break; + case FDB_TYPE_DSTBLK: + l2entry_t->process = FDB_TYPE_DSTBLK; + l2entry_t->memberPortMask = 0; + break; + case FDB_TYPE_SRCBLK: + l2entry_t->process = FDB_TYPE_SRCBLK; + l2entry_t->memberPortMask = 0; + break; + case FDB_TYPE_TRAPCPU: + l2entry_t->process = FDB_TYPE_TRAPCPU; + l2entry_t->memberPortMask = portMask; + break; + default: assert(0); + } + + /*write the SW l2 entry */ + + if (SLIST_FIRST(&(fdb_t->database[rowIdx]))) + { + SLIST_FOREACH(tmpL2, &(fdb_t->database[rowIdx]), nextFDB) + { + if (memcmp(&(tmpL2->macAddr), macAddr, 6)== 0) + { + if( (tmpL2->auth != auth) || + (tmpL2->process != type) || + (tmpL2->SrcBlk != SrcBlk) || + (tmpL2->memberPortMask != portMask) || + (tmpL2->l2type != l2Type) ) + { + tmpL2->auth = auth; + tmpL2->process = type; + tmpL2->SrcBlk = SrcBlk; + tmpL2->memberPortMask = portMask; + tmpL2->l2type = l2Type; + + /*duplicate entry,avoid memory leak*/ + SLIST_INSERT_HEAD(&sw_FDB_Table.freefdbList.filterDBentry, l2entry_t, nextFDB); + break; +/* tmpL2 ->refCount = 1;*/ + } + else + { +/* tmpL2->refCount +=1;*/ + + /*duplicate entry,avoid memory leak*/ + SLIST_INSERT_HEAD(&sw_FDB_Table.freefdbList.filterDBentry, l2entry_t, nextFDB); + return SUCCESS; + } + } + else if (tmpL2->nextFDB.sle_next == NULL) + { +/* l2entry_t ->refCount = 1;*/ + tmpL2->nextFDB.sle_next = l2entry_t; + l2entry_t->nextFDB.sle_next = NULL; + break; + } + } + } + else + { +/* l2entry_t ->refCount = 1;*/ + SLIST_INSERT_HEAD(&(fdb_t->database[rowIdx]), l2entry_t, nextFDB); + } + + /* TypeII entry can not exceed RTL8651_L2TBL_COLUMN */ +/* if (typeII == RTL8651_L2TBL_COLUMN && l2Type == RTL8651_L2_TYPEII) + return RTL_NOFREEBUFFER; +*/ + rtl865x_raiseEvent(EVENT_ADD_FDB, (void *)(l2entry_t)); + + return SUCCESS; +} + +/* +@func int32 | rtl8651_delFilterDatabaseEntry | Remove a filter database entry. +@parm uint16 | fid | Filter database entry. +@parm ether_addr_t * | macAddr | Pointer to a MAC Address. +@rvalue RTL_EINVALIDFID | Filter database ID. +@rvalue RTL_NULLMACADDR | The specified MAC address is NULL. +@rvalue RTL_EINVALIDINPUT | Invalid input parameter. +*/ +int32 rtl865x_delFilterDatabaseEntry(uint16 l2Type, uint16 fid, ether_addr_t * macAddr) { + int32 retval; + unsigned long flags; + if (fid >= RTL865x_FDB_NUMBER) + return RTL_EINVALIDINPUT; + if (macAddr == (ether_addr_t *)NULL) + return RTL_EINVALIDINPUT; + if (sw_FDB_Table.filterDB[fid].valid == 0) + return RTL_EINVALIDFID; + +/* L2 lock */ + //rtl_down_interruptible(&l2_sem); + local_irq_save(flags); + retval = _rtl865x_delFilterDatabaseEntry(RTL865x_L2_TYPEII, fid, macAddr); +/* L2 unlock */ + //rtl_up(&l2_sem); + local_irq_restore(flags); + return retval; +} + +int32 _rtl865x_delFilterDatabaseEntry(uint16 l2Type, uint16 fid, ether_addr_t * macAddr) +{ + uint32 rowIdx = 0; + uint32 colIdx = 0; + rtl865x_tblAsicDrv_l2Param_t L2temp, *L2buff ; + rtl865x_filterDbTableEntry_t * l2entry_t = NULL; + rtl865x_filterDbTable_t *fdb_t = &sw_FDB_Table.filterDB[fid]; + int32 found = FALSE; + + rowIdx = rtl8651_filterDbIndex(macAddr, fid); + + L2buff = &L2temp; + memset(L2buff, 0 , sizeof (rtl865x_tblAsicDrv_l2Param_t)); + for(colIdx=0; colIdx<RTL8651_L2TBL_COLUMN; colIdx++) + { + if ((rtl8651_getAsicL2Table(rowIdx, colIdx, L2buff))==SUCCESS) + { + /*check whether mac address has been learned to SW or not*/ + if (memcmp(&(L2buff->macAddr), macAddr, 6)== 0) + { + /*the entry has been auto learned*/ + found = TRUE; + break; + } + } + } + + /* + when a sta from eth0 to wlan0, the layer driver fdb will be deleted, but linux bridge fdb still exist, + so delete the asic entry anyway to avoid layer connection issue. + eg: + first moment .sta is at eth0 + second moment:connect sta to wlan0, the layer driver fdb will be deleted, but linux bridge fdb still there + third moment:move sta to eth0 again, layer driver fdb won't be created due to linux bridge fdb already exist. + */ + if (found == TRUE) + { + rtl8651_delAsicL2Table(rowIdx, colIdx); + } + + SLIST_FOREACH(l2entry_t, &(fdb_t->database[rowIdx]), nextFDB) + { + if (!memcmp(&l2entry_t->macAddr, macAddr, sizeof(ether_addr_t))) + { + /* l2entry_t->refCount -= 1;*/ + /* if (l2entry_t->refCount == 0)*/ + { + SLIST_REMOVE( + &(fdb_t->database[rowIdx]), + l2entry_t, + rtl865x_filterDbTableEntry_s, + nextFDB + ); + SLIST_INSERT_HEAD(&sw_FDB_Table.freefdbList.filterDBentry, l2entry_t, nextFDB); + + rtl865x_raiseEvent(EVENT_DEL_FDB, (void *)(l2entry_t)); + } + break; + } + } + return SUCCESS; +} + +#ifdef CONFIG_RTL865X_SYNC_L2 +int32 rtl865x_arrangeFdbEntry(const unsigned char *timeout_addr, int32 *port) +{ + int32 found = FAILED; + ether_addr_t *macAddr; + int32 column; + rtl865x_tblAsicDrv_l2Param_t fdbEntry; + rtl865x_filterDbTableEntry_t l2temp_entry; + int32 rowIdx; + + macAddr = (ether_addr_t *)(timeout_addr); + rowIdx = rtl8651_filterDbIndex(macAddr, RTL_LAN_FID); + found = rtl865x_Lookup_fdb_entry(RTL_LAN_FID, macAddr, FDB_DYNAMIC, &column, &fdbEntry); + if (found != SUCCESS) + { + if (rtl865x_lookup_FilterDatabaseEntry(RTL_LAN_FID, macAddr, &l2temp_entry) == SUCCESS) + { +/* printk("\nlook up sw fdb success\n"); + printk("\nport mask is %x\n", l2temp_entry.memberPortMask); +*/ + *port = rtl865x_ConvertPortMasktoPortNum(l2temp_entry.memberPortMask); + return RTL865X_FDBENTRY_TIMEOUT; + } + + } + else + { + if(fdbEntry.ageSec == 450) + { + return RTL865X_FDBENTRY_450SEC; + } + if(fdbEntry.ageSec == 300) + { + return RTL865X_FDBENTRY_300SEC; + } + if(fdbEntry.ageSec == 150) + { + return RTL865X_FDBENTRY_150SEC; + } + } + return FAILED; +} + +void update_hw_l2table(const char *srcName,const unsigned char *addr) +{ + + //int32 found = FAILED; + ether_addr_t *macAddr; + int32 ret = 0; +#if defined (CONFIG_RTL_LAYERED_DRIVER) && defined (CONFIG_RTL_LAYERED_DRIVER_L2) + int32 column; + rtl865x_tblAsicDrv_l2Param_t fdbEntry; +#endif + macAddr = (ether_addr_t *)(addr); + + if (memcmp(srcName, RTL_WLAN_NAME, 4) ==0) + { + +#if defined (CONFIG_RTL_LAYERED_DRIVER) +#if defined (CONFIG_RTL_LAYERED_DRIVER_L2) + if (rtl865x_Lookup_fdb_entry(RTL_LAN_FID, macAddr, FDB_DYNAMIC, &column,&fdbEntry) == SUCCESS) +#endif +#else + if (rtl8651_lookupL2table(0, macAddr, FDB_DYNAMIC) == SUCCESS) +#endif + { + + if((fdbEntry.memberPortMask & RTL8651_PHYSICALPORTMASK)!=0) + { +#if defined (CONFIG_RTL_LAYERED_DRIVER) +#if defined (CONFIG_RTL_LAYERED_DRIVER_L2) + ret = rtl865x_delFilterDatabaseEntry(RTL865x_L2_TYPEII, RTL_LAN_FID, macAddr); +#endif +#else + ret = rtl8651_delFilterDatabaseEntry(0, macAddr); +#endif + } + + } + +#if defined (CONFIG_RTL_IVL_SUPPORT) + +#if defined (CONFIG_RTL_LAYERED_DRIVER) +#if defined (CONFIG_RTL_LAYERED_DRIVER_L2) + if (rtl865x_Lookup_fdb_entry(RTL_WAN_FID, macAddr, FDB_DYNAMIC, &column,&fdbEntry) == SUCCESS) +#endif +#endif + { + + if((fdbEntry.memberPortMask & RTL8651_PHYSICALPORTMASK)!=0) + { +#if defined (CONFIG_RTL_LAYERED_DRIVER) +#if defined (CONFIG_RTL_LAYERED_DRIVER_L2) + ret = rtl865x_delFilterDatabaseEntry(RTL865x_L2_TYPEII, RTL_WAN_FID, macAddr); +#endif +#endif + } + + } +#endif + + } + + +} + + +int32 rtl865x_addFDBEntry(const unsigned char *addr) +{ + int32 found = FAILED; + ether_addr_t *macAddr; + int32 ret=FAILED; + int8 port_num = -1; + int32 column; + rtl865x_tblAsicDrv_l2Param_t fdbEntry; + rtl865x_filterDbTableEntry_t l2temp_entry; + + if (addr == NULL) + return RTL_EINVALIDINPUT; + + macAddr = (ether_addr_t *)(addr); + found = rtl865x_Lookup_fdb_entry(RTL_LAN_FID, macAddr, FDB_DYNAMIC, &column, &fdbEntry); + if (found == SUCCESS ) + { + port_num = rtl865x_ConvertPortMasktoPortNum(fdbEntry.memberPortMask); + +/* printk("\nbefore rtl865x_lookup_FilterDatabaseEntry, port is %d\n", port_num); */ + if (rtl865x_lookup_FilterDatabaseEntry(fdbEntry.fid, macAddr, &l2temp_entry) != SUCCESS) + { + l2temp_entry.l2type = (fdbEntry.nhFlag==0)?RTL865x_L2_TYPEI: RTL865x_L2_TYPEII; + l2temp_entry.process = FDB_TYPE_FWD; + l2temp_entry.memberPortMask = fdbEntry.memberPortMask; +/* l2temp_entry.auth = TRUE;*/ +/* l2temp_entry.SrcBlk = FALSE;*/ + memcpy(&(l2temp_entry.macAddr), macAddr, sizeof(ether_addr_t)); + ret =_rtl865x_addFilterDatabaseEntry( l2temp_entry.l2type, + fdbEntry.fid, + &(l2temp_entry.macAddr), + l2temp_entry.process, + l2temp_entry.memberPortMask, + FALSE, + FALSE); + } + } + else + { + /*add */ + } + return ret; +} + + +int32 rtl865x_delLanFDBEntry(uint16 l2Type, const unsigned char *addr) +{ + int32 ret=FAILED; + ether_addr_t *macAddr; + + if (addr == NULL) + { + return RTL_EINVALIDINPUT; + } + macAddr = (ether_addr_t *)(addr); + + ret =_rtl865x_delFilterDatabaseEntry( l2Type, RTL_LAN_FID, macAddr); + + return ret; +} + +int32 rtl865x_ConvertPortMasktoPortNum(int32 portmask) +{ + int32 i = 0; + + for (i = PHY0; i < EXT3; i++) + { + if(((portmask >> i) & 0x01) == 1) + { + return i; + } + } + return FAILED; +} + +#if defined(CONFIG_RTL865X_LANPORT_RESTRICTION) +int32 rtl_check_fdb_entry_check_exist(uint32 fid, ether_addr_t *mac, uint32 flags) +{ + uint32 rowIdx; + uint32 colIdx; + int32 retval; + rtl865x_tblAsicDrv_l2Param_t L2buff; + + rowIdx = rtl8651_filterDbIndex(mac, fid); + colIdx = 0; + + for(colIdx=0; colIdx<RTL8651_L2TBL_COLUMN; colIdx++) + { + retval = rtl8651_getAsicL2Table(rowIdx, colIdx, &L2buff); + + if (retval !=SUCCESS || + memcmp(&(L2buff.macAddr), mac, 6)!= 0) + continue; + if (((flags&FDB_STATIC) && L2buff.isStatic) || + ((flags&FDB_DYNAMIC) && !L2buff.isStatic)) { + return SUCCESS; + } + + } + return FAILED; +} + +int32 rtl_check_fdb_entry_check_srcBlock(uint32 fid, ether_addr_t *mac, int32 *SrcBlk) +{ + rtl865x_filterDbTable_t *fdb_t = &sw_FDB_Table.filterDB[fid]; + rtl865x_filterDbTableEntry_t * l2entry_t ; + uint32 rowIdx; + + rowIdx = rtl8651_filterDbIndex(mac, fid); + + if (SLIST_FIRST(&(fdb_t->database[rowIdx]))) + { + SLIST_FOREACH(l2entry_t, &(fdb_t->database[rowIdx]), nextFDB) + { + if (memcmp(&(l2entry_t->macAddr), mac, 6)== 0) + { + *SrcBlk = l2entry_t->SrcBlk; + return SUCCESS; + } + } + } + return FAILED; +} + +int32 lanrestrict_callbackFn_for_add_fdb(void *param) +{ + int32 port_num; + rtl865x_filterDbTableEntry_t *fdbEntry; + + if(param==NULL) + { + return EVENT_CONTINUE_EXECUTE; + } + + fdbEntry=(rtl865x_filterDbTableEntry_t *)param; + + port_num = rtl865x_ConvertPortMasktoPortNum(fdbEntry->memberPortMask); + + if (lan_restrict_tbl[port_num].enable == TRUE) + { +/* printk("\nadd authed port[%d], num:%d\n", port_num, lan_restrict_tbl[port_num].curr_num);*/ + lan_restrict_tbl[port_num].curr_num ++; + } + + return SUCCESS; +} + +int32 lanrestrict_callbackFn_for_del_fdb(void *param) +{ + int32 port_num; + rtl865x_filterDbTableEntry_t *fdbEntry; + + if(param==NULL) + { + return EVENT_CONTINUE_EXECUTE; + } + + fdbEntry=(rtl865x_filterDbTableEntry_t *)param; + + port_num = rtl865x_ConvertPortMasktoPortNum(fdbEntry->memberPortMask); + if (lan_restrict_tbl[port_num].enable == TRUE) + { +/* printk("\ndel authed port[%d], num:%d\n", port_num, lan_restrict_tbl[port_num].curr_num);*/ + lan_restrict_tbl[port_num].curr_num --; + if (lan_restrict_tbl[port_num].curr_num < 0) + { + lan_restrict_tbl[port_num].curr_num = 0; + } + } + return SUCCESS; +} + +static int32 lanrestrict_authadd_unRegister_event(void) +{ + rtl865x_event_Param_t eventParam; + eventParam.eventLayerId=DEFAULT_LAYER2_EVENT_LIST_ID; + eventParam.eventId=EVENT_ADD_AUTHED_FDB; + eventParam.eventPriority=0; + eventParam.event_action_fn=lanrestrict_callbackFn_for_add_fdb; + rtl865x_unRegisterEvent(&eventParam); + return SUCCESS; +} + +static int32 lanrestrict_authdel_unRegister_event(void) +{ + rtl865x_event_Param_t eventParam; + eventParam.eventLayerId=DEFAULT_LAYER2_EVENT_LIST_ID; + eventParam.eventId=EVENT_DEL_AUTHED_FDB; + eventParam.eventPriority=0; + eventParam.event_action_fn=lanrestrict_callbackFn_for_del_fdb; + rtl865x_unRegisterEvent(&eventParam); + return SUCCESS; +} + +int32 lanrestrict_unRegister_event(void) +{ + lanrestrict_authadd_unRegister_event(); + lanrestrict_authdel_unRegister_event(); + return SUCCESS; +} + +static int32 lanrestrict_authadd_register_event(void) +{ + rtl865x_event_Param_t eventParam; + eventParam.eventLayerId=DEFAULT_LAYER2_EVENT_LIST_ID; + eventParam.eventId=EVENT_ADD_AUTHED_FDB; + eventParam.eventPriority=0; + eventParam.event_action_fn=lanrestrict_callbackFn_for_add_fdb; + rtl865x_registerEvent(&eventParam); + return SUCCESS; +} + +static int32 lanrestrict_authdel_register_event(void) +{ + rtl865x_event_Param_t eventParam; + eventParam.eventLayerId=DEFAULT_LAYER2_EVENT_LIST_ID; + eventParam.eventId=EVENT_DEL_AUTHED_FDB; + eventParam.eventPriority=0; + eventParam.event_action_fn=lanrestrict_callbackFn_for_del_fdb; + rtl865x_registerEvent(&eventParam); + return SUCCESS; +} + +int32 lanrestrict_register_event(void) +{ + lanrestrict_authadd_register_event(); + lanrestrict_authdel_register_event(); + return SUCCESS; +} + +int32 _rtl865x_addAuthFilterDatabaseEntry(uint16 l2Type, uint16 fid, ether_addr_t * macAddr, uint32 type, uint32 portMask, uint8 auth, uint8 SrcBlk) +{ + uint32 rowIdx = 0; + uint32 colIdx = 0; + uint32 col_num = 0; + uint32 col_tmp = 0; + uint16 tmp_age = 0xffff; + int32 found = FALSE; + int32 flag = FALSE; + int32 nexthp_flag = FALSE; + int32 isStatic = FALSE; + int32 toCpu = FALSE; + rtl865x_filterDbTableEntry_t * l2entry_t = NULL; + rtl865x_filterDbTableEntry_t *tmpL2; + rtl865x_filterDbTable_t *fdb_t = &sw_FDB_Table.filterDB[fid]; + rtl865x_tblAsicDrv_l2Param_t l2entry_tmp,*L2buff; + int32 retval = 0; + int32 overwite_blk_flag = FALSE; + + L2buff = &l2entry_tmp; + memset(L2buff,0,sizeof(rtl865x_tblAsicDrv_l2Param_t)); + rowIdx = rtl8651_filterDbIndex(macAddr, fid); + for(colIdx=0; colIdx<RTL8651_L2TBL_COLUMN; colIdx++) + { + retval = rtl8651_getAsicL2Table(rowIdx, colIdx, L2buff); + if ((retval)==SUCCESS) + { + /*check whether mac address has been learned to HW or not*/ + if (memcmp(&(L2buff->macAddr), macAddr, 6)== 0) + { + /*the entry has been auto learned*/ + if (L2buff->memberPortMask==portMask) + { + /*the entry has been auto learned */ + if ((L2buff->srcBlk == TRUE) && (L2buff->auth == FALSE)) + { + overwite_blk_flag = TRUE; + } + found = TRUE; + col_tmp = colIdx; + } + else + /*portmask is different , it should be overwrited*/ + { + found = FALSE; + flag = TRUE; + } + break; + } + /*no matched entry, try get minimum aging time L2 Asic entry*/ + if (tmp_age> L2buff->ageSec) + { + tmp_age = L2buff->ageSec; + col_num = colIdx; + } + } + else + { + /*there is still empty l2 asic entry*/ + flag = TRUE; + break; + } + } + + switch(l2Type) { + case RTL865x_L2_TYPEI: + nexthp_flag = FALSE;isStatic = FALSE; + break; + case RTL865x_L2_TYPEII: + nexthp_flag = TRUE; isStatic = TRUE; + break; + case RTL865x_L2_TYPEIII: + nexthp_flag = FALSE;isStatic = TRUE; + break; + default: assert(0); + } + + switch(type) { + case FDB_TYPE_FWD: + toCpu = FALSE; + break; + case FDB_TYPE_DSTBLK: + toCpu = FALSE; + break; + case FDB_TYPE_SRCBLK: + toCpu = FALSE; + break; + case FDB_TYPE_TRAPCPU: + toCpu = TRUE; + break; + default: assert(0); + } + + if (found == FALSE) + { + /*no empty entry, overwrite the biggest aging time asic l2 entry*/ + if(flag == FALSE) + { + /*delete the biggest aging time software entry*/ + rtl8651_getAsicL2Table(rowIdx, col_num, L2buff); + _rtl865x_removeFilterDatabaseEntry(fid, &(L2buff->macAddr), rowIdx); + + /*overwrite asic entry*/ + rtl8651_setAsicL2Table_Patch( + rowIdx, + col_num, + macAddr, + toCpu, + SrcBlk, + portMask, + arpAgingTime, + isStatic, + nexthp_flag, + fid, + auth); + col_tmp = col_num; + } + /*portmask is different , so it should overwrite the original asic entry. Or there is empty entry, set it to asic*/ + else if(flag == TRUE) + { + rtl8651_setAsicL2Table_Patch( + rowIdx, + colIdx, + macAddr, + toCpu, + SrcBlk, + portMask, + arpAgingTime, + isStatic, + nexthp_flag, + fid, + auth); + col_tmp = colIdx; + } + } + /*find the same asic entry, should update the aging time*/ + else + { + rtl8651_setAsicL2Table_Patch( + rowIdx, + col_tmp, + macAddr, + toCpu, + SrcBlk, + portMask, + arpAgingTime, + isStatic, + nexthp_flag, + fid, + auth); + } + +/* + colIdx=0; + + tmpL2 = SLIST_FIRST(&(fdb_t->database[rowIdx])); + tmpL2->nextFDB.sle_next = NULL; + + for(colIdx=0; colIdx<RTL8651_L2TBL_COLUMN; colIdx++) + { + if ((rtl8651_getAsicL2Table(rowIdx, colIdx, L2buff))==SUCCESS) + { + l2entry_t->asicPos =colIdx; + l2entry_t->auth = L2buff->auth; + l2entry_t->configToAsic = 0; + l2entry_t->memberPortMask = L2buff->memberPortMask; + l2entry_t->SrcBlk = L2buff->srcBlk; + memcpy(&l2entry_t->macAddr, &L2buff->macAddr, sizeof(ether_addr_t)); + + tmpL2->nextFDB.sle_next = l2entry_t; + l2entry_t->nextFDB.sle_next = NULL; + tmpL2 = l2entry_t; + } + } +*/ + + if (SLIST_FIRST(&sw_FDB_Table.freefdbList.filterDBentry) == NULL) + return RTL_ENOFREEBUFFER; + + /*config the SW l2 entry */ + l2entry_t = SLIST_FIRST(&sw_FDB_Table.freefdbList.filterDBentry); + SLIST_REMOVE_HEAD(&sw_FDB_Table.freefdbList.filterDBentry, nextFDB); + + l2entry_t->asicPos =col_tmp; + l2entry_t->auth = auth; + l2entry_t->configToAsic = 0; + l2entry_t->memberPortMask = portMask; + l2entry_t->l2type = l2Type; + l2entry_t->nhFlag = nexthp_flag; + + l2entry_t->SrcBlk = SrcBlk; + memcpy(&l2entry_t->macAddr, macAddr, sizeof(ether_addr_t)); + switch(type) { + case FDB_TYPE_FWD: + l2entry_t->process = FDB_TYPE_FWD; + l2entry_t->memberPortMask = portMask; + break; + case FDB_TYPE_DSTBLK: + l2entry_t->process = FDB_TYPE_DSTBLK; + l2entry_t->memberPortMask = 0; + break; + case FDB_TYPE_SRCBLK: + l2entry_t->process = FDB_TYPE_SRCBLK; + l2entry_t->memberPortMask = 0; + break; + case FDB_TYPE_TRAPCPU: + l2entry_t->process = FDB_TYPE_TRAPCPU; + l2entry_t->memberPortMask = portMask; + break; + default: assert(0); + } + + /*write the SW l2 entry */ +check_swfdb: + if (SLIST_FIRST(&(fdb_t->database[rowIdx]))) + { + SLIST_FOREACH(tmpL2, &(fdb_t->database[rowIdx]), nextFDB) + { + if (memcmp(&(tmpL2->macAddr), macAddr, 6)== 0) + { + if( (tmpL2->auth != auth) || + (tmpL2->process != type) || + (tmpL2->SrcBlk != SrcBlk) || + (tmpL2->memberPortMask != portMask) || + (tmpL2->l2type != l2Type) ) + { + tmpL2->auth = auth; + tmpL2->process = type; + tmpL2->SrcBlk = SrcBlk; + tmpL2->memberPortMask = portMask; + tmpL2->l2type = l2Type; +/* tmpL2 ->refCount = 0;*/ + break; + } + else + { + goto out; + } + } + /*try to check whether there is timeout sw fdb entry*/ + else if(tmpL2->asicPos == col_tmp) + { +/* if ((tmpL2->SrcBlk == TRUE) && (tmpL2->auth == FALSE))*/ + { + _rtl865x_removeFilterDatabaseEntry(fid, &(tmpL2->macAddr), rowIdx); + goto check_swfdb; + } + } + else if (tmpL2->nextFDB.sle_next == NULL) + { +/* l2entry_t->refCount = 0;*/ + tmpL2->nextFDB.sle_next = l2entry_t; + l2entry_t->nextFDB.sle_next = NULL; + break; + } + } + } + else + { +/* l2entry_t ->refCount = 0;*/ + SLIST_INSERT_HEAD(&(fdb_t->database[rowIdx]), l2entry_t, nextFDB); + } + + /* TypeII entry can not exceed RTL8651_L2TBL_COLUMN */ +/* if (typeII == RTL8651_L2TBL_COLUMN && l2Type == RTL8651_L2_TYPEII) + return RTL_NOFREEBUFFER; +*/ + if (!((l2entry_t->SrcBlk == TRUE) && (l2entry_t->auth == FALSE))) + { + rtl865x_raiseEvent(EVENT_ADD_FDB, (void *)(l2entry_t)); + } + + if (overwite_blk_flag != TRUE) + { + rtl865x_raiseEvent(EVENT_ADD_AUTHED_FDB, (void *)(l2entry_t)); + } + else + { +/* printk("\nover blk entry, no raise event\n");*/ + } + +out: + return SUCCESS; +} + + +int32 _rtl865x_addAuthSWl2Entry(uint16 l2Type, uint16 fid, ether_addr_t * macAddr, uint32 type, int32 port, uint8 auth, uint8 SrcBlk) +{ + uint32 rowIdx = 0; + int32 nexthp_flag = FALSE; + rtl865x_filterDbTableEntry_t * l2entry_t = NULL; + rtl865x_filterDbTableEntry_t *tmpL2; + rtl865x_filterDbTable_t *fdb_t = &sw_FDB_Table.filterDB[fid]; + rtl865x_tblAsicDrv_l2Param_t l2entry_tmp,*L2buff; + int32 overwite_blk_flag = FALSE; + + L2buff = &l2entry_tmp; + memset(L2buff,0,sizeof(rtl865x_tblAsicDrv_l2Param_t)); + rowIdx = rtl8651_filterDbIndex(macAddr, fid); + + + if (SLIST_FIRST(&sw_FDB_Table.freefdbList.filterDBentry) == NULL) + return RTL_ENOFREEBUFFER; + + /*config the SW l2 entry */ + l2entry_t = SLIST_FIRST(&sw_FDB_Table.freefdbList.filterDBentry); + SLIST_REMOVE_HEAD(&sw_FDB_Table.freefdbList.filterDBentry, nextFDB); + + l2entry_t->auth = auth; + l2entry_t->configToAsic = 0; + l2entry_t->memberPortMask = 1<<port; + l2entry_t->l2type = l2Type; + l2entry_t->nhFlag = nexthp_flag; + + l2entry_t->SrcBlk = SrcBlk; + memcpy(&l2entry_t->macAddr, macAddr, sizeof(ether_addr_t)); + switch(type) { + case FDB_TYPE_FWD: + l2entry_t->process = FDB_TYPE_FWD; + l2entry_t->memberPortMask = 1<<port; + break; + case FDB_TYPE_DSTBLK: + l2entry_t->process = FDB_TYPE_DSTBLK; + l2entry_t->memberPortMask = 0; + break; + case FDB_TYPE_SRCBLK: + l2entry_t->process = FDB_TYPE_SRCBLK; + l2entry_t->memberPortMask = 0; + break; + case FDB_TYPE_TRAPCPU: + l2entry_t->process = FDB_TYPE_TRAPCPU; + l2entry_t->memberPortMask = 1<<port; + break; + default: assert(0); + } + + /*write the SW l2 entry */ + if (SLIST_FIRST(&(fdb_t->database[rowIdx]))) + { + SLIST_FOREACH(tmpL2, &(fdb_t->database[rowIdx]), nextFDB) + { + if (memcmp(&(tmpL2->macAddr), macAddr, 6)== 0) + { + if( (tmpL2->auth != auth) || + (tmpL2->process != type) || + (tmpL2->SrcBlk != SrcBlk) || + (tmpL2->memberPortMask != 1<<port) || + (tmpL2->l2type != l2Type) ) + { + + if ( ( tmpL2->auth == FALSE) && (tmpL2->SrcBlk == TRUE)) + { + overwite_blk_flag = TRUE; + } + tmpL2->auth = auth; + tmpL2->process = type; + tmpL2->SrcBlk = SrcBlk; + tmpL2->memberPortMask = 1<<port; + tmpL2->l2type = l2Type; +/* tmpL2 ->refCount = 0;*/ + break; + } + else + { + SLIST_INSERT_HEAD(&sw_FDB_Table.freefdbList.filterDBentry, l2entry_t, nextFDB); + goto out; + } + } + + else if (tmpL2->nextFDB.sle_next == NULL) + { +/* l2entry_t->refCount = 0;*/ + tmpL2->nextFDB.sle_next = l2entry_t; + l2entry_t->nextFDB.sle_next = NULL; + break; + } + } + } + else + { +/* l2entry_t ->refCount = 0;*/ + SLIST_INSERT_HEAD(&(fdb_t->database[rowIdx]), l2entry_t, nextFDB); + } + + /* TypeII entry can not exceed RTL8651_L2TBL_COLUMN */ +/* if (typeII == RTL8651_L2TBL_COLUMN && l2Type == RTL8651_L2_TYPEII) + return RTL_NOFREEBUFFER; +*/ + + rtl865x_raiseEvent(EVENT_ADD_FDB, (void *)(l2entry_t)); + + + if (overwite_blk_flag != TRUE) + { + rtl865x_raiseEvent(EVENT_ADD_AUTHED_FDB, (void *)(l2entry_t)); + } + else + { +/* printk("\nover blk entry, no raise event\n");*/ + } + +out: + return SUCCESS; +} + + +int32 rtl865x_addAuthFilterDatabaseEntryExtension( uint16 fid, rtl865x_filterDbTableEntry_t * L2entry) +{ + int32 retval; + unsigned long flags; + if (L2entry->process != FDB_TYPE_FWD && L2entry->process != FDB_TYPE_SRCBLK && L2entry->process != FDB_TYPE_TRAPCPU) + return RTL_EINVALIDINPUT; /* Invalid parameter */ + + if (fid >= RTL865x_FDB_NUMBER) + return RTL_EINVALIDINPUT; + if (&(L2entry->macAddr) == (ether_addr_t *)NULL) + return RTL_EINVALIDINPUT; + if (sw_FDB_Table.filterDB[fid].valid == 0) + return RTL_EINVALIDFID; + + /*l2 lock*/ + //rtl_down_interruptible(&l2_sem); + local_irq_save(flags); + retval = _rtl865x_addAuthFilterDatabaseEntry( L2entry->l2type, + fid, + &(L2entry->macAddr), + L2entry->process, + L2entry->memberPortMask, + L2entry->auth, + L2entry->SrcBlk); + /*l2 unlock*/ + //rtl_up(&l2_sem); + local_irq_restore(flags); + return retval; +} + + +/* +@func int32 | rtl8651_delFilterDatabaseEntry | Remove a filter database entry. +@parm uint16 | fid | Filter database entry. +@parm ether_addr_t * | macAddr | Pointer to a MAC Address. +@rvalue RTL_EINVALIDFID | Filter database ID. +@rvalue RTL_NULLMACADDR | The specified MAC address is NULL. +@rvalue RTL_EINVALIDINPUT | Invalid input parameter. +*/ +int32 rtl865x_delAuthFilterDatabaseEntry(uint16 l2Type, uint16 fid, ether_addr_t * macAddr) { + int32 retval; + unsigned long flags; + if (fid >= RTL865x_FDB_NUMBER) + return RTL_EINVALIDINPUT; + if (macAddr == (ether_addr_t *)NULL) + return RTL_EINVALIDINPUT; + if (sw_FDB_Table.filterDB[fid].valid == 0) + return RTL_EINVALIDFID; + +/* L2 lock */ + //rtl_down_interruptible(&l2_sem); + local_irq_save(flags); + retval = _rtl865x_delAuthFilterDatabaseEntry(RTL865x_L2_TYPEII, fid, macAddr); +/* L2 unlock */ + //rtl_up(&l2_sem); + local_irq_restore(flags); + return retval; +} + + +int32 _rtl865x_delAuthFilterDatabaseEntry(uint16 l2Type, uint16 fid, ether_addr_t * macAddr) +{ + uint32 rowIdx = 0; + uint32 colIdx = 0; + rtl865x_tblAsicDrv_l2Param_t L2temp, *L2buff ; + rtl865x_filterDbTableEntry_t * l2entry_t = NULL; + rtl865x_filterDbTable_t *fdb_t = &sw_FDB_Table.filterDB[fid]; + int32 found = FALSE; + + rowIdx = rtl8651_filterDbIndex(macAddr, fid); + + L2buff = &L2temp; + memset(L2buff, 0 , sizeof (rtl865x_tblAsicDrv_l2Param_t)); + for(colIdx=0; colIdx<RTL8651_L2TBL_COLUMN; colIdx++) + { + if ((rtl8651_getAsicL2Table(rowIdx, colIdx, L2buff))==SUCCESS) + { + /*check whether mac address has been learned to SW or not*/ + if (memcmp(&(L2buff->macAddr), macAddr, 6)== 0) + { + /*the entry has been auto learned*/ + found = TRUE; + break; + } + } + } + + SLIST_FOREACH(l2entry_t, &(fdb_t->database[rowIdx]), nextFDB) + if (!memcmp(&l2entry_t->macAddr, macAddr, sizeof(ether_addr_t))) + { +/* l2entry_t->refCount -= 1;*/ +/* if (l2entry_t->refCount == 0)*/ + { + SLIST_REMOVE( + &(fdb_t->database[rowIdx]), + l2entry_t, + rtl865x_filterDbTableEntry_s, + nextFDB + ); + SLIST_INSERT_HEAD(&sw_FDB_Table.freefdbList.filterDBentry, l2entry_t, nextFDB); + if (found == TRUE) + { + rtl8651_delAsicL2Table(rowIdx, colIdx); + } + rtl865x_raiseEvent(EVENT_DEL_FDB, (void *)(l2entry_t)); +/* printk("raise event EVENT_DEL_AUTHED_FDB : %x", l2entry_t->memberPortMask);*/ + rtl865x_raiseEvent(EVENT_DEL_AUTHED_FDB, (void *)(l2entry_t)); + + } + break; + } + + return SUCCESS; +} + +int32 rtl865x_check_authfdbentry_Byport(int32 port_num, const unsigned char *macAddr) +{ + uint32 rowIdx; + int32 retval = FAILED; + rtl865x_tblAsicDrv_l2Param_t *L2buff, l2temp; + rtl865x_filterDbTable_t *fdb_t = &sw_FDB_Table.filterDB[0]; + rtl865x_filterDbTableEntry_t * l2entry_t ; + + L2buff = &l2temp; + memset(L2buff, 0, sizeof(rtl865x_tblAsicDrv_l2Param_t)); + for(rowIdx=0; rowIdx<RTL8651_L2TBL_ROW; rowIdx++) + { + if (SLIST_FIRST(&(fdb_t->database[rowIdx]))) + { + SLIST_FOREACH(l2entry_t, &(fdb_t->database[rowIdx]), nextFDB) + { + if ((l2entry_t ->auth == FALSE) && (l2entry_t->SrcBlk == TRUE)) + { + memcpy((ether_addr_t *)macAddr, &(l2entry_t->macAddr), sizeof(ether_addr_t)); +#if 0 + printk("\nfind block entry, rowIdx is %d, address2 is %x %x %x %x %x %x\n", rowIdx, ((ether_addr_t *)macAddr)->octet[0], + ((ether_addr_t *)macAddr)->octet[1], + ((ether_addr_t *)macAddr)->octet[2], + ((ether_addr_t *)macAddr)->octet[3], + ((ether_addr_t *)macAddr)->octet[4], + ((ether_addr_t *)macAddr)->octet[5]); +#endif + + + retval = SUCCESS; + break; + } + } + } + + } + return retval; +} + +int32 rtl865x_addAuthFDBEntry(const unsigned char *addr, int32 auth, int32 port) +{ + int32 found = FAILED; + ether_addr_t *macAddr; + int32 ret=FAILED; + int8 port_num = -1; + int32 column; + rtl865x_tblAsicDrv_l2Param_t fdbEntry; + rtl865x_filterDbTableEntry_t l2temp_entry; + int32 srcblk; + + if (addr == NULL) + return RTL_EINVALIDINPUT; + + macAddr = (ether_addr_t *)(addr); + found = rtl865x_Lookup_fdb_entry(RTL_LAN_FID, macAddr, FDB_DYNAMIC, &column, &fdbEntry); + if (auth == TRUE) + srcblk = FALSE; + else + srcblk = TRUE; + + if (found == SUCCESS ) + { + port_num = rtl865x_ConvertPortMasktoPortNum(fdbEntry.memberPortMask); + +/* printk("\nbefore rtl865x_lookup_FilterDatabaseEntry, port is %d, auth is %d\n", port_num, auth); */ + if (rtl865x_lookup_FilterDatabaseEntry(fdbEntry.fid, macAddr, &l2temp_entry) != SUCCESS) + { + l2temp_entry.l2type = (fdbEntry.nhFlag==0)?RTL865x_L2_TYPEI: RTL865x_L2_TYPEII; + l2temp_entry.process = FDB_TYPE_FWD; + l2temp_entry.memberPortMask = fdbEntry.memberPortMask; +/* l2temp_entry.auth = TRUE;*/ +/* l2temp_entry.SrcBlk = FALSE;*/ + memcpy(&(l2temp_entry.macAddr), macAddr, sizeof(ether_addr_t)); + ret =_rtl865x_addAuthFilterDatabaseEntry( l2temp_entry.l2type, + fdbEntry.fid, + &(l2temp_entry.macAddr), + l2temp_entry.process, + l2temp_entry.memberPortMask, + auth, + srcblk); + + } +#if 1 + else + { + if ((l2temp_entry.auth == FALSE) && (l2temp_entry.SrcBlk == TRUE)) + { + l2temp_entry.l2type = (fdbEntry.nhFlag==0)?RTL865x_L2_TYPEI: RTL865x_L2_TYPEII; + l2temp_entry.process = FDB_TYPE_FWD; + l2temp_entry.memberPortMask = fdbEntry.memberPortMask; + memcpy(&(l2temp_entry.macAddr), macAddr, sizeof(ether_addr_t)); + ret =_rtl865x_addAuthFilterDatabaseEntry( l2temp_entry.l2type, + fdbEntry.fid, + &(l2temp_entry.macAddr), + l2temp_entry.process, + l2temp_entry.memberPortMask, + auth, + srcblk); + } + } +#endif + } + else + { + /*just add sw l2 table */ + l2temp_entry.l2type = RTL865x_L2_TYPEII; + l2temp_entry.process = FDB_TYPE_FWD; +/* l2temp_entry.auth = TRUE;*/ +/* l2temp_entry.SrcBlk = FALSE;*/ + memcpy(&(l2temp_entry.macAddr), macAddr, sizeof(ether_addr_t)); + ret =_rtl865x_addAuthSWl2Entry( l2temp_entry.l2type, + 0, + &(l2temp_entry.macAddr), + l2temp_entry.process, + 1<<port, + auth, + srcblk); + } + return ret; +} + + +int32 rtl865x_delAuthLanFDBEntry(uint16 l2Type, const unsigned char *addr) +{ + int32 ret=FAILED; + ether_addr_t *macAddr; + + if (addr == NULL) + { + return RTL_EINVALIDINPUT; + } + macAddr = (ether_addr_t *)(addr); + + ret =_rtl865x_delAuthFilterDatabaseEntry( l2Type, RTL_LAN_FID, macAddr); + + return ret; +} + +int32 rtl865x_BlkCheck(const unsigned char *addr) +{ + ether_addr_t *macAddr; + rtl865x_filterDbTableEntry_t l2temp_entry; + + if (addr == NULL) + return RTL_EINVALIDINPUT; + + macAddr = (ether_addr_t *)(addr); +#if 0 + printk("\nin rtl865x_BlkCheck, address2 is %x %x %x %x %x %x\n", ((ether_addr_t *)macAddr)->octet[0], + ((ether_addr_t *)macAddr)->octet[1], + ((ether_addr_t *)macAddr)->octet[2], + ((ether_addr_t *)macAddr)->octet[3], + ((ether_addr_t *)macAddr)->octet[4], + ((ether_addr_t *)macAddr)->octet[5]); +#endif + + if(rtl865x_lookup_FilterDatabaseEntry(RTL_LAN_FID, macAddr, &l2temp_entry) == SUCCESS) + { + if (l2temp_entry.SrcBlk == TRUE) + { + return TRUE; + } + } + return FALSE; +} +/* +@func int32 | rtl865x_enableLanPortNumRestrict | enable max guest number restrict feature. +@parm uint8 | isEnable | enable feature or not. +@rvalue SUCCESS | enable feature. +@comm This API may change wan & lan port 802.1x mac base ablity +*/ +int32 rtl865x_enableLanPortNumRestrict(uint8 isEnable) +{ + if( isEnable == TRUE) + { + rtl8651_setAsic802D1xMacBaseDirection(Dot1xMAC_OPDIR_IN); + rtl8651_setAsicGuestVlanProcessControl(EN_8021X_TOCPU); + } + else + { + rtl8651_setAsic802D1xMacBaseDirection(Dot1xMAC_OPDIR_BOTH); + rtl8651_setAsicGuestVlanProcessControl( EN_8021X_DROP); + } + + return SUCCESS; +} + + +/* +@func int32 | rtl865x_setRestrictPortNum | set per port max guest number for max host restrict feature. +@parm int32 | port | set port number . +@parm int8 | isEnable | enable max host restrict feature or not +@parm int32 | number | set max guest number +@rvalue SUCCESS | set number for this port ok. +*/ +int32 rtl865x_setRestrictPortNum(int32 port, uint8 isEnable, int32 number) +{ + int32 i = 0; + + if(isEnable==TRUE) + { + + for (i = PHY0; i < EXT3; i++) + { + if( i == port) + { + rtl8651_setAsic802D1xMacBaseAbility(i, TRUE); + break; + } + } + } + + if(isEnable==FALSE) + { + + for (i = PHY0; i < EXT3; i++) + { + if( i == port) + { + rtl8651_setAsic802D1xMacBaseAbility(i, FALSE); + break; + } + } + + } + return SUCCESS; +} +#endif + +#endif + +#ifdef CONFIG_RTL_LINKCHG_PROCESS +int32 _rtl865x_ClearFDBEntryByPort(int32 port_num) +{ + int i, j; + rtl865x_tblAsicDrv_l2Param_t l2entry_tmp,*L2buff; + + L2buff = &l2entry_tmp; + for (i = 0; i < RTL8651_L2TBL_ROW; i++) + for (j = 0; j < RTL8651_L2TBL_COLUMN; j++) + { + if ((rtl8651_getAsicL2Table(i, j, L2buff))!=SUCCESS) + continue; + + if ((rtl865x_ConvertPortMasktoPortNum(L2buff->memberPortMask)) != port_num) + continue; + + if (L2buff->isStatic == TRUE) + continue; + + rtl8651_delAsicL2Table(i, j); + _rtl865x_removeFilterDatabaseEntry(RTL_LAN_FID, &(L2buff->macAddr), i); + } + + return SUCCESS; + +} + +int32 rtl865x_LinkChange_Process(void) +{ + uint32 i, status; + + /* Check each port. */ + for ( i = 0; i < RTL8651_MAC_NUMBER; i++ ) + { + /* Read Port Status Register to know the port is link-up or link-down. */ + status = READ_MEM32( PSRP0 + i * 4 ); + if ( ( status & PortStatusLinkUp ) == FALSE ) + { + /* Link is down. */ + rtl8651_setAsicEthernetLinkStatus( i, FALSE ); + _rtl865x_ClearFDBEntryByPort(i); + } + else + { + /* Link is up. */ + rtl8651_setAsicEthernetLinkStatus( i, TRUE ); + } + } + + return SUCCESS; + +} +#endif + +#ifdef CONFIG_RTL_PROC_DEBUG +int32 rtl865x_sw_l2_proc_read( char *page, char **start, off_t off, int count, int *eof, void *data ) +{ + int32 index = 0; + int32 index1 = 0; + int len=0; + uint32 port, m=0; + rtl865x_filterDbTable_t *filterDbPtr; + rtl865x_filterDbTableEntry_t *tempFilterDbPtr; + + len = sprintf(page, "%s\n", "sw l2 table:"); + + for(index=0,filterDbPtr=&sw_FDB_Table.filterDB[0]; index<RTL865x_FDB_NUMBER; index++,filterDbPtr++) { + for(index1=0; index1<RTL8651_L2TBL_ROW; index1++) + if (SLIST_FIRST(&(filterDbPtr->database[index1]))) + { + SLIST_FOREACH(tempFilterDbPtr, &(filterDbPtr->database[index1]), nextFDB) + { + len += sprintf(page + len, "%4d.[%3d,%d] %02x:%02x:%02x:%02x:%02x:%02x FID:%x mbr(",m, index1, tempFilterDbPtr->asicPos, + tempFilterDbPtr->macAddr.octet[0], tempFilterDbPtr->macAddr.octet[1], tempFilterDbPtr->macAddr.octet[2], + tempFilterDbPtr->macAddr.octet[3], tempFilterDbPtr->macAddr.octet[4], tempFilterDbPtr->macAddr.octet[5], index); + + m++; + + for (port = 0 ; port < RTL8651_PORT_NUMBER + rtl8651_totalExtPortNum ; port ++) + { + if (tempFilterDbPtr->memberPortMask & (1<<port)) + { + len += sprintf(page + len,"%d ", port); + } + } + len += sprintf(page + len,")"); + + switch(tempFilterDbPtr->process) + { + case FDB_TYPE_FWD: + len += sprintf(page + len,"%s ", "FWD"); + break; + case FDB_TYPE_DSTBLK: + len += sprintf(page + len,"%s ", "DSTBLK"); + break; + case FDB_TYPE_SRCBLK: + len += sprintf(page + len,"%s ", "SRCBLK"); + break; + case FDB_TYPE_TRAPCPU: + len += sprintf(page + len,"%s ", "CPU"); + break; + } +// len += sprintf(page + len,"%s %s %s",tempFilterDbPtr->process?"CPU":"FWD", tempFilterDbPtr->l2type?"STA":"DYN", tempFilterDbPtr->SrcBlk?"BLK":""); + len += sprintf(page + len,"%s ", (tempFilterDbPtr->l2type != RTL865x_L2_TYPEI)?"STA":"DYN"); + len += sprintf(page + len,"%s ", (tempFilterDbPtr->l2type == RTL865x_L2_TYPEII)?"NH":""); + + len += sprintf(page + len,"%s ", tempFilterDbPtr->SrcBlk?"BLK":""); + + if (tempFilterDbPtr->auth) + { + len += sprintf(page + len,"AUTH:%d ",tempFilterDbPtr->auth); + } + +/* len += sprintf(page + len,"reference count:%d",tempFilterDbPtr->refCount);*/ + len += sprintf(page + len,"\n"); + } + } + } + + return len; +} + +int32 rtl865x_sw_l2_proc_write( struct file *filp, const char *buff,unsigned long len, void *data ) +{ + return len; +} +#endif + |