/* * * Copyright (c) 2011 Realtek Semiconductor Corp. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #include #include #include #include #include #include #include "AsicDriver/asicRegs.h" //#include #ifdef CONFIG_RTL_LAYERED_ASIC_DRIVER //#include #include "AsicDriver/rtl865x_asicCom.h" #include "AsicDriver/rtl865x_asicL2.h" #else #include #include #include "rtl8651_tblDrvPatch.h" #endif #include #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]; int lan_restrict_tble_reset_port(int port) { #if 0 //disable by jwj lan_restrict_tbl[port].curr_num = 0; #endif return SUCCESS; } #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; indexdatabase[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; indexdatabase[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; colIdxmacAddr), 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; colIdxageing_timer = 300*HZ; macAddr = (ether_addr_t *)(addr); if (rtl865x_Lookup_fdb_entry(RTL_LAN_FID, macAddr, FDB_DYNAMIC, &column,&fdbEntry) == SUCCESS) { /*find the fdb entry*/ port_num = rtl865x_ConvertPortMasktoPortNum(fdbEntry.memberPortMask); } else { /*can't find */ } return port_num; } 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; colIdxmacAddr), 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 ; /*printk("rowIdx:%dfid:%d\n",rowIdx,fid);*/ /*printk("\n mac address is %x %x %x %x %x %x\n", mac->octet[0], mac->octet[1], mac->octet[2], mac->octet[3], mac->octet[4], mac->octet[5]); */ 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; colIdxmacAddr), 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; colIdxasicPos =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; //printk("[%s][%d].\n", __FUNCTION__, __LINE__); rowIdx = rtl8651_filterDbIndex(macAddr, fid); L2buff = &L2temp; memset(L2buff, 0 , sizeof (rtl865x_tblAsicDrv_l2Param_t)); for(colIdx=0; colIdxmacAddr), 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; //printk("[%s][%d].\n", __FUNCTION__, __LINE__); 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("[%s][%d].\n", __FUNCTION__, __LINE__); //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 { //printk("[%s][%d].\n", __FUNCTION__, __LINE__); /*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) extern int rtl_delFdbByMac(const unsigned char *macAddr, const char* devName); char *rtl_getDevNameByPort(int32 port_num); 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; colIdxdatabase[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) { 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) { lan_restrict_tbl[port_num].curr_num --; if (lan_restrict_tbl[port_num].curr_num < 0) { lan_restrict_tbl[port_num].curr_num = 0; } /*printk("\ndel authed port[%d], num:%d\n", port_num, lan_restrict_tbl[port_num].curr_num);*/ } 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); #if 0 if (rtl865x_registerEvent(&eventParam)== SUCCESS) { printk("register Event SUCCESS:%x\n",EVENT_ADD_AUTHED_FDB); return SUCCESS; } else if(rtl865x_registerEvent(&eventParam)== RTL_EENTRYALREADYEXIST) { printk("the Event already exist\n"); return SUCCESS; } else { printk("register Event FAILED:%d \n",rtl865x_registerEvent(&eventParam)); return FAILED; } #endif 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); #if 0 if (rtl865x_registerEvent(&eventParam)== SUCCESS) { printk("register Event SUCCESS:%x\n",EVENT_DEL_AUTHED_FDB); return SUCCESS; } else if(rtl865x_registerEvent(&eventParam)== RTL_EENTRYALREADYEXIST) { printk("the Event already exist\n"); return SUCCESS; } else { printk("register Event FAILED:%d \n",rtl865x_registerEvent(&eventParam)); return FAILED; } #endif 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; //printk("auth:%d,srcblk:%d\n",auth,SrcBlk); L2buff = &l2entry_tmp; memset(L2buff,0,sizeof(rtl865x_tblAsicDrv_l2Param_t)); rowIdx = rtl8651_filterDbIndex(macAddr, fid); for(colIdx=0; colIdxmacAddr), 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; } } /*printk("found:%d,overwite_blk_flag:%d",found, overwite_blk_flag);*/ 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; colIdxasicPos =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 { return SUCCESS; //goto out; appear errorr:label used but not defined } } /*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 (overwite_blk_flag != TRUE) { /*Add a new entry*/ 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<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<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<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<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<l2type = l2Type; /* tmpL2 ->refCount = 0;*/ break; } else { SLIST_INSERT_HEAD(&sw_FDB_Table.freefdbList.filterDBentry, l2entry_t, nextFDB); //goto out; return SUCCESS; } } 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 (overwite_blk_flag != TRUE) { //printk("\nauth:,srcblk:\n",auth,SrcBlk); rtl865x_raiseEvent(EVENT_ADD_AUTHED_FDB, (void *)(l2entry_t)); } else { /*printk("\nNO need to add currnum,over 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); /*print message printk("rowIdx%d:\n",rowIdx); printk("fid%d:\n",fid); printk("\n the mac address is %x %x %x %x %x %x\n", macAddr->octet[0], macAddr->octet[1], macAddr->octet[2], macAddr->octet[3], macAddr->octet[4], macAddr->octet[5]);*/ L2buff = &L2temp; memset(L2buff, 0 , sizeof (rtl865x_tblAsicDrv_l2Param_t)); for(colIdx=0; colIdxmacAddr.octet[0], L2buff->macAddr.octet[1], L2buff->macAddr.octet[2], L2buff->macAddr.octet[3], L2buff->macAddr.octet[4], L2buff->macAddr.octet[5]);*/ /*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); } /*printk("l2entry_t->srcblk:%d,l2entry_t->auth:%d\n", l2entry_t->SrcBlk,l2entry_t->auth);*/ if ((l2entry_t->SrcBlk == FALSE) && (l2entry_t->auth == TRUE)) { uint32 memberPortMask_t; memberPortMask_t=l2entry_t->memberPortMask; /*after del an auth fdb, consider add an auth fdb*/ #if defined (CONFIG_RTL865X_LANPORT_RESTRICTION) && defined(CONFIG_RTL_LAYERED_DRIVER) && defined(CONFIG_RTL_LAYERED_DRIVER_L2)&& defined(CONFIG_RTL865X_SYNC_L2) { unsigned char swap_addr[ETHER_ADDR_LEN]; int32 port_num; /*try to find blocked l2 entry, then set it to authed*/ port_num = rtl865x_ConvertPortMasktoPortNum(memberPortMask_t); if (port_num != FAILED) { /*printk("\ntime out port num is %d\n", port_num);*/ if ((lan_restrict_getBlockAddr(port_num, swap_addr)) == SUCCESS) { //struct hlist_head *head = &br->hash[br_mac_hash(swap_addr)]; /* printk("\n arrange block entry is %x %x %x %x %x %x\n", swap_addr[0], swap_addr[1], swap_addr[2], swap_addr[3], swap_addr[4], swap_addr[5]); */ rtl865x_addAuthFDBEntry(swap_addr, TRUE, port_num, FALSE); } } else {/*port_num==FAILED*/} } #endif /* #if defined (CONFIG_RTL865X_LANPORT_RESTRICTION) && defined(CONFIG_RTL_LAYERED_DRIVER) && defined(CONFIG_RTL_LAYERED_DRIVER_L2) && defined(CONFIG_RTL865X_SYNC_L2) */ //consider add an auth fdb entry } //SLIST_INSERT_HEAD(&sw_FDB_Table.freefdbList.filterDBentry, l2entry_t, nextFDB); rtl865x_raiseEvent(EVENT_DEL_FDB, (void *)(l2entry_t)); //if(lanrestrict_authdel_register_event()==SUCCESS); rtl865x_raiseEvent(EVENT_DEL_AUTHED_FDB, (void *)(l2entry_t)); break; } } /*SLIST_FOREACH*/ 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; rowIdxdatabase[rowIdx]))) { SLIST_FOREACH(l2entry_t, &(fdb_t->database[rowIdx]), nextFDB) { if ( (l2entry_t->memberPortMask&(1<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 srcblk) { 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<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; #ifdef CONFIG_RTL865X_LANPORT_RESTRICTION char *name; #endif 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); #ifdef CONFIG_RTL865X_LANPORT_RESTRICTION name = rtl_getDevNameByPort(port_num); if(name){ rtl_delFdbByMac((unsigned char *)(&(L2buff->macAddr.octet)), name); } #endif _rtl865x_removeFilterDatabaseEntry(RTL_LAN_FID, &(L2buff->macAddr), i); } #if defined(CONFIG_RTL865X_LANPORT_RESTRICTION) /*when link is down, set curr_num of port to 0 */ lan_restrict_tble_reset_port(port_num); #endif 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 ); #if defined(CONFIG_RTL865X_LANPORT_RESTRICTION) _rtl865x_ClearFDBEntryByPort(i); #endif } 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]; indexdatabase[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<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