/* *************************************************************************** * Ralink Tech Inc. * 4F, No. 2 Technology 5th Rd. * Science-based Industrial Park * Hsin-chu, Taiwan, R.O.C. * * (c) Copyright 2002-2007, Ralink Technology, Inc. * * All rights reserved. Ralink's source code is an unpublished work and the * use of a copyright notice does not imply otherwise. This source code * contains confidential trade secret material of Ralink Tech. Any attemp * or participation in deciphering, decoding, reverse engineering or in any * way altering the source code is stricitly prohibited, unless the prior * written consent of Ralink Technology, Inc. is obtained. *************************************************************************** Module Name: cmm_mat.c Abstract: Support Mac Address Translation function. Note: MAC Address Translation(MAT) engine subroutines, we should just take care packet to bridge. Revision History: Who When What -------------- ---------- ---------------------------------------------- Shiang 02-26-2007 Init version */ #ifdef MAT_SUPPORT #include "rt_config.h" extern MATProtoOps MATProtoIPHandle; extern MATProtoOps MATProtoARPHandle; extern MATProtoOps MATProtoPPPoEDisHandle; extern MATProtoOps MATProtoPPPoESesHandle; extern MATProtoOps MATProtoIPv6Handle; extern UCHAR SNAP_802_1H[]; extern UCHAR SNAP_BRIDGE_TUNNEL[]; #define MAX_MAT_NODE_ENTRY_NUM 128 /* We support maximum 128 node entry for our system */ #define MAT_NODE_ENTRY_SIZE 40 /*28 // bytes //change to 40 for IPv6Mac Table */ typedef struct _MATNodeEntry { UCHAR data[MAT_NODE_ENTRY_SIZE]; struct _MATNodeEntry *next; }MATNodeEntry, *PMATNodeEntry; #ifdef KMALLOC_BATCH /*static MATNodeEntry *MATNodeEntryPoll = NULL; */ #endif static MATProtoTable MATProtoTb[]= { {ETH_P_IP, &MATProtoIPHandle}, /* IP handler */ {ETH_P_ARP, &MATProtoARPHandle}, /* ARP handler */ {ETH_P_PPP_DISC, &MATProtoPPPoEDisHandle}, /* PPPoE discovery stage handler */ {ETH_P_PPP_SES, &MATProtoPPPoESesHandle}, /* PPPoE session stage handler */ {ETH_P_IPV6, &MATProtoIPv6Handle}, /* IPv6 handler */ }; #define MAX_MAT_SUPPORT_PROTO_NUM (sizeof(MATProtoTb)/sizeof(MATProtoTable)) /* --------------------------------- Public Function-------------------------------- */ NDIS_STATUS MATDBEntryFree( IN MAT_STRUCT *pMatStruct, IN PUCHAR NodeEntry) { #ifdef KMALLOC_BATCH MATNodeEntry *pPtr, *pMATNodeEntryPoll; pMATNodeEntryPoll = (MATNodeEntry *)pAd->MatCfg.MATNodeEntryPoll; pPtr = (MATNodeEntry *)NodeEntry; NdisZeroMemory(pPtr, sizeof(MATNodeEntry)); if (pMATNodeEntryPoll->next) { pPtr->next = pMATNodeEntryPoll->next; pMATNodeEntryPoll->next = pPtr; } else { pMATNodeEntryPoll->next = pPtr; } #else os_free_mem(NULL, NodeEntry); #endif return TRUE; } PUCHAR MATDBEntryAlloc(IN MAT_STRUCT *pMatStruct, IN UINT32 size) { #ifdef KMALLOC_BATCH MATNodeEntry *pPtr = NULL, *pMATNodeEntryPoll; pMATNodeEntryPoll = (MATNodeEntry *)pMatStruct->pMATNodeEntryPoll; if (pMATNodeEntryPoll->next) { pPtr = pMATNodeEntryPoll->next; pMATNodeEntryPoll->next = pPtr->next; } #else UCHAR *pPtr = NULL; os_alloc_mem(NULL, (PUCHAR *)&pPtr, size); /*pPtr = kmalloc(size, MEM_ALLOC_FLAG); */ #endif return (PUCHAR)pPtr; } VOID dumpPkt(PUCHAR pHeader, int len) { int i; PSTRING tmp; tmp = (PSTRING)pHeader; DBGPRINT(RT_DEBUG_OFF, ("--StartDump\n")); for(i=0;iPointer to our adapter pPkt =>pointer to the 802.11 header of outgoing packet ifIdx =>Interface Index want to dispatch to. Return Value: Success => TRUE Mapped mac address if found, else return specific default mac address depends on the upper layer protocol type. Error => FALSE. Note: 1.the pPktHdr must be a 802.3 packet. 2.Maybe we need a TxD arguments? 3.We check every packet here including group mac address becasue we need to handle DHCP packet. ======================================================================== */ PUCHAR MATEngineTxHandle( IN PRTMP_ADAPTER pAd, IN PNDIS_PACKET pPkt, IN UINT ifIdx, IN UCHAR OpMode) { PUCHAR pLayerHdr = NULL, pPktHdr = NULL, pMacAddr = NULL; UINT16 protoType, protoType_ori; INT i; struct _MATProtoOps *pHandle = NULL; PUCHAR retSkb = NULL; BOOLEAN bVLANPkt = FALSE; if(pAd->MatCfg.status != MAT_ENGINE_STAT_INITED) return NULL; pPktHdr = GET_OS_PKT_DATAPTR(pPkt); if (!pPktHdr) return NULL; protoType_ori = get_unaligned((PUINT16)(pPktHdr + 12)); /* Get the upper layer protocol type of this 802.3 pkt. */ protoType = OS_NTOHS(protoType_ori); /* handle 802.1q enabled packet. Skip the VLAN tag field to get the protocol type. */ if (protoType == 0x8100) { protoType_ori = get_unaligned((PUINT16)(pPktHdr + 12 + 4)); protoType = OS_NTOHS(protoType_ori); bVLANPkt = TRUE; } /* For differnet protocol, dispatch to specific handler */ for (i=0; i < MAX_MAT_SUPPORT_PROTO_NUM; i++) { if (protoType == MATProtoTb[i].protocol) { pHandle = MATProtoTb[i].pHandle; /* the pHandle must not be null! */ pLayerHdr = bVLANPkt ? (pPktHdr + MAT_VLAN_ETH_HDR_LEN) : (pPktHdr + MAT_ETHER_HDR_LEN); #ifdef CONFIG_AP_SUPPORT #ifdef APCLI_SUPPORT IF_DEV_CONFIG_OPMODE_ON_AP(pAd) pMacAddr = &pAd->ApCfg.ApCliTab[ifIdx].CurrentAddress[0]; #endif /* APCLI_SUPPORT */ #endif /* CONFIG_AP_SUPPORT */ #ifdef CONFIG_STA_SUPPORT #endif /* CONFIG_STA_SUPPORT */ if (pHandle->tx!=NULL) retSkb = pHandle->tx((PVOID)&pAd->MatCfg, RTPKT_TO_OSPKT(pPkt), pLayerHdr, pMacAddr); return retSkb; } } return retSkb; } /* ======================================================================== Routine Description: Depends on the Received packet, check the upper layer protocol type and search for specific mapping table to find out the real destination MAC address. Arguments: pAd =>Pointer to our adapter pPkt =>pointer to the 802.11 header of receviced packet infIdx =>Interface Index want to dispatch to. Return Value: Success => Mapped mac address if found, else return specific default mac address depends on the upper layer protocol type. Error => NULL Note: ======================================================================== */ PUCHAR MATEngineRxHandle( IN PRTMP_ADAPTER pAd, IN PNDIS_PACKET pPkt, IN UINT infIdx) { PUCHAR pMacAddr = NULL; PUCHAR pLayerHdr = NULL, pPktHdr = NULL; UINT16 protoType; INT i =0; struct _MATProtoOps *pHandle = NULL; if(pAd->MatCfg.status != MAT_ENGINE_STAT_INITED) return NULL; pPktHdr = GET_OS_PKT_DATAPTR(pPkt); if (!pPktHdr) return NULL; /* If it's a multicast/broadcast packet, we do nothing. */ if (IS_GROUP_MAC(pPktHdr)) return NULL; /* Get the upper layer protocol type of this 802.3 pkt and dispatch to specific handler */ protoType = OS_NTOHS(get_unaligned((PUINT16)(pPktHdr + 12))); for (i=0; irx!=NULL) pMacAddr = pHandle->rx((PVOID)&pAd->MatCfg, RTPKT_TO_OSPKT(pPkt), pLayerHdr, NULL); /* RTMP_SEM_UNLOCK(&MATDBLock); */ break; } } if (pMacAddr) NdisMoveMemory(pPktHdr, pMacAddr, MAC_ADDR_LEN); return NULL; } BOOLEAN MATPktRxNeedConvert( IN PRTMP_ADAPTER pAd, IN PNET_DEV net_dev) { #ifdef CONFIG_AP_SUPPORT IF_DEV_CONFIG_OPMODE_ON_AP(pAd) { #ifdef APCLI_SUPPORT int i = 0; /* Check if the packet will be send to apcli interface. */ while(iApCfg.ApCliTab[i].Valid == TRUE) && (net_dev == pAd->ApCfg.ApCliTab[i].dev)) return TRUE; i++; } #endif /* APCLI_SUPPORT */ } #endif /* CONFIG_AP_SUPPORT */ #ifdef CONFIG_STA_SUPPORT #endif /* CONFIG_STA_SUPPORT */ return FALSE; } NDIS_STATUS MATEngineExit( IN RTMP_ADAPTER *pAd) { struct _MATProtoOps *pHandle = NULL; int i; if(pAd->MatCfg.status == MAT_ENGINE_STAT_EXITED) return TRUE; /* For each registered protocol, we call it's exit handler. */ for (i=0; iexit!=NULL) pHandle->exit(&pAd->MatCfg); } #ifdef KMALLOC_BATCH /* Free the memory used to store node entries. */ if (pAd->MatCfg.pMATNodeEntryPoll) { os_free_mem(pAd, pAd->MatCfg.pMATNodeEntryPoll); pAd->MatCfg.pMATNodeEntryPoll = NULL; } #endif pAd->MatCfg.status = MAT_ENGINE_STAT_EXITED; return TRUE; } NDIS_STATUS MATEngineInit( IN RTMP_ADAPTER *pAd) { MATProtoOps *pHandle = NULL; int i, status; if(pAd->MatCfg.status == MAT_ENGINE_STAT_INITED) return TRUE; #ifdef KMALLOC_BATCH /* Allocate memory for node entry, we totally allocate 128 entries and link them together. */ /* pAd->MatCfg.pMATNodeEntryPoll = kmalloc(sizeof(MATNodeEntry) * MAX_MAT_NODE_ENTRY_NUM, GFP_KERNEL); */ os_alloc_mem_suspend(NULL, (UCHAR **)&(pAd->MatCfg.pMATNodeEntryPoll), sizeof(MATNodeEntry) * MAX_MAT_NODE_ENTRY_NUM); if (pAd->MatCfg.pMATNodeEntryPoll != NULL) { MATNodeEntry *pPtr=NULL; NdisZeroMemory(pAd->MatCfg.pMATNodeEntryPoll, sizeof(MATNodeEntry) * MAX_MAT_NODE_ENTRY_NUM); pPtr = pAd->MatCfg.pMATNodeEntryPoll; for (i = 0; i < (MAX_MAT_NODE_ENTRY_NUM -1); i++) { pPtr->next = (MATNodeEntry *)(pPtr+1); pPtr = pPtr->next; } pPtr->next = NULL; } else { return FALSE; } #endif /* For each specific protocol, call it's init function. */ for (i = 0; i < MAX_MAT_SUPPORT_PROTO_NUM; i++) { pHandle = MATProtoTb[i].pHandle; ASSERT(pHandle); if (pHandle->init != NULL) { status = pHandle->init(&pAd->MatCfg); if (status == FALSE) { DBGPRINT(RT_DEBUG_ERROR, ("MATEngine Init Protocol (0x%x) failed, Stop the MAT Funciton initialization failed!\n", MATProtoTb[i].protocol)); goto init_failed; } DBGPRINT(RT_DEBUG_TRACE, ("MATEngine Init Protocol (0x%04x) success!\n", MATProtoTb[i].protocol)); } } NdisAllocateSpinLock(pAd, &pAd->MatCfg.MATDBLock); pAd->MatCfg.pPriv = (VOID *)pAd; pAd->MatCfg.status = MAT_ENGINE_STAT_INITED; return TRUE; init_failed: /* For each specific protocol, call it's exit function. */ for (i = 0; i < MAX_MAT_SUPPORT_PROTO_NUM; i++) { if ((pHandle = MATProtoTb[i].pHandle) != NULL) { if (pHandle->exit != NULL) { status = pHandle->exit(&pAd->MatCfg); if (status == FALSE) goto init_failed; } } } #ifdef KMALLOC_BATCH if (pAd->MatCfg.pMATNodeEntryPoll) os_free_mem(pAd, pAd->MatCfg.pMATNodeEntryPoll); pAd->MatCfg.status = MAT_ENGINE_STAT_EXITED; #endif /* KMALLOC_BATCH */ return FALSE; } #endif /* MAT_SUPPORT */