/* * Copyright c Realtek Semiconductor Corporation, 2009 * All rights reserved. * * Program : Switch table Layer3 route driver,following features are included: * Route/Multicast * Abstract : * Author : hyking (hyking_liu@realsil.com.cn) */ #include <net/rtl/rtl_types.h> #include <net/ipv6.h> #include "asicRegs.h" #include "rtl865x_asicCom.h" #include "rtl865x_asicBasic.h" #include "rtl865x_asicL3.h" //#include "rtl_utils.h" #include "rtl865x_hwPatch.h" #include <net/rtl/rtl865x_route_api.h> #include "../l3Driver/rtl865x_route.h" #if defined(CONFIG_RTL_8685S_HWNAT) #include "../testModel/testModel.h" #include "../common/rtl_utils.h" #include <net/rtl/rtl_types.h> #endif /* CONFIG_RTL_8685S_HWNAT */ int32 rtl8651_setAsicExtIntIpTable(uint32 index, rtl865x_tblAsicDrv_extIntIpParam_t *extIntIpp) { rtl8651_tblAsic_extIpTable_t entry; if((index >= RTL8651_IPTABLE_SIZE) || (extIntIpp == NULL) || ((extIntIpp->localPublic == TRUE) && (extIntIpp->nat == TRUE))) //Local public IP and NAT property cannot co-exist return FAILED; memset(&entry,0,sizeof(entry)); entry.externalIP = extIntIpp->extIpAddr; entry.internalIP = extIntIpp->intIpAddr; entry.isLocalPublic = extIntIpp->localPublic==TRUE? 1: 0; entry.isOne2One = extIntIpp->nat==TRUE? 1: 0; entry.nextHop = extIntIpp->nhIndex; entry.valid = 1; return _rtl8651_forceAddAsicEntry(TYPE_EXT_INT_IP_TABLE, index, &entry); } int32 rtl8651_delAsicExtIntIpTable(uint32 index) { rtl8651_tblAsic_extIpTable_t entry; if(index >= RTL8651_IPTABLE_SIZE) return FAILED; memset(&entry,0,sizeof(entry)); entry.valid = 0; return _rtl8651_forceAddAsicEntry(TYPE_EXT_INT_IP_TABLE, index, &entry); } int32 rtl8651_getAsicExtIntIpTable(uint32 index, rtl865x_tblAsicDrv_extIntIpParam_t *extIntIpp) { rtl8651_tblAsic_extIpTable_t entry; if((index>=RTL8651_IPTABLE_SIZE) || (extIntIpp == NULL)) return FAILED; _rtl8651_readAsicEntry(TYPE_EXT_INT_IP_TABLE, index, &entry); if(entry.valid == 0) return FAILED;//Entry not found extIntIpp->extIpAddr = entry.externalIP; extIntIpp->intIpAddr = entry.internalIP; extIntIpp->localPublic = entry.isLocalPublic==1? TRUE: FALSE; extIntIpp->nat = entry.isOne2One==1? TRUE: FALSE; extIntIpp->nhIndex = entry.nextHop; return SUCCESS; } int32 rtl8651_setAsicPppoe(uint32 index, rtl865x_tblAsicDrv_pppoeParam_t *pppoep) { rtl8651_tblAsic_pppoeTable_t entry; if((index >= RTL8651_PPPOETBL_SIZE) || (pppoep == NULL) || (pppoep->sessionId == 0xffff)) return FAILED; memset(&entry,0,sizeof(entry)); entry.sessionID = pppoep->sessionId; #if 1 //chhuang: #ifdef CONFIG_RTL865XB //entry.ageTime = pppoep->age; entry.ageTime = (pppoep->age>0)?0x07:0; #endif /*CONFIG_RTL865XB*/ return _rtl8651_forceAddAsicEntry(TYPE_PPPOE_TABLE, index, &entry); } int32 rtl8651_getAsicPppoe(uint32 index, rtl865x_tblAsicDrv_pppoeParam_t *pppoep) { rtl8651_tblAsic_pppoeTable_t entry; if((index >= RTL8651_PPPOETBL_SIZE) || (pppoep == NULL)) return FAILED; _rtl8651_readAsicEntry(TYPE_PPPOE_TABLE, index, &entry); pppoep->sessionId = entry.sessionID; #if 1 //chhuang: #ifdef CONFIG_RTL865XB pppoep->age = entry.ageTime; #endif /*CONFIG_RTL865XB*/ return SUCCESS; } int32 rtl8651_setAsicNextHopTable(uint32 index, rtl865x_tblAsicDrv_nextHopParam_t *nextHopp) { rtl8651_tblAsic_nextHopTable_t entry; if((index >= RTL8651_NEXTHOPTBL_SIZE ) || (nextHopp == NULL)) return FAILED; /* for debug rtlglue_printf("[%s:%d] rtl8651_setAsicNextHopTable(idx=%d,Row=%d,Col=%d,PPPIdx=%d,dvid=%d,IPIdx=%d,type=%d)\n", __FILE__,__LINE__,index, nextHopp->nextHopRow,nextHopp->nextHopColumn,nextHopp->pppoeIdx, nextHopp->dvid,nextHopp->extIntIpIdx,nextHopp->isPppoe); */ memset(&entry,0,sizeof(entry)); entry.nextHop = (nextHopp->nextHopRow <<2) | nextHopp->nextHopColumn; entry.PPPoEIndex = nextHopp->pppoeIdx; entry.dstVid = nextHopp->dvid; entry.IPIndex = nextHopp->extIntIpIdx; entry.type = nextHopp->isPppoe==TRUE? 1: 0; return _rtl8651_forceAddAsicEntry(TYPE_NEXT_HOP_TABLE, index, &entry); } int32 rtl8651_getAsicNextHopTable(uint32 index, rtl865x_tblAsicDrv_nextHopParam_t *nextHopp) { rtl8651_tblAsic_nextHopTable_t entry; if((index>=RTL8651_NEXTHOPTBL_SIZE) || (nextHopp == NULL)) return FAILED; _rtl8651_readAsicEntry(TYPE_NEXT_HOP_TABLE, index, &entry); nextHopp->nextHopRow = entry.nextHop>>2; nextHopp->nextHopColumn = entry.nextHop&0x3; nextHopp->pppoeIdx = entry.PPPoEIndex; nextHopp->dvid = entry.dstVid; nextHopp->extIntIpIdx = entry.IPIndex; nextHopp->isPppoe = entry.type==1? TRUE: FALSE; return SUCCESS; } #if defined(CONFIG_RTL_8685S_HWNAT) int32 rtl8198C_setAsicIpv6Routing(uint32 index, rtl8198C_tblAsicDrv_ipv6routingParam_t *routingp) { rtl8198C_tblAsic_IPv6_l3RouteTable_t entry; if((index >= RTL8198C_IPv6ROUTINGTBL_SIZE) || (routingp == NULL)) return FAILED; memset(&entry,0,sizeof(entry)); entry.IPAddr0 = routingp->ipAddr.s6_addr32[3]; entry.IPAddr1 = routingp->ipAddr.s6_addr32[2]; entry.IPAddr2 = routingp->ipAddr.s6_addr32[1]; entry.IPAddr3 = routingp->ipAddr.s6_addr32[0]; entry.v6rdEg =routingp->v6rdeg ; entry.v6rdIdx =routingp->v6rdIdx ; switch(routingp->process) { case 0://PPPoE entry.linkTo.PPPoEEntry.ipMaskNum = routingp->ipMaskNum; entry.linkTo.PPPoEEntry.valid = 1; entry.linkTo.PPPoEEntry.process = routingp->process; entry.linkTo.PPPoEEntry.netif = routingp->netif; if(IS_AFTER_RL6405) { entry.linkTo.PPPoEEntry.nextHop = ((routingp->nextHopRow <<2) | routingp->nextHopColumn)&0x3ff; entry.linkTo.PPPoEEntry.nextHop10_10 = (routingp->nextHopRow >>8)&0x1 ; } else { entry.linkTo.PPPoEEntry.nextHop = (routingp->nextHopRow <<2) | routingp->nextHopColumn; } entry.linkTo.PPPoEEntry.pppIdx = routingp->pppoeIdx; break; case 1://Direct entry.linkTo.L2Entry.ipMaskNum = routingp->ipMaskNum; entry.linkTo.L2Entry.valid = 1; entry.linkTo.L2Entry.process = routingp->process; entry.linkTo.L2Entry.netif = routingp->netif; if(IS_AFTER_RL6405) { entry.linkTo.L2Entry.nextHop = ((routingp->nextHopRow <<2) | routingp->nextHopColumn)&0x3ff; entry.linkTo.L2Entry.nextHop10_10 = (routingp->nextHopRow >>8)&0x1 ; } else { entry.linkTo.L2Entry.nextHop = (routingp->nextHopRow <<2) | routingp->nextHopColumn; } break; case 2://arp entry.linkTo.ARPEntry.ipMaskNum = routingp->ipMaskNum; entry.linkTo.ARPEntry.valid = 1; entry.linkTo.ARPEntry.process = routingp->process; entry.linkTo.ARPEntry.netif = routingp->netif; entry.linkTo.ARPEntry.subnetIdx=routingp->subnetIdx; break; case 3://CPU case 4://DROP /* * Note: although the process of this routing entry is CPU/DROP, * we still have to assign "vid" field for packet decision process use. * - 2005.3.23 - */ entry.linkTo.ARPEntry.netif = routingp->netif; entry.linkTo.ARPEntry.ipMaskNum = routingp->ipMaskNum; entry.linkTo.ARPEntry.process = routingp->process; entry.linkTo.ARPEntry.valid = 1; break; case 5://NAPT NextHop entry.linkTo.NxtHopEntry.nhStart = routingp->nhStart ; entry.linkTo.NxtHopEntry.nhNum = routingp->nhNum; // switch (routingp->nhNum) // { // case 2: entry.linkTo.NxtHopEntry.nhNum = 0; break; // case 4: entry.linkTo.NxtHopEntry.nhNum = 1; break; // case 8: entry.linkTo.NxtHopEntry.nhNum = 2; break; // case 16: entry.linkTo.NxtHopEntry.nhNum = 3; break; // case 32: entry.linkTo.NxtHopEntry.nhNum = 4; break; // default: return FAILED; // } entry.linkTo.NxtHopEntry.ipMaskNum = routingp->ipMaskNum; entry.linkTo.NxtHopEntry.valid = 1; entry.linkTo.NxtHopEntry.process = routingp->process; entry.linkTo.NxtHopEntry.nhNum = (routingp->nhNum>>1)-1; entry.linkTo.NxtHopEntry.nhStart = routingp->nhStart>>1; entry.linkTo.NxtHopEntry.nhNxt = routingp->nhNxt; entry.linkTo.NxtHopEntry.nhAlgo = routingp->nhAlgo; break; default: return FAILED; } return _rtl8651_forceAddAsicEntry(TYPE_IPv6_ROUTING_TABLE, index, &entry); } int32 rtl8198C_getAsicIpv6Routing(uint32 index, rtl8198C_tblAsicDrv_ipv6routingParam_t *routingp) { rtl8198C_tblAsic_IPv6_l3RouteTable_t entry; if((index >= RTL8198C_IPv6ROUTINGTBL_SIZE) || (routingp == NULL)) return FAILED; _rtl8651_readAsicEntry(TYPE_IPv6_ROUTING_TABLE, index, &entry); if(entry.linkTo.ARPEntry.valid == 0) return FAILED; routingp->ipAddr.s6_addr32[3] = entry.IPAddr0; routingp->ipAddr.s6_addr32[2] = entry.IPAddr1; routingp->ipAddr.s6_addr32[1] = entry.IPAddr2; routingp->ipAddr.s6_addr32[0] = entry.IPAddr3; routingp->process = entry.linkTo.ARPEntry.process; routingp->ipMaskNum= entry.linkTo.PPPoEEntry.ipMaskNum; routingp->v6rdeg =entry.v6rdEg; routingp->v6rdIdx =entry.v6rdIdx; switch(routingp->process) { case 0://PPPoE routingp->netif =entry.linkTo.PPPoEEntry.netif; routingp->valid =1; if(IS_AFTER_RL6405) { routingp->nextHopRow = (entry.linkTo.PPPoEEntry.nextHop>>2) | (entry.linkTo.PPPoEEntry.nextHop10_10 <<8); } else { routingp->nextHopRow = entry.linkTo.PPPoEEntry.nextHop>>2; } routingp->nextHopColumn = entry.linkTo.PPPoEEntry.nextHop & 0x3; routingp->pppoeIdx = entry.linkTo.PPPoEEntry.pppIdx; break; case 1://Direct routingp->pppoeIdx = 0; routingp->valid = 1; routingp ->netif =entry.linkTo.L2Entry.netif; if(IS_AFTER_RL6405) { routingp->nextHopRow = (entry.linkTo.L2Entry.nextHop>>2) | (entry.linkTo.L2Entry.nextHop10_10 <<8); } else { routingp->nextHopRow = entry.linkTo.L2Entry.nextHop>>2; } routingp->nextHopColumn = entry.linkTo.L2Entry.nextHop&0x3; break; case 2://Indirect routingp->pppoeIdx = 0; routingp->nextHopRow = 0; routingp->nextHopColumn = 0; routingp->valid =1 ; routingp ->netif =entry.linkTo.L2Entry.netif; routingp->subnetIdx = entry.linkTo.ARPEntry.subnetIdx; break; case 3: /* CPU */ routingp->valid = 1; case 4: /* Drop */ routingp->valid = 1; routingp->pppoeIdx = 0; routingp->nextHopRow = 0; routingp->nextHopColumn = 0; break; case 5: routingp->nhStart = (entry.linkTo.NxtHopEntry.nhStart) << 1; switch (entry.linkTo.NxtHopEntry.nhNum) { case 0: routingp->nhNum = 2; break; case 1: routingp->nhNum = 4; break; case 2: routingp->nhNum = 8; break; case 3: routingp->nhNum = 16; break; case 4: routingp->nhNum = 32; break; break; default: return FAILED; } routingp->valid =1 ; // routingp->nhNum =entry.linkTo.NxtHopEntry.nhNum ; // routingp->nhStart =entry.linkTo.NxtHopEntry.nhStart; routingp->nhNxt = entry.linkTo.NxtHopEntry.nhNxt; routingp->nhAlgo = entry.linkTo.NxtHopEntry.nhAlgo; break; default: printk("Unknown Process! @ %s %d\n",__func__,__LINE__); return FAILED; } return SUCCESS; } int32 rtl8198C_delAsicIpv6Routing(uint32 index) { rtl8198C_tblAsic_IPv6_l3RouteTable_t entry; if(index >= RTL8198C_IPv6ROUTINGTBL_SIZE ) return FAILED; memset(&entry,0,sizeof(entry)); return _rtl8651_forceAddAsicEntry(TYPE_IPv6_ROUTING_TABLE, index, &entry); } int32 rtl8198C_setAsicArp6(rtl8198C_tblAsicDrv_v6NeighParam_t *arpp) { rtl8198C_tblAsic_v6NeighTable_t entry; uint32 index; uint32 i; index = rtl8198C_Arp6HashFunction(arpp); if((index >= RTL8198C_V6NEIGHTBL_SIZE) || (arpp == NULL)) return FAILED; for(i=0;i<4;i++){ _rtl8651_readAsicEntry(TYPE_IPV6_NEIGH_TABLE, (index*4)+i, &entry); if(entry.valid == 0) { memset(&entry,0,sizeof(entry)); entry.valid = 1; if(IS_AFTER_RL6405) { entry.nexthop = ((arpp->nextHopRow<<2) | (arpp->nextHopColumn&0x3)) &0x3ff; entry.nexthop10_10 = (arpp->nextHopRow >>8 )&0x1; } else { entry.nexthop = (arpp->nextHopRow<<2) | (arpp->nextHopColumn&0x3); } entry.subnetIdx = arpp->subnetIdx; entry.hostID17_0 = (arpp->hostID); entry.hostID49_18 = (arpp->hostID) >>18 ; entry.hostID63_50 = (arpp->hostID) >>50 ; entry.age=arpp->age; return _rtl8651_forceAddAsicEntry(TYPE_IPV6_NEIGH_TABLE, (index*4)+i, &entry); } } printk("rtl8198C_setAsicArp6 hash entry filled \n"); return FAILED; } int32 rtl8198C_setAsicArp6_idx(uint32 index,rtl8198C_tblAsicDrv_v6NeighParam_t *arpp) { rtl8198C_tblAsic_v6NeighTable_t entry; if((index >= RTL8198C_V6NEIGHTBL_SIZE) || (arpp == NULL)) return FAILED; memset(&entry,0,sizeof(entry)); entry.valid = 1; if(IS_AFTER_RL6405) { entry.nexthop = ((arpp->nextHopRow<<2) | (arpp->nextHopColumn&0x3))&0x3ff ; entry.nexthop10_10 = (arpp->nextHopRow >>8)&0x1; } else { entry.nexthop = (arpp->nextHopRow<<2) | (arpp->nextHopColumn&0x3); } entry.subnetIdx = arpp->subnetIdx; entry.hostID17_0 = (arpp->hostID); entry.hostID49_18 = (arpp->hostID) >>18 ; entry.hostID63_50 = (arpp->hostID) >>50 ; entry.age=arpp->age; return _rtl8651_forceAddAsicEntry(TYPE_IPV6_NEIGH_TABLE, index, &entry); } int32 rtl8198C_getAsicArp6(uint32 index ,rtl8198C_tblAsicDrv_v6NeighParam_t *arpp) { rtl8198C_tblAsic_v6NeighTable_t entry; if((index >= RTL8198C_V6NEIGHTBL_SIZE) || (arpp == NULL)) return FAILED; _rtl8651_readAsicEntry(TYPE_IPV6_NEIGH_TABLE, index, &entry); if(entry.valid == 0) return FAILED; arpp->valid=1; if(IS_AFTER_RL6405) { arpp->nextHopRow = entry.nexthop>>2 | entry.nexthop10_10 <<8; } else { arpp->nextHopRow = entry.nexthop>>2; } arpp->nextHopColumn = entry.nexthop&0x3; arpp ->subnetIdx = entry.subnetIdx; arpp ->hostID = ( ((uint64)entry.hostID63_50) << 50) | (((uint64)entry.hostID49_18)<<18) | ((uint64)entry.hostID17_0) ; arpp->age=entry.age&0x1f; return SUCCESS; } int32 rtl8198C_delAsicArp6(uint32 index) { rtl8198C_tblAsic_v6NeighTable_t entry; if((index >= RTL8198C_V6NEIGHTBL_SIZE) ) return FAILED; memset(&entry,0,sizeof(entry)); return _rtl8651_forceAddAsicEntry(TYPE_IPV6_NEIGH_TABLE, index, &entry); } int32 rtl8198C_setAsicDSLite(uint32 index, rtl8198C_tblAsicDrv_DSLiteParam_t *dslp) { rtl8198C_tblAsic_DSLiteTable_t entry; if((index >= RTL8198C_DSLITETBL_SIZE) || (dslp == NULL)) return FAILED; memset(&entry,0,sizeof(entry)); entry.hostIP0 =dslp ->hostIP.s6_addr32[3]; entry.hostIP1 =dslp ->hostIP.s6_addr32[2]; entry.hostIP2 =dslp ->hostIP.s6_addr32[1]; entry.hostIP3 =dslp ->hostIP.s6_addr32[0]; entry.hostIPMaskNum =dslp ->hostIPMaskNum; entry.ipAFTR24_0 =dslp->ipAFTR.s6_addr32[3]; entry.ipAFTR56_25 = (dslp->ipAFTR.s6_addr32[3] >>25) | (dslp->ipAFTR.s6_addr32[2] << 7); entry.ipAFTR88_57 = (dslp->ipAFTR.s6_addr32[2] >>25) | (dslp->ipAFTR.s6_addr32[1] << 7); entry.ipAFTR120_89 = (dslp->ipAFTR.s6_addr32[1] >>25) | (dslp->ipAFTR.s6_addr32[0] << 7); entry.ipAFTR127_121 = (dslp->ipAFTR.s6_addr32[0] >>25) ; entry.ipMaskAFTRNum = dslp ->ipMaskAFTRNum; entry.dslMtu = dslp->dslMtu; entry.valid =dslp->valid; return _rtl8651_forceAddAsicEntry(TYPE_DS_LITE_TABLE, index, &entry); } int32 rtl8198C_getAsicDSLite(uint32 index, rtl8198C_tblAsicDrv_DSLiteParam_t *dslp) { rtl8198C_tblAsic_DSLiteTable_t entry; if((index >= RTL8198C_DSLITETBL_SIZE) || (dslp == NULL)) return FAILED; _rtl8651_readAsicEntry(TYPE_DS_LITE_TABLE, index, &entry); if(entry.valid == 0) return FAILED; dslp ->hostIP.s6_addr32[3]=entry.hostIP0 ; dslp ->hostIP.s6_addr32[2]=entry.hostIP1 ; dslp ->hostIP.s6_addr32[1]=entry.hostIP2 ; dslp ->hostIP.s6_addr32[0]=entry.hostIP3 ; dslp ->hostIPMaskNum=entry.hostIPMaskNum ; dslp->ipAFTR.s6_addr32[3] = (entry.ipAFTR24_0) | (entry.ipAFTR56_25 <<25); dslp->ipAFTR.s6_addr32[2] = (entry.ipAFTR56_25 >> 7) | entry.ipAFTR88_57 <<25 ; dslp->ipAFTR.s6_addr32[1] = (entry.ipAFTR88_57 >> 7) | entry.ipAFTR120_89 <<25 ; dslp->ipAFTR.s6_addr32[0] = (entry.ipAFTR120_89 >>7) | entry.ipAFTR127_121 <<25 ; dslp ->ipMaskAFTRNum=entry.ipMaskAFTRNum ; dslp->dslMtu=entry.dslMtu ; dslp ->valid =1; return SUCCESS; } int32 rtl8198C_delAsicDSLite(uint32 index) { rtl8198C_tblAsic_DSLiteTable_t entry; if((index >= RTL8198C_DSLITETBL_SIZE) ) return FAILED; memset(&entry,0,sizeof(entry)); return _rtl8651_forceAddAsicEntry(TYPE_DS_LITE_TABLE, index, &entry); } int32 rtl8198C_setAsicNexthop6(uint32 index, rtl8198C_tblAsicDrv_v6NexthopParam_t *nxt6p) { rtl8198C_tblAsic_v6NexthopTable_t entry; if((index >= RTL8198C_V6NEXTHOPTBL_SIZE) || (nxt6p == NULL)) return FAILED; memset(&entry,0,sizeof(entry)); entry.isPppoe =nxt6p->isPppoe; entry.destVlanIdx=nxt6p->destVlanIdx; entry.pppTbIdx =nxt6p ->pppTbIdx ; entry.nexthop = (nxt6p->nextHopRow<<2) | (nxt6p->nextHopColumn&0x3); return _rtl8651_forceAddAsicEntry(TYPE_IPv6_NEXTHOP_TABLE, index, &entry); } int32 rtl8198C_getAsicNexthop6(uint32 index, rtl8198C_tblAsicDrv_v6NexthopParam_t *nxt6p) { rtl8198C_tblAsic_v6NexthopTable_t entry; if((index >= RTL8198C_V6NEXTHOPTBL_SIZE) || (nxt6p == NULL)) return FAILED; _rtl8651_readAsicEntry(TYPE_IPv6_NEXTHOP_TABLE, index, &entry); nxt6p->isPppoe = entry.isPppoe; nxt6p->destVlanIdx =entry.destVlanIdx; nxt6p->pppTbIdx = entry.pppTbIdx; nxt6p->nextHopRow = entry.nexthop>>2; nxt6p->nextHopColumn = entry.nexthop&0x3; return SUCCESS; } int32 rtl8198C_delAsicNexthop6(uint32 index) { rtl8198C_tblAsic_v6NexthopTable_t entry; if((index >= RTL8198C_V6NEXTHOPTBL_SIZE)) return FAILED; memset(&entry,0,sizeof(entry)); return _rtl8651_forceAddAsicEntry(TYPE_IPv6_NEXTHOP_TABLE, index, &entry); } int32 rtl8198C_setAsicV6Rd(uint32 index, rtl8198C_tblAsicDrv_v6RDParam_t *v6rdp) { rtl8198C_tblAsic_v6RDTable_t entry; if((index >= RTL8198C_IPv6RDTBL_SIZE) || (v6rdp == NULL)) return FAILED; memset(&entry,0,sizeof(entry)); entry.ipCE =v6rdp->ipCE; entry.ipMaskCENum =v6rdp->ipMaskCENum; entry.v6rdPrefix25_0 =v6rdp->v6rdPrefix; entry.v6rdPrefix57_26=v6rdp->v6rdPrefix >>26; entry.v6rdPrefix63_58=v6rdp->v6rdPrefix>>58; entry.maskPrefixNum=v6rdp->maskPrefixNum; entry.ipBR19_0=v6rdp->ipBR ; entry.ipBR31_20=v6rdp->ipBR >>20 ; entry.maskBRNum = v6rdp->maskBRNum; entry.v6RDmtu = v6rdp->v6RDmtu; entry.valid = v6rdp->valid; return _rtl8651_forceAddAsicEntry(TYPE_6RD_TABLE, index, &entry); } int32 rtl8198C_getAsicV6Rd(uint32 index, rtl8198C_tblAsicDrv_v6RDParam_t *v6rdp) { rtl8198C_tblAsic_v6RDTable_t entry; if((index >= RTL8198C_IPv6RDTBL_SIZE) || (v6rdp == NULL)) return FAILED; _rtl8651_readAsicEntry(TYPE_6RD_TABLE, index, &entry); if(entry.valid == 0) return FAILED; v6rdp->ipCE =entry.ipCE ; v6rdp->ipMaskCENum = entry.ipMaskCENum; v6rdp->v6rdPrefix= entry.v6rdPrefix25_0 | (((uint64)entry.v6rdPrefix57_26) <<26) | (((uint64)entry.v6rdPrefix63_58) <<58) ; v6rdp->maskPrefixNum =entry.maskPrefixNum; v6rdp->ipBR = entry.ipBR19_0 | (entry.ipBR31_20 <<20); v6rdp->maskBRNum=entry.maskBRNum; v6rdp->v6RDmtu = entry.v6RDmtu; v6rdp->valid =1 ; return SUCCESS; } int32 rtl8198C_delAsicV6Rd(uint32 index) { rtl8198C_tblAsic_v6RDTable_t entry; if((index >= RTL8198C_IPv6RDTBL_SIZE)) return FAILED; memset(&entry,0,sizeof(entry)); return _rtl8651_forceAddAsicEntry(TYPE_6RD_TABLE, index, &entry); } /*type =2 idx = srcAddr.s6_addr32[3]&0xFF , type =3 idx = dstAddr.s6_addr32[3]&0xFF other IPM hash function */ uint32 rtl8198C_ipMulticastv6TableIndex(uint32 hash_type,struct in6_addr srcAddr,struct in6_addr dstAddr) { uint32 idx=0,hash_idx_sip,hash_idx_dip; static uint32 sip[128],dip[128]; uint32 sip_hash[8],dip_hash[8]; uint32 i,j,offset,src,dst; if(hash_type==2) { idx = srcAddr.s6_addr32[3]&0xFF; return idx; } else if(hash_type==3) { idx = dstAddr.s6_addr32[3]&0xFF; return idx; } for(i=0; i<8; i++) { sip_hash[i]=0; dip_hash[i]=0; } for(j=0;j<4;j++) { offset = j*32; src = srcAddr.s6_addr32[j]; dst = dstAddr.s6_addr32[j]; for(i=0; i<32; i++) { if((src& (1<<i))!=0) { sip[i+offset]=1; } else { sip[i+offset]=0; } if((dst & (1<<i))!=0) { dip[i+offset]=1; } else { dip[i+offset]=0; } } } sip_hash[0] = sip[7] ^ sip[15] ^ sip[23] ^ sip[31] ^ sip[39] ^ sip[47] ^ sip[55] ^ sip[63] ^ sip[71] ^ sip[79] ^ sip[87] ^ sip[95] ^ sip[103]^ sip[111] ^ sip[119] ^ sip[127]; sip_hash[1] = sip[6] ^ sip[14] ^ sip[22] ^ sip[30] ^ sip[38] ^ sip[46] ^ sip[54] ^ sip[62] ^ sip[70] ^ sip[78] ^ sip[86] ^ sip[94] ^ sip[102]^ sip[110] ^ sip[118] ^ sip[126]; sip_hash[2] = sip[5] ^ sip[13] ^ sip[21] ^ sip[29] ^ sip[37] ^ sip[45] ^ sip[53] ^ sip[61] ^ sip[69] ^ sip[77] ^ sip[85] ^ sip[93] ^ sip[101]^ sip[109] ^ sip[117] ^ sip[125]; sip_hash[3] = sip[4] ^ sip[12] ^ sip[20] ^ sip[28] ^ sip[36] ^ sip[44] ^ sip[52] ^ sip[60] ^ sip[68] ^ sip[76] ^ sip[84] ^ sip[92] ^ sip[100]^ sip[108] ^ sip[116] ^ sip[124]; sip_hash[4] = sip[3] ^ sip[11] ^ sip[19] ^ sip[27] ^ sip[35] ^ sip[43] ^ sip[51] ^ sip[59] ^ sip[67] ^ sip[75] ^ sip[83] ^ sip[91] ^ sip[99] ^ sip[107] ^ sip[115] ^ sip[123]; sip_hash[5] = sip[2] ^ sip[10] ^ sip[18] ^ sip[26] ^ sip[34] ^ sip[42] ^ sip[50] ^ sip[58] ^ sip[66] ^ sip[74] ^ sip[82] ^ sip[90] ^ sip[98] ^ sip[106] ^ sip[114] ^ sip[122]; sip_hash[6] = sip[1] ^ sip[9] ^ sip[17] ^ sip[25] ^ sip[33] ^ sip[41] ^ sip[49] ^ sip[57] ^ sip[65] ^ sip[73] ^ sip[81] ^ sip[89] ^ sip[97] ^ sip[105] ^ sip[113] ^ sip[121]; sip_hash[7] = sip[0] ^ sip[8] ^ sip[16] ^ sip[24] ^ sip[32] ^ sip[40] ^ sip[48] ^ sip[56] ^ sip[64] ^ sip[72] ^ sip[80] ^ sip[88] ^ sip[96] ^ sip[104] ^ sip[112] ^ sip[120]; dip_hash[7] = dip[7] ^ dip[15] ^ dip[23] ^ dip[31] ^ dip[39] ^ dip[47] ^ dip[55] ^ dip[63] ^ dip[71] ^ dip[79] ^ dip[87] ^ dip[95] ^ dip[103]^ dip[111] ^ dip[119] ^ dip[127]; dip_hash[6] = dip[6] ^ dip[14] ^ dip[22] ^ dip[30] ^ dip[38] ^ dip[46] ^ dip[54] ^ dip[62] ^ dip[70] ^ dip[78] ^ dip[86] ^ dip[94] ^ dip[102]^ dip[110] ^ dip[118] ^ dip[126]; dip_hash[5] = dip[5] ^ dip[13] ^ dip[21] ^ dip[29] ^ dip[37] ^ dip[45] ^ dip[53] ^ dip[61] ^ dip[69] ^ dip[77] ^ dip[85] ^ dip[93] ^ dip[101]^ dip[109] ^ dip[117] ^ dip[125]; dip_hash[4] = dip[4] ^ dip[12] ^ dip[20] ^ dip[28] ^ dip[36] ^ dip[44] ^ dip[52] ^ dip[60] ^ dip[68] ^ dip[76] ^ dip[84] ^ dip[92] ^ dip[100]^ dip[108] ^ dip[116] ^ dip[124]; dip_hash[3] = dip[3] ^ dip[11] ^ dip[19] ^ dip[27] ^ dip[35] ^ dip[43] ^ dip[51] ^ dip[59] ^ dip[67] ^ dip[75] ^ dip[83] ^ dip[91] ^ dip[99] ^ dip[107] ^ dip[115] ^ dip[123]; dip_hash[2] = dip[2] ^ dip[10] ^ dip[18] ^ dip[26] ^ dip[34] ^ dip[42] ^ dip[50] ^ dip[58] ^ dip[66] ^ dip[74] ^ dip[82] ^ dip[90] ^ dip[98] ^ dip[106] ^ dip[114] ^ dip[122]; dip_hash[1] = dip[1] ^ dip[9] ^ dip[17] ^ dip[25] ^ dip[33] ^ dip[41] ^ dip[49] ^ dip[57] ^ dip[65] ^ dip[73] ^ dip[81] ^ dip[89] ^ dip[97] ^ dip[105] ^ dip[113] ^ dip[121]; dip_hash[0] = dip[0] ^ dip[8] ^ dip[16] ^ dip[24] ^ dip[32] ^ dip[40] ^ dip[48] ^ dip[56] ^ dip[64] ^ dip[72] ^ dip[80] ^ dip[88] ^ dip[96] ^ dip[104] ^ dip[112] ^ dip[120]; for(i=0; i<8; i++) { sip_hash[i]=sip_hash[i] & (0x01); dip_hash[i]=dip_hash[i] & (0x01); } hash_idx_sip=0; for(i=0; i<8; i++) { hash_idx_sip=hash_idx_sip+(sip_hash[i]<<i); } hash_idx_dip=0; for(i=0; i<8; i++) { hash_idx_dip=hash_idx_dip+(dip_hash[i]<<i); } idx=0; idx = hash_idx_dip ^ hash_idx_sip; return idx; } int32 rtl8198C_setAsicIpv6MulticastTable(uint32 index,rtl8198C_tblAsicDrv_IPv6multiCastParam_t *v6mcastp) { rtl8198C_tblAsic_IPv6ipMulticastTable_t entry; if((index >= RTL8198C_IPv6MCASTTBL_SIZE) || (v6mcastp == NULL)) return FAILED; memset(&entry,0,sizeof(entry)); entry.srcIPAddr0 = v6mcastp->srcIPAddr.s6_addr32[3]; entry.srcIPAddr1 = v6mcastp->srcIPAddr.s6_addr32[2]; entry.srcIPAddr2 = v6mcastp->srcIPAddr.s6_addr32[1]; entry.srcIPAddr3 = v6mcastp->srcIPAddr.s6_addr32[0]; entry.destIPAddr0 = v6mcastp->destIPAddr.s6_addr32[3]; entry.destIPAddr1 = v6mcastp->destIPAddr.s6_addr32[2]; entry.destIPAddr2 = v6mcastp->destIPAddr.s6_addr32[1]; entry.destIPAddr3 = (v6mcastp->destIPAddr.s6_addr32[0] & 0xfffffff); entry.srcPort = v6mcastp->srcPort; entry.portMember = v6mcastp->portMember; entry.extPortMember = v6mcastp->extPortMember; entry.v6rdEngress = v6mcastp->v6rdEngress; entry.v6rdTbIdx = v6mcastp->v6rdTbIdx; entry.valid=1; entry.toCPU = v6mcastp->toCPU; entry.ageTime = v6mcastp->ageTime; if(IS_AFTER_RL6405) { entry.difidx = v6mcastp->difidx; } return _rtl8651_forceAddAsicEntry(TYPE_IPv6_MULTICAST_TABLE, index, &entry); } int32 rtl8198C_getAsicIpv6MulticastTable(uint32 index, rtl8198C_tblAsicDrv_IPv6multiCastParam_t *v6mcastp) { rtl8198C_tblAsic_IPv6ipMulticastTable_t entry; if((index >= RTL8198C_IPv6MCASTTBL_SIZE) || (v6mcastp == NULL)) return FAILED; _rtl8651_readAsicEntry(TYPE_IPv6_MULTICAST_TABLE, index, &entry); if(entry.valid == 0) return FAILED; v6mcastp->srcIPAddr.s6_addr32[3]= entry.srcIPAddr0 ; v6mcastp->srcIPAddr.s6_addr32[2]= entry.srcIPAddr1 ; v6mcastp->srcIPAddr.s6_addr32[1]= entry.srcIPAddr2 ; v6mcastp->srcIPAddr.s6_addr32[0]= entry.srcIPAddr3 ; v6mcastp->destIPAddr.s6_addr32[3]=entry.destIPAddr0 ; v6mcastp->destIPAddr.s6_addr32[2]=entry.destIPAddr1 ; v6mcastp->destIPAddr.s6_addr32[1]=entry.destIPAddr2 ; v6mcastp->destIPAddr.s6_addr32[0]=entry.destIPAddr3 ; v6mcastp->destIPAddr.s6_addr32[0] |= 0xf0000000; // [1111,entry.destIPAddr3] /*spec error !?*/ //v6mcastp->destIPAddr.s6_addr32[0] |= 0xe0000000; // [1110,entry.destIPAddr3] v6mcastp->srcPort=entry.srcPort ; v6mcastp->portMember=entry.portMember ; v6mcastp->extPortMember=entry.extPortMember ; v6mcastp->v6rdEngress=entry.v6rdEngress ; v6mcastp->v6rdTbIdx=entry.v6rdTbIdx ; v6mcastp->valid=1; v6mcastp->toCPU=entry.toCPU ; v6mcastp->ageTime=entry.ageTime ; if(IS_AFTER_RL6405) { v6mcastp->difidx = entry.difidx; } return SUCCESS; } int32 rtl8198C_delAsicIpv6MulticastTable(uint32 index) { rtl8198C_tblAsic_IPv6ipMulticastTable_t entry; memset(&entry,0,sizeof(entry)); return _rtl8651_forceAddAsicEntry(TYPE_IPv6_MULTICAST_TABLE, index, &entry); } int32 rtl8198C_delAsicIpMulticastTable(uint32 index) { rtl8198C_tblAsic_IPv6ipMulticastTable_t entry; if((index >= RTL8198C_IPv6MCASTTBL_SIZE)) return FAILED; memset(&entry,0,sizeof(entry)); return _rtl8651_forceAddAsicEntry(TYPE_IPv6_MULTICAST_TABLE, index, &entry); } /*========================================= * ASIC DRIVER API: IPv6 ARP Table *=========================================*/ int32 rtl8198C_Arp6HashFunction(rtl8198C_tblAsicDrv_v6NeighParam_t *arpp) { uint32 idx; uint8 hID[64]; uint8 subIdx[3]; uint8 hash[8]; uint32 i; for(i=0; i<8; i++) { hash[i]=0; } for(i=0; i<64; i++) { if(((arpp->hostID)>>i)&1) { hID[i]=1; } else { hID[i]=0; } } for(i=0; i<3; i++) { if(((arpp->subnetIdx) & (1<<i))!=0) { subIdx[i]=1; } else { subIdx[i]=0; } } /* ARPV6 4-way hash algorithm: ID[66:0]={SUBNET_IDX, HOSTID} ID[66]=subIdx[2] ID[65]=subIdx[1] ID[64]=subIdx[0] ARPV6_IDX[0] = ID[0] ID[6] ID[12] ID[18] D[24] D[30] ?n D[36] ID[42] ID[48] ID[54] ID[60] D[66] ARPV6_IDX[1] = ID[1] ID[7] ID[13] ID[19] D[25] D[31] ?n D[37] ID[43] ID[49] ID[55] ID[61] ARPV6_IDX[2] = ID[2] ID[8] ID[14] ID[20] D[26] D[32] ?n D[38] ID[44] ID[50] ID[56] ID[62] ARPV6_IDX[3] = ID[3] ID[9] ID[15] ID[21] D[27] D[33] ?n D[39] ID[45] ID[51] ID[57] ID[63] ARPV6_IDX[4] = ID[4] ID[10] ID[16] ID[22] D[28] D[34] ?n D[40] ID[46] ID[52] ID[58] ID[64] ARPV6_IDX[5] = ID[5] ID[11] ID[17] ID[23] D[29] D[35] ?n D[41] ID[47] ID[53] ID[59] ID[65] */ hash[0] = hID[0] ^ hID[6] ^ hID[12] ^ hID[18] ^ hID[24] ^ hID[30] ^ \ hID[36] ^ hID[42] ^hID[48] ^ hID[54] ^ hID[60] ^ subIdx[2]; hash[1] = hID[1] ^ hID[7] ^ hID[13] ^ hID[19] ^ hID[25] ^ hID[31] ^ \ hID[37] ^ hID[43] ^hID[49] ^ hID[55] ^ hID[61]; hash[2] = hID[2] ^ hID[8] ^ hID[14] ^ hID[20] ^ hID[26] ^ hID[32] ^ \ hID[38] ^ hID[44] ^hID[50] ^ hID[56] ^ hID[62]; hash[3] = hID[3] ^ hID[9] ^ hID[15] ^ hID[21] ^ hID[27] ^ hID[33] ^ \ hID[39] ^ hID[45] ^hID[51] ^ hID[57] ^ hID[63]; hash[4] = hID[4] ^ hID[10] ^ hID[16] ^ hID[22] ^ hID[28] ^ hID[34] ^ \ hID[40] ^ hID[46] ^hID[52] ^ hID[58] ^ subIdx[0]; hash[5] = hID[5] ^ hID[11] ^ hID[17] ^ hID[23] ^ hID[29] ^ hID[35] ^ \ hID[41] ^ hID[47] ^hID[53] ^ hID[59] ^ subIdx[1]; for(i=0; i<8; i++) { hash[i]=hash[i] & (0x01); } idx=0; for(i=0; i<8; i++) { idx=idx+(hash[i]<<i); } return idx; } int32 rtl8198C_setAsicV6MulticastEnable(uint32 enable) { if (enable == TRUE) { //0xBB804428, Frame Forwarding Configuration Register WRITE_MEM32(V6CTR0, READ_MEM32(V6CTR0)|CF_IPMSTCTL_V6_EN); } else { WRITE_MEM32(V6CTR0, READ_MEM32(V6CTR0) & ~CF_IPMSTCTL_V6_EN); } return SUCCESS; } int rtl8198C_getAsicV6MulticastAge(struct in6_addr *sip,struct in6_addr *gip) { rtl8198C_tblAsicDrv_IPv6multiCastParam_t v6mCastEntry; uint32 i; int age=0; for(i=0; i<RTL8198C_v6MULTICASTTBL_SIZE; i++) { rtl8198C_getAsicIpv6MulticastTable(i,&v6mCastEntry); if ( v6mCastEntry.valid && ipv6_addr_equal(&v6mCastEntry.destIPAddr,gip) && ipv6_addr_equal(&v6mCastEntry.srcIPAddr,sip)) { age = v6mCastEntry.ageTime; break; } } return age; } int32 rtl8198C_getAsicV6MulticastEnable(uint32 *enable) { if (enable == NULL) { return FAILED; } *enable = (READ_MEM32(V6CTR0) & CF_IPMSTCTL_V6_EN) ? TRUE : FALSE; return SUCCESS; } #endif //END defined(CONFIG_RTL_8685S_HWNAT) int32 rtl8651_setAsicRouting(uint32 index, rtl865x_tblAsicDrv_routingParam_t *routingp) { uint32 i, asicMask; rtl865xc_tblAsic_l3RouteTable_t entry; #ifdef FPGA if (index==2) index=6; if (index==3) index=7; if (index>=4 && index <=5) rtlglue_printf("Out of range\n"); #endif if((index >= RTL8651_ROUTINGTBL_SIZE) || (routingp == NULL)) return FAILED; if (routingp->ipMask) { for(i=0; i<32; i++) if(routingp->ipMask & (1<<i)) break; asicMask = 31 - i; } else asicMask = 0; memset(&entry,0,sizeof(entry)); entry.IPAddr = routingp->ipAddr; #if defined(CONFIG_RTL_8685S_HWNAT) entry.linkTo.ARPEntry.DSLiteEgress = routingp->DSLiteEgress; entry.linkTo.ARPEntry.DSLiteIdx1_0 = routingp->DSLiteIdx; entry.DSLiteIdx2_2 = (routingp->DSLiteIdx) >>2; #endif switch(routingp->process) { case 0://PPPoE entry.linkTo.PPPoEEntry.PPPoEIndex = routingp->pppoeIdx; #if defined(CONFIG_RTL_8685S_HWNAT) if(IS_AFTER_RL6405) { entry.linkTo.PPPoEEntry.nextHop = ((routingp->nextHopRow <<2) | routingp->nextHopColumn)&0x3ff; entry.linkTo.PPPoEEntry.nextHop10_10= ((routingp->nextHopRow) >>8 )&0x1; } else #endif { entry.linkTo.PPPoEEntry.nextHop = (routingp->nextHopRow <<2) | routingp->nextHopColumn; } entry.linkTo.PPPoEEntry.IPMask = asicMask; entry.linkTo.PPPoEEntry.netif = routingp->vidx; entry.linkTo.PPPoEEntry.internal=routingp->internal; entry.linkTo.PPPoEEntry.isDMZ=routingp->DMZFlag; entry.linkTo.PPPoEEntry.process = routingp->process; entry.linkTo.PPPoEEntry.valid = 1; break; case 1://Direct #if defined(CONFIG_RTL_8685S_HWNAT) if(IS_AFTER_RL6405) { entry.linkTo.L2Entry.nextHop = ((routingp->nextHopRow <<2) | routingp->nextHopColumn)&0x3ff; entry.linkTo.L2Entry.nextHop10_10= ((routingp->nextHopRow) >>8 )&0x1; } else #endif { entry.linkTo.L2Entry.nextHop = (routingp->nextHopRow <<2) | routingp->nextHopColumn; } entry.linkTo.L2Entry.IPMask = asicMask; entry.linkTo.L2Entry.netif = routingp->vidx; entry.linkTo.L2Entry.internal=routingp->internal; entry.linkTo.L2Entry.isDMZ=routingp->DMZFlag; entry.linkTo.L2Entry.process = routingp->process; entry.linkTo.L2Entry.valid = 1; break; case 2://arp entry.linkTo.ARPEntry.ARPEnd = routingp->arpEnd >> 3; entry.linkTo.ARPEntry.ARPStart = routingp->arpStart >> 3; entry.linkTo.ARPEntry.IPMask = asicMask; entry.linkTo.ARPEntry.netif = routingp->vidx; entry.linkTo.ARPEntry.internal=routingp->internal; entry.linkTo.ARPEntry.isDMZ = routingp->DMZFlag; entry.linkTo.ARPEntry.process = routingp->process; entry.linkTo.ARPEntry.valid = 1; entry.linkTo.ARPEntry.ARPIpIdx = routingp->arpIpIdx; /* for RTL8650B C Version Only */ break; case 4://CPU case 6://DROP /* * Note: although the process of this routing entry is CPU/DROP, * we still have to assign "vid" field for packet decision process use. * - 2005.3.23 - */ entry.linkTo.ARPEntry.netif = routingp->vidx; entry.linkTo.ARPEntry.IPMask = asicMask; entry.linkTo.ARPEntry.process = routingp->process; entry.linkTo.ARPEntry.valid = 1; entry.linkTo.ARPEntry.internal=routingp->internal; break; case 5://NAPT NextHop entry.linkTo.NxtHopEntry.nhStart = routingp->nhStart >> 1; switch (routingp->nhNum) { case 2: entry.linkTo.NxtHopEntry.nhNum = 0; break; case 4: entry.linkTo.NxtHopEntry.nhNum = 1; break; case 8: entry.linkTo.NxtHopEntry.nhNum = 2; break; case 16: entry.linkTo.NxtHopEntry.nhNum = 3; break; case 32: entry.linkTo.NxtHopEntry.nhNum = 4; break; default: return FAILED; } entry.linkTo.NxtHopEntry.nhNxt = routingp->nhNxt; entry.linkTo.NxtHopEntry.nhAlgo = routingp->nhAlgo; entry.linkTo.NxtHopEntry.IPMask = asicMask; entry.linkTo.NxtHopEntry.process = routingp->process; entry.linkTo.NxtHopEntry.valid = 1; entry.linkTo.NxtHopEntry.IPDomain = routingp->ipDomain; entry.linkTo.NxtHopEntry.internal = routingp->internal; entry.linkTo.NxtHopEntry.isDMZ = routingp->DMZFlag; break; default: return FAILED; } return _rtl8651_forceAddAsicEntry(TYPE_L3_ROUTING_TABLE, index, &entry); } int32 rtl8651_delAsicRouting(uint32 index) { rtl865xc_tblAsic_l3RouteTable_t entry; if(index >= RTL8651_ROUTINGTBL_SIZE) return FAILED; memset(&entry,0,sizeof(entry)); entry.linkTo.ARPEntry.valid = 0; return _rtl8651_forceAddAsicEntry(TYPE_L3_ROUTING_TABLE, index, &entry); } int32 rtl8651_getAsicRouting(uint32 index, rtl865x_tblAsicDrv_routingParam_t *routingp) { uint32 i; rtl865xc_tblAsic_l3RouteTable_t entry; if((index >= RTL8651_ROUTINGTBL_SIZE) || (routingp == NULL)) return FAILED; _rtl8651_readAsicEntry(TYPE_L3_ROUTING_TABLE, index, &entry); if(entry.linkTo.ARPEntry.valid == 0) return FAILED; routingp->ipAddr = entry.IPAddr; routingp->process = entry.linkTo.ARPEntry.process; #if defined(CONFIG_RTL_8685S_HWNAT) routingp->DSLiteEgress=entry.linkTo.ARPEntry.DSLiteEgress; routingp->DSLiteIdx = entry.linkTo.ARPEntry.DSLiteIdx1_0 | ((entry.DSLiteIdx2_2)<<2) ; #endif for(i=0, routingp->ipMask = 0; i<=entry.linkTo.ARPEntry.IPMask; i++) routingp->ipMask |= 1<<(31-i); routingp->vidx = entry.linkTo.ARPEntry.netif; routingp->internal= entry.linkTo.PPPoEEntry.internal; switch(routingp->process) { case 0://PPPoE routingp->arpStart = 0; routingp->arpEnd = 0; routingp->pppoeIdx = entry.linkTo.PPPoEEntry.PPPoEIndex; routingp->nextHopRow = entry.linkTo.PPPoEEntry.nextHop>>2; #if defined(CONFIG_RTL_8685S_HWNAT) if(IS_AFTER_RL6405) { routingp->nextHopRow |= ((entry.linkTo.PPPoEEntry.nextHop10_10&0x1)<<8); } #endif routingp->nextHopColumn = entry.linkTo.PPPoEEntry.nextHop & 0x3; routingp->DMZFlag= entry.linkTo.NxtHopEntry.isDMZ; break; case 1://Direct routingp->arpStart = 0; routingp->arpEnd = 0; routingp->pppoeIdx = 0; routingp->nextHopRow = entry.linkTo.L2Entry.nextHop>>2; routingp->nextHopColumn = entry.linkTo.L2Entry.nextHop&0x3; routingp->DMZFlag= entry.linkTo.NxtHopEntry.isDMZ; break; case 2://Indirect routingp->arpEnd = entry.linkTo.ARPEntry.ARPEnd; routingp->arpStart = entry.linkTo.ARPEntry.ARPStart; routingp->pppoeIdx = 0; routingp->nextHopRow = 0; routingp->nextHopColumn = 0; routingp->arpIpIdx = entry.linkTo.ARPEntry.ARPIpIdx; routingp->DMZFlag= entry.linkTo.NxtHopEntry.isDMZ; break; case 4: /* CPU */ case 6: /* Drop */ routingp->arpStart = 0; routingp->arpEnd = 0; routingp->pppoeIdx = 0; routingp->nextHopRow = 0; routingp->nextHopColumn = 0; routingp->DMZFlag= entry.linkTo.NxtHopEntry.isDMZ; break; #if 1 //chhuang: #ifdef CONFIG_RTL865XB case 5: routingp->nhStart = (entry.linkTo.NxtHopEntry.nhStart) << 1; switch (entry.linkTo.NxtHopEntry.nhNum) { case 0: routingp->nhNum = 2; break; case 1: routingp->nhNum = 4; break; case 2: routingp->nhNum = 8; break; case 3: routingp->nhNum = 16; break; case 4: routingp->nhNum = 32; break; default: return FAILED; } routingp->nhNxt = entry.linkTo.NxtHopEntry.nhNxt; routingp->nhAlgo = entry.linkTo.NxtHopEntry.nhAlgo; routingp->ipDomain = entry.linkTo.NxtHopEntry.IPDomain; routingp->internal= entry.linkTo.NxtHopEntry.internal; routingp->DMZFlag= entry.linkTo.NxtHopEntry.isDMZ; break; #endif default: return FAILED; } return SUCCESS; } int32 rtl8651_setAsicArp(uint32 index, rtl865x_tblAsicDrv_arpParam_t *arpp) { rtl865xc_tblAsic_arpTable_t entry; if((index >= RTL8651_ARPTBL_SIZE) || (arpp == NULL)) return FAILED; memset(&entry,0,sizeof(entry)); #if defined(CONFIG_RTL_8685S_HWNAT) if(IS_AFTER_RL6405) { entry.nextHop = (arpp->nextHopRow<<2) | (arpp->nextHopColumn&0x3); entry.nextHop10_10 = (arpp->nextHopRow >>8); } else #endif { entry.nextHop = (arpp->nextHopRow<<2) | (arpp->nextHopColumn&0x3); } entry.valid = 1; entry.aging=arpp->aging; return _rtl8651_forceAddAsicEntry(TYPE_ARP_TABLE, index, &entry); } int32 rtl8651_delAsicArp(uint32 index) { rtl865xc_tblAsic_arpTable_t entry; if(index >= RTL8651_ARPTBL_SIZE) return FAILED; memset(&entry,0,sizeof(entry)); entry.valid = 0; return _rtl8651_forceAddAsicEntry(TYPE_ARP_TABLE, index, &entry); } int32 rtl8651_getAsicArp(uint32 index, rtl865x_tblAsicDrv_arpParam_t *arpp) { rtl865xc_tblAsic_arpTable_t entry; if((index >= RTL8651_ARPTBL_SIZE) || (arpp == NULL)) return FAILED; _rtl8651_readAsicEntry(TYPE_ARP_TABLE, index, &entry); /*for 8196B patch,read arp table and ip multicast table should stop TLU*/ //_rtl8651_readAsicEntryStopTLU(TYPE_ARP_TABLE, index, &entry); //No need to Stop_Table_Lookup process if(entry.valid == 0) return FAILED; #if defined(CONFIG_RTL_8685S_HWNAT) if(IS_AFTER_RL6405) { arpp->nextHopRow = (entry.nextHop>>2) | (entry.nextHop10_10 <<8); } else #endif { arpp->nextHopRow = entry.nextHop>>2; } arpp->nextHopColumn = entry.nextHop&0x3; arpp->aging=entry.aging&0x1f; return SUCCESS; } /*========================================= * ASIC DRIVER API: Multicast Table *=========================================*/ uint32 rtl8651_ipMulticastTableIndex(ipaddr_t srcAddr, ipaddr_t dstAddr) { uint32 idx; #if defined(CONFIG_RTL_819X) || defined(CONFIG_RTL_8676HWNAT) #if defined (CONFIG_RTL8196C_REVISION_B) || defined (CONFIG_RTL8198_REVISION_B) uint32 sip[32],dip[32]; uint32 hash[8]; uint32 i; for(i=0; i<8; i++) { hash[i]=0; } for(i=0; i<32; i++) { if((srcAddr & (1<<i))!=0) { sip[i]=1; } else { sip[i]=0; } if((dstAddr & (1<<i))!=0) { dip[i]=1; } else { dip[i]=0; } } hash[7] = sip[0] ^ sip[8] ^ sip[16] ^ sip[24] ^ dip[7] ^ dip[15] ^ dip[23] ^ dip[31]; hash[6] = sip[1] ^ sip[9] ^ sip[17] ^ sip[25] ^ dip[6] ^ dip[14] ^ dip[22] ^ dip[30]; hash[5] = sip[2] ^ sip[10] ^ sip[18] ^ sip[26] ^ dip[5] ^ dip[13] ^ dip[21] ^ dip[29]; hash[4] = sip[3] ^ sip[11] ^ sip[19] ^ sip[27] ^ dip[4] ^ dip[12] ^ dip[20] ^ dip[28]; hash[3] = sip[4] ^ sip[12] ^ sip[20] ^ sip[28] ^ dip[3] ^ dip[11] ^ dip[19] ^ dip[27]; hash[2] = sip[5] ^ sip[13] ^ sip[21] ^ sip[29] ^ dip[2] ^ dip[10] ^ dip[18] ^ dip[26]; hash[1] = sip[6] ^ sip[14] ^ sip[22] ^ sip[30] ^ dip[1] ^ dip[9] ^ dip[17] ^ dip[25]; hash[0] = sip[7] ^ sip[15] ^ sip[23] ^ sip[31] ^ dip[0] ^ dip[8] ^ dip[16] ^ dip[24]; for(i=0; i<8; i++) { hash[i]=hash[i] & (0x01); } idx=0; for(i=0; i<8; i++) { idx=idx+(hash[i]<<i); } return idx; #else { #if 0 uint32 sip[32],dip[32]; uint32 hash[6]; uint32 i; uint32 bitmask; for(i=0; i<32; i++) { bitmask=1<<i; if((srcAddr & bitmask)!=0) { sip[i]=1; } else { sip[i]=0; } if((dstAddr & bitmask)!=0) { dip[i]=1; } else { dip[i]=0; } } hash[0] = dip[0]^dip[6]^dip[12]^dip[18]^dip[24]^dip[26]^dip[28]^dip[30]^ sip[23]^sip[5]^sip[11]^sip[17]^sip[31]^sip[25]^sip[27]^sip[29]; hash[1] = dip[1]^dip[7]^dip[13]^dip[19]^dip[25]^dip[27]^dip[29]^dip[31]^ sip[0]^sip[6]^sip[12]^sip[18]^sip[24]^sip[26]^sip[28]^sip[30]; hash[2] = dip[2]^dip[8]^dip[14]^dip[20]^sip[1]^sip[7]^sip[13]^sip[19]; hash[3] = dip[3]^dip[9]^dip[15]^dip[21]^sip[2]^sip[8]^sip[14]^sip[20]; hash[4] = dip[4]^dip[10]^dip[16]^dip[22]^sip[3]^sip[9]^sip[15]^sip[21]; hash[5] = dip[5]^dip[11]^dip[17]^dip[23]^sip[4]^sip[10]^sip[16]^sip[22]; idx=0; for(i=0; i<6; i++) { hash[i]=hash[i] & (0x01); idx=idx+(hash[i]<<i); } #else uint32 hashSrcAddr; uint32 hashDstAddr; hashDstAddr=((dstAddr ^ (dstAddr>>6) ^ (dstAddr>>12) ^ (dstAddr>>18)) ) ^ (((dstAddr>>24) ^ (dstAddr>>26) ^ (dstAddr>>28) ^ (dstAddr>>30) ) & 0x03); hashSrcAddr=( ( (((srcAddr>>23) ^(srcAddr>>31)) & 0x01) ^ ((srcAddr ^ (srcAddr >>24))<<1) ^ (srcAddr>>5) ^ (srcAddr>>11) ^ (srcAddr>>17) ^ (srcAddr>>25) ^ (srcAddr>>27) ^ (srcAddr>>29) ) & 0x03 ) | ( ( (srcAddr>>1) ^ (srcAddr>>7) ^ (srcAddr>>13) ^ (srcAddr>>19) ) <<2 ); idx= (hashDstAddr ^ hashSrcAddr) & 0x3F; #endif } #endif #else #error "wrong compile flag, not supported IC reversion" { idx = srcAddr ^ (srcAddr>>8) ^ (srcAddr>>16) ^ (srcAddr>>24) ^ dstAddr ^ (dstAddr>>8) ^ (dstAddr>>16) ^ (dstAddr>>24); idx = ((idx >> 2) ^ (idx & 0x3)) & (RTL8651_IPMULTICASTTBL_SIZE-1); } #endif return idx; } int32 rtl8651_setAsicIpMulticastTable(rtl865x_tblAsicDrv_multiCastParam_t *mCast_t) { uint32 idx; rtl865xc_tblAsic_ipMulticastTable_t entry; int16 age; if(mCast_t->dip >>28 != 0xe || mCast_t->port >= RTL8651_PORT_NUMBER+rtl8651_totalExtPortNum) return FAILED;//Non-IP multicast destination address memset(&entry,0,sizeof(entry)); entry.srcIPAddr = mCast_t->sip; entry.destIPAddrLsbs = mCast_t->dip & 0xfffffff; idx = rtl8651_ipMulticastTableIndex(mCast_t->sip, mCast_t->dip); #if (defined (CONFIG_RTL8196C_REVISION_B) || defined (CONFIG_RTL8198_REVISION_B)) && !defined(CONFIG_RTL_8685S_HWNAT) entry.srcPort = mCast_t->port; entry.portList = mCast_t->mbr; #elif defined(CONFIG_RTL_8685S_HWNAT) entry.srcPort = mCast_t->port; entry.portList = mCast_t->mbr&0x3f; entry.extPortList = (mCast_t->mbr>>6)&0x7; if(IS_AFTER_RL6405) { entry.difidx = mCast_t->difidx &0x7; } #else if (mCast_t->port >= RTL8651_PORT_NUMBER) { /* extension port */ entry.srcPortExt = 1; entry.srcPort = (mCast_t->port-RTL8651_PORT_NUMBER); } else { entry.srcPortExt = 0; entry.srcPort = mCast_t->port; } entry.extPortList = mCast_t->mbr >> RTL8651_PORT_NUMBER; entry.srcVidH = ((mCast_t->svid)>>4) &0xff; entry.srcVidL = (mCast_t->svid)&0xf; entry.portList = mCast_t->mbr & (RTL8651_PHYSICALPORTMASK); #endif entry.toCPU = 0; entry.valid = 1; entry.extIPIndex = mCast_t->extIdx; entry.ageTime = 0; age = (int16)mCast_t->age; while ( age > 0 ) { if ( (++entry.ageTime) == 7) break; age -= 5; } #ifdef CONFIG_RTL_HARDWARE_MULTICAST entry.ageTime = 7; #endif return _rtl8651_forceAddAsicEntry(TYPE_MULTICAST_TABLE, idx, &entry); } int32 rtl8651_delAsicIpMulticastTable(uint32 index) { rtl865xc_tblAsic_ipMulticastTable_t entry; memset(&entry,0,sizeof(entry)); return _rtl8651_forceAddAsicEntry(TYPE_MULTICAST_TABLE, index, &entry); } int32 rtl8651_getAsicIpMulticastTable(uint32 index, rtl865x_tblAsicDrv_multiCastParam_t *mCast_t) { rtl865xc_tblAsic_ipMulticastTable_t entry; if (mCast_t == NULL) return FAILED; _rtl8651_readAsicEntry(TYPE_MULTICAST_TABLE, index, &entry); //_rtl8651_readAsicEntryStopTLU(TYPE_MULTICAST_TABLE, index, &entry); //No need to Stop_Table_Lookup process mCast_t->sip = entry.srcIPAddr; if(entry.valid) { mCast_t->dip = entry.destIPAddrLsbs | 0xe0000000; } else { if(entry.destIPAddrLsbs==0) { mCast_t->dip = entry.destIPAddrLsbs; } else { mCast_t->dip = entry.destIPAddrLsbs | 0xe0000000; } } #if (defined (CONFIG_RTL8196C_REVISION_B) || defined (CONFIG_RTL8198_REVISION_B)) && !defined(CONFIG_RTL_8685S_HWNAT) mCast_t->svid = 0; mCast_t->port = entry.srcPort; mCast_t->mbr = entry.portList; #elif defined(CONFIG_RTL_8685S_HWNAT) mCast_t->svid = 0; mCast_t->port = entry.srcPort; mCast_t->mbr = entry.portList | (entry.extPortList<<6); if(IS_AFTER_RL6405) { mCast_t->difidx = entry.difidx ; } #else mCast_t->svid = (entry.srcVidH<<4) | entry.srcVidL; #if 1 //#ifdef CONFIG_RTL8650BBASIC #if 1 if (entry.srcPortExt) { mCast_t->port = entry.srcPort + RTL8651_PORT_NUMBER; } else { mCast_t->port = entry.srcPort; } #else mCast_t->port = entry.srcPortExt<<3 | entry.srcPortH<<1 | entry.srcPortL; #endif mCast_t->mbr = entry.extPortList<<RTL8651_PORT_NUMBER | entry.portList; #else mCast_t->port = entry.srcPortH<<1 | entry.srcPortL; mCast_t->mbr = entry.portList; #endif #endif mCast_t->extIdx = entry.extIPIndex ; mCast_t->age = entry.ageTime * 5; mCast_t->cpu = entry.toCPU; if(entry.valid == 0) { return FAILED; } return SUCCESS; } /* @func int32 | rtl8651_setAsicMulticastEnable | Enable / disable ASIC IP multicast support. @parm uint32 | enable | TRUE to indicate ASIC IP multicast process is enabled; FALSE to indicate ASIC IP multicast process is disabled. @rvalue FAILED | Failed @rvalue SUCCESS | Success @comm We would use this API to enable/disable ASIC IP multicast process. If it's disabled here, Hardware IP multicast table would be ignored. If it's enabled here, IP multicast table is used to forwarding IP multicast packets. */ int32 rtl8651_setAsicMulticastEnable(uint32 enable) { if (enable == TRUE) { //0xBB804428, Frame Forwarding Configuration Register WRITE_MEM32(FFCR, READ_MEM32(FFCR)|EN_MCAST); } else { WRITE_MEM32(FFCR, READ_MEM32(FFCR) & ~EN_MCAST); WRITE_MEM32(FFCR, READ_MEM32(FFCR) |= IPMltCstCtrl_TrapToCpu); } return SUCCESS; } /* @func int32 | rtl8651_getAsicMulticastEnable | Get the state about ASIC IP multicast support. @parm uint32* | enable | Pointer to store the state about ASIC IP multicast support. @rvalue FAILED | Failed @rvalue SUCCESS | Success @comm We would use this API to get the status of ASIC IP multicast process. TRUE to indicate ASIC IP multicast process is enabled; FALSE to indicate ASIC IP multicast process is disabled. */ int32 rtl8651_getAsicMulticastEnable(uint32 *enable) { if (enable == NULL) { return FAILED; } *enable = (READ_MEM32(FFCR) & EN_MCAST) ? TRUE : FALSE; return SUCCESS; } /* @func int32 | rtl8651_setAsicMulticastPortInternal | Configure internal/external state for each port @parm uint32 | port | Port to set its state. @parm int8 | isInternal | set TRUE to indicate <p port> is internal port; set FALSE to indicate <p port> is external port @rvalue FAILED | Failed @rvalue SUCCESS | Success @comm In RTL865x platform, user would need to config the Internal/External state for each port to support HW multicast NAPT. If packet is sent from internal port to external port, and source VLAN member port checking indicates that L34 is needed. Source IP modification would be applied. */ int32 rtl8651_setAsicMulticastPortInternal(uint32 port, int8 isInternal) { if (port >= RTL8651_PORT_NUMBER + rtl8651_totalExtPortNum) { /* Invalid port */ return FAILED; } /* RTL865XC : All multicast mode are stored in [SWTCR0 / Switch Table Control Register 0] */ if (isInternal == FALSE) {//external //0xBB804418, Switch Table Control Register 0 WRITE_MEM32(SWTCR0, READ_MEM32(SWTCR0) | (((1 << port) & MCAST_PORT_EXT_MODE_MASK) << MCAST_PORT_EXT_MODE_OFFSET)); } else {//internal WRITE_MEM32(SWTCR0, READ_MEM32(SWTCR0) & ~(((1 << port) & MCAST_PORT_EXT_MODE_MASK) << MCAST_PORT_EXT_MODE_OFFSET)); } return SUCCESS; } /* @func int32 | rtl8651_getAsicMulticastPortInternal | Get internal/external state for each port @parm uint32 | port | Port to set its state. @parm int8* | isInternal | Pointer to get port state of <p port>. @rvalue FAILED | Failed @rvalue SUCCESS | Success @comm To get the port internal / external state for <p port>: TRUE to indicate <p port> is internal port; FALSE to indicate <p port> is external port */ int32 rtl8651_getAsicMulticastPortInternal(uint32 port, int8 *isInternal) { if (isInternal == NULL) { return FAILED; } if (port >= RTL8651_PORT_NUMBER + rtl8651_totalExtPortNum) { /* Invalid port */ return FAILED; } if (READ_MEM32(SWTCR0) & (((1 << port) & MCAST_PORT_EXT_MODE_MASK) << MCAST_PORT_EXT_MODE_OFFSET)) { *isInternal = TRUE; } else { *isInternal = FALSE; } return SUCCESS; } /* @func int32 | rtl8651_setAsicMulticastMTU | Set MTU for ASIC IP multicast forwarding @parm uint32 | mcastMTU | MTU used by HW IP multicast forwarding. @rvalue FAILED | Failed @rvalue SUCCESS | Success @comm To set the MTU for ASIC IP multicast forwarding. Its independent from other packet forwarding because IP multicast would include L2/L3/L4 at one time. */ int32 rtl8651_setAsicMulticastMTU(uint32 mcastMTU) { if (mcastMTU & ~(MultiCastMTU_MASK) ) { /* multicast MTU overflow */ return FAILED; } //0xBB80440C, ALE Control Register UPDATE_MEM32(ALECR, mcastMTU, MultiCastMTU_MASK, MultiCastMTU_OFFSET); return SUCCESS; } /* @func int32 | rtl8651_setAsicMulticastMTU | Get MTU for ASIC IP multicast forwarding @parm uint32* | mcastMTU | Pointer to get MTU used by HW IP multicast forwarding. @rvalue FAILED | Failed @rvalue SUCCESS | Success @comm To get the MTU value for ASIC IP multicast forwarding. Its independent from other packet forwarding because IP multicast would include L2/L3/L4 at one time. */ int32 rtl8651_getAsicMulticastMTU(uint32 *mcastMTU) { if (mcastMTU == NULL) { return FAILED; } *mcastMTU = GET_MEM32_VAL(ALECR, MultiCastMTU_MASK, MultiCastMTU_OFFSET); return SUCCESS; } int32 rtl865x_setAsicMulticastAging(uint32 enable) { if (enable == TRUE) { //0xBB804400, multicast entry aging. WRITE_MEM32(TEACR, READ_MEM32(TEACR) & ~IPMcastAgingDisable); } else { WRITE_MEM32(TEACR, READ_MEM32(TEACR)|IPMcastAgingDisable); } return SUCCESS; } int32 rtl865x_initAsicL3(void) { int32 index; rtl865x_tblAsicDrv_routingParam_t rth; /*clear asic table*/ rtl8651_clearSpecifiedAsicTable(TYPE_EXT_INT_IP_TABLE, RTL8651_IPTABLE_SIZE); rtl8651_clearSpecifiedAsicTable(TYPE_ARP_TABLE, RTL8651_ARPTBL_SIZE); rtl8651_clearSpecifiedAsicTable(TYPE_PPPOE_TABLE, RTL8651_PPPOETBL_SIZE); rtl8651_clearSpecifiedAsicTable(TYPE_NEXT_HOP_TABLE, RTL8651_NEXTHOPTBL_SIZE); rtl8651_clearSpecifiedAsicTable(TYPE_L3_ROUTING_TABLE, RTL8651_ROUTINGTBL_SIZE); rtl8651_clearSpecifiedAsicTable(TYPE_MULTICAST_TABLE, RTL8651_IPMULTICASTTBL_SIZE); rtl8651_setAsicMulticastEnable(TRUE); /* Enable multicast table */ //0xBB80440C, Enable PPPoE auto encap. WRITE_MEM32(ALECR, READ_MEM32(ALECR)|(uint32)EN_PPPOE);//enable PPPoE auto encapsulation rtl8651_setAsicMulticastMTU(1522); //0xBB80440C, Enable TTL-1 WRITE_MEM32(TTLCR,READ_MEM32(TTLCR)|(uint32)EN_TTL1);//Don't hide this router. enable TTL-1 when routing on this gateway. for (index=0; index<RTL8651_PORT_NUMBER+rtl8651_totalExtPortNum; index++) { if( rtl8651_setAsicMulticastPortInternal(index, TRUE) ) return FAILED; } if(0) { memset(&rth, 0, sizeof(rtl865x_tblAsicDrv_routingParam_t)); rth.process = 0x4; /* CPU */ rth.ipAddr = 0; rth.ipMask = 0; rth.vidx = 0; rth.internal = 0; rtl8651_setAsicRouting(7, &rth); } #if defined(CONFIG_RTL_HWNAT_IPv6_SUPPORT) //Enable IPv6 multicasting rtl8198C_setAsicV6MulticastEnable(TRUE); // Configure IPv6 default routing { rtl8198C_tblAsicDrv_ipv6routingParam_t asic_t; memset(&asic_t, 0, sizeof(rtl8198C_tblAsicDrv_ipv6routingParam_t)); asic_t.process = RT_CPU; rtl8198C_setAsicIpv6Routing(V6RT_ASIC_ENTRY_NUM-1, &asic_t); } //Disable Neigh & MC table aging WRITE_MEM32(TEACR, READ_MEM32(TEACR) | EnIPv6ARPAgingDisable); WRITE_MEM32(TEACR, READ_MEM32(TEACR) | EnIPv6MulticastAgingDisable); #endif #if defined(CONFIG_RTL_HWNAT_DUAL_STACK_LITE) WRITE_MEM32(DSLITECTR0,CF_UNK_DSLDIP_CPU | CF_DSLITE_EN); #endif return SUCCESS; }