/*
 ***************************************************************************
 * Ralink Tech Inc.
 * 4F, No. 2 Technology 5th Rd.
 * Science-based Industrial Park
 * Hsin-chu, Taiwan, R.O.C.
 *
 * (c) Copyright 2002-2006, 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:
	mesh.c

	Abstract:

	Revision History:
	Who			When			What
	--------	----------		----------------------------------------------
	Fonchi		2007-06-25      For mesh (802.11s) support.
*/

#ifdef MESH_SUPPORT


#include "rt_config.h"
#include "mesh_sanity.h"

extern UCHAR OUI_WPA_NONE_AKM[4];
extern UCHAR OUI_WPA_TKIP[4];
extern UCHAR OUI_WPA_CCMP[4];
extern UCHAR OUI_WPA2_TKIP[4];
extern UCHAR OUI_WPA2_CCMP[4];
extern UCHAR OUI_MSA_8021X_AKM[4];		/* Not yet final - IEEE 802.11s-D1.06 */
extern UCHAR OUI_MSA_PSK_AKM[4];		/* Not yet final - IEEE 802.11s-D1.06 */


typedef VOID (*MESH_ACT_FRAME_HANDLER_FUNC)(IN PRTMP_ADAPTER pAd, IN RX_BLK *pRxBlk);

typedef struct _MESH_ACTION_HANDLER
{
	UINT8 Category;
	UINT8 ActionCode;
	MESH_ACT_FRAME_HANDLER_FUNC pHandle;
} MESH_ACTION_HANDLER, *PMESH_ACTION_HANDLER;

static MESH_ACTION_HANDLER MeshActHandler[] = 
{
	/* Peer Link Management. */
	{CATEGORY_MESH_PEER_LINK, ACT_CODE_PEER_LINK_OPEN, (MESH_ACT_FRAME_HANDLER_FUNC)MeshPeerLinkOpenProcess},
	{CATEGORY_MESH_PEER_LINK, ACT_CODE_PEER_LINK_CONFIRM, (MESH_ACT_FRAME_HANDLER_FUNC)MeshPeerLinkConfirmProcess},
	{CATEGORY_MESH_PEER_LINK, ACT_CODE_PEER_LINK_CLOSE, (MESH_ACT_FRAME_HANDLER_FUNC)MeshPeerLinkCloseProcess},

	/* Peer Link Metric. */
	{CATEGORY_MESH_LINK_METRIC, ACT_CODE_LINK_METRIC_REP, (MESH_ACT_FRAME_HANDLER_FUNC)MeshPeerLinkMetricReportProcess},

	/* HWMP. */
	{CATEGORY_MESH_PATH_SELECTION, ACT_CODE_PATH_REQUEST, (MESH_ACT_FRAME_HANDLER_FUNC)MeshPreqRcvProcess},
	{CATEGORY_MESH_PATH_SELECTION, ACT_CODE_PATH_REPLY, (MESH_ACT_FRAME_HANDLER_FUNC)MeshPrepRcvProcess},
	{CATEGORY_MESH_PATH_SELECTION, ACT_CODE_PATH_ERROR, (MESH_ACT_FRAME_HANDLER_FUNC)MeshPerrRcvProcess},
	{CATEGORY_MESH_PATH_SELECTION, ACT_CODE_MULTIPATH_NOTICE,
															(MESH_ACT_FRAME_HANDLER_FUNC)MeshMultipathNoticeRcvProcess},

	{CATEGORY_MESH_RES_COORDINATION, RESOURCE_CHANNEL_SWITCH_ANNOUNCEMENT,
															(MESH_ACT_FRAME_HANDLER_FUNC)MeshChSwAnnounceProcess}
};
#define MESH_ACT_HANDLER_TAB_SIZE (sizeof(MeshActHandler) / sizeof(MESH_ACTION_HANDLER))



#if 0 /* os abl move to common/mesh_inf.c */
#ifdef LINUX
#if (WIRELESS_EXT >= 12)
struct iw_statistics *Mesh_VirtualIF_get_wireless_stats(
	IN  struct net_device *net_dev);
#endif
#endif /* LINUX */
#endif /* 0 */

INT Set_MeshId_Proc(RTMP_ADAPTER *pAd, RTMP_STRING *arg)
{
	INT   success = FALSE;
	POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie;

	if(!IS_MESH_IF(pObj))
		return FALSE;

	if(strlen(arg) <= MAX_MESH_ID_LEN)
	{
		NdisZeroMemory(pAd->MeshTab.MeshId, MAX_MESH_ID_LEN);
		NdisMoveMemory(pAd->MeshTab.MeshId, arg, strlen(arg));
		pAd->MeshTab.MeshIdLen = (UCHAR)strlen(arg);
		success = TRUE;

		DBGPRINT(RT_DEBUG_TRACE, ("I/F(mesh0) Set_MeshId_Proc::(Len=%d,MeshId=%s)\n",
			pAd->MeshTab.MeshIdLen, pAd->MeshTab.MeshId));
	
		MeshDown(pAd, TRUE);
		MeshUp(pAd);		
	}
	else
		success = FALSE;

	return success;
}

INT Set_MeshHostName_Proc(RTMP_ADAPTER *pAd, RTMP_STRING *arg)
{
	INT   success = FALSE;
	POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie;

	if(!IS_MESH_IF(pObj))
		return FALSE;

	if(strlen(arg) <= MAX_HOST_NAME_LEN)
	{
		NdisZeroMemory(pAd->MeshTab.HostName, MAX_HOST_NAME_LEN);
		NdisMoveMemory(pAd->MeshTab.HostName, arg, strlen(arg));
		success = TRUE;

		DBGPRINT(RT_DEBUG_TRACE, ("I/F(mesh0) Set_MeshHostName_Proc::(HostName=%s)\n",
			pAd->MeshTab.HostName));
	}
	else
		success = FALSE;

	return success;
}

INT Set_MeshAutoLink_Proc(RTMP_ADAPTER *pAd, RTMP_STRING *arg)
{
	UINT Enable;
	POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie;

	if(!IS_MESH_IF(pObj))
		return FALSE;

	Enable = simple_strtol(arg, 0, 16);

	pAd->MeshTab.MeshAutoLink = (Enable > 0) ? TRUE : FALSE;

	DBGPRINT(RT_DEBUG_TRACE, ("%s::(enable = %d)\n", __FUNCTION__, pAd->MeshTab.MeshAutoLink));
	
	return TRUE;
}


INT Set_MeshForward_Proc(RTMP_ADAPTER *pAd, RTMP_STRING *arg)
{
	UINT Enable;
	POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie;

	if(!IS_MESH_IF(pObj))
		return FALSE;

	Enable = simple_strtol(arg, 0, 16);

	pAd->MeshTab.MeshCapability.field.Forwarding = (Enable > 0) ? (1) : (0);

	DBGPRINT(RT_DEBUG_TRACE, ("%s::(enable = %d)\n", __FUNCTION__, pAd->MeshTab.MeshCapability.field.Forwarding));
	
	return TRUE;
}


#ifdef RELEASE_EXCLUDE
/*
========================================================================
Note:
		if we r not MAP or MP with proxy , we will drop all packets SA is not us or MeshDA and DA are not us.
		if MP is bridged , it must enable proxy or layer 3 packets will not be forwarded correctly
		because bridge mac will not be the same as MP wireless card mac.
========================================================================
*/
#endif /* RELEASE_EXCLUDE */
INT Set_MeshPortal_Proc(RTMP_ADAPTER *pAd, RTMP_STRING *arg)
{
	UINT Enable;
	POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie;

	if(!IS_MESH_IF(pObj))
		return FALSE;

	Enable = simple_strtol(arg, 0, 16);

	if (Enable)
		pAd->MeshTab.OpMode |= MESH_POTAL;
	else
		pAd->MeshTab.OpMode ^= MESH_POTAL;	
	

	DBGPRINT(RT_DEBUG_TRACE, ("%s::(enable = %d)\n", __FUNCTION__, pAd->MeshTab.OpMode));
	
	return TRUE;
}

INT Set_MeshAddLink_Proc(RTMP_ADAPTER *pAd, RTMP_STRING *arg)
{
	INT i;
	RTMP_STRING *value;
	UCHAR PeerMac[MAC_ADDR_LEN];	
	ULONG LinkIdx;
	POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie;

	if(!IS_MESH_IF(pObj))
		return FALSE;

	if(strlen(arg) == 17)  /*Mac address acceptable format 01:02:03:04:05:06 length 17 */
	{
		for (i=0, value = rstrtok(arg,":"); value; value = rstrtok(NULL,":"), i++) 
		{
			if((strlen(value) != 2) || (!isxdigit(*value)) || (!isxdigit(*(value+1))) ) 
				return FALSE;  /*Invalid */

			AtoH(value, &PeerMac[i], 1);
		}

		if(i != 6)
			return FALSE;  /*Invalid */
	}

	LinkIdx = GetMeshLinkId(pAd, (PCHAR)PeerMac);
	if (LinkIdx == BSS_NOT_FOUND)
	{
		LinkIdx = MeshLinkAlloc(pAd, PeerMac, MESH_LINK_STATIC);
		if (LinkIdx == BSS_NOT_FOUND)
		{
			DBGPRINT(RT_DEBUG_TRACE, ("%s() All Mesh-Links been occupied.\n", __FUNCTION__));
			return FALSE;
		}
	}

	if (!VALID_MESH_LINK_ID(LinkIdx))
		return FALSE;

	MlmeEnqueue(pAd, MESH_LINK_MNG_STATE_MACHINE, MESH_LINK_MNG_ACTOPN, 0, NULL, LinkIdx);

	DBGPRINT(RT_DEBUG_TRACE, ("%s::(LinkIdx = %ld)\n", __FUNCTION__, LinkIdx));
	
	return TRUE;
}

INT Set_MeshDelLink_Proc(RTMP_ADAPTER *pAd, RTMP_STRING *arg)
{
	INT i;
	RTMP_STRING *value;
	UCHAR PeerMac[MAC_ADDR_LEN];	
	ULONG LinkIdx;
	POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie;

	if(!IS_MESH_IF(pObj))
		return FALSE;

	if(strlen(arg) == 17)  /*Mac address acceptable format 01:02:03:04:05:06 length 17 */
	{
		for (i=0, value = rstrtok(arg,":"); value; value = rstrtok(NULL,":"), i++) 
		{
			if((strlen(value) != 2) || (!isxdigit(*value)) || (!isxdigit(*(value+1))) ) 
				return FALSE;  /*Invalid */

			AtoH(value, &PeerMac[i], 1);
		}

		if(i != 6)
			return FALSE;  /*Invalid */
	}

	LinkIdx = GetMeshLinkId(pAd, (PCHAR)PeerMac);
	if (!VALID_MESH_LINK_ID(LinkIdx))
		return FALSE;

	pAd->MeshTab.MeshLink[LinkIdx].Entry.LinkType = MESH_LINK_DYNAMIC;
	MlmeEnqueue(pAd, MESH_LINK_MNG_STATE_MACHINE, MESH_LINK_MNG_CNCL, 0, NULL, LinkIdx);

	DBGPRINT(RT_DEBUG_TRACE, ("%s::(LinkIdx = %ld)\n", __FUNCTION__, LinkIdx));
	
	return TRUE;
}

INT Set_MeshMaxTxRate_Proc(RTMP_ADAPTER *pAd, RTMP_STRING *arg)
{
	UINT Rate;
	POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie;

	if(!IS_MESH_IF(pObj))
		return FALSE;

	Rate = simple_strtol(arg, 0, 10);

	if (Rate <= 12)
		pAd->MeshTab.MeshMaxTxRate = Rate;
	else 
		DBGPRINT(RT_DEBUG_ERROR, ("%s::Wrong Tx Rate setting(%d), (0 ~ 12))\n", __FUNCTION__, Rate));

	DBGPRINT(RT_DEBUG_TRACE, ("%s::(Max Tx Rate = %ld)\n", __FUNCTION__, pAd->MeshTab.MeshMaxTxRate));
	
	return TRUE;
}

INT Set_MeshRouteAdd_Proc(RTMP_ADAPTER *pAd, RTMP_STRING *arg)
{
	INT	success = TRUE;
#if 0
	PUCHAR thisChar = NULL;
	UCHAR DestAddr[MAC_ADDR_LEN];
	UCHAR MeshDestAddr[MAC_ADDR_LEN];
	UCHAR NextHop[MAC_ADDR_LEN];
	UCHAR Addr[MAC_ADDR_LEN];
	ULONG Metric = 0;
	UCHAR i;
	PUCHAR value;
	UCHAR Count = 0;
	PMESH_ROUTING_ENTRY pEntry = NULL;
	PMAC_TABLE_ENTRY pMacEntry = NULL;
	POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie;

	if(!IS_MESH_IF(pObj))
		return FALSE;

	while ((thisChar = strsep((char **)&arg, "-")) != NULL)
	{
		if (Count == 0)
		{
			/* Get Dest Addr */
			if(strlen(thisChar) == 17)
			{
				for (i=0, value = rstrtok(thisChar,":"); value; value = rstrtok(NULL,":"))
				{
					if((strlen(value) != 2) || (!isxdigit(*value)) || (!isxdigit(*(value+1))) ) 
						return FALSE;  /*Invalid */

					AtoH(value, &Addr[i++], 1);
				}

				if(i != 6)
					return FALSE;  /*Invalid */
			}
			else
			{
				return FALSE;  /*Invalid */
			}

			COPY_MAC_ADDR(DestAddr, Addr);
		}
		else if (Count == 1)
		{
			/* Get Mesh DA */
			if(strlen(thisChar) == 17)
			{
				for (i=0, value = rstrtok(thisChar,":"); value; value = rstrtok(NULL,":"))
				{
					if((strlen(value) != 2) || (!isxdigit(*value)) || (!isxdigit(*(value+1))) ) 
						return FALSE;  /*Invalid */

					AtoH(value, &Addr[i++], 1);
				}

				if(i != 6)
					return FALSE;  /*Invalid */
			}
			else
			{
				return FALSE;	
			}

			COPY_MAC_ADDR(MeshDestAddr, Addr);
		}
		else if (Count == 2)
		{
			/* Get Next Hop */
			if(strlen(thisChar) == 17)
			{
				for (i=0, value = rstrtok(thisChar,":"); value; value = rstrtok(NULL,":"))
				{
					if((strlen(value) != 2) || (!isxdigit(*value)) || (!isxdigit(*(value+1))) ) 
						return FALSE;  /*Invalid */

					AtoH(value, &Addr[i++], 1);
				}

				if(i != 6)
					return FALSE;  /*Invalid */
			}
			else
			{
				return FALSE;	
			}

			COPY_MAC_ADDR(NextHop, Addr);
		}
		else if (Count == 3)
		{
			/* Get Metric */
			if ((thisChar != NULL) && (strlen(thisChar) > 0))
				Metric = simple_strtol(thisChar, 0, 10);
			else
				return FALSE;
		}
		else
		{
			return FALSE;
		}

		Count++;
	}

	if (MeshEntryTableLookUp(pAd, DestAddr))
	{
		DBGPRINT(RT_DEBUG_TRACE, ("The Dest Mesh Point aleady on Route Table!!!\n"));
		return FALSE;
	}
	else
	{
		pMacEntry = MeshTableLookup(pAd, NextHop, TRUE);

		if (pMacEntry == NULL)
		{
			DBGPRINT(RT_DEBUG_TRACE, ("Next Hop have not on Mac Table !!!\n"));
			return FALSE;
		}

		pEntry = MeshRoutingTableLookup(pAd, MeshDestAddr);
		if (!(pEntry && MAC_ADDR_EQUAL(pEntry->NextHop, NextHop)))
		{
			pEntry = MeshRoutingTableInsert(pAd, DestAddr, MeshDestAddr, 0, NextHop, pMacEntry->func_tb_idx, Metric);
			if (!pEntry)
			{
				DBGPRINT(RT_DEBUG_TRACE, ("Add Dest Mesh Point Route fail !!!\n"));
				return FALSE;
			}
		}

		if (!MeshEntryTableInsert(pAd, DestAddr, pEntry->Idx))
		{
			DBGPRINT(RT_DEBUG_TRACE, ("Add Dest Mesh Point Route fail !!!\n"));
			return FALSE;
		}

		if (MeshTableLookup(pAd, DestAddr, FALSE) == NULL)
		{
			MeshEntryTableInsert(pAd, MeshDestAddr, pEntry->Idx);
		}
	}
#endif
	return success;
}

INT Set_MeshRouteDelete_Proc(RTMP_ADAPTER *pAd, RTMP_STRING *arg)
{
	INT	success = TRUE;
#if 0
	PUCHAR value;
	UCHAR DestAddr[MAC_ADDR_LEN];
	UCHAR i;
	PMESH_ENTRY pMeshEntry = NULL;
	PMESH_ROUTING_ENTRY pRouteEntry = NULL;
	POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie;

	if(!IS_MESH_IF(pObj))
		return FALSE;

	if(strlen(arg) == 17)
	{
		for (i=0, value = rstrtok(arg,":"); value; value = rstrtok(NULL,":"))
		{
			if((strlen(value) != 2) || (!isxdigit(*value)) || (!isxdigit(*(value+1))) ) 
				return FALSE;  /*Invalid */

			AtoH(value, &DestAddr[i++], 1);
		}

		if(i != 6)
			return FALSE;  /*Invalid */
	}
	else
	{
		return FALSE;  /*Invalid */
	}

	pMeshEntry = MeshEntryTableLookUp(pAd, DestAddr);
	pRouteEntry = MeshRoutingTableLookup(pAd, DestAddr);

	if (pMeshEntry && pRouteEntry)
		MeshRoutingTableDelete(pAd, DestAddr);
	else
	MeshEntryTableDelete(pAd, DestAddr);
#endif
	return success;
}

INT Set_MeshRouteUpdate_Proc(RTMP_ADAPTER *pAd, RTMP_STRING *arg)
{
	INT	success = TRUE;
#if 0
	PUCHAR thisChar = NULL;
	UCHAR DestAddr[MAC_ADDR_LEN];
	UCHAR MeshDestAddr[MAC_ADDR_LEN];
	UCHAR NextHop[MAC_ADDR_LEN];
	UCHAR Addr[MAC_ADDR_LEN];
	ULONG Metric = 0;
	UCHAR i;
	PUCHAR value;
	UCHAR Count = 0;
	PMESH_ENTRY pMeshEntry = NULL;
	PMESH_ROUTING_ENTRY pRouteEntry = NULL;
	POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie;

	if(!IS_MESH_IF(pObj))
		return FALSE;

	while ((thisChar = strsep((char **)&arg, "-")) != NULL)
	{
		if (Count == 0)
		{
			/* Get Dest Addr */
			if(strlen(thisChar) == 17)
			{
				for (i=0, value = rstrtok(thisChar,":"); value; value = rstrtok(NULL,":"))
				{
					if((strlen(value) != 2) || (!isxdigit(*value)) || (!isxdigit(*(value+1))) ) 
						return FALSE;  /*Invalid */

					AtoH(value, &Addr[i++], 1);
				}

				if(i != 6)
					return FALSE;  /*Invalid */
			}
			else
			{
				return FALSE;  /*Invalid */
			}

			COPY_MAC_ADDR(DestAddr, Addr);
		}
		else if (Count == 1)
		{
			/* Get Mesh DA */
			if(strlen(thisChar) == 17)
			{
				for (i=0, value = rstrtok(thisChar,":"); value; value = rstrtok(NULL,":"))
				{
					if((strlen(value) != 2) || (!isxdigit(*value)) || (!isxdigit(*(value+1))) ) 
						return FALSE;  /*Invalid */

					AtoH(value, &Addr[i++], 1);
				}

				if(i != 6)
					return FALSE;  /*Invalid */
			}
			else
			{
				return FALSE;	
			}

			COPY_MAC_ADDR(MeshDestAddr, Addr);
		}
		else if (Count == 2)
		{
			/* Get Next Hop */
			if(strlen(thisChar) == 17)
			{
				for (i=0, value = rstrtok(thisChar,":"); value; value = rstrtok(NULL,":"))
				{
					if((strlen(value) != 2) || (!isxdigit(*value)) || (!isxdigit(*(value+1))) ) 
						return FALSE;  /*Invalid */

					AtoH(value, &Addr[i++], 1);
				}

				if(i != 6)
					return FALSE;  /*Invalid */
			}
			else
			{
				return FALSE;	
			}

			COPY_MAC_ADDR(NextHop, Addr);
		}
		else if (Count == 3)
		{
			/* Get Metric */
			if ((thisChar != NULL) && (strlen(thisChar) > 0))
				Metric = simple_strtol(thisChar, 0, 10);
			else
				return FALSE;
		}
		else
		{
			return FALSE;
		}

		Count++;
	}

	pMeshEntry = MeshEntryTableLookUp(pAd, DestAddr);
	pRouteEntry = MeshRoutingTableLookup(pAd, MeshDestAddr);
	
	if (pMeshEntry)
	{
		pRouteEntry = &pAd->MeshTab.MeshRouteTab.Content[pMeshEntry->Idx];
		
		COPY_MAC_ADDR(pRouteEntry->MeshDestAddr, MeshDestAddr);
		COPY_MAC_ADDR(pRouteEntry->NextHop, NextHop);
		pRouteEntry->PathMetric = Metric;
	}
	else
	{
		DBGPRINT(RT_DEBUG_ERROR, ("The can not find the Mesh Route !!!\n"));
		return FALSE;
	}
#endif
	return success;
}

INT Set_MeshMultiCastAgeOut_Proc(RTMP_ADAPTER *pAd, RTMP_STRING *arg)
{
	UINT AgeTime;
	POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie;

	if(!IS_MESH_IF(pObj))
		return FALSE;

	AgeTime = simple_strtol(arg, 0, 10);

	if ((AgeTime <= 65535) && (AgeTime >= 1))
		pAd->MeshTab.MeshMultiCastAgeOut = AgeTime;
	else 
		DBGPRINT(RT_DEBUG_ERROR, ("%s::Wrong MeshMultiCastAgeOut setting(%d), (1 ~ 65535))\n", __FUNCTION__, AgeTime));

	DBGPRINT(RT_DEBUG_TRACE, ("%s::(MeshMultiCastAgeOut = %ld)\n", __FUNCTION__, pAd->MeshTab.MeshMultiCastAgeOut));

	pAd->MeshTab.MeshMultiCastAgeOut = (AgeTime * 1000);

	return TRUE;
}

INT Set_MeshAuthMode_Proc(RTMP_ADAPTER *pAd, RTMP_STRING *arg)
{
	UCHAR	i;
	INT		success = TRUE;
	POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie;
	struct wifi_dev *wdev;

	if(!IS_MESH_IF(pObj))
		return FALSE;

	wdev = &pAd->MeshTab.wdev;
	if (rtstrcasecmp(arg, "WPANONE") == TRUE)
		wdev->AuthMode = Ndis802_11AuthModeWPANone;		
	else
		wdev->AuthMode = Ndis802_11AuthModeOpen;

	/* Set all mesh link as Port_Not_Secure */
	for (i=0; i<MAX_LEN_OF_MAC_TABLE; i++)
	{
		if (IS_ENTRY_MESH(&pAd->MacTab.Content[i]))
			pAd->MacTab.tr_entry[i].PortSecured  = WPA_802_1X_PORT_NOT_SECURED;
	}
		
	RTMPMakeRSNIE(pAd, wdev->AuthMode, wdev->WepStatus, MIN_NET_DEVICE_FOR_MESH);
	
	if(wdev->AuthMode >= Ndis802_11AuthModeWPA)
	{	
		if (wdev->AuthMode == Ndis802_11AuthModeWPANone)
			wdev->DefaultKeyId = 0;
		else
			wdev->DefaultKeyId = 1;
	}

	DBGPRINT(RT_DEBUG_TRACE, ("I/F(mesh0) Set_MeshAuthMode_Proc::(MeshAuthMode(%d)=%s)\n",
			wdev->AuthMode, GetAuthMode(wdev->AuthMode)));
	
	return success;
}

INT Set_MeshEncrypType_Proc(RTMP_ADAPTER *pAd, RTMP_STRING *arg)
{
	INT	success = TRUE;
	POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie;
	struct wifi_dev *wdev;


	if(!IS_MESH_IF(pObj))
		return FALSE;

	wdev = &pAd->MeshTab.wdev;
	if (rtstrcasecmp(arg, "WEP") == TRUE)
    {
		if (wdev->AuthMode < Ndis802_11AuthModeWPA)
			wdev->WepStatus = Ndis802_11WEPEnabled;				  
	}
	else if (rtstrcasecmp(arg, "TKIP") == TRUE)
	{
		if (wdev->AuthMode >= Ndis802_11AuthModeWPA)
			wdev->WepStatus = Ndis802_11TKIPEnable;                       
    }
	else if (rtstrcasecmp(arg, "AES") == TRUE)
	{
		if (wdev->AuthMode >= Ndis802_11AuthModeWPA)
			wdev->WepStatus = Ndis802_11AESEnable;                            
	}    
	else
	{
		wdev->WepStatus = Ndis802_11WEPDisabled;                 
	}

	if(wdev->WepStatus >= Ndis802_11TKIPEnable)
	{		
		if (wdev->AuthMode == Ndis802_11AuthModeWPANone)
			wdev->DefaultKeyId = 0;
		else
			wdev->DefaultKeyId = 1;
	}
								
	RTMPMakeRSNIE(pAd, wdev->AuthMode, wdev->WepStatus, MIN_NET_DEVICE_FOR_MESH);

	DBGPRINT(RT_DEBUG_TRACE, ("I/F(mesh0) Set_MeshEncrypType_Proc::(MeshEncrypType(%d)=%s)\n",
			wdev->WepStatus, GetEncryptType(wdev->WepStatus)));

	return success;
}

INT Set_MeshDefaultkey_Proc(RTMP_ADAPTER *pAd, RTMP_STRING *arg)
{
	ULONG		KeyIdx;
	INT			success = TRUE;
	POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie;
	struct wifi_dev *wdev;

	if(!IS_MESH_IF(pObj))
		return FALSE;

	wdev = &pAd->MeshTab.wdev;
	KeyIdx = simple_strtol(arg, 0, 10);
	if((KeyIdx >= 1 ) && (KeyIdx <= 4))
		wdev->DefaultKeyId = (UCHAR) (KeyIdx - 1);
	else
		wdev->DefaultKeyId = 0;	/* Default value */

	DBGPRINT(RT_DEBUG_TRACE, ("I/F(mesh0) Set_MeshDefaultkey_Proc::(MeshDefaultkey=%d)\n",
										wdev->DefaultKeyId));

	return success;
}

INT Set_MeshWEPKEY_Proc(RTMP_ADAPTER *pAd, RTMP_STRING *arg)
{
	UCHAR		i;
	UCHAR		KeyLen;
	UCHAR		CipherAlg = CIPHER_NONE;
	INT			success = TRUE;
	POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie;

	if(!IS_MESH_IF(pObj))
		return FALSE;

	KeyLen = strlen(arg);

	switch (KeyLen)
	{
		case 5: /*wep 40 Ascii type */
		case 13: /*wep 104 Ascii type */
			pAd->MeshTab.SharedKey.KeyLen = KeyLen;
			NdisMoveMemory(pAd->MeshTab.SharedKey.Key, arg, KeyLen);
			if (KeyLen == 5)
				CipherAlg = CIPHER_WEP64;
			else
				CipherAlg = CIPHER_WEP128;

			NdisMoveMemory(pAd->MeshTab.DesiredWepKey, arg, KeyLen);
			pAd->MeshTab.DesiredWepKeyLen= KeyLen;
			
			DBGPRINT(RT_DEBUG_TRACE, ("IF(mesh0) Set_MeshWEPKRY_Proc::(WepKey=%s ,type=%s, Alg=%s)\n", arg, "Ascii", CipherName[CipherAlg]));		
			break;
		case 10: /*wep 40 Hex type */
		case 26: /*wep 104 Hex type */
			for(i=0; i < KeyLen; i++)
			{
				if( !isxdigit(*(arg+i)) )
					return FALSE;  /*Not Hex value; */
			}
			pAd->MeshTab.SharedKey.KeyLen = KeyLen/2 ;
			AtoH(arg, pAd->MeshTab.SharedKey.Key, KeyLen/2);
			if (KeyLen == 10)
				CipherAlg = CIPHER_WEP64;
			else
				CipherAlg = CIPHER_WEP128;

			NdisMoveMemory(pAd->MeshTab.DesiredWepKey, arg, KeyLen);
			pAd->MeshTab.DesiredWepKeyLen = KeyLen;
			
			DBGPRINT(RT_DEBUG_TRACE, ("IF(mesh0) Set_MeshWEPKRY_Proc::(WepKey=%s, type=%s, Alg=%s)\n", arg, "Hex", CipherName[CipherAlg]));		
			break;				
		default: /*Invalid argument */
			pAd->MeshTab.SharedKey.KeyLen = 0;
			pAd->MeshTab.DesiredWepKeyLen = KeyLen;
			DBGPRINT(RT_DEBUG_ERROR, ("IF(mesh0) Set_MeshWEPKRY_Proc::Invalid argument (=%s)\n", arg));		
			return FALSE;
	}

	pAd->MeshTab.SharedKey.CipherAlg = CipherAlg;
    

	return success;
}


INT Set_MeshWPAKEY_Proc(RTMP_ADAPTER *pAd, RTMP_STRING *arg)
{
	/*UCHAR	keyMaterial[40]; */
	INT		success = TRUE;
	POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie;

	if(!IS_MESH_IF(pObj))
		return FALSE;

#if 0
	if ((strlen(arg) < 8) || (strlen(arg) > 64))
	{
		DBGPRINT(RT_DEBUG_ERROR, ("IF(mesh0) Set failed!!(PassPhrasKey=%s), the key string required 8 ~ 64 characters \n", arg));
		return FALSE;
	}

	NdisMoveMemory(pAd->MeshTab.WPAPassPhraseKey, arg, strlen(arg));
	pAd->MeshTab.WPAPassPhraseKeyLen = strlen(arg);

	if (strlen(arg) == 64)
	{
	    AtoH(arg, pAd->MeshTab.PMK, 32);
	}
	else
	{
	    RtmpPasswordHash((char *)arg, pAd->MeshTab.MeshId, pAd->MeshTab.MeshIdLen, keyMaterial);
	    NdisMoveMemory(pAd->MeshTab.PMK, keyMaterial, 32);
	}
#else
	success = RT_CfgSetWPAPSKKey(pAd, arg, strlen(arg), pAd->MeshTab.MeshId, pAd->MeshTab.MeshIdLen, pAd->MeshTab.PMK);
	if (success == FALSE)
		return FALSE;

	NdisMoveMemory(pAd->MeshTab.WPAPassPhraseKey, arg, strlen(arg));
	pAd->MeshTab.WPAPassPhraseKeyLen = strlen(arg);

#endif
	DBGPRINT(RT_DEBUG_TRACE, ("IF(mesh0) Set_MeshWPAKEY_Proc::PassPhrasKey (=%s)\n", arg));		
	
	return success;
}

INT Set_MeshRouteInfo_Display_Proc(RTMP_ADAPTER *pAd, RTMP_STRING *arg)
{
	INT i;
	POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie;
	PMESH_ROUTING_TABLE	pRouteTab = pAd->MeshTab.pMeshRouteTab;

	if (pRouteTab == NULL)
	{
		DBGPRINT(RT_DEBUG_ERROR, ("%s: Mesh Route Table doesn't exist.\n", __FUNCTION__));
		return FALSE;
	}

	if(!IS_MESH_IF(pObj))
		return FALSE;

	DBGPRINT(RT_DEBUG_OFF, ("\n\n"));

	DBGPRINT(RT_DEBUG_OFF, ("\n%-19s%-6s%-19s%-16s%-12s%-9s\n",
		"MESH DA", "DSN", "NEXTHOP", "NEXTHOPLINKID", "METRICS", "ROUTE_IDX"));
	
	for (i=0; i<MAX_ROUTE_TAB_SIZE; i++)
	{
		PMESH_ROUTING_ENTRY pEntry = &pRouteTab->Content[i];
		if (pEntry->Valid)
		{
			DBGPRINT(RT_DEBUG_OFF, ("%02X:%02X:%02X:%02X:%02X:%02X  ", PRINT_MAC(pEntry->MeshDA)));
			DBGPRINT(RT_DEBUG_OFF, ("%-6d", pEntry->Dsn));
			DBGPRINT(RT_DEBUG_OFF, ("%02X:%02X:%02X:%02X:%02X:%02X  ", PRINT_MAC(pEntry->NextHop)));
			DBGPRINT(RT_DEBUG_OFF, ("%-16d", (int)pEntry->NextHopLinkID));
			DBGPRINT(RT_DEBUG_OFF, ("%-12d", pEntry->PathMetric));
			DBGPRINT(RT_DEBUG_OFF, ("%-9d\n", (int)pEntry->Idx));
		}
	} 

	return TRUE;
}


INT Set_MeshProxyInfo_Display_Proc(RTMP_ADAPTER *pAd, RTMP_STRING *arg)
{

	PMESH_PROXY_ENTRY	pEntry = NULL;
	SHORT	EntryIndex;
	PMESH_PROXY_ENTRY_TABLE	pProxyTab = pAd->MeshTab.pMeshProxyTab;
	int i=0;

	DBGPRINT(RT_DEBUG_OFF, ("pProxyTab size:%d free:%d\n",pProxyTab->AgeList.Number,pProxyTab->FreeEntryList.Number));

	EntryIndex=pProxyTab->AgeList.Head;
	if (EntryIndex >= 0)
	pEntry=&pProxyTab->Content[EntryIndex];

	DBGPRINT(RT_DEBUG_OFF, ("Mesh Proxy Age Out List\n"));
	DBGPRINT(RT_DEBUG_OFF, ("Index,DLNext,DLPrev,HashNext,Mac\n"));
	while(EntryIndex!=-1)
	{
		DBGPRINT(RT_DEBUG_OFF, ("%02d %02d %02d %02d MAC:%02x:%02x:%02x:%02x:%02x:%02x \n",
			
			EntryIndex,pEntry->DLNext,pEntry->DLPrev,pEntry->Next,
			pEntry->MacAddr[0],pEntry->MacAddr[1],pEntry->MacAddr[2],
			pEntry->MacAddr[3],pEntry->MacAddr[4],pEntry->MacAddr[5]));

		EntryIndex=pEntry->DLNext;
		pEntry=&pProxyTab->Content[EntryIndex];
	
	}

	DBGPRINT(RT_DEBUG_TRACE, ("Mesh Proxy Mac Hash Table \n"));
	for(i=0;i<MAX_HASH_ENTRY_TAB_SIZE;i++)
	{
		if (pProxyTab->Hash[i]!=-1)
			DBGPRINT(RT_DEBUG_TRACE, ("%03d : %d \n",i,pProxyTab->Hash[i]));
	
	}


	DBGPRINT(RT_DEBUG_OFF, ("Mesh Content Table \n"));
	DBGPRINT(RT_DEBUG_OFF, ("No,HashNext,DLNext,DLPrev\n"));
	for(i=0;i<MAX_HASH_PROXY_ENTRY_TAB_SIZE;i++)
	{
		DBGPRINT(RT_DEBUG_OFF, (" %d: %02d %02d %02d\n",i,pProxyTab->Content[i].Next,pProxyTab->Content[i].DLNext,pProxyTab->Content[i].DLPrev));
	}

	return TRUE;
}

INT Set_MeshEntryInfo_Display_Proc(RTMP_ADAPTER *pAd, RTMP_STRING *arg)
{
	POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie;

	if(!IS_MESH_IF(pObj))
		return FALSE;

	DBGPRINT(RT_DEBUG_OFF, ("\n%-19s%-10s\n", "DESTMAC", "ROUTE_IDX"));
	
	MeshEntryTableGet(pAd);
	return TRUE;
}

INT Set_MeshInfo_Display_Proc(RTMP_ADAPTER *pAd, RTMP_STRING *arg)
{
	INT i;
	POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie;
	struct wifi_dev *wdev;
	if(!IS_MESH_IF(pObj))
		return FALSE;

	wdev = &pAd->MeshTab.wdev;
	DBGPRINT(RT_DEBUG_OFF, ("HostName = %s, Len=%d\n", pAd->MeshTab.HostName, strlen((RTMP_STRING *)pAd->MeshTab.HostName)));
	DBGPRINT(RT_DEBUG_OFF, ("Mesh Id = %s, Len=%d\n", pAd->MeshTab.MeshId, pAd->MeshTab.MeshIdLen));
	DBGPRINT(RT_DEBUG_OFF, ("Mesh AutoLink = %s\n", pAd->MeshTab.MeshAutoLink == TRUE ? "Enable" : "Disable"));
	DBGPRINT(RT_DEBUG_OFF, ("Channel Precedence (CPI) = %d\n", pAd->MeshTab.CPI));
	DBGPRINT(RT_DEBUG_OFF, ("mesh ctrl current state =%d\n", pAd->MeshTab.CtrlCurrentState));
	DBGPRINT(RT_DEBUG_OFF, ("Mesh AuthMode(%d)=%s, EncrypType(%d)=%s \n", 
							wdev->AuthMode, GetAuthMode(wdev->AuthMode), 
							wdev->WepStatus, GetEncryptType(wdev->WepStatus)));


	for (i = 0; i < MAX_MESH_LINKS; i++)
	{
		DBGPRINT(RT_DEBUG_OFF, ("mesh link (%d) current state =%d,", i, pAd->MeshTab.MeshLink[i].CurrentState));
		DBGPRINT(RT_DEBUG_OFF, (" Valid =%d,", pAd->MeshTab.MeshLink[i].Entry.Valid));
		DBGPRINT(RT_DEBUG_OFF, (" MatchWcid =%d,", pAd->MeshTab.MeshLink[i].Entry.MacTabMatchWCID));
		DBGPRINT(RT_DEBUG_OFF, (" LocalId =%x,", pAd->MeshTab.MeshLink[i].Entry.LocalLinkId));
		DBGPRINT(RT_DEBUG_OFF, (" PeerId =%x,", pAd->MeshTab.MeshLink[i].Entry.PeerLinkId));
		DBGPRINT(RT_DEBUG_OFF, (" ExtChOffset =%d,", pAd->MeshTab.MeshLink[i].Entry.ExtChOffset));
		DBGPRINT(RT_DEBUG_OFF, (" PeerMacAddr =%02x:%02x:%02x:%02x:%02x:%02x\n",
			PRINT_MAC(pAd->MeshTab.MeshLink[i].Entry.PeerMacAddr)));
	}
	DBGPRINT(RT_DEBUG_OFF, ("\n\n"));

	DBGPRINT(RT_DEBUG_OFF, ("\n%-19s%-4s%-4s%-4s%-7s%-7s%-7s%-10s%-6s%-6s%-6s%-6s\n",
			"MAC", "IDX", "AID", "PSM", "RSSI0", "RSSI1", "RSSI2", "PhMd", "BW", "MCS", "SGI", "STBC"));
	
	for (i=0; i<MAX_LEN_OF_MAC_TABLE; i++)
	{
		PMAC_TABLE_ENTRY pEntry = &pAd->MacTab.Content[i];
		if (IS_ENTRY_MESH(pEntry))
		{
			DBGPRINT(RT_DEBUG_OFF, ("%02X:%02X:%02X:%02X:%02X:%02X  ",
				pEntry->Addr[0], pEntry->Addr[1], pEntry->Addr[2],
				pEntry->Addr[3], pEntry->Addr[4], pEntry->Addr[5]));
			DBGPRINT(RT_DEBUG_OFF, ("%-4d", (int)pEntry->func_tb_idx));
			DBGPRINT(RT_DEBUG_OFF, ("%-4d", (int)pEntry->Aid));
			DBGPRINT(RT_DEBUG_OFF, ("%-4d", (int)pEntry->PsMode));
			DBGPRINT(RT_DEBUG_OFF, ("%-7d", pEntry->RssiSample.AvgRssi[0]));
			DBGPRINT(RT_DEBUG_OFF, ("%-7d", pEntry->RssiSample.AvgRssi[1]));
			DBGPRINT(RT_DEBUG_OFF, ("%-7d", pEntry->RssiSample.AvgRssi[2]));
#ifdef DOT11_N_SUPPORT
			DBGPRINT(RT_DEBUG_OFF, ("%-10s", get_phymode_str(pEntry->HTPhyMode.field.MODE)));
			DBGPRINT(RT_DEBUG_OFF, ("%-6s", get_bw_str(pEntry->HTPhyMode.field.BW)));
			DBGPRINT(RT_DEBUG_OFF, ("%-6d", pEntry->HTPhyMode.field.MCS));
			DBGPRINT(RT_DEBUG_OFF, ("%-6d", pEntry->HTPhyMode.field.ShortGI));
			DBGPRINT(RT_DEBUG_OFF, ("%-6d\n", pEntry->HTPhyMode.field.STBC));
#endif /* DOT11_N_SUPPORT */
		}
	} 

	return TRUE;
}

INT Set_NeighborInfo_Display_Proc(RTMP_ADAPTER *pAd, RTMP_STRING *arg)
{
	int i;
	POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie;

	if(!IS_MESH_IF(pObj))
		return FALSE;

	if (pAd->MeshTab.pMeshNeighborTab == NULL)
	{
		DBGPRINT(RT_DEBUG_OFF, ("Mesh Neighbor Tab not ready.\n"));
		return TRUE;
	}
		

	if (pAd->MeshTab.pMeshNeighborTab->NeighborNr == 0)
	{
		DBGPRINT(RT_DEBUG_OFF, ("Mesh Neighbor Tab empty.\n"));
		return TRUE;
	}

	DBGPRINT(RT_DEBUG_OFF, ("Neighbor MP Num = %d\n", pAd->MeshTab.pMeshNeighborTab->NeighborNr));
#if 0
	for (i = 0; i < MAX_NEIGHBOR_MP; i++ )
	{
		if (pAd->MeshTab.pMeshNeighborTab->NeighborMP[i].Valid != TRUE)
			continue;

		DBGPRINT(RT_DEBUG_OFF, ("%d, HostName=%s,", i, pAd->MeshTab.pMeshNeighborTab->NeighborMP[i].HostName));
		DBGPRINT(RT_DEBUG_OFF, (" Rssi=%d,", pAd->MeshTab.pMeshNeighborTab->NeighborMP[i].RealRssi));
		DBGPRINT(RT_DEBUG_OFF, (" Ch=%d,", pAd->MeshTab.pMeshNeighborTab->NeighborMP[i].Channel));
		DBGPRINT(RT_DEBUG_OFF, (" CPI=%d,", pAd->MeshTab.pMeshNeighborTab->NeighborMP[i].CPI));
		DBGPRINT(RT_DEBUG_OFF, (" State=%d,", pAd->MeshTab.pMeshNeighborTab->NeighborMP[i].State));
		DBGPRINT(RT_DEBUG_OFF, (" LinkId=%d,", pAd->MeshTab.pMeshNeighborTab->NeighborMP[i].MeshLinkIdx));
		DBGPRINT(RT_DEBUG_OFF, (" MeshId=%s, len=%d", pAd->MeshTab.pMeshNeighborTab->NeighborMP[i].MeshId,
			pAd->MeshTab.pMeshNeighborTab->NeighborMP[i].MeshIdLen));
		DBGPRINT(RT_DEBUG_OFF, (" Mac=%02x:%02x:%02x:%02x:%02x:%02x,",
			pAd->MeshTab.pMeshNeighborTab->NeighborMP[i].PeerMac[0], pAd->MeshTab.pMeshNeighborTab->NeighborMP[i].PeerMac[1],
			pAd->MeshTab.pMeshNeighborTab->NeighborMP[i].PeerMac[2], pAd->MeshTab.pMeshNeighborTab->NeighborMP[i].PeerMac[3],
			pAd->MeshTab.pMeshNeighborTab->NeighborMP[i].PeerMac[4], pAd->MeshTab.pMeshNeighborTab->NeighborMP[i].PeerMac[5]));

		if (pAd->MeshTab.pMeshNeighborTab->NeighborMP[i].MeshEncrypType == ENCRYPT_OPEN_WEP)
			DBGPRINT(RT_DEBUG_OFF, (" Encryption=OPEN-WEP\n"));
		else if (pAd->MeshTab.pMeshNeighborTab->NeighborMP[i].MeshEncrypType == ENCRYPT_WPANONE_TKIP) 
			DBGPRINT(RT_DEBUG_OFF, (" Encryption=WPANONE-TKIP\n"));
		else if (pAd->MeshTab.pMeshNeighborTab->NeighborMP[i].MeshEncrypType == ENCRYPT_WPANONE_AES) 
			DBGPRINT(RT_DEBUG_OFF, (" Encryption=WPANONE-AES\n"));
		else
			DBGPRINT(RT_DEBUG_OFF, (" Encryption=OPEN-NONE\n"));
		
	}
#else
	DBGPRINT(RT_DEBUG_OFF, ("\n%-4s%-19s%-6s%-4s%-4s%-6s%-8s%-6s%-8s%-14s%-16s%-6s\n",
		"IDX", "MAC", "MRSI", "CH", "BW", "CHOF", "CPI", "STATE", "LINKID", "ECRP", "MESHID", "HSTN"));
	
	for (i=0; i<MAX_NEIGHBOR_MP; i++)
	{
		UCHAR	MeshEncrypType = ENCRYPT_OPEN_NONE;
		PMESH_NEIGHBOR_ENTRY pEntry = &pAd->MeshTab.pMeshNeighborTab->NeighborMP[i];
		if (pEntry->Valid)
		{
			DBGPRINT(RT_DEBUG_OFF, ("%-4d", i));
			DBGPRINT(RT_DEBUG_OFF, ("%02X:%02X:%02X:%02X:%02X:%02X  ",
				pEntry->PeerMac[0], pEntry->PeerMac[1], pEntry->PeerMac[2],
				pEntry->PeerMac[3], pEntry->PeerMac[4], pEntry->PeerMac[5]));
			DBGPRINT(RT_DEBUG_OFF, ("%-6d", (int)pEntry->RealRssi));
			DBGPRINT(RT_DEBUG_OFF, ("%-4d", (int)pEntry->Channel));
			DBGPRINT(RT_DEBUG_OFF, ("%-4d", (int)pEntry->ChBW));
			DBGPRINT(RT_DEBUG_OFF, ("%-6d", (int)pEntry->ExtChOffset));
			DBGPRINT(RT_DEBUG_OFF, ("%-8d", (int)pEntry->CPI));
			DBGPRINT(RT_DEBUG_OFF, ("%-6d", (int)pEntry->State));
			DBGPRINT(RT_DEBUG_OFF, ("%-8x", (int)pEntry->MeshLinkIdx));
			MeshEncrypType = MeshCheckPeerMpCipher(pEntry->CapabilityInfo, pEntry->RSNIE, pEntry->RSNIE_Len);
			if (MeshEncrypType == ENCRYPT_OPEN_WEP)
			{
				DBGPRINT(RT_DEBUG_OFF, ("%-14s", "OPEN-WEP"));
			}
			else if (MeshEncrypType == ENCRYPT_WPANONE_TKIP) 
			{
				DBGPRINT(RT_DEBUG_OFF, ("%-14s", "WPANONE-TKIP"));
			}
			else if (MeshEncrypType == ENCRYPT_WPANONE_AES) 
			{
				DBGPRINT(RT_DEBUG_OFF, ("%-14s", "WPANONE-AES"));
			}
			else
			{
				DBGPRINT(RT_DEBUG_OFF, ("%-14s", "OPEN-NONE"));
			}
			DBGPRINT(RT_DEBUG_OFF, ("%-16s", pEntry->MeshId));
			DBGPRINT(RT_DEBUG_OFF, ("%s\n", pEntry->HostName));
		}
	} 
#endif

	return TRUE;
}

INT Set_MultipathInfo_Display_Proc(RTMP_ADAPTER *pAd, RTMP_STRING *arg)
{
	INT i;
	LONG HashId;
	PMESH_MULTIPATH_ENTRY pEntry;
	POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie;

	if(!IS_MESH_IF(pObj))
		return FALSE;

	for (i = 0; i < MAX_MESH_LINKS; i++)
	{
		if (!PeerLinkValidCheck(pAd, i))
			continue;
		DBGPRINT(RT_DEBUG_OFF, ("Link(%d) ", i));
		for (HashId = 0; HashId < MULTIPATH_HASH_TAB_SIZE; HashId++)
		{
			pEntry = (PMESH_MULTIPATH_ENTRY)(pAd->MeshTab.MeshLink[i].Entry.MultiPathHash[HashId].pHead);
			if (pEntry == NULL)
				continue;

			DBGPRINT(RT_DEBUG_OFF, (" HashId(%ld):", HashId));
			while (pEntry)
			{
				DBGPRINT(RT_DEBUG_OFF, ("SA=%02x:%02x:%02x:%02x:%02x:%02x ",
					PRINT_MAC(pEntry->MeshSA)));
				pEntry = pEntry->pNext;
			}
		}
		DBGPRINT(RT_DEBUG_OFF, ("\n"));
	}

	return TRUE;
}

INT Set_MultiCastAgeOut_Display_Proc(RTMP_ADAPTER *pAd, RTMP_STRING *arg)
{
	POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie;

	if(!IS_MESH_IF(pObj))
		return FALSE;

	DBGPRINT(RT_DEBUG_OFF, ("Multi Cast Age Timeout = %ld sec\n", (pAd->MeshTab.MeshMultiCastAgeOut) / 1000));
	
	return TRUE;
}

INT Set_MeshOnly_Proc(RTMP_ADAPTER *pAd, RTMP_STRING *arg)
{
	UINT Enable;
	POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie;

	if(!IS_MESH_IF(pObj))
		return FALSE;

	Enable = (UINT) simple_strtol(arg, 0, 16);

	pAd->MeshTab.MeshOnly= (Enable > 0) ? TRUE : FALSE;

	DBGPRINT(RT_DEBUG_TRACE, ("%s::(enable = %d)\n", __FUNCTION__, pAd->MeshTab.MeshOnly));
	
	return TRUE;
}

INT Set_PktSig_Display_Proc(RTMP_ADAPTER *pAd, RTMP_STRING *arg)
{
	INT i;
	POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie;
	PMESH_BMPKTSIG_TAB pTab = pAd->MeshTab.pBMPktSigTab;

	if(!IS_MESH_IF(pObj))
		return FALSE;

	DBGPRINT(RT_DEBUG_OFF, ("\n%-4s%-19s%-4s\n", "IDX", "MAC", "SEQ"));
	for (i=0; i<MAX_BMPKTSIG_TAB_SIZE; i++)
	{
		PMESH_BMPKTSIG_ENTRY pEntry = &(pTab->Content[i]);
		if (pTab->Content[i].Valid == FALSE)
			continue;

		DBGPRINT(RT_DEBUG_OFF, ("%-4d", i));
		DBGPRINT(RT_DEBUG_OFF, ("%02x:%02x:%02x:%02x:%02x:%02x  ",
				PRINT_MAC(pEntry->MeshSA)));
		DBGPRINT(RT_DEBUG_OFF, ("%-8x:%-9x%-9x%-9x%-9x",
			pEntry->MeshSeqBased, pEntry->Offset[0], pEntry->Offset[1],
			pEntry->Offset[2], pEntry->Offset[3]));
		DBGPRINT(RT_DEBUG_OFF, ("\n"));
	}

	return TRUE;
}

/* --------------------------------- Public -------------------------------- */
/*
========================================================================
Routine Description:
    Close Mesh network interface.

Arguments:
    ad_p            points to our adapter

Return Value:
    None

Note:
========================================================================
*/
VOID RTMP_Mesh_Close(
	IN PRTMP_ADAPTER pAd)
{
	struct wifi_dev *wdev;

	
#ifdef RELEASE_EXCLUDE
	DBGPRINT(RT_DEBUG_INFO, ("%s --->\n", __FUNCTION__));
#endif /* RELEASE_EXCLUDE */
	/* free Mesh Tables and allocate spin locks */
	NdisFreeSpinLock(&pAd->MeshTabLock);

	wdev = &pAd->MeshTab.wdev;
	/* close virtual interface. */
	if (wdev->if_dev)
		RtmpOSNetDevClose(wdev->if_dev);
#ifdef RELEASE_EXCLUDE
	DBGPRINT(RT_DEBUG_INFO, ("%s <---\n", __FUNCTION__));
#endif /* RELEASE_EXCLUDE */

}


/*
========================================================================
Routine Description:
    Remove Mesh network interface.

Arguments:
    ad_p            points to our adapter

Return Value:
    None

Note:
========================================================================
*/
VOID MESH_Remove(
	IN PRTMP_ADAPTER pAd)
{
	struct wifi_dev *wdev;

#ifdef RELEASE_EXCLUDE
	DBGPRINT(RT_DEBUG_INFO, ("%s --->\n", __FUNCTION__));
#endif /* RELEASE_EXCLUDE */

#ifdef CONFIG_STA_SUPPORT
#ifdef RTMP_MAC_USB
	IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
	{
		BOOLEAN Cancelled = FALSE;
#ifndef BCN_OFFLOAD_SUPPORT
		RTMPCancelTimer(&pAd->CommonCfg.BeaconUpdateTimer, &Cancelled);
#endif
		RTUSBBssBeaconExit(pAd);
	}
#endif /* RTMP_MAC_USB */
#endif /* CONFIG_STA_SUPPORT */

	wdev = &pAd->MeshTab.wdev;
	/* remove virtual interface. */
	if (wdev->if_dev)
	{
		RtmpOSNetDevProtect(1);
		RtmpOSNetDevDetach(wdev->if_dev);
		RtmpOSNetDevProtect(0);

		rtmp_wdev_idx_unreg(pAd, wdev);
		RtmpOSNetDevFree(wdev->if_dev);
	}

	NeighborTableDestroy(pAd);
	BMPktSigTabExit(pAd);
	MultipathPoolExit(pAd);

	MeshRoutingTable_Exit(pAd);
	MeshEntryTable_Exit(pAd);
	MeshProxyEntryTable_Exit(pAd);
#ifdef RELEASE_EXCLUDE
	DBGPRINT(RT_DEBUG_INFO, ("%s <---\n", __FUNCTION__));
#endif /* RELEASE_EXCLUDE */

}


/* --------------------------------- Private -------------------------------- */

VOID MeshUp(
	IN PRTMP_ADAPTER pAd)
{
	BOOLEAN TxPreamble;
	struct wifi_dev *wdev = &pAd->MeshTab.wdev;

    DBGPRINT(RT_DEBUG_TRACE, ("%s: ===> \n", __FUNCTION__));
	if ( RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS) ||
		 RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS))
		 /*||!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_START_UP)) */
		return;

	pAd->MeshTab.MeshChannel = pAd->CommonCfg.Channel;

	/* Make regular Beacon frame */
	MeshMakeBeacon(pAd, MESH_BEACON_IDX(pAd));

	/* Check if the security is supported */
	if (pAd->MeshTab.EasyMeshSecurity)
	{
#ifdef RELEASE_EXCLUDE
		/* 1. This mode can support OPEN, WEP, WPANONE and Mesh-PSK. */
		/* 2. These setting doesn't need MKD and MA. An MP can connect */
		/* 	  to the other MP directly. */
		/* 3. This is does't be defined in IEEE 802.11s standard. */
#endif /* RELEASE_EXCLUDE */
		if (wdev->AuthMode != Ndis802_11AuthModeOpen && 
			wdev->AuthMode != Ndis802_11AuthModeWPANone)
		{
			wdev->AuthMode = Ndis802_11AuthModeOpen;
			wdev->WepStatus = Ndis802_11WEPDisabled;
		}			
		pAd->MeshTab.OpMode &= ~(MESH_MKD);
		
		DBGPRINT(RT_DEBUG_TRACE, ("MeshUp: the Easy MSA is enabled. \n"));
	}
	else
	{
#ifdef RELEASE_EXCLUDE
		/* 1. It refer to the definition of IEEE 802.11s */
		/* 2. It ONLY supports Mesh-PSK and Mesh-802.1X authentication. */
		/* 3. An MP can't connect to the other MP directly. */
		/*	  It MUST bulid its security link with an MA or MKD. */
#endif /* RELEASE_EXCLUDE */
		if (wdev->AuthMode != Ndis802_11AuthModeWPA2 && 
			wdev->AuthMode != Ndis802_11AuthModeWPA2PSK)
		{
			wdev->AuthMode = Ndis802_11AuthModeWPA2;
			wdev->WepStatus = Ndis802_11AESEnable;
		}

		DBGPRINT(RT_DEBUG_TRACE, ("MeshUp: the Easy MSA is disabled. \n"));
	}

#ifdef RELEASE_EXCLUDE
	/* If the MP implements the MKD function, set value into the MKDD-ID field. */
	/* Otherwise, zero the MKDD-ID value. */
#endif /* RELEASE_EXCLUDE */
	if (pAd->MeshTab.OpMode & MESH_MKD)
	{
		NdisMoveMemory(pAd->MeshTab.LocalMSCIE.MKDDID, wdev->if_addr, MAC_ADDR_LEN);
		pAd->MeshTab.bInitialMsaDone = TRUE;
		pAd->MeshTab.bKeyholderDone  = TRUE;
		pAd->MeshTab.bConnectedToMKD = TRUE;
	}
	else
	{
		NdisZeroMemory(&pAd->MeshTab.LocalMSCIE, sizeof(MESH_SECURITY_CAPABILITY_IE));
		pAd->MeshTab.bInitialMsaDone = FALSE;
		pAd->MeshTab.bKeyholderDone  = FALSE;
		pAd->MeshTab.bConnectedToMKD = FALSE;
	}

#ifdef CONFIG_STA_SUPPORT
	/* set my current address as my BSSID */
	IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
	AsicSetBssid(pAd, pAd->CurrentAddress, 0x0);
#endif /* CONFIG_STA_SUPPORT */

	/* Init PMKID */
	pAd->MeshTab.PMKID_Len = 0;
	NdisZeroMemory(pAd->MeshTab.PMKID, LEN_PMKID);

	TxPreamble = (pAd->CommonCfg.TxPreamble == Rt802_11PreambleLong ? 0 : 1);

	pAd->MeshTab.CapabilityInfo =
			CAP_GENERATE(0, 0, (wdev->WepStatus != Ndis802_11EncryptionDisabled), TxPreamble, pAd->CommonCfg.bUseShortSlotTime, 0);

	if (wdev->AuthMode == Ndis802_11AuthModeWPANone)
	{
		wdev->DefaultKeyId = 0;	/* always be zero */
		
        NdisZeroMemory(&pAd->MeshTab.SharedKey, sizeof(CIPHER_KEY));  
		pAd->MeshTab.SharedKey.KeyLen = LEN_TK;

		NdisMoveMemory(pAd->MeshTab.SharedKey.Key, pAd->MeshTab.PMK, LEN_TK);
            
        if (wdev->WepStatus == Ndis802_11TKIPEnable)
        {
    		NdisMoveMemory(pAd->MeshTab.SharedKey.RxMic, &pAd->MeshTab.PMK[16], LEN_TKIP_MIC);
    		NdisMoveMemory(pAd->MeshTab.SharedKey.TxMic, &pAd->MeshTab.PMK[16], LEN_TKIP_MIC);
        }

		/* Decide its ChiperAlg */
		if (wdev->WepStatus == Ndis802_11TKIPEnable)
			pAd->MeshTab.SharedKey.CipherAlg = CIPHER_TKIP;
		else if (wdev->WepStatus == Ndis802_11AESEnable)
			pAd->MeshTab.SharedKey.CipherAlg = CIPHER_AES;
		else
        {         
            DBGPRINT(RT_DEBUG_WARN, ("Unknow Cipher (=%d), set Cipher to AES\n", wdev->WepStatus));
			pAd->MeshTab.SharedKey.CipherAlg = CIPHER_AES;
        } 
	}

	DBGPRINT(RT_DEBUG_TRACE, ("!!! %s - AuthMode(%d)=%s, WepStatus(%d)=%s !!!\n", 
									__FUNCTION__,
									wdev->AuthMode, GetAuthMode(wdev->AuthMode),
									wdev->WepStatus, GetEncryptType(wdev->WepStatus)));

	MlmeEnqueue(pAd, MESH_CTRL_STATE_MACHINE, MESH_CTRL_JOIN, 0, NULL, 0);
	DBGPRINT(RT_DEBUG_TRACE, ("%s: <=== \n", __FUNCTION__));
}

BOOLEAN MeshLinkCheck(
	IN VOID *pAdSrc)
{
	PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)pAdSrc;
	BOOLEAN WaitMeshClose = FALSE;
	INT idx;


	for (idx = 0; idx < MAX_MESH_LINKS; idx++)
	{
		if (PeerLinkMngRuning(pAd, idx) || PeerLinkValidCheck(pAd, idx))
			WaitMeshClose = TRUE;
	}
	return WaitMeshClose;
}

VOID MeshDown(
	IN PRTMP_ADAPTER pAd,
	IN BOOLEAN WaitFlag)
{
	INT idx;
#if 0 /* os abl move */
	ULONG WaitCnt;
#endif /* 0 */

	/* clear PMKID */
	pAd->MeshTab.PMKID_Len = 0;
	NdisZeroMemory(pAd->MeshTab.PMKID, LEN_PMKID);

	/* clear these flag */
	pAd->MeshTab.bInitialMsaDone = FALSE;	
	pAd->MeshTab.bKeyholderDone  = FALSE;
	pAd->MeshTab.bConnectedToMKD = FALSE;

#ifdef CONFIG_STA_SUPPORT
#ifdef RTMP_MAC_USB
	IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
	{
		RTUSBBssBeaconStop(pAd);
	}
#endif /* RTMP_MAC_USB */
#endif /* CONFIG_STA_SUPPORT */

	MlmeEnqueue(pAd, MESH_CTRL_STATE_MACHINE, MESH_CTRL_DISCONNECT, 0, NULL, 0);
	RTMP_MLME_HANDLER(pAd);

#if 0 /* os abl move */
	WaitCnt = 0;
	do
	{
		BOOLEAN WaitMeshClose;
		wait_queue_head_t wait;

		if (WaitFlag == FALSE)
			break;

		WaitMeshClose = FALSE;
		init_waitqueue_head(&wait);

		for (idx = 0; idx < MAX_MESH_LINKS; idx++)
		{
			if (PeerLinkMngRuning(pAd, idx) || PeerLinkValidCheck(pAd, idx))
				WaitMeshClose = TRUE;
		}

		if(WaitMeshClose == TRUE)
			wait_event_interruptible_timeout(wait, 0, 10 * OS_HZ/1000);
		else
			break;
	} while (WaitCnt++ < 1000);
#endif /* 0 */

	RtmpMeshDown(pAd, WaitFlag, MeshLinkCheck);

	/* delete all mesh links. */
	for (idx = 0; idx < MAX_MESH_LINKS; idx++)
	{
		if (pAd->MeshTab.MeshLink[idx].Entry.Valid)
			MeshLinkDelete(pAd, pAd->MeshTab.MeshLink[idx].Entry.PeerMacAddr, idx);
	}

	/* when the ra interface is down, do not send its beacon frame */
	MeshCleanBeaconFrame(pAd, MESH_BEACON_IDX(pAd));

#ifdef CONFIG_STA_SUPPORT
	/* resume BSSID for infra mode */
	IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
	AsicSetBssid(pAd, pAd->CommonCfg.Bssid);
#endif /* CONFIG_STA_SUPPORT */
}

VOID MeshHalt(
	IN PRTMP_ADAPTER pAd)
{
	int idx;
	BOOLEAN 	  Cancelled;

	RTMPCancelTimer(&pAd->MeshTab.PldTimer, &Cancelled);
	RTMPCancelTimer(&pAd->MeshTab.McsTimer, &Cancelled);
	for (idx = 0; idx < MAX_MESH_LINKS; idx++)
	{
		RTMPCancelTimer(&pAd->MeshTab.MeshLink[idx].TOR, &Cancelled);
		RTMPCancelTimer(&pAd->MeshTab.MeshLink[idx].TOC, &Cancelled);
		RTMPCancelTimer(&pAd->MeshTab.MeshLink[idx].TOH, &Cancelled);
	}
}

VOID TearDownAllMeshLink(
		IN PRTMP_ADAPTER pAd)
{
	INT i;
	PMESH_NEIGHBOR_ENTRY pNeighbor = NULL;
	DBGPRINT(RT_DEBUG_TRACE, ("%s: tear down all Mesh Link.\n", __FUNCTION__));

	for (i = 0; i < MAX_MESH_LINKS; i++)
	{
			if(PeerLinkValidCheck(pAd, i))
			{
				/*
				SendMeshPeerLinkClose(pAd, pAd->MeshTab.MeshLink[i].Entry.PeerMacAddr,
				pAd->MeshTab.MeshLink[i].Entry.LocalLinkId,
				pAd->MeshTab.MeshLink[i].Entry.PeerLinkId,
				MESH_LINK_CANCELLED);
				*/
				/*send link close message */
				{
					PUCHAR pPeerMac=pAd->MeshTab.MeshLink[i].Entry.PeerMacAddr;
					UINT32 LocalLinkId=pAd->MeshTab.MeshLink[i].Entry.LocalLinkId;
					UINT32 PeerLinkId=pAd->MeshTab.MeshLink[i].Entry.PeerLinkId;
					HEADER_802_11 MeshHdr;
					PUCHAR pOutBuffer = NULL;
					NDIS_STATUS NStatus;
					ULONG FrameLen;
					MESH_FLAG MeshFlag;
					UINT32 MeshSeq = INC_MESH_SEQ(pAd->MeshTab.MeshSeq);

					NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer);  /*Get an unused nonpaged memory */
					if(NStatus != NDIS_STATUS_SUCCESS)
					{
						DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __FUNCTION__));
						return;
					}

					MeshHeaderInit(pAd, &MeshHdr,
						pPeerMac,		/* addr1 */
						pAd->MeshTab.wdev.if_addr,							/* addr2 */
						ZERO_MAC_ADDR);		/* addr3 */
					NdisMoveMemory(pOutBuffer, (PCHAR)&MeshHdr, sizeof(HEADER_802_11));
					FrameLen = sizeof(HEADER_802_11);

					/* Mesh Header */
					MeshFlag.word = 0;
					MeshFlag.field.AE = 0;	/* Peer-Link manager frame never carry 6 addresses. */
					InsertMeshHeader(pAd, (pOutBuffer + FrameLen), &FrameLen, MeshFlag.word,
						pAd->MeshTab.TTL, MeshSeq, NULL, NULL, NULL);

					/* Action field */
					InsertMeshActField(pAd, (pOutBuffer + FrameLen), &FrameLen, CATEGORY_MESH_PEER_LINK, ACT_CODE_PEER_LINK_CLOSE);

					/* Reason code */
					InsertReasonCode(pAd, (pOutBuffer + FrameLen), &FrameLen, MESH_LINK_CANCELLED);

					/* Mesh Peer Link Management IE */
					InsertMeshPeerLinkMngIE(pAd, (pOutBuffer + FrameLen), &FrameLen, SUBTYPE_PEER_LINK_CLOSE,
						LocalLinkId, PeerLinkId, MESH_LINK_CANCELLED);

					MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen);
					MlmeFreeMemory(pAd, pOutBuffer);

					DBGPRINT(RT_DEBUG_TRACE, ("%s: LocalLinkId=%x, PeerLinkId=%x, Reason=%d\n",
						__FUNCTION__, LocalLinkId, PeerLinkId, MESH_LINK_CANCELLED));

				}

			
				pNeighbor = NeighborSearch(pAd, pAd->MeshTab.MeshLink[i].Entry.PeerMacAddr);
				if (pNeighbor)
				{
					pNeighbor->State = NEIGHBOR_MP;
					pNeighbor->MeshLinkIdx = 0;
				}

				if (pAd->MeshTab.LinkSize == 0)
				{
					pAd->MeshTab.bInitialMsaDone = FALSE;
				}

				MultipathListDelete(pAd, i);


				if(MeshTableLookup(pAd, pAd->MeshTab.MeshLink[i].Entry.PeerMacAddr, TRUE))
					MacTableDeleteMeshEntry(pAd, pAd->MeshTab.MeshLink[i].Entry.MacTabMatchWCID,
						pAd->MeshTab.MeshLink[i].Entry.PeerMacAddr);


				if (pAd->MeshTab.MeshLink[i].Entry.Valid)
				{	
					MeshLinkDelete(pAd, pAd->MeshTab.MeshLink[i].Entry.PeerMacAddr, i);
				}
			}
	}
}

BOOLEAN MeshAcceptPeerLink(
	IN PRTMP_ADAPTER pAd)
{
	return (pAd->MeshTab.LinkSize < MAX_MESH_LINKS) ? 1 : 0;
}

#ifdef RELEASE_EXCLUDE
/*
================================================================
Description : because Mesh and CLI share the same WCID table in ASIC. 
Mesh entry also insert to pAd->MacTab.content[].
Also fills the pairwise key.
Because front MAX_AID_BA entries have direct mapping to BAEntry, which is only used as CLI. So we insert Mesh
from index MAX_AID_BA.
================================================================
*/
#endif /* RELEASE_EXCLUDE */
MAC_TABLE_ENTRY *MacTableInsertMeshEntry(
	IN  PRTMP_ADAPTER   pAd, 
	IN  PUCHAR pAddr,
	IN  UINT MeshLinkIdx)
{
	PMAC_TABLE_ENTRY pEntry = NULL;
	struct wifi_dev *wdev;

	/* if FULL, return */
	if (pAd->MacTab.Size >= MAX_LEN_OF_MAC_TABLE)
		return NULL;

	wdev = &pAd->MeshTab.wdev;
	do
	{
		if((pEntry = MeshTableLookup(pAd, pAddr, TRUE)) != NULL)
			break;

		/* allocate one MAC entry */
		pEntry = MacTableInsertEntry(pAd, pAddr, wdev, ENTRY_MESH, OPMODE_AP, TRUE);
		if (pEntry)
		{
			pAd->MeshTab.MeshLink[MeshLinkIdx].Entry.MacTabMatchWCID = pEntry->wcid;
			pEntry->func_tb_idx = MeshLinkIdx;

			pEntry->MaxHTPhyMode.word = wdev->MaxHTPhyMode.word;
			pEntry->MinHTPhyMode.word = wdev->MinHTPhyMode.word;
			pEntry->HTPhyMode.word = wdev->HTPhyMode.word;
			
#ifdef DOT11_N_SUPPORT
			if (wdev->HTPhyMode.field.MODE >= MODE_HTMIX)
			{
				if (wdev->DesiredTransmitSetting.field.MCS != MCS_AUTO)
				{
					DBGPRINT(RT_DEBUG_TRACE, ("IF-mesh0 : Desired MCS = %d\n",
						wdev->DesiredTransmitSetting.field.MCS));
					
					if (wdev->DesiredTransmitSetting.field.MCS == 32)
					{
						/* Fix MCS as HT Duplicated Mode */
						pEntry->MaxHTPhyMode.field.BW = 1;
						pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX;
						pEntry->MaxHTPhyMode.field.STBC = 0;
						pEntry->MaxHTPhyMode.field.ShortGI = 0;
						pEntry->MaxHTPhyMode.field.MCS = 32;
					}
					else if (pEntry->MaxHTPhyMode.field.MCS > wdev->HTPhyMode.field.MCS)
					{
						/* STA supports fixed MCS */
						pEntry->MaxHTPhyMode.field.MCS = wdev->HTPhyMode.field.MCS;
					}
				}
			}
#endif /* DOT11_N_SUPPORT */
			
			DBGPRINT(RT_DEBUG_TRACE, ("MacTableInsertMeshEntry - allocate entry #%d, Total= %d\n",pEntry->wcid, pAd->MacTab.Size));
			break;
		}
	} while(FALSE);

	return pEntry;
}


/*
	==========================================================================
	Description:
		Delete all Mesh Entry in pAd->MacTab
	==========================================================================
 */
BOOLEAN MacTableDeleteMeshEntry(
	IN PRTMP_ADAPTER pAd,
	IN USHORT wcid,
	IN PUCHAR pAddr)
{
	if (!VALID_WCID(wcid))
		return FALSE;

	MacTableDeleteEntry(pAd, wcid, pAddr);
	MeshCreatePerrAction(pAd, pAddr);

	return TRUE;
}

MAC_TABLE_ENTRY *MeshTableLookup(
	IN PRTMP_ADAPTER pAd,
	IN PUCHAR pAddr,
	IN BOOLEAN bResetIdelCount)
{
	ULONG HashIdx;
	MAC_TABLE_ENTRY *pEntry = NULL;

	RTMP_SEM_LOCK(&pAd->MacTabLock);
	HashIdx = MAC_ADDR_HASH_INDEX(pAddr);
	pEntry = pAd->MacTab.Hash[HashIdx];

	while (pEntry)
	{
		if (IS_ENTRY_MESH(pEntry)
			&& MAC_ADDR_EQUAL(pEntry->Addr, pAddr))
		{
			if(bResetIdelCount) {
				pEntry->NoDataIdleCount = 0;
				// TODO: shiang-usw,  remove upper setting becasue we need to migrate to tr_entry!
				pAd->MacTab.tr_entry[pEntry->wcid].NoDataIdleCount = 0;
			}
			break;
		}
		else
			pEntry = pEntry->pNext;
	}

	RTMP_SEM_UNLOCK(&pAd->MacTabLock);
	return pEntry;
}

MAC_TABLE_ENTRY *MeshTableLookupByWcid(
	IN PRTMP_ADAPTER pAd,
	IN UCHAR wcid,
	IN PUCHAR pAddr,
	IN BOOLEAN bResetIdelCount)
{
	ULONG MeshIndex;
	PMAC_TABLE_ENTRY pCurEntry = NULL;
	PMAC_TABLE_ENTRY pEntry = NULL;

	if (!VALID_WCID(wcid))
		return NULL;

	RTMP_SEM_LOCK(&pAd->MeshTabLock);
	RTMP_SEM_LOCK(&pAd->MacTabLock);

	do
	{
		pCurEntry = &pAd->MacTab.Content[wcid];

		MeshIndex = 0xff;
		if ((pCurEntry) && IS_ENTRY_MESH(pCurEntry))
		{
			MeshIndex = pCurEntry->wdev_idx;
		}

		if (MeshIndex == 0xff)
			break;

		if (pAd->MeshTab.MeshLink[MeshIndex].Entry.Valid != TRUE)
			break;

		if (MAC_ADDR_EQUAL(pCurEntry->Addr, pAddr))
		{
			if(bResetIdelCount) {
				pCurEntry->NoDataIdleCount = 0;
				// TODO: shiang-usw,  remove upper setting becasue we need to migrate to tr_entry!
				pAd->MacTab.tr_entry[pCurEntry->wcid].NoDataIdleCount = 0;
			}
			pEntry = pCurEntry;
			break;
		}
	} while(FALSE);

	RTMP_SEM_UNLOCK(&pAd->MacTabLock);
	RTMP_SEM_UNLOCK(&pAd->MeshTabLock);

	return pEntry;
}

MAC_TABLE_ENTRY *FindMeshEntry(
	IN PRTMP_ADAPTER	pAd,
	IN UCHAR 			Wcid,
	IN PUCHAR			pAddr)
{
	MAC_TABLE_ENTRY *pEntry;

	/* lookup the match wds entry for the incoming packet. */
	pEntry = MeshTableLookupByWcid(pAd, Wcid, pAddr, TRUE);

	return pEntry;
}


VOID MlmeHandleRxMeshFrame(RTMP_ADAPTER *pAd, RX_BLK *pRxBlk)
{
	int i;
	HEADER_802_11 *pHeader = pRxBlk->pHeader;
	UCHAR Category;
	UCHAR ActionField;
	UCHAR MeshHdrLen;

	if (!MESH_ON(pAd))
		return;

#ifdef RELEASE_EXCLUDE
	DBGPRINT(RT_DEBUG_INFO, ("-----> CmmRxMeshMgmtFrameHandle\n"));
#endif /* RELEASE_EXCLUDE */
	

#ifdef WDS_SUPPORT
	if (WdsTableLookup(pAd, pHeader->Addr2, FALSE) != NULL)
	{
#ifdef RELEASE_EXCLUDE
		DBGPRINT(RT_DEBUG_INFO, ("%s() Peer WDS entry.\n", __FUNCTION__));
#endif /* RELEASE_EXCLUDE */
		
		return;
	}
#endif /* WDS_SUPPORT */


	pRxBlk->pData = (UCHAR *)pHeader;
	pRxBlk->pData += LENGTH_802_11;
	pRxBlk->DataSize -= LENGTH_802_11;

	MeshHdrLen = GetMeshHederLen(pRxBlk->pData);
	/* get Category */
	NdisMoveMemory(&Category, pRxBlk->pData + MeshHdrLen, 1);
	/* get ActionField */
	NdisMoveMemory(&ActionField, pRxBlk->pData + MeshHdrLen + 1, 1);

	for (i = 0;  i < MESH_ACT_HANDLER_TAB_SIZE; i++)
	{
		if ((Category == MeshActHandler[i].Category)
			&& (ActionField == MeshActHandler[i].ActionCode)
			&& (MeshActHandler[i].pHandle))
		{
			(*(MeshActHandler[i].pHandle))(pAd, pRxBlk);
			break;
		}
	}
#ifdef RELEASE_EXCLUDE
	DBGPRINT(RT_DEBUG_INFO, ("<----- CmmRxMeshMgmtFrameHandle\n"));
#endif /* RELEASE_EXCLUDE */

}

LONG
PathRouteIDSearch(
	IN	PRTMP_ADAPTER	pAd,
	IN	PUCHAR	pAddr)
{
	MESH_ENTRY *pEntry = NULL;
	UCHAR	DestAddr[MAC_ADDR_LEN];

	
#ifdef RELEASE_EXCLUDE
	DBGPRINT(RT_DEBUG_INFO, ("-----> PathRouteIDSearch\n"));
#endif /* RELEASE_EXCLUDE */
	if (*pAddr & 0x01) /* B/Mcast packet. */
		return BMCAST_ROUTE_ID;

	COPY_MAC_ADDR(DestAddr, pAddr);
	pEntry = MeshEntryTableLookUp(pAd, DestAddr);

	if (pEntry)
	{
		if (pEntry->PathReqTimerRunning)
		{
#ifdef RELEASE_EXCLUDE
			DBGPRINT(RT_DEBUG_INFO, ("%s ---> PathReqTimerRunning is TRUE\n", __FUNCTION__));
#endif /* RELEASE_EXCLUDE */
			
			return -1;
		}
		else
			return (ULONG)pEntry->Idx;
	}

	
#ifdef RELEASE_EXCLUDE
	DBGPRINT(RT_DEBUG_INFO, ("<----- PathRouteIDSearch\n"));
#endif /* RELEASE_EXCLUDE */
	return -1;
}

PUCHAR
PathRouteAddrSearch(
	IN	PRTMP_ADAPTER	pAd,
	IN	UCHAR	RouteIdx)
{
	MESH_ROUTING_ENTRY *pEntry = NULL;
	PMESH_ROUTING_TABLE	pRouteTab = pAd->MeshTab.pMeshRouteTab;

	if (pRouteTab == NULL)
	{
		DBGPRINT(RT_DEBUG_ERROR, ("%s: Mesh Route Table doesn't exist.\n", __FUNCTION__));
		return NULL;
	}

	if (RouteIdx >= MAX_ROUTE_TAB_SIZE)
		return NULL;

	if (pRouteTab->Content[RouteIdx].Valid == TRUE)
	{
		pEntry = &pRouteTab->Content[RouteIdx];
	}
	else
	{
		DBGPRINT(RT_DEBUG_TRACE, ("Can't find the Route Index = (%d)\n", (int)RouteIdx));
		return NULL;
	}

	return pEntry->MeshDA;
}

INT
PathMeshLinkIDSearch(
	IN	PRTMP_ADAPTER	pAd,
	IN	UCHAR	RouteIdx)
{
	MESH_ROUTING_ENTRY *pEntry = NULL;
	PMESH_ROUTING_TABLE	pRouteTab = pAd->MeshTab.pMeshRouteTab;

	if (pRouteTab == NULL)
	{
		DBGPRINT(RT_DEBUG_ERROR, ("%s: Mesh Route Table doesn't exist.\n", __FUNCTION__));
		return -1;
	}

	if (RouteIdx >= MAX_ROUTE_TAB_SIZE)
		return -1;

	if (pRouteTab->Content[RouteIdx].Valid == TRUE)
	{
		pEntry = &pRouteTab->Content[RouteIdx];
		return pEntry->NextHopLinkID;
	}
	else
	{
		DBGPRINT(RT_DEBUG_TRACE, ("Can't find the Route Index = (%d)\n", (int)RouteIdx));
	}

	return -1;
}

UINT GetMeshHederLen(
	IN PUCHAR pSrcBufVA)
{
	UINT MeshHdrLen = 0;

	switch(GetMeshFlagAE(pSrcBufVA))
	{
		case 0:
			MeshHdrLen = 6;
			break;
		case 1:
			MeshHdrLen = 12;
			break;
		case 2:
			MeshHdrLen = 18;
			break;
		case 3:
			MeshHdrLen = 24;
			break;
		default:
			DBGPRINT(RT_DEBUG_ERROR, ("%s: Undown Mesh AE type=%x\n", __FUNCTION__, GetMeshFlagAE(pSrcBufVA)));
			break;
	}


	return MeshHdrLen; 
}

UINT8 GetMeshFlag(
	IN PUCHAR pSrcBufVA)
{
	PMESH_HEADER pMeshHead;

	pMeshHead = (PMESH_HEADER)(pSrcBufVA);

	return pMeshHead->MeshFlag; 
}

UINT8 GetMeshFlagAE(
	IN PUCHAR pSrcBufVA)
{
	PMESH_HEADER pMeshHead;

	pMeshHead = (PMESH_HEADER)(pSrcBufVA);

	return (UINT8)((PMESH_FLAG)&pMeshHead->MeshFlag)->field.AE;
}

UINT8 GetMeshTTL(
	IN PUCHAR pSrcBufVA)
{
	PMESH_HEADER pMeshHead;

	pMeshHead = (PMESH_HEADER)(pSrcBufVA);

	return pMeshHead->MeshTTL; 
}

UINT32 GetMeshSeq(
	IN PUCHAR pSrcBufVA)
{
	PMESH_HEADER pMeshHead;
	UINT32 MeshSeq;

	pMeshHead = (PMESH_HEADER)(pSrcBufVA);
	MeshSeq = le2cpu32(pMeshHead->MeshSeq);

	return MeshSeq;
}

PUCHAR GetMeshAddr4(
	IN PUCHAR pSrcBufVA)
{
	PMESH_HEADER pMeshHead;

	pMeshHead = (PMESH_HEADER)(pSrcBufVA);
	if (((PMESH_FLAG)&pMeshHead->MeshFlag)->field.AE == 1
		|| ((PMESH_FLAG)&pMeshHead->MeshFlag)->field.AE == 3)
		return (PUCHAR)(pSrcBufVA + 6);
	else
		return NULL; 
}

PUCHAR GetMeshAddr5(
	IN PUCHAR pSrcBufVA)
{
	PMESH_HEADER pMeshHead;

	pMeshHead = (PMESH_HEADER)(pSrcBufVA);
	if (((PMESH_FLAG)&pMeshHead->MeshFlag)->field.AE == 2)
		return (PUCHAR)(pSrcBufVA + 6);
	else if (((PMESH_FLAG)&pMeshHead->MeshFlag)->field.AE == 3)
		return (PUCHAR)(pSrcBufVA + 6 + MAC_ADDR_LEN);
	else
		return NULL; 
}

PUCHAR GetMeshAddr6(
	IN PUCHAR pSrcBufVA)
{
	PMESH_HEADER pMeshHead;

	pMeshHead = (PMESH_HEADER)(pSrcBufVA);
	if (((PMESH_FLAG)&pMeshHead->MeshFlag)->field.AE == 2)
		return (PUCHAR)(pSrcBufVA + 6 + MAC_ADDR_LEN);
	else if (((PMESH_FLAG)&pMeshHead->MeshFlag)->field.AE == 3)
		return (PUCHAR)(pSrcBufVA + 6 + MAC_ADDR_LEN + MAC_ADDR_LEN);
	else
		return NULL; 
}

ULONG GetMeshLinkId(
	IN PRTMP_ADAPTER pAd,
	IN PCHAR PeerMacAddr)
{
	ULONG i;

	for (i = 0; i < MAX_MESH_LINKS; i++)
	{
		if (MAC_ADDR_EQUAL(PeerMacAddr, pAd->MeshTab.MeshLink[i].Entry.PeerMacAddr))
			break;
	}

	if (i == MAX_MESH_LINKS)
		return BSS_NOT_FOUND;

	return (ULONG)i;
}

VOID MeshDataPktProcess(
	IN PRTMP_ADAPTER pAd,
	IN PNDIS_PACKET pPacket,
	IN USHORT MeshLinkIdx,
	OUT PNDIS_PACKET *pMeshForwardPacket,
	OUT BOOLEAN *pbDirectForward,
	OUT BOOLEAN *pbAnnounce)

{
	PUCHAR pHeader802_3 = GET_OS_PKT_DATAPTR(pPacket);
	PUCHAR pMeshHdr = pHeader802_3 + LENGTH_802_3;
	UINT MeshHdrLen = GetMeshHederLen(pMeshHdr);
	UINT8 MeshTTL = GetMeshTTL(pMeshHdr);
	UINT8 MeshFlagAE = GetMeshFlagAE(pMeshHdr);
	INT PktLen;

	do
	{
		*pbAnnounce = FALSE;
		*pbDirectForward = FALSE;

		if (!MESH_ON(pAd))
			break;

		if (*pHeader802_3 & 0x01)
		{
			if (--MeshTTL > 0)
				*pbDirectForward = TRUE;
			else
				*pbDirectForward = FALSE;
			*pbAnnounce = TRUE;
		}
		else
		{
			if (MAC_ADDR_EQUAL(pHeader802_3, pAd->MeshTab.wdev.if_addr))
			{
				*pbAnnounce = TRUE;
				*pbDirectForward = FALSE;

#ifdef RELEASE_EXCLUDE
				/*if we r not MAP or MP with proxy , we will drop all packets which MeshDa is us and Da is not. */
				/*if MP is bridged , it must enable proxy or layer 3 packets will not be forwarded correctly */
				/*because bridge mac will not be the same as MP wireless card mac. */
#endif /* RELEASE_EXCLUDE */
				if ((!(pAd->MeshTab.OpMode & MESH_AP) && !(pAd->MeshTab.OpMode & MESH_POTAL)) &&
				     (MeshFlagAE == 2 && !MAC_ADDR_EQUAL(GetMeshAddr5(pMeshHdr),pAd->MeshTab.wdev.if_addr)))
					*pbAnnounce = FALSE;
			}
			else
			{
				if (--MeshTTL > 0)
					*pbDirectForward = TRUE;
				else
					*pbDirectForward = FALSE;
				*pbAnnounce = FALSE;
			}
		}

		if (pAd->MeshTab.MeshCapability.field.Forwarding == 0)
			*pbDirectForward = FALSE;

		if (*pbDirectForward == TRUE)
		{
			PUCHAR pFwdPktHeader = NULL;
			if (*pbAnnounce == TRUE)
			{
				*pMeshForwardPacket = (PNDIS_PACKET)OS_PKT_COPY(RTPKT_TO_OSPKT(pPacket));
				if (*pMeshForwardPacket == NULL)
				{
					/*ASSERT(*pMeshForwardPacket); */
					*pbAnnounce = FALSE;
					*pbDirectForward = FALSE;
					break;
				}
				pFwdPktHeader = GET_OS_PKT_DATAPTR(*pMeshForwardPacket);
			}
			else
				pFwdPktHeader = pHeader802_3;
			
#ifdef RELEASE_EXCLUDE
			/* override eth type/len field. */
			/* ApHardTransmit will check the field to decide that to add LLC or not. */
			/* Thus override eth type/lens field here let ApHardTransmit added LLC for the packet. */
#endif /* RELEASE_EXCLUDE */

			if (NdisEqualMemory(SNAP_802_1H, pFwdPktHeader + LENGTH_802_3 + MeshHdrLen, 6)  || 
				NdisEqualMemory(SNAP_BRIDGE_TUNNEL, pFwdPktHeader + LENGTH_802_3 + MeshHdrLen, 6))   
			{
				NdisMoveMemory(pFwdPktHeader + 12, pFwdPktHeader + LENGTH_802_3 + MeshHdrLen + 6, 2);
			}
			else
			{	
				PktLen=GET_OS_PKT_LEN(pPacket)-LENGTH_802_3;
				*(pFwdPktHeader+12)=(UCHAR)(PktLen / 256);
				*(pFwdPktHeader+13)=(UCHAR)(PktLen % 256);
			}			
		}

		if (*pbAnnounce == TRUE)
		{
			PUCHAR pSrcBuf,pData=pMeshHdr + MeshHdrLen;	
			UINT Offset;
			BOOLEAN WithLLC=TRUE;
			UCHAR Header802_3[14];
	

			if (NdisEqualMemory(SNAP_802_1H, pData, 6)  || NdisEqualMemory(SNAP_BRIDGE_TUNNEL, pData, 6))                 
			{  
				pSrcBuf = pMeshHdr + MeshHdrLen + 6 - LENGTH_802_3_NO_TYPE; 	
			}
			else
			{
				pSrcBuf = pMeshHdr + MeshHdrLen - LENGTH_802_3;
				WithLLC=FALSE;
			}


			if (MeshFlagAE == 2)
			{	/* the lenght of hdr shall be 16 bytes here. */
				COPY_MAC_ADDR(Header802_3,GetMeshAddr5(pMeshHdr));
				COPY_MAC_ADDR(Header802_3+MAC_ADDR_LEN,GetMeshAddr6(pMeshHdr));
			}
			else if(MeshFlagAE == 1)
			{
				/* Mesh Data frame never AE=1. */
				/* drop the frame. */
				DBGPRINT(RT_DEBUG_ERROR, ("%s: Receive Mesh-Data frame carry AE=1. Drop the frame.\n", __FUNCTION__));
				*pbAnnounce = FALSE;
				*pbDirectForward = FALSE;
				if (*pMeshForwardPacket != NULL)
					RELEASE_NDIS_PACKET(pAd, *pMeshForwardPacket, NDIS_STATUS_FAILURE);
				*pMeshForwardPacket = NULL;
				break;
			}
			else
			{
				COPY_MAC_ADDR(Header802_3,pHeader802_3);
				COPY_MAC_ADDR(Header802_3+MAC_ADDR_LEN,pHeader802_3 + MAC_ADDR_LEN);				
			}

			Offset = pSrcBuf - pHeader802_3;
/*			GET_OS_PKT_DATAPTR(pPacket) = pSrcBuf; */
/*			GET_OS_PKT_LEN(pPacket) -= Offset; */
			SET_OS_PKT_DATAPTR(pPacket, pSrcBuf);
			SET_OS_PKT_LEN(pPacket, (GET_OS_PKT_LEN(pPacket) - Offset));

			if (WithLLC==FALSE)
			{
				PktLen=GET_OS_PKT_LEN(pPacket)-14;
				Header802_3[12]=(UCHAR)(PktLen / 256); 
				Header802_3[13]=(UCHAR)(PktLen % 256);
				memcpy(pSrcBuf,Header802_3,14);
			}
			else
			{
				memcpy(pSrcBuf,Header802_3,12);
			}
			

		}
	} while (FALSE);

	return;
}

ULONG InsertPktMeshHeader(
	IN PRTMP_ADAPTER pAd,
	IN TX_BLK *pTxBlk, 
	IN PUCHAR *pHeaderBufPtr)
{
	ULONG TempLen = 0;
	MESH_FLAG MeshFlag;
	UINT16 MeshTTL;
	UINT32 MeshSeq;
	PUCHAR pMeshAddr5 = NULL;
	PUCHAR pMeshAddr6 = NULL;

	PerpareMeshHeader(pAd, pTxBlk, &MeshFlag, &MeshTTL, &MeshSeq, &pMeshAddr5, &pMeshAddr6);
	InsertMeshHeader(pAd, *pHeaderBufPtr, &TempLen, MeshFlag.word, MeshTTL, MeshSeq,
						NULL, pMeshAddr5, pMeshAddr6);

	*pHeaderBufPtr += TempLen;
	pTxBlk->MpduHeaderLen += TempLen;

	return TempLen;
}

UINT32 RandomMeshCPI(
	IN PRTMP_ADAPTER pAd)
{
	return (UINT32)((RandomByte(pAd) << 8) + (RandomByte(pAd)));
}

UINT16 RandomLinkId(
	IN PRTMP_ADAPTER pAd)
{
	return (UINT16)((RandomByte(pAd) << 8) + (RandomByte(pAd)));
}

UINT8 RandomChSwWaitTime(
	IN PRTMP_ADAPTER pAd)
{
	UINT8 ChSwCnt = RandomByte(pAd);

	ChSwCnt = (ChSwCnt >= 50) ? ChSwCnt : (UINT8)(50 + RandomByte(pAd));
	return ChSwCnt;
}

void rtmp_read_mesh_from_file(
	IN PRTMP_ADAPTER pAd,
	RTMP_STRING *tmpbuf,
	RTMP_STRING *buffer)
{
	/*UCHAR		keyMaterial[40]; */
	ULONG		KeyIdx;
	ULONG		KeyLen;
	struct wifi_dev *wdev;

	/*MeshId */
	wdev = &pAd->MeshTab.wdev;
	if(RTMPGetKeyParameter("MeshId", tmpbuf, 255, buffer, FALSE))
	{
		/*MeshId acceptable strlen must be less than 32 and bigger than 0. */
		if((strlen(tmpbuf) < 0) || (strlen(tmpbuf) > 32))
			pAd->MeshTab.MeshIdLen = 0;
		else
			pAd->MeshTab.MeshIdLen = strlen(tmpbuf);

		if(pAd->MeshTab.MeshIdLen > 0)
		{
			NdisMoveMemory(&pAd->MeshTab.MeshId, tmpbuf, pAd->MeshTab.MeshIdLen);
		}
		else
		{
			NdisZeroMemory(&pAd->MeshTab.MeshId, MAX_MESH_ID_LEN);
		}
		DBGPRINT(RT_DEBUG_TRACE, ("MeshIdLen=%d, MeshId=%s\n", pAd->MeshTab.MeshIdLen, pAd->MeshTab.MeshId));
	}

	/*MeshAutoLink */
	if (RTMPGetKeyParameter("MeshAutoLink", tmpbuf, 255, buffer, TRUE))
	{
		LONG Enable;
		Enable = simple_strtol(tmpbuf, 0, 10);
		pAd->MeshTab.MeshAutoLink = (Enable > 0) ? TRUE : FALSE;
		DBGPRINT(RT_DEBUG_TRACE, ("%s::(MeshAutoLink=%d)\n", __FUNCTION__, pAd->MeshTab.MeshAutoLink));
	}
	else 
		pAd->MeshTab.MeshAutoLink = TRUE;

	/*MeshForward */
	if (RTMPGetKeyParameter("MeshForward", tmpbuf, 255, buffer, TRUE))
	{
		LONG Enable;
		Enable = simple_strtol(tmpbuf, 0, 10);
		pAd->MeshTab.MeshCapability.field.Forwarding = (Enable > 0) ? (1) : (0);
		DBGPRINT(RT_DEBUG_TRACE, ("%s::(MeshForward=%d)\n", __FUNCTION__, pAd->MeshTab.MeshCapability.field.Forwarding));
	}

	/*MeshAuthMode */
	if (RTMPGetKeyParameter("MeshAuthMode", tmpbuf, 255, buffer, TRUE))
	{										
		if ((strncmp(tmpbuf, "WPANONE", 7) == 0) || (strncmp(tmpbuf, "wpanone", 7) == 0))
			wdev->AuthMode = Ndis802_11AuthModeWPANone;				
		else
			wdev->AuthMode = Ndis802_11AuthModeOpen;
			
		DBGPRINT(RT_DEBUG_TRACE, ("I/F(mesh0) MeshAuthMode(%d)=%s \n", wdev->AuthMode, GetAuthMode(wdev->AuthMode)));
		RTMPMakeRSNIE(pAd, wdev->AuthMode, wdev->WepStatus, MIN_NET_DEVICE_FOR_MESH);		

		if(wdev->AuthMode >= Ndis802_11AuthModeWPA)
		{	
			if (wdev->AuthMode == Ndis802_11AuthModeWPANone)
				wdev->DefaultKeyId = 0;
			else
				wdev->DefaultKeyId = 1;
		}

	}

	/*MeshEncrypType */
	if (RTMPGetKeyParameter("MeshEncrypType", tmpbuf, 255, buffer, TRUE))
	{										
		if (rtstrcasecmp(tmpbuf, "WEP") == TRUE)
        {
			if (wdev->AuthMode < Ndis802_11AuthModeWPA)
				wdev->WepStatus = Ndis802_11WEPEnabled;				  
		}
		else if (rtstrcasecmp(tmpbuf, "TKIP") == TRUE)
		{
			if (wdev->AuthMode >= Ndis802_11AuthModeWPA)
				wdev->WepStatus = Ndis802_11TKIPEnable;                       
        }
		else if (rtstrcasecmp(tmpbuf, "AES") == TRUE)
		{
			if (wdev->AuthMode >= Ndis802_11AuthModeWPA)
				wdev->WepStatus = Ndis802_11AESEnable;                            
		}    
		else
		{
			wdev->WepStatus = Ndis802_11WEPDisabled;                 
		}
							
		DBGPRINT(RT_DEBUG_TRACE, ("I/F(mesh0) MeshEncrypType(%d)=%s \n", wdev->WepStatus, GetEncryptType(wdev->WepStatus)));
		RTMPMakeRSNIE(pAd, wdev->AuthMode, wdev->WepStatus, MIN_NET_DEVICE_FOR_MESH);
		
	}
	
	/*MeshWPAKEY */
	if (RTMPGetKeyParameter("MeshWPAKEY", tmpbuf, 255, buffer, TRUE))
	{
		/* The WPA KEY must be 8~64 characters */
#if 0
		if((strlen(tmpbuf) >= 8) && (strlen(tmpbuf) <= 64))
		{
			NdisMoveMemory(pAd->MeshTab.WPAPassPhraseKey, tmpbuf, strlen(tmpbuf));
			pAd->MeshTab.WPAPassPhraseKeyLen = strlen(tmpbuf);
						
			if (strlen(tmpbuf) == 64)
			{/* Hex mode */
				AtoH(tmpbuf, pAd->MeshTab.PMK, 32);
			}
			else
			{/* ASCII mode */
				RtmpPasswordHash((char *)tmpbuf, pAd->MeshTab.MeshId, pAd->MeshTab.MeshIdLen, keyMaterial);
				NdisMoveMemory(pAd->MeshTab.PMK, keyMaterial, 32);
			}	
			DBGPRINT(RT_DEBUG_TRACE, ("I/F(mesh0) MeshWPAKEY=%s, its length=%d\n", pAd->MeshTab.WPAPassPhraseKey, pAd->MeshTab.WPAPassPhraseKeyLen));
		}
		else
		{
			DBGPRINT(RT_DEBUG_ERROR, ("I/F(mesh0) set MeshWPAKEY fail, key string required 8 ~ 64 characters!!!\n"));
		}
#else
		int success;

		success = RT_CfgSetWPAPSKKey(pAd, tmpbuf, strlen(tmpbuf), pAd->MeshTab.MeshId, pAd->MeshTab.MeshIdLen, pAd->MeshTab.PMK);
		if (success == TRUE)
		{
			NdisMoveMemory(pAd->MeshTab.WPAPassPhraseKey, tmpbuf, strlen(tmpbuf));
			pAd->MeshTab.WPAPassPhraseKeyLen = strlen(tmpbuf);
		}
		else
		{
			DBGPRINT(RT_DEBUG_ERROR, ("I/F(mesh0) set MeshWPAKEY fail, key string required 8 ~ 64 characters!!!\n"));
		}
#endif
																				
	}

	/*MeshDefaultkey */
	if (RTMPGetKeyParameter("MeshDefaultkey", tmpbuf, 255, buffer, TRUE))
	{								
		KeyIdx = simple_strtol(tmpbuf, 0, 10);
		if((KeyIdx >= 1 ) && (KeyIdx <= 4))
			wdev->DefaultKeyId = (UCHAR) (KeyIdx - 1);
		else
			wdev->DefaultKeyId = 0;

		DBGPRINT(RT_DEBUG_TRACE, ("I/F(mesh0) DefaultKeyID(0~3)=%d\n", wdev->DefaultKeyId));
	}

	/*MeshWEPKEY */
	if (RTMPGetKeyParameter("MeshWEPKEY", tmpbuf, 255, buffer, TRUE))
	{		    		                
		KeyLen = strlen(tmpbuf);
			
		/* Hex type */
		if((KeyLen == 10) || (KeyLen == 26))
		{
			pAd->MeshTab.SharedKey.KeyLen = KeyLen / 2;
			AtoH(tmpbuf, pAd->MeshTab.SharedKey.Key, KeyLen / 2);
			if (KeyLen == 10)
				pAd->MeshTab.SharedKey.CipherAlg = CIPHER_WEP64;
			else
				pAd->MeshTab.SharedKey.CipherAlg = CIPHER_WEP128;

			NdisMoveMemory(pAd->MeshTab.DesiredWepKey, tmpbuf, KeyLen);
			pAd->MeshTab.DesiredWepKeyLen = KeyLen;
							
			DBGPRINT(RT_DEBUG_TRACE, ("I/F(mesh0) MeshWEPKEY=%s, it's HEX type and %s\n", tmpbuf, (KeyLen == 10) ? "wep64":"wep128"));
		}
		/* ASCII type */
		else if ((KeyLen == 5) || (KeyLen == 13))
		{
			pAd->MeshTab.SharedKey.KeyLen = KeyLen;
			NdisMoveMemory(pAd->MeshTab.SharedKey.Key, tmpbuf, KeyLen);
			if (KeyLen == 5)
				pAd->MeshTab.SharedKey.CipherAlg = CIPHER_WEP64;
			else
				pAd->MeshTab.SharedKey.CipherAlg = CIPHER_WEP128;

			NdisMoveMemory(pAd->MeshTab.DesiredWepKey, tmpbuf, KeyLen);
			pAd->MeshTab.DesiredWepKeyLen = KeyLen;
									
			DBGPRINT(RT_DEBUG_TRACE, ("I/F(mesh0) MeshWEPKEY=%s, it's ASCII type and %s\n", tmpbuf, (KeyLen == 5) ? "wep64":"wep128"));
		}
		/*Invalid key length */
		else
		{ 
			pAd->MeshTab.DesiredWepKeyLen = 0;
			DBGPRINT(RT_DEBUG_ERROR, ("I/F(mesh0) MeshWEPKEY is Invalid key length(%d)!\n", (UCHAR)KeyLen));
		}
	}	

	return;
}


VOID LocalMsaIeInit(
	IN PRTMP_ADAPTER pAd,
	IN INT			 idx)
{
	PMSA_HANDSHAKE_IE	pLocalMsaIe;
	struct wifi_dev *wdev;

	/* clear the local MP's MSAIE field */
	wdev = &pAd->MeshTab.wdev;
	NdisZeroMemory(pAd->MeshTab.MeshLink[idx].Entry.LocalMsaIe, MESH_MAX_MSAIE_LEN);	
	pAd->MeshTab.MeshLink[idx].Entry.LocalMsaIeLen = 0;

	pLocalMsaIe = (PMSA_HANDSHAKE_IE)pAd->MeshTab.MeshLink[idx].Entry.LocalMsaIe;

#ifdef RELEASE_EXCLUDE
	/* Requests Authentication subfield of the Handshake Control field shall be set to 1 if the local MP */
	/* requests Initial MSA Authentication during this MSA authentication mechanism. This subfield */
	/* shall be set to zero if the PMKID list field of the RSNIE contains one or more entries. */
#endif /* RELEASE_EXCLUDE */

	pLocalMsaIe->MeshHSControl.word = 0;	
	if (pAd->MeshTab.bInitialMsaDone == FALSE || pAd->MeshTab.PMKID_Len == 0)
		pLocalMsaIe->MeshHSControl.field.RequestAuth = 1;	
	
#ifdef RELEASE_EXCLUDE
	/* Selected AKM and Pairwise-Cipher Suite */
	/* If the local MP is the Selector MP, the field shall contain the local MP's selection */
#endif /* RELEASE_EXCLUDE */
	if (pAd->MeshTab.MeshLink[idx].Entry.bValidLocalMpAsSelector)
	{
		UCHAR	AuthMode = wdev->AuthMode;
		UCHAR	EncrypType = wdev->WepStatus;
	
		switch (AuthMode)
        {
           	case Ndis802_11AuthModeWPA2:            	
               	NdisMoveMemory(pLocalMsaIe->SelectedAKM, OUI_MSA_8021X_AKM, LEN_OUI_SUITE);
            break;

          	case Ndis802_11AuthModeWPA2PSK:
           		NdisMoveMemory(pLocalMsaIe->SelectedAKM, OUI_MSA_PSK_AKM, LEN_OUI_SUITE);
            break;

			/*default: */
			case Ndis802_11AuthModeWPANone:                
	            NdisMoveMemory(pLocalMsaIe->SelectedAKM, OUI_WPA_NONE_AKM, LEN_OUI_SUITE);
            break;
        }	
			
		switch (EncrypType)
        {
           	case Ndis802_11TKIPEnable:  
				if (wdev->AuthMode == Ndis802_11AuthModeWPANone)
	               	NdisMoveMemory(pLocalMsaIe->SelectedPairwiseCipher, OUI_WPA_TKIP, LEN_OUI_SUITE);
				else
					NdisMoveMemory(pLocalMsaIe->SelectedPairwiseCipher, OUI_WPA2_TKIP, LEN_OUI_SUITE);
			break;

          	case Ndis802_11AESEnable:
           		if (wdev->AuthMode == Ndis802_11AuthModeWPANone)
	               	NdisMoveMemory(pLocalMsaIe->SelectedPairwiseCipher, OUI_WPA_CCMP, LEN_OUI_SUITE);
				else
					NdisMoveMemory(pLocalMsaIe->SelectedPairwiseCipher, OUI_WPA2_CCMP, LEN_OUI_SUITE);
            break;			
        }			
	}

	pAd->MeshTab.MeshLink[idx].Entry.LocalMsaIeLen = sizeof(MSA_HANDSHAKE_IE);

}

/* 
    ==========================================================================
    Description:
        It shall be queried about mesh security information through IOCTL     
	Arguments:
	    pAd		Pointer to our adapter
	    wrq		Pointer to the ioctl argument
    ==========================================================================
*/
VOID RTMPIoctlQueryMeshSecurityInfo(
		IN PRTMP_ADAPTER pAd, 
		IN RTMP_IOCTL_INPUT_STRUCT *wrq)
{
	UCHAR	key_len = 0;
	MESH_SECURITY_INFO	meshInfo;
	struct wifi_dev *wdev;


	DBGPRINT(RT_DEBUG_TRACE, ("RTMPIoctlQueryMeshSecurityInfo==>\n"));
	
	NdisZeroMemory((PUCHAR)&meshInfo, sizeof(MESH_SECURITY_INFO));
	wdev = &pAd->MeshTab.wdev;
	if (wdev->AuthMode == Ndis802_11AuthModeOpen && wdev->WepStatus == Ndis802_11WEPEnabled)
		meshInfo.EncrypType = ENCRYPT_OPEN_WEP;		/* 1 - 	OPEN-WEP */
	else if (wdev->AuthMode == Ndis802_11AuthModeWPANone && wdev->WepStatus == Ndis802_11TKIPEnable)
		meshInfo.EncrypType = ENCRYPT_WPANONE_TKIP;	/* 2 -	WPANONE-TKIP */
	else if (wdev->AuthMode == Ndis802_11AuthModeWPANone && wdev->WepStatus == Ndis802_11AESEnable)
		meshInfo.EncrypType = ENCRYPT_WPANONE_AES;	/* 3 -	WPANONE-AES */
	else
		meshInfo.EncrypType = ENCRYPT_OPEN_NONE;	/* 0 - 	OPEN-NONE */

	meshInfo.KeyIndex = wdev->DefaultKeyId + 1;
				
	if (meshInfo.EncrypType == ENCRYPT_OPEN_WEP)
	{
		key_len = pAd->MeshTab.DesiredWepKeyLen;
		if (key_len > 0)
		{
			meshInfo.KeyLength = key_len;
			NdisMoveMemory(meshInfo.KeyMaterial, pAd->MeshTab.DesiredWepKey, key_len);
		}
	}
	else if (meshInfo.EncrypType == ENCRYPT_WPANONE_TKIP || meshInfo.EncrypType == ENCRYPT_WPANONE_AES)
	{
		key_len = pAd->MeshTab.WPAPassPhraseKeyLen;
		if (key_len > 0)
		{
			meshInfo.KeyLength = key_len;
			NdisMoveMemory(meshInfo.KeyMaterial, pAd->MeshTab.WPAPassPhraseKey, key_len);
		}
	}

	wrq->u.data.length = sizeof(MESH_SECURITY_INFO);
	if (copy_to_user(wrq->u.data.pointer, &meshInfo, wrq->u.data.length))
	{
		DBGPRINT(RT_DEBUG_TRACE, ("%s: copy_to_user() fail\n", __FUNCTION__));
	}

}


/* 
    ==========================================================================
    Description:
        It shall be set mesh security through IOCTL        
	Arguments:
	    pAd		Pointer to our adapter
	    wrq		Pointer to the ioctl argument
    ==========================================================================
*/
INT RTMPIoctlSetMeshSecurityInfo(
		IN PRTMP_ADAPTER pAd, 
		IN RTMP_IOCTL_INPUT_STRUCT *wrq)
{	
	INT 	Status = NDIS_STATUS_SUCCESS;
	MESH_SECURITY_INFO	meshInfo;
	UCHAR	MeshKey[255];
	struct wifi_dev *wdev;

	DBGPRINT(RT_DEBUG_TRACE, ("RTMPIoctlSetMeshSecurityInfo==>\n"));

	wdev = &pAd->MeshTab.wdev;
	if (wrq->u.data.length != sizeof(MESH_SECURITY_INFO))
	{
		DBGPRINT(RT_DEBUG_ERROR, ("%s: the length is too large \n", __FUNCTION__));
		return -EINVAL;
	}

	if (copy_from_user(&meshInfo, wrq->u.data.pointer, wrq->u.data.length))
	{
		DBGPRINT(RT_DEBUG_ERROR, ("%s: copy_from_user() fail\n", __FUNCTION__));
		return -EFAULT;
	}

	/* Default security mode is OPEN-NONE */
	wdev->AuthMode = Ndis802_11AuthModeOpen;
	wdev->WepStatus = Ndis802_11EncryptionDisabled;
	NdisZeroMemory((PUCHAR)&pAd->MeshTab.SharedKey, sizeof(CIPHER_KEY));

	/* Set default key index */
	if((meshInfo.KeyIndex >= 1) && (meshInfo.KeyIndex <= 4))
		wdev->DefaultKeyId = meshInfo.KeyIndex - 1;
	else
		wdev->DefaultKeyId = 0;
		
	NdisZeroMemory(MeshKey, 255);
	if (meshInfo.KeyLength > 0)
		NdisMoveMemory(MeshKey, meshInfo.KeyMaterial, meshInfo.KeyLength);
	MeshKey[sizeof(MeshKey)-1] = 0x00;
		
	/* OPEN-WEP */
	if (meshInfo.EncrypType == ENCRYPT_OPEN_WEP)					
	{
		if (!Set_MeshWEPKEY_Proc(pAd, (RTMP_STRING *) MeshKey))
		{
			DBGPRINT(RT_DEBUG_ERROR, ("%s: Mesh WEP key isn't valid \n", __FUNCTION__));
			return -EFAULT;
		}

		wdev->AuthMode = Ndis802_11AuthModeOpen;
		wdev->WepStatus = Ndis802_11WEPEnabled;
	}
	else if (meshInfo.EncrypType == ENCRYPT_WPANONE_TKIP || meshInfo.EncrypType == ENCRYPT_WPANONE_AES) 
	{
		if (!Set_MeshWPAKEY_Proc(pAd, (RTMP_STRING *) MeshKey))
		{
			DBGPRINT(RT_DEBUG_ERROR, ("%s: Mesh WPA key isn't valid \n", __FUNCTION__));
			return -EFAULT;
		}

		wdev->AuthMode = Ndis802_11AuthModeWPANone;
		if (meshInfo.EncrypType == ENCRYPT_WPANONE_TKIP)
			wdev->WepStatus = Ndis802_11TKIPEnable;
		else
			wdev->WepStatus = Ndis802_11AESEnable;

		RTMPMakeRSNIE(pAd, wdev->AuthMode, wdev->WepStatus, MIN_NET_DEVICE_FOR_MESH);
	}
			
	return Status;

}

UCHAR GetMeshSecurity(RTMP_ADAPTER *pAd)
{
	struct wifi_dev *wdev;
	UCHAR	EncrypType = ENCRYPT_OPEN_NONE;

	wdev = &pAd->MeshTab.wdev;
	if (wdev->AuthMode==Ndis802_11AuthModeOpen
	&& wdev->WepStatus == Ndis802_11WEPDisabled)
	{

	}
	else if (wdev->AuthMode==Ndis802_11AuthModeOpen
	&& wdev->WepStatus == Ndis802_11WEPEnabled)
	{

		EncrypType = ENCRYPT_OPEN_WEP;
	}
	else if (wdev->AuthMode==Ndis802_11AuthModeWPANone
	&& wdev->WepStatus == Ndis802_11TKIPEnable)
	{
		EncrypType = ENCRYPT_WPANONE_TKIP;
	}
	else if (wdev->AuthMode==Ndis802_11AuthModeWPANone
	&& wdev->WepStatus == Ndis802_11AESEnable)
	{
		EncrypType = ENCRYPT_WPANONE_AES;
	}
	else
	{
		DBGPRINT(RT_DEBUG_ERROR,
			("%s: Can not find correct mesh security ,return OPEN_NONE Auth:%d WepStatus:%d \n",
			__FUNCTION__, wdev->AuthMode,wdev->WepStatus));
	}


	return EncrypType;
}

UCHAR MeshCheckPeerMpCipher(
		IN USHORT 		 CapabilityInfo, 
		IN PUCHAR 		 pVIE,
		IN USHORT		 LenVIE)
{
	UCHAR	EncrypType = ENCRYPT_OPEN_NONE;
	
	if (CAP_IS_PRIVACY_ON(CapabilityInfo))
	{
		PUCHAR  		pVarIEs;
		USHORT			VarIELen;				
		PEID_STRUCT     pEid;

		EncrypType = ENCRYPT_OPEN_WEP;
			
		pVarIEs  = pVIE;
		VarIELen = LenVIE;
		
		while (VarIELen > 0)
		{
			pEid = (PEID_STRUCT) pVarIEs;

			if ((pEid->Eid == IE_WPA) && (VarIELen > (sizeof(RSNIE) + 2)) && (NdisEqualMemory(pEid->Octet, WPA_OUI, 4)))
			{
				RSNIE	*pRsnie;

				pRsnie = (RSNIE*)pEid->Octet;

				if(RTMPEqualMemory(OUI_WPA_TKIP, pRsnie->ucast[0].oui, 4))						
				EncrypType = ENCRYPT_WPANONE_TKIP;
				else if (RTMPEqualMemory(OUI_WPA_CCMP, pRsnie->ucast[0].oui, 4))			
				EncrypType = ENCRYPT_WPANONE_AES;			

				break;
		}
			/* For WPA2/WPA2PSK */
#if 0
			else if ((pEid->Eid == IE_RSN) && (VarIELen > sizeof(RSNIE2)) && (NdisEqualMemory(pEid->Octet + 2, RSN_OUI, 3)))
		{
				/* Not implement yet */
			}
#endif
			
			pVarIEs   += (pEid->Len + 2);
			VarIELen  -= (pEid->Len + 2);
		}
														
	}

	return EncrypType;
}

BOOLEAN MeshAllowToSendPacket(
	IN RTMP_ADAPTER *pAd,
	IN struct wifi_dev *wdev,
	IN PNDIS_PACKET pPacket,
	OUT UCHAR		*pWcid)
{
	BOOLEAN	allowed = FALSE;
	PMESH_PROXY_ENTRY	pMeshProxyEntry = NULL;
	PUCHAR pSrcBufVA = GET_OS_PKT_DATAPTR(pPacket);
//+++Add by shiang for merge code
	PMESH_STRUCT pMesh;

	pMesh = (PMESH_STRUCT)&pAd->MeshTab;
	do
	{
		if (MeshValid(pMesh) != TRUE)
			break;
		/* find the device in our Mesh list */
		if (pMesh->wdev.if_dev == pDev)
		{
			/* ya! find it */
			pAd->RalinkCounters.PendingNdisPacketCount ++;
			RTMP_SET_PACKET_MOREDATA(pPktSrc, FALSE);
			RTMP_SET_PACKET_WDEV(pPktSrc, wdev->wdev_idx);
			SET_OS_PKT_NETDEV(pPktSrc, pAd->net_dev);
#ifdef RELEASE_EXCLUDE			
			if (!(*(GET_OS_PKT_DATAPTR(pPktSrc)) & 0x01))
			{
				DBGPRINT(RT_DEBUG_INFO,
							("%s(Mesh) - unicast packet to "
							"(Mesh0)\n", __FUNCTION__));
			}
 #endif /* RELEASE_EXCLUDE */


			/* transmit the packet */
			return Func(RTPKT_TO_OSPKT(pPktSrc));
		}
    } while(FALSE);
//---Add by shiang for merge code


	if (MESH_ON(pAd))
	{
		LONG RouteId = PathRouteIDSearch(pAd, pSrcBufVA);

		if (!MAC_ADDR_EQUAL(pAd->MeshTab.wdev.if_addr, pSrcBufVA + MAC_ADDR_LEN))
		{
			if ((pAd->MeshTab.OpMode & MESH_AP) || (pAd->MeshTab.OpMode & MESH_POTAL))
			{
				pMeshProxyEntry = MeshProxyEntryTableLookUp(pAd, pSrcBufVA + MAC_ADDR_LEN);

				if (!pMeshProxyEntry)
					pMeshProxyEntry = MeshProxyEntryTableInsert(pAd, pAd->MeshTab.wdev.if_addr, pSrcBufVA + MAC_ADDR_LEN);
			}
			else
			{
#ifdef RELEASE_EXCLUDE
				/*if we r not MAP or MP with proxy , we will drop all packets which sa is not us. */
				/*if MP is bridged , it must enable proxy or layer 3 packets will not be forwarded correctly */
				/*because bridge mac will not be the same as MP wireless card mac. */
#endif /* RELEASE_EXCLUDE */
				return FALSE;
			}
		}

		if (RouteId == BMCAST_ROUTE_ID)
		{
			MeshClonePacket(pAd, pPacket, MESH_PROXY, 0);
		}
		else if (RouteId >= 0)
		{
			INT LinkId;

			LinkId = PathMeshLinkIDSearch(pAd, RouteId);
			if ((LinkId >= 0) && VALID_MESH_LINK_ID(LinkId))
			{
				*pWcid = pAd->MeshTab.MeshLink[LinkId].Entry.MacTabMatchWCID;
				RTMP_SET_MESH_ROUTE_ID(pPacket, (UINT8)RouteId);

				/* MESH_PROXY indicate the packet come from os layer to mesh0 virtual interface. */
				RTMP_SET_MESH_SOURCE(pPacket, MESH_PROXY);
				allowed = TRUE;
			}
		}
		else
		{
			/* entity is not exist, start path discovery. */
			if (MAC_ADDR_EQUAL(pSrcBufVA + MAC_ADDR_LEN, pAd->MeshTab.wdev.if_addr))
				MeshCreatePreqAction(pAd, NULL, pSrcBufVA);
			else
				MeshCreatePreqAction(pAd, pSrcBufVA + MAC_ADDR_LEN, pSrcBufVA);
		}
	}
 
	return allowed;
}


VOID PerpareMeshHeader(
	IN RTMP_ADAPTER *pAd,
	IN TX_BLK *pTxBlk,
	OUT PMESH_FLAG pMeshFlag,
	OUT UINT16 *pMeshTTL,
	OUT UINT32 *pMeshSeq,
	OUT PUCHAR *ppMeshAddr5,
	OUT PUCHAR *ppMeshAddr6)
{
	UINT MeshHdrLen = 0;
	PNDIS_PACKET pPacket = pTxBlk->pPacket;
	PUCHAR pSrcBufVA = GET_OS_PKT_DATAPTR(pPacket);
	UINT8 TXWISize = pAd->chipCap.TXWISize;
	PHEADER_802_11 pHeader_802_11 = (PHEADER_802_11)&pTxBlk->HeaderBuf[TXINFO_SIZE + pAd->chipCap.TXWISize];

	if (RTMP_GET_MESH_SOURCE(pPacket) == MESH_PROXY)
	{
		pMeshFlag->word = 0;
		*pMeshTTL = pAd->MeshTab.TTL;
		*pMeshSeq = INC_MESH_SEQ(pAd->MeshTab.MeshSeq);
		if (( (*pSrcBufVA & 0x01) /* B/Mcast packet. */
				|| MAC_ADDR_EQUAL(pSrcBufVA, pHeader_802_11->Addr3)) /* or DA is a MP. */
			&& MAC_ADDR_EQUAL(pSrcBufVA + MAC_ADDR_LEN, pAd->MeshTab.wdev.if_addr))
		{	
#ifdef RELEASE_EXCLUDE
			/* the packet if come from current MP to another MP. */
			/* Since DA equal to MesH DA, and SA equal to current MP's MAC addr. */
#endif /* RELEASE_EXCLUDE */
			pMeshFlag->field.AE = 0;
			*ppMeshAddr5 = NULL;
			*ppMeshAddr6 = NULL;
		}
		else
		{
			pMeshFlag->field.AE = 2;
			*ppMeshAddr5 = pSrcBufVA;
			*ppMeshAddr6 = pSrcBufVA + MAC_ADDR_LEN;
		}
	}
	else
	{
#ifdef RELEASE_EXCLUDE
		/* must be MESH_FORWARD here. */
		/* shift pSrcBufVA pointer to Mesh header. */
#endif /* RELEASE_EXCLUDE */
		pSrcBufVA += LENGTH_802_3;
		MeshHdrLen = GetMeshHederLen(pSrcBufVA);
		pMeshFlag->word = GetMeshFlag(pSrcBufVA);
		*pMeshTTL = GetMeshTTL(pSrcBufVA) - 1;
		*pMeshSeq = GetMeshSeq(pSrcBufVA);
		*ppMeshAddr5 = GetMeshAddr5(pSrcBufVA);
		*ppMeshAddr6 = GetMeshAddr6(pSrcBufVA);

		if (NdisEqualMemory(SNAP_802_1H, pTxBlk->pSrcBufData + MeshHdrLen, 6)  || NdisEqualMemory(SNAP_BRIDGE_TUNNEL, pTxBlk->pSrcBufData + MeshHdrLen, 6))             
		{
			/* skip Mesh header and LLC Header (8 Bytes). */
			pTxBlk->pSrcBufData = pTxBlk->pSrcBufData + MeshHdrLen + 8;
			pTxBlk->SrcBufLen  -= (MeshHdrLen + 8);
		}
		else
		{
			pTxBlk->pSrcBufData = pTxBlk->pSrcBufData + MeshHdrLen;
			pTxBlk->SrcBufLen  -= (MeshHdrLen);		
		}
	}

	return;
}

BOOLEAN MeshChCheck(
	IN RTMP_ADAPTER *pAd,
	IN PMESH_NEIGHBOR_ENTRY pNeighborEntry)
{
	BOOLEAN result = FALSE;
	
#ifdef DOT11_N_SUPPORT
	if (WMODE_CAP_N(pAd->CommonCfg.PhyMode)
		&& (pAd->CommonCfg.RegTransmitSetting.field.BW == BW_40)
		&& (pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth == BW_40)
		&& (pNeighborEntry->ChBW == BW_40)
		)
	{
		result = ((pNeighborEntry->Channel == pAd->CommonCfg.Channel)
					&& (pNeighborEntry->ChBW == pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth)
					&& (pNeighborEntry->ExtChOffset == pAd->CommonCfg.AddHTInfo.AddHtInfo.ExtChanOffset)) ? TRUE : FALSE;
	}
	else
#endif /* DOT11_N_SUPPORT */
	{	
		result = (pNeighborEntry->Channel == pAd->CommonCfg.Channel) ? TRUE : FALSE;
	}


	return result;
}

/*
	==========================================================================
	Description:
		Pre-build a BEACON frame in the shared memory
	==========================================================================
*/
VOID MeshMakeBeacon(
	IN PRTMP_ADAPTER	pAd,
	IN UCHAR			idx)
{
	UCHAR DsLen = 1, SsidLen, *tmac_info = (UCHAR *)(&pAd->BeaconTxWI);
	UCHAR RSNIe=IE_WPA;
	HEADER_802_11 BcnHdr;
	LARGE_INTEGER FakeTimestamp;
	ULONG FrameLen = 0;
	PUCHAR pBeaconFrame = (PUCHAR)pAd->MeshTab.BeaconBuf;
	UCHAR *ptr;
	UINT i;
	UINT32 longValue;
	UCHAR ASupRate[] = {0x8C, 0x12, 0x98, 0x24, 0xb0, 0x48, 0x60, 0x6C};
	UCHAR ASupRateLen = sizeof(ASupRate)/sizeof(UCHAR);
	ULONG TmpLen;
	HTTRANSMIT_SETTING BeaconTransmit;   /* MGMT frame PHY rate setting when operatin at Ht rate. */
	UINT8 TXWISize = pAd->chipCap.TXWISize;
	struct wifi_dev *wdev;
	MAC_TX_INFO mac_info;

	/* ignore SSID for MP. Refer to IEEE 802.11s-D1.06 */
	SsidLen = 0;
	wdev = &pAd->MeshTab.wdev;
	if (pAd->MeshTab.bcn_buf.bBcnSntReq == FALSE)
		return;

#ifdef RTMP_MAC_USB
	RTUSBBssBeaconStop(pAd);
#endif /* RTMP_MAC_USB */

	DBGPRINT(RT_DEBUG_TRACE, ("MeshMakeBeacon - %02x:%02x:%02x:%02x:%02x:%02x\n",
					PRINT_MAC(wdev->if_addr)));
	MgtMacHeaderInit(pAd, &BcnHdr, SUBTYPE_BEACON, 0, BROADCAST_ADDR,
						wdev->if_addr, wdev->if_addr);

	if (wdev->AuthMode == Ndis802_11AuthModeWPANone)		
		RSNIe = IE_WPA;
	else if ((wdev->AuthMode == Ndis802_11AuthModeWPA2) || 
			(wdev->AuthMode == Ndis802_11AuthModeWPA2PSK))
		RSNIe = IE_WPA2;
	
	/* for update framelen to TxWI later. */
	MakeOutgoingFrame(pBeaconFrame,                  &FrameLen,
					sizeof(HEADER_802_11),           &BcnHdr, 
					TIMESTAMP_LEN,                   &FakeTimestamp,
					2,                               &pAd->CommonCfg.BeaconPeriod,
					2,                               &pAd->MeshTab.CapabilityInfo,
					1,                               &SsidIe, 
					1,                               &SsidLen,
					END_OF_ARGS);

	if (pAd->CommonCfg.Channel <= 14)
	{
		MakeOutgoingFrame(pBeaconFrame+FrameLen,         &TmpLen,
					1,                               &SupRateIe, 
					1,                               &pAd->CommonCfg.SupRateLen,
					pAd->CommonCfg.SupRateLen,       pAd->CommonCfg.SupRate, 
						END_OF_ARGS);
		FrameLen += TmpLen;
	}
	else
	{
		MakeOutgoingFrame(pBeaconFrame+FrameLen,         &TmpLen,
						1,                               &SupRateIe, 
						1,                               &ASupRateLen,
						pAd->CommonCfg.SupRateLen,       ASupRate, 
						END_OF_ARGS);
		FrameLen += TmpLen;
	}

	MakeOutgoingFrame(pBeaconFrame+FrameLen,         &TmpLen,
					1,                               &DsIe, 
					1,                               &DsLen, 
					1,                               &pAd->MeshTab.MeshChannel,
					END_OF_ARGS);
	FrameLen += TmpLen;

#ifdef RELEASE_EXCLUDE
	/* 5G band supported rates all list on support rate IE. */
	/* no necessary extending rate here. */
#endif /* RELEASE_EXCLUDE */
	if ((pAd->CommonCfg.Channel <= 14)
		&& (pAd->CommonCfg.ExtRateLen))
	{
		MakeOutgoingFrame(pBeaconFrame+FrameLen,         &TmpLen,
						1,                               &ExtRateIe, 
						1,                               &pAd->CommonCfg.ExtRateLen,
						pAd->CommonCfg.ExtRateLen,           pAd->CommonCfg.ExtRate, 
						END_OF_ARGS);
		FrameLen += TmpLen;
	}

	/* Append RSN_IE when  WPA OR WPAPSK, */
	if (wdev->AuthMode >= Ndis802_11AuthModeWPA)
	{
		MakeOutgoingFrame(pBeaconFrame+FrameLen,        &TmpLen,
						  1,                            &RSNIe,
						  1,                            &pAd->MeshTab.RSNIE_Len,
						  pAd->MeshTab.RSNIE_Len,      	pAd->MeshTab.RSN_IE,
						  END_OF_ARGS);
		FrameLen += TmpLen;
	}
        
#ifdef DOT11_N_SUPPORT
	/* AP Channel Report */
	if (pAd->CommonCfg.PhyMode == (WMODE_B | WMODE_G | WMODE_GN)
		&& ((pAd->CommonCfg.HT_DisallowTKIP == FALSE)
			|| (pAd->CommonCfg.HT_DisallowTKIP
				&& !IS_INVALID_HT_SECURITY(wdev->WepStatus))) 
		) /*wayne_note */
	{
		UCHAR APChannelReportIe = IE_AP_CHANNEL_REPORT;
		ULONG	TmpLen;

		/* 802.11n D2.0 Annex J */
		/* USA */
		/* regulatory class 32, channel set 1~7 */
		/* regulatory class 33, channel set 5-11 */

		UCHAR rclass32[]={32, 1, 2, 3, 4, 5, 6, 7};
        UCHAR rclass33[]={33, 5, 6, 7, 8, 9, 10, 11};
		UCHAR rclasslen = 8; /*sizeof(rclass32); */

		
			MakeOutgoingFrame(pBeaconFrame+FrameLen,&TmpLen,
							  1,                    &APChannelReportIe,
							  1,                    &rclasslen,
							  rclasslen,            rclass32,
   							  1,                    &APChannelReportIe,
							  1,                    &rclasslen,
							  rclasslen,            rclass33,
							  END_OF_ARGS);
			FrameLen += TmpLen;		
		}
#endif /* DOT11_N_SUPPORT */
    
	BeaconTransmit.word = 0;

	NdisZeroMemory((UCHAR *)&mac_info, sizeof(mac_info));	
	mac_info.FRAG = FALSE;
	
	mac_info.CFACK = FALSE;
	mac_info.InsTimestamp = TRUE;
	mac_info.AMPDU = FALSE;
	
	mac_info.BM = 1;
	mac_info.Ack = FALSE;
	mac_info.NSeq = TRUE;
	mac_info.BASize = 0;
	
	mac_info.WCID = BSS0Mcast_WCID;
	mac_info.Length = FrameLen;
	mac_info.PID = PID_MGMT;
	
	mac_info.TID = 0;
	mac_info.TxRate = 0;
	mac_info.Txopmode = IFS_HTTXOP;
	mac_info.Preamble = LONG_PREAMBLE;
	// TODO: shiang-MT7603
	mac_info.q_idx = Q_IDX_BCN;

	mac_info.SpeEn = 1;

	write_tmac_info(pAd, tmac_info, &mac_info, &BeaconTransmit);

	/*
		step 6. move BEACON TXD and frame content to on-chip memory
	*/
	ptr = (PUCHAR)&pAd->BeaconTxWI;
#ifdef RT_BIG_ENDIAN
    RTMPWIEndianChange(pAd, ptr, TYPE_TXWI);
#endif


	for (i=0; i<TXWISize; i+=4)
	{
		longValue =  *ptr + (*(ptr+1)<<8) + (*(ptr+2)<<16) + (*(ptr+3)<<24);
		RTMP_CHIP_UPDATE_BEACON(pAd, pAd->BeaconOffset[idx] + i, longValue, 4);
		ptr +=4;
	}


	/* update BEACON frame content. start right after the 24-byte TXINFO field */
	ptr = (PUCHAR)pAd->MeshTab.BeaconBuf;
#ifdef RT_BIG_ENDIAN
    RTMPFrameEndianChange(pAd, ptr, DIR_WRITE, FALSE);
#endif


	for (i= 0; i< FrameLen; i+=4)
	{
		longValue =  *ptr + (*(ptr+1)<<8) + (*(ptr+2)<<16) + (*(ptr+3)<<24);
		RTMP_CHIP_UPDATE_BEACON(pAd, pAd->BeaconOffset[idx] + TXWISize + i, longValue, 4);
		ptr += 4;
	}


	pAd->MeshTab.TimIELocationInBeacon = (UCHAR)FrameLen; 
	pAd->MeshTab.bcn_buf.cap_ie_pos = sizeof(HEADER_802_11) + TIMESTAMP_LEN + 2;

#ifdef RTMP_MAC_USB
	RTUSBBssBeaconStart(pAd);
#endif /* RTMP_MAC_USB */

#ifdef CONFIG_STA_SUPPORT
	// TODO: shiang-7603
	if (pAd->chipCap.hif_type != HIF_MT) {
		RTMP_IO_READ32(pAd, MAC_BSSID_DW1, &longValue);
		longValue &= 0x0000FFFF;
		RTMP_IO_WRITE32(pAd, MAC_BSSID_DW1, longValue);
	}
#endif /* CONFIG_STA_SUPPORT */

}

/*
	==========================================================================
	Description:
		Update the BEACON frame in the shared memory. Because TIM IE is variable
		length. other IEs after TIM has to shift and total frame length may change
		for each BEACON period.
	Output:
		pAd->ApCfg.MBSSID[apidx].CapabilityInfo
		pAd->ApCfg.ErpIeContent
	==========================================================================
*/
VOID MeshUpdateBeaconFrame(
	IN PRTMP_ADAPTER	pAd,
	IN UCHAR			idx) 
{
	PUCHAR pBeaconFrame = (PUCHAR)pAd->MeshTab.BeaconBuf;
	UCHAR *ptr;
	ULONG FrameLen = pAd->MeshTab.TimIELocationInBeacon;
	ULONG UpdatePos = pAd->MeshTab.TimIELocationInBeacon;
	HTTRANSMIT_SETTING BeaconTransmit;   /* MGMT frame PHY rate setting when operatin at Ht rate. */
	struct wifi_dev *wdev;
	MAC_TX_INFO mac_info;

	if (pAd->MeshTab.bcn_buf.bBcnSntReq == FALSE)
		return;

	/* The beacon of mesh isn't be initialized */
	if (FrameLen == 0)
		return;

	wdev = &pAd->MeshTab.wdev;
	/* */
	/* step 1 - update BEACON's Capability */
	/* */
	ptr = pBeaconFrame + pAd->MeshTab.bcn_buf.cap_ie_pos;
	*ptr = (UCHAR)(pAd->MeshTab.CapabilityInfo & 0x00ff);
	*(ptr+1) = (UCHAR)((pAd->MeshTab.CapabilityInfo & 0xff00) >> 8);

#ifdef DOT11_N_SUPPORT
	/* */
	/* step 5. Update HT. Since some fields might change in the same BSS. */
	/* */
	if (WMODE_CAP_N(pAd->CommonCfg.PhyMode)
		&& ((pAd->CommonCfg.HT_DisallowTKIP == FALSE)
		|| (pAd->CommonCfg.HT_DisallowTKIP
			&& !IS_INVALID_HT_SECURITY(wdev->WepStatus))) 
	) /*wayne_note */
	{
		ULONG TmpLen;
		UCHAR HtLen, HtLen1;
		/*UCHAR i; */

#ifdef RT_BIG_ENDIAN
		HT_CAPABILITY_IE HtCapabilityTmp;
		ADD_HT_INFO_IE	addHTInfoTmp;
		USHORT	b2lTmp, b2lTmp2;
#endif

		/* add HT Capability IE */
		HtLen = sizeof(pAd->CommonCfg.HtCapability);
		HtLen1 = sizeof(pAd->CommonCfg.AddHTInfo);
#ifndef RT_BIG_ENDIAN
		MakeOutgoingFrame(pBeaconFrame+FrameLen,         &TmpLen,
								  1,                                &HtCapIe,
								  1,                                &HtLen,
								 HtLen,          &pAd->CommonCfg.HtCapability, 
								  1,                                &AddHtInfoIe,
								  1,                                &HtLen1,
								 HtLen1,          &pAd->CommonCfg.AddHTInfo, 
						  END_OF_ARGS);
#else
		NdisMoveMemory(&HtCapabilityTmp, &pAd->CommonCfg.HtCapability, HtLen);
		*(USHORT *)(&HtCapabilityTmp.HtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.HtCapInfo));
		*(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo));

		NdisMoveMemory(&addHTInfoTmp, &pAd->CommonCfg.AddHTInfo, HtLen1);
		*(USHORT *)(&addHTInfoTmp.AddHtInfo2) = SWAP16(*(USHORT *)(&addHTInfoTmp.AddHtInfo2));
		*(USHORT *)(&addHTInfoTmp.AddHtInfo3) = SWAP16(*(USHORT *)(&addHTInfoTmp.AddHtInfo3));

		MakeOutgoingFrame(pBeaconFrame+FrameLen,         &TmpLen,
								  1,                                &HtCapIe,
								  1,                                &HtLen,
								 HtLen,                   &HtCapabilityTmp, 
								  1,                                &AddHtInfoIe,
								  1,                                &HtLen1,
								 HtLen1,                   &addHTInfoTmp, 
						  END_OF_ARGS);
#endif
		FrameLen += TmpLen;

	}
#endif /* DOT11_N_SUPPORT */

#if 0	/* remove it temporarily */
	/* add WMM IE here */
	if (pAd->ApCfg.MBSSID[apidx].wdev.bWmmCapable)
	{
		ULONG TmpLen;
		UCHAR i;
		UCHAR WmeParmIe[26] = {IE_VENDOR_SPECIFIC, 24, 0x00, 0x50, 0xf2, 0x02, 0x01, 0x01, 0, 0}; 
		WmeParmIe[8] = pAd->ApCfg.BssEdcaParm.EdcaUpdateCount & 0x0f;
#ifdef UAPSD_SUPPORT
        UAPSD_MR_IE_FILL(WmeParmIe[8], pAd);
#endif /* UAPSD_SUPPORT */
		for (i=QID_AC_BE; i<=QID_AC_VO; i++)
		{
			WmeParmIe[10+ (i*4)] = (i << 5)                                         +     /* b5-6 is ACI */
								   ((UCHAR)pAd->ApCfg.BssEdcaParm.bACM[i] << 4)     +     /* b4 is ACM */
								   (pAd->ApCfg.BssEdcaParm.Aifsn[i] & 0x0f);              /* b0-3 is AIFSN */
			WmeParmIe[11+ (i*4)] = (pAd->ApCfg.BssEdcaParm.Cwmax[i] << 4)           +     /* b5-8 is CWMAX */
								   (pAd->ApCfg.BssEdcaParm.Cwmin[i] & 0x0f);              /* b0-3 is CWMIN */
			WmeParmIe[12+ (i*4)] = (UCHAR)(pAd->ApCfg.BssEdcaParm.Txop[i] & 0xff);        /* low byte of TXOP */
			WmeParmIe[13+ (i*4)] = (UCHAR)(pAd->ApCfg.BssEdcaParm.Txop[i] >> 8);          /* high byte of TXOP */
		}

		MakeOutgoingFrame(pBeaconFrame+FrameLen,         &TmpLen,
						  26,                            WmeParmIe,
						  END_OF_ARGS);
		FrameLen += TmpLen;
	}
#endif

#ifdef DOT11_N_SUPPORT
	if (WMODE_CAP_N(pAd->CommonCfg.PhyMode)
		&& ((pAd->CommonCfg.HT_DisallowTKIP == FALSE)
 		|| (pAd->CommonCfg.HT_DisallowTKIP 
			&& !IS_INVALID_HT_SECURITY(wdev->WepStatus))) 
		)/*wayne_note */
	{
		ULONG TmpLen;
		UCHAR HtLen, HtLen1;
		/*UCHAR i; */
#ifdef RT_BIG_ENDIAN
		HT_CAPABILITY_IE HtCapabilityTmp;
		ADD_HT_INFO_IE	addHTInfoTmp;
		USHORT	b2lTmp, b2lTmp2;
#endif
		/* add HT Capability IE */
		HtLen = sizeof(pAd->CommonCfg.HtCapability);
		HtLen1 = sizeof(pAd->CommonCfg.AddHTInfo);

		if (pAd->bBroadComHT == TRUE)
		{
			UCHAR epigram_ie_len;
			UCHAR BROADCOM_HTC[4] = {0x0, 0x90, 0x4c, 0x33};
			UCHAR BROADCOM_AHTINFO[4] = {0x0, 0x90, 0x4c, 0x34};


			epigram_ie_len = HtLen + 4;
#ifndef RT_BIG_ENDIAN
			MakeOutgoingFrame(pBeaconFrame + FrameLen,      &TmpLen,
						  1,                                &WpaIe,
						  1,                                &epigram_ie_len,
						  4,                                &BROADCOM_HTC[0],
						  HtLen,          					&pAd->CommonCfg.HtCapability, 
						  END_OF_ARGS);
#else
			NdisMoveMemory(&HtCapabilityTmp, &pAd->CommonCfg.HtCapability, HtLen);
			*(USHORT *)(&HtCapabilityTmp.HtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.HtCapInfo));
			*(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo));

			MakeOutgoingFrame(pBeaconFrame + FrameLen,       &TmpLen,
						1,                               &WpaIe,
						1,                               &epigram_ie_len,
						4,                               &BROADCOM_HTC[0], 
						HtLen,                           &HtCapabilityTmp,
						END_OF_ARGS);
#endif

			FrameLen += TmpLen;

			epigram_ie_len = HtLen1 + 4;
#ifndef RT_BIG_ENDIAN
			MakeOutgoingFrame(pBeaconFrame + FrameLen,        &TmpLen,
						  1,                                &WpaIe,
						  1,                                &epigram_ie_len,
						  4,                                &BROADCOM_AHTINFO[0],
						  HtLen1, 							&pAd->CommonCfg.AddHTInfo, 
						  END_OF_ARGS);
#else
			NdisMoveMemory(&addHTInfoTmp, &pAd->CommonCfg.AddHTInfo, HtLen1);
			*(USHORT *)(&addHTInfoTmp.AddHtInfo2) = SWAP16(*(USHORT *)(&addHTInfoTmp.AddHtInfo2));
			*(USHORT *)(&addHTInfoTmp.AddHtInfo3) = SWAP16(*(USHORT *)(&addHTInfoTmp.AddHtInfo3));

			MakeOutgoingFrame(pBeaconFrame + FrameLen,         &TmpLen,
							1,                             &WpaIe,
							1,                             &epigram_ie_len,
							4,                             &BROADCOM_AHTINFO[0],
							HtLen1,                        &addHTInfoTmp,
							END_OF_ARGS);
#endif
			FrameLen += TmpLen;
		}

	}

	/* P802.11n_D1.10 */
	/* 7.3.2.27 Extended Capabilities IE */
	/* HT Information Exchange Support */
	if (WMODE_CAP_N(pAd->CommonCfg.PhyMode)
		&& ((pAd->CommonCfg.HT_DisallowTKIP == FALSE) 
		|| (pAd->CommonCfg.HT_DisallowTKIP 
			&& !IS_INVALID_HT_SECURITY(wdev->WepStatus))) 
		) /*wayne_note */
	{
		ULONG TmpLen;
		UCHAR ExtCapIe[3] = {IE_EXT_CAPABILITY, 1, 0x01};
		MakeOutgoingFrame(pBeaconFrame+FrameLen, &TmpLen,
							3,                   ExtCapIe,
							END_OF_ARGS);
		FrameLen += TmpLen;

	}
#endif /* DOT11_N_SUPPORT */

   	/* add Ralink-specific IE here - Byte0.b0=1 for aggregation, Byte0.b1=1 for piggy-back */
   	if ((pAd->CommonCfg.HT_DisallowTKIP == FALSE) || (pAd->CommonCfg.HT_DisallowTKIP && !IS_INVALID_HT_SECURITY(wdev->WepStatus)))	
	{/*wayne_note */
		ULONG TmpLen;
		UCHAR RalinkSpecificIe[9] = {IE_VENDOR_SPECIFIC, 7, 0x00, 0x0c, 0x43, 0x00, 0x00, 0x00, 0x00};

		if (pAd->CommonCfg.bAggregationCapable)
			RalinkSpecificIe[5] |= 0x1;
		if (pAd->CommonCfg.bPiggyBackCapable)
			RalinkSpecificIe[5] |= 0x2;
#ifdef DOT11_N_SUPPORT
		if (pAd->CommonCfg.bRdg)
			RalinkSpecificIe[5] |= 0x4;
#endif /* DOT11_N_SUPPORT */
		MakeOutgoingFrame(pBeaconFrame+FrameLen, &TmpLen,
							9,                   RalinkSpecificIe,
							END_OF_ARGS);
		FrameLen += TmpLen;
	}
	
	/* Insert MeshIDIE and MeshConfigurationIE in Beacon frame */
	/*if (MeshValid(&pAd->MeshTab)) */
	{
		pAd->MeshTab.MeshCapability.field.AcceptPeerLinks = MeshAcceptPeerLink(pAd);
		InsertMeshIdIE(pAd, pBeaconFrame+FrameLen, &FrameLen);
		InsertMeshConfigurationIE(pAd, pBeaconFrame+FrameLen, &FrameLen, FALSE);
		InsertMeshHostNameIE(pAd, pBeaconFrame+FrameLen, &FrameLen);
	}
	
	/* Insert MSCIE */
	InsertMSCIE(pAd, pBeaconFrame+FrameLen, &FrameLen);
	
	/* */
	/* step 6. Since FrameLen may change, update TXWI. */
	/* */
	/* Update in real buffer */
	/* Update sw copy. */
	if (pAd->CommonCfg.Channel <= 14)
		BeaconTransmit.word = 0;
	else
		BeaconTransmit.word = 0x4000;
	
	NdisZeroMemory((UCHAR *)&mac_info, sizeof(mac_info));	
	mac_info.FRAG = FALSE;
	
	mac_info.CFACK = FALSE;
	mac_info.InsTimestamp = TRUE;
	mac_info.AMPDU = FALSE;
	
	mac_info.BM = 1;
	mac_info.Ack = FALSE;
	mac_info.NSeq = TRUE;
	mac_info.BASize = 0;
	
	mac_info.WCID = RESERVED_WCID;
	mac_info.Length = FrameLen;
	mac_info.PID = PID_MGMT;
	
	mac_info.TID = QID_MGMT;
	mac_info.TxRate = 0;
	mac_info.Txopmode = IFS_HTTXOP;
	mac_info.Preamble = LONG_PREAMBLE;
	// TODO: shiang-MT7603
	mac_info.q_idx = Q_IDX_BCN;

	mac_info.SpeEn = 1;

	write_tmac_info(pAd, (UCHAR *)&pAd->BeaconTxWI, &mac_info, &BeaconTransmit);

	/*
		step 7. move BEACON TXWI and frame content to on-chip memory
	*/
	RT28xx_UpdateBeaconToAsic(pAd, idx + MIN_NET_DEVICE_FOR_MESH, FrameLen, UpdatePos);
}

VOID MeshCleanBeaconFrame(
	IN PRTMP_ADAPTER	pAd,
	IN UCHAR			idx) 
{
	INT i;
	UINT8 TXWISize = pAd->chipCap.TXWISize;


	/* when the ra interface is down, do not send its beacon frame */
	/* clear all zero */
	for(i=0; i < TXWISize; i+=4)
		RTMP_CHIP_UPDATE_BEACON(pAd, pAd->BeaconOffset[idx] + i, 0, 4);



}

/*
	==========================================================================
	Description:
	Note: 
		BEACON frame in shared memory should be built ok before this routine
		can be called. Otherwise, a garbage frame maybe transmitted out every
		Beacon period.
 
	==========================================================================
 */
VOID AsicEnableMESHSync(
	IN PRTMP_ADAPTER pAd)
{
	BCN_TIME_CFG_STRUC csr;

	// TODO: shiang-7603
	if (pAd->chipCap.hif_type == HIF_MT) {
		DBGPRINT(RT_DEBUG_OFF, ("%s(): Not support for HIF_MT yet!\n",
					__FUNCTION__));
		return FALSE;
	}

	RTMP_IO_READ32(pAd, BCN_TIME_CFG, &csr.word);

#ifdef RELEASE_EXCLUDE
	/* */
	/* For Wi-Fi faily generated beacons between participating stations. */
	/* Set TBTT phase adaptive adjustment step to 8us (default 16us) */
	/* don't change settings 2006-5- by Jerry */
	/* RTMP_IO_WRITE32(pAd, TBTT_SYNC_CFG, 0x00001010); */
#endif /* RELEASE_EXCLUDE */
	
	/* start sending BEACON */
	csr.field.BeaconInterval = pAd->CommonCfg.BeaconPeriod << 4; /* ASIC register in units of 1/16 TU */
	csr.field.bTsfTicking = 1;
	csr.field.TsfSyncMode = 3; /* sync TSF in IBSS mode */
	csr.field.bTBTTEnable = 1;
	csr.field.bBeaconGen = 1;
	RTMP_IO_WRITE32(pAd, BCN_TIME_CFG, csr.word);
}


#ifdef CONFIG_STA_SUPPORT
BOOLEAN MeshWirelessForward(
	IN RTMP_ADAPTER *pAd,
	IN PNDIS_PACKET pPacket,
	IN ULONG wdev_idx)
{
	BOOLEAN bAnnounce, bDirectForward;
	UCHAR *pHeader802_3;
	PNDIS_PACKET pForwardPacket = NULL;
	PNDIS_PACKET pMeshForwardPacket = NULL;
	struct wifi_dev *wdev;
	
	ASSERT(wdev_idx < WDEV_NUM_MAX);

	if (wdev_idx >= WDEV_NUM_MAX)
		return FALSE;

	wdev = pAd->wdev_list[wdev_idx];
	if (wdev->wdev_type != WDEV_TYPE_MESH)
		return TRUE;

	ASSERT(wdev->func_idx < MAX_MESH_LINKS);
	pHeader802_3 = GET_OS_PKT_DATAPTR(pPacket);
	MeshDataPktProcess(pAd, pPacket, wdev->func_idx,
							&pMeshForwardPacket, &bDirectForward, &bAnnounce);

	if (bDirectForward)
	{
		LONG RouteId;

		/* build an NDIS packet */
		if ((bDirectForward == TRUE) && (bAnnounce == TRUE))
			pForwardPacket = pMeshForwardPacket;
		else
			pForwardPacket = DuplicatePacket(wdev->if_dev, pPacket);

		if (pForwardPacket == NULL)
			return bAnnounce;

		RouteId = PathRouteIDSearch(pAd, pHeader802_3);
			if (RouteId == BMCAST_ROUTE_ID)
			{
				MeshClonePacket(pAd, pForwardPacket, MESH_FORWARD, wdev->func_idx);
				/* release packet */
				RELEASE_NDIS_PACKET(pAd, pForwardPacket, NDIS_STATUS_SUCCESS);
			}
			else if (RouteId >= 0)
			{
				INT LinkId;

				LinkId = PathMeshLinkIDSearch(pAd, RouteId);
				if ((LinkId >= 0) && VALID_MESH_LINK_ID(LinkId))
				{
					RTMP_SET_PACKET_WDEV(pForwardPacket, wdev_idx);
					RTMP_SET_PACKET_MOREDATA(pForwardPacket, FALSE);
					RTMP_SET_PACKET_WCID(pForwardPacket,
											pAd->MeshTab.MeshLink[LinkId].Entry.MacTabMatchWCID);
					RTMP_SET_MESH_ROUTE_ID(pForwardPacket, RouteId);
					RTMP_SET_MESH_SOURCE(pForwardPacket, MESH_FORWARD);
					STASendPacket(pAd, pForwardPacket);
				}
				else
				{
					/* release packet */
					RELEASE_NDIS_PACKET(pAd, pForwardPacket, NDIS_STATUS_FAILURE);
				}
			}
			else
			{
				/* entity is not exist. */
				/* start path discovery. */
				MeshCreatePreqAction(pAd, NULL, pHeader802_3);

				/* release packet */
				RELEASE_NDIS_PACKET(pAd, pForwardPacket, NDIS_STATUS_FAILURE);
			}

		RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, WCID_ALL, MAX_TX_PROCESS);
	}
	
	return bAnnounce;
}
#endif /* CONFIG_STA_SUPPORT */


UINT32 MeshAirLinkTime(
	IN PRTMP_ADAPTER pAd,
	IN PMAC_TABLE_ENTRY pMacEntry,
	IN HTTRANSMIT_SETTING HTTxMode)
{
#ifdef RELEASE_EXCLUDE
	/*
		metric = (Phy-Overhead + (Bt / Rate))(1 /(1 - Pkt-Error-Rate))
		Rate: (Mbit / sescon).
		Pkt Error Rate: 
		Bt: 8192.
		Phy-Overhead: 
		   CCK: 75us + 110 us
		   OFDM: 335us + 364us
	*/
#endif /* RELEASE_EXCLUDE */

typedef struct __TX_RATE
{
	UINT8 PhyMode;
	UINT8 MCS;
	UINT8 RateIdx;
	ULONG DataRate;
} _TX_RATE;

_TX_RATE TxRate[] =
{
	{MODE_CCK,    0,   0, 10}, /* 1 Mbps */
	{MODE_CCK,    1,   1, 20}, /* 2 Mbps */
	{MODE_CCK,    2,   2, 55}, /* 5.5 Mbps */
	{MODE_CCK,    3,   3, 110}, /* 11 Mbps */

	{MODE_OFDM,   0,   4, 60}, /* 6 Mbps */
	{MODE_OFDM,   1,   5, 90}, /* 9 Mbps */
	{MODE_OFDM,   2,   6, 120}, /* 12 Mbps */
	{MODE_OFDM,   3,   7, 180}, /* 18 Mbps */
	{MODE_OFDM,   4,   8, 240}, /* 24 Mbps */
	{MODE_OFDM,   5,   9, 360}, /* 36 Mbps */
	{MODE_OFDM,   6,  10, 480}, /* 48 Mbps */
	{MODE_OFDM,   7,  11, 540}, /* 54 Mbps */

#ifdef DOT11_N_SUPPORT
	{MODE_HTMIX,  0,  12, 65}, /* 6.5 Mbps */
	{MODE_HTMIX,  1,  13, 130}, /* 13 Mbps */
	{MODE_HTMIX,  2,  14, 195}, /* 19.5 Mbps */
	{MODE_HTMIX,  3,  15, 260}, /* 26 Mbps */
	{MODE_HTMIX,  4,  16, 390}, /* 39 Mbps */
	{MODE_HTMIX,  5,  17, 520}, /* 52 Mbps */
	{MODE_HTMIX,  6,  18, 585}, /* 58.5 Mbps */
	{MODE_HTMIX,  7,  19, 650}, /* 65 Mbps */
	{MODE_HTMIX,  8,  20, 130}, /* 13 Mbps */
	{MODE_HTMIX,  9,  21, 260}, /* 26 Mbps */
	{MODE_HTMIX, 10,  22, 390}, /* 39 Mbps */
	{MODE_HTMIX, 11,  23, 520}, /* 52 Mbps */
	{MODE_HTMIX, 12,  24, 780}, /* 78 Mbps */
	{MODE_HTMIX, 13,  25, 1040}, /* 104 Mbps */
	{MODE_HTMIX, 14,  26, 1170}, /* 117 Mbps */
	{MODE_HTMIX, 15,  27, 1300}, /* 130 Mbps */
#endif /* DOT11_N_SUPPORT */
};
#define _TX_RATE_TAB_SIZE (sizeof(TxRate) /  sizeof(_TX_RATE))

	INT loopIdx;
	ULONG Rate = 10;
	ULONG ErrRate = 0;
	UINT PhyMode;
	ULONG Metric;
	ULONG PhyOverHead;

	PhyMode = HTTxMode.field.MODE;
#ifdef DOT11_N_SUPPORT
	PhyMode = (HTTxMode.field.MODE > MODE_HTMIX) ?
					MODE_HTMIX : HTTxMode.field.MODE;
#endif /* DOT11_N_SUPPORT */

	for (loopIdx = 0; loopIdx < _TX_RATE_TAB_SIZE; loopIdx++)
	{
		if ((TxRate[loopIdx].PhyMode == HTTxMode.field.MODE)
			&& (TxRate[loopIdx].MCS == HTTxMode.field.MCS))
		{
			Rate = TxRate[loopIdx].DataRate;
			if (pMacEntry != NULL)
				ErrRate = pMacEntry->PER[TxRate[loopIdx].RateIdx] >= 100
							? 99 : pMacEntry->PER[TxRate[loopIdx].RateIdx];
			else
				ErrRate = 0;
			break;
		}
	}

#ifdef DOT11_N_SUPPORT
	if ((PhyMode > MODE_OFDM)
			&& (HTTxMode.field.BW == 1))
	{
		Rate *= 2;
	}
#endif /* DOT11_N_SUPPORT */

	if (PhyMode == MODE_CCK)
		PhyOverHead = 335 + 346;
	else
		PhyOverHead = 75 + 110;

	Metric = (PhyOverHead + (8192 * 10 / Rate)) * (100 /(100 - ErrRate));

	return Metric;
}

UINT32 MESH_LinkMetricUpdate(
	IN PRTMP_ADAPTER pAd,
	IN PCHAR pDestAddr)
{
	PMAC_TABLE_ENTRY pEntry;
	HTTRANSMIT_SETTING HTTxMode;
	ULONG Idx = GetMeshLinkId(pAd, pDestAddr);

	pEntry = MacTableLookup(pAd, (PUCHAR)pDestAddr);
	if (pEntry == NULL)
		HTTxMode.word = pAd->CommonCfg.MlmeTransmit.word;
	else 
		HTTxMode.word = pEntry->HTPhyMode.word;

	if (Idx < MAX_MESH_LINKS)
		pAd->MeshTab.MeshLink[Idx].Entry.Metrics =
			MeshAirLinkTime(pAd, pEntry, HTTxMode);

	return pAd->MeshTab.MeshLink[Idx].Entry.Metrics;
}

VOID EnqueuePeerLinkMetricReport(
	IN PRTMP_ADAPTER pAd,
	IN PUCHAR pDestAddr,
	IN UINT32 Metric)
{
	HEADER_802_11 MeshHdr;
	PUCHAR pOutBuffer = NULL;
	NDIS_STATUS NStatus;
	ULONG FrameLen;
	MESH_FLAG MeshFlag;
	UINT32 MeshSeq = INC_MESH_SEQ(pAd->MeshTab.MeshSeq);

	NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer);  /*Get an unused nonpaged memory */
	if(NStatus != NDIS_STATUS_SUCCESS)
	{
		DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __FUNCTION__));
		return;
	}

	MeshHeaderInit(pAd, &MeshHdr,
		pDestAddr,		/* addr1 */
		pAd->MeshTab.wdev.if_addr,							/* addr2 */
		ZERO_MAC_ADDR);		/* addr3 */
	NdisMoveMemory(pOutBuffer, (PCHAR)&MeshHdr, sizeof(HEADER_802_11));
	FrameLen = sizeof(HEADER_802_11);

	/* Mesh Header */
	MeshFlag.word = 0;
	MeshFlag.field.AE = 0;	/* Peer-Link manager frame never carry 6 addresses. */
	InsertMeshHeader(pAd, (pOutBuffer + FrameLen), &FrameLen, MeshFlag.word,
		pAd->MeshTab.TTL, MeshSeq, NULL, NULL, NULL);

	/* Action field */
	InsertMeshActField(pAd, (pOutBuffer + FrameLen), &FrameLen, CATEGORY_MESH_LINK_METRIC, ACT_CODE_LINK_METRIC_REP);

	/* Insert Link Metric Report IE */
	InsertLinkMetricReportIE(pAd, (pOutBuffer+FrameLen), &FrameLen, Metric);

	MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen);
	MlmeFreeMemory(pAd, pOutBuffer);

	DBGPRINT(RT_DEBUG_TRACE, ("%s: Dest address(%02x:%02x:%02x:%02x:%02x:%02x)\n",
		__FUNCTION__, pDestAddr[0], pDestAddr[1], pDestAddr[2], 
		pDestAddr[4], pDestAddr[4], pDestAddr[5]));

	return;
}

VOID MeshPeerLinkMetricReportProcess(
	IN PRTMP_ADAPTER pAd,
	IN RX_BLK *pRxBlk)
{
	PHEADER_802_11 pHeader = (PHEADER_802_11)pRxBlk->pHeader;
	PUCHAR pFrame;
	ULONG FrameLen;
	UINT MeshLinkId = 0;
	UINT32 LinkMetric;

	do 
	{
		ULONG Idx;
		UCHAR MeshHdrLen;

		Idx = GetMeshLinkId(pAd, (PCHAR)pHeader->Addr2);
		if (Idx == BSS_NOT_FOUND)
		{
			DBGPRINT(RT_DEBUG_TRACE, ("%s() Link Metric Report Ignore, PeerLink Not found.\n", __FUNCTION__));
			return;
		}
		MeshLinkId = (UINT)Idx;

		MeshHdrLen = GetMeshHederLen(pRxBlk->pData);
		/* skip Mesh Header */
		pRxBlk->pData += MeshHdrLen;
		pRxBlk->DataSize -= MeshHdrLen;

		/* skip Category and ActionCode */
		pFrame = (PUCHAR)(pRxBlk->pData + 2);
		FrameLen = pRxBlk->DataSize - 2;

		MeshLinkMetricReportSanity(	pAd,
							pFrame,
							FrameLen,
							&LinkMetric);

		DBGPRINT(RT_DEBUG_TRACE, ("%s: LinkMetric=%d, PeerMac=%02x:%02x:%02x:%02x:%02x:%02x\n",
			__FUNCTION__, LinkMetric, pHeader->Addr2[0], pHeader->Addr2[1],
			pHeader->Addr2[2], pHeader->Addr2[3], pHeader->Addr2[4], pHeader->Addr2[5]));

		pAd->MeshTab.MeshLink[Idx].Entry.Metrics = LinkMetric;
	} while (FALSE);

	return;
}

#ifdef RTMP_MAC_USB
VOID MeshTimerInit(
	IN PRTMP_ADAPTER pAd)
{
#ifndef BCN_OFFLOAD_SUPPORT
	/* for OS_ABL */
	RTMPInitTimer(pAd, &pAd->CommonCfg.BeaconUpdateTimer, GET_TIMER_FUNCTION(BeaconUpdateExec), pAd, TRUE);
#endif
}
#endif /* RTMP_MAC_USB */

VOID MeshCfgInit(RTMP_ADAPTER *pAd, RTMP_STRING *pHostName)
{
	INT	i;

	/* default configuration of Mesh. */
	pAd->MeshTab.OpMode = MESH_MP;

#ifdef CONFIG_AP_SUPPORT
	IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
		pAd->MeshTab.OpMode |= MESH_AP;
#endif /* CONFIG_AP_SUPPORT */

	pAd->MeshTab.PathProtocolId = MESH_HWMP;
	pAd->MeshTab.PathMetricId = MESH_AIRTIME;
	pAd->MeshTab.ContgesionCtrlId = NULL_PROTOCOL;
	pAd->MeshTab.TTL = MESH_TTL;
	pAd->MeshTab.MeshMaxTxRate = 0;
	pAd->MeshTab.MeshMultiCastAgeOut = MULTIPATH_AGEOUT;
	pAd->MeshTab.UCGEnable = FALSE;
	pAd->MeshTab.MeshCapability.field.Forwarding = 1;
	if (pAd->MeshTab.MeshIdLen == 0)
	{
		pAd->MeshTab.MeshIdLen = strlen(DEFAULT_MESH_ID);
		NdisMoveMemory(pAd->MeshTab.MeshId, DEFAULT_MESH_ID, pAd->MeshTab.MeshIdLen);
	}

	/* initialize state */
	pAd->MeshTab.EasyMeshSecurity = TRUE;	/* Default is TRUE for CMPC */
	pAd->MeshTab.bInitialMsaDone = FALSE;
	pAd->MeshTab.bKeyholderDone  = FALSE;
	pAd->MeshTab.bConnectedToMKD = FALSE;
	pAd->MeshTab.MeshOnly = FALSE;

	pAd->MeshTab.wdev.bAutoTxRateSwitch = TRUE;
	pAd->MeshTab.wdev.DesiredTransmitSetting.field.MCS = MCS_AUTO;

	for (i = 0; i < MAX_MESH_LINKS; i++)
		NdisZeroMemory(&pAd->MeshTab.MeshLink[i].Entry, sizeof(MESH_LINK_ENTRY));

	if (strlen(pHostName) > 0)
	{
		if (strlen(pHostName) < MAX_HOST_NAME_LEN)
			strcpy((RTMP_STRING *) pAd->MeshTab.HostName, pHostName);
		else
			strncpy((RTMP_STRING *) pAd->MeshTab.HostName, pHostName, MAX_HOST_NAME_LEN-1);
	}
	else
		strcpy((RTMP_STRING *) pAd->MeshTab.HostName, DEFAULT_MESH_HOST_NAME);

}


VOID MeshInit(
	IN PRTMP_ADAPTER pAd,
	IN RTMP_OS_NETDEV_OP_HOOK *pNetDevOps)
{
#define MESH_MAX_DEV_NUM	32
	PNET_DEV	new_dev_p;
	struct wifi_dev *wdev;

	
	/* sanity check to avoid redundant virtual interfaces are created */
	if (pAd->flg_mesh_init != FALSE)
		return;

#ifdef RELEASE_EXCLUDE
	DBGPRINT(RT_DEBUG_INFO, ("%s --->\n", __FUNCTION__));
#endif /* RELEASE_EXCLUDE */

	wdev = &pAd->MeshTab.wdev;

	/* create virtual network interface */
	do {
		UINT32 MC_RowID = 0, IoctlIF = 0;
		char *dev_name;

#ifdef MULTIPLE_CARD_SUPPORT
		MC_RowID = pAd->MC_RowID;
#endif /* MULTIPLE_CARD_SUPPORT */
#ifdef HOSTAPD_SUPPORT
		IoctlIF = pAd->IoctlIF;
#endif /* HOSTAPD_SUPPORT */

		dev_name = get_dev_name_prefix(pAd, INT_MESH);
		new_dev_p = RtmpOSNetDevCreate(MC_RowID, &IoctlIF, INT_MESH, 0, sizeof(struct mt_dev_priv), dev_name);
#ifdef HOSTAPD_SUPPORT
		pAd->IoctlIF = IoctlIF;
#endif /* HOSTAPD_SUPPORT */
		if (new_dev_p == NULL)
		{
			DBGPRINT(RT_DEBUG_ERROR, ("Allocate network device fail (MESH)...\n"));
			break;
		}

		wdev->wdev_type = WDEV_TYPE_MESH;
		wdev->func_dev = &pAd->MeshTab;
		wdev->func_idx = 0;
		wdev->sys_handle = (void *)pAd;
		wdev->if_dev = new_dev_p; 
		wdev->tx_pkt_allowed = MeshAllowToSendPacket;
		// TODO: shiang-usw, modify this to MeshSendPacket!
		wdev->tx_pkt_handle = APSendPacket;
		wdev->wdev_hard_tx = APHardTransmit;
		wdev->rx_pkt_foward = mesh_rx_foward_handle;

		RTMP_OS_NETDEV_SET_PRIV(new_dev_p, pAd);
		RTMP_OS_NETDEV_SET_WDEV(new_dev_p, wdev);

		if (rtmp_wdev_idx_reg(pAd, wdev) < 0) {
			DBGPRINT(RT_DEBUG_ERROR, ("Assign wdev idx for %s failed, free net device!\n",
						RTMP_OS_NETDEV_GET_DEVNAME(new_dev_p)));
			RtmpOSNetDevFree(new_dev_p);
			break;
		}

		/* init MAC address of virtual network interface */
		COPY_MAC_ADDR(wdev->if_addr, pAd->CurrentAddress);
#ifdef CONFIG_AP_SUPPORT
		if (pAd->chipCap.MBSSIDMode == MBSSID_MODE1)
		{
		if (pAd->ApCfg.BssidNum > 0) 
		{
			/* 	
				Refer to HW definition - 
					Bit1 of MAC address Byte0 is local administration bit 
					and should be set to 1 in extended multiple BSSIDs'
					Bit3~ of MAC address Byte0 is extended multiple BSSID index.
			 */ 
			wdev->if_addr[0] += 2; 	
			wdev->if_addr[0] += ((pAd->ApCfg.BssidNum - 1) << 2);
		}
		}
		else
		{
			wdev->if_addr[MAC_ADDR_LEN - 1] =
					(wdev->if_addr[MAC_ADDR_LEN - 1] + pAd->ApCfg.BssidNum) & 0xFF;
		}
#endif /* CONFIG_AP_SUPPORT */

#if 0 /* os able move */
		/* init operation functions */
#ifdef CONFIG_STA_SUPPORT
#if WIRELESS_EXT >= 12
		if (pAd->OpMode == OPMODE_STA)
		{
			pNetDevOps->iw_handler = (void *)&rt28xx_iw_handler_def;
		}
#endif /*WIRELESS_EXT >= 12 */
#endif /* CONFIG_STA_SUPPORT */

#ifdef CONFIG_APSTA_MIXED_SUPPORT
#if WIRELESS_EXT >= 12
		if (pAd->OpMode == OPMODE_AP)
		{
			pNetDevOps->iw_handler = &rt28xx_ap_iw_handler_def;
		}
#endif /*WIRELESS_EXT >= 12 */
#endif /* CONFIG_APSTA_MIXED_SUPPORT */
#endif /* 0 */

		pNetDevOps->priv_flags = INT_MESH; /* we are virtual interface */
		pNetDevOps->needProtcted = TRUE;
		pNetDevOps->wdev = wdev;
		NdisMoveMemory(&pNetDevOps->devAddr[0], &wdev->if_addr[0], MAC_ADDR_LEN);
		
		/* register this device to OS */
		RtmpOSNetDevAttach(pAd->OpMode, new_dev_p, pNetDevOps);
	} while(FALSE);

	/* Initialize Mesh configuration */
	/*MeshCfgInit(pAd, pHostName); */

	/* initialize Mesh Tables and allocate spin locks */
	NdisAllocateSpinLock(pAd, &pAd->MeshTabLock);

	NeighborTableInit(pAd);
	BMPktSigTabInit(pAd);
	MultipathPoolInit(pAd);

	MeshRoutingTable_Init(pAd);
	MeshEntryTable_Init(pAd);
	MeshProxyEntryTable_Init(pAd);

#ifdef CONFIG_STA_SUPPORT
#ifdef RTMP_MAC_USB
	IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
	{
		MeshTimerInit(pAd);
/*		RTMPInitTimer(pAd, &pAd->CommonCfg.BeaconUpdateTimer, GET_TIMER_FUNCTION(BeaconUpdateExec), pAd, TRUE); */

		RTUSBBssBeaconInit(pAd);
	}
#endif /* RTMP_MAC_USB */
#endif /* CONFIG_STA_SUPPORT */

	pAd->flg_mesh_init = TRUE;
}


INT MESH_OpenPre(PNET_DEV pDev)
{
	PRTMP_ADAPTER pAd;


	pAd = RTMP_OS_NETDEV_GET_PRIV(pDev);
	if (ADHOC_ON(pAd))
		return -1;

	pAd->MeshTab.bcn_buf.bBcnSntReq = TRUE;
	return 0;
}


INT MESH_OpenPost(PNET_DEV pDev)
{
	PRTMP_ADAPTER pAd;


	pAd = RTMP_OS_NETDEV_GET_PRIV(pDev);

	/* Statup Mesh Protocol Stack. */
	MeshUp(pAd);

#ifdef CONFIG_STA_SUPPORT
	AsicSetPreTbtt(pAd, TRUE);
	AsicEnableMESHSync(pAd);
#endif /* CONFIG_STA_SUPPORT */
	return 0;
}


INT MESH_Close(PNET_DEV pDev)
{
	PRTMP_ADAPTER pAd;


	pAd = RTMP_OS_NETDEV_GET_PRIV(pDev);
	MeshDown(pAd, TRUE);

	pAd->MeshTab.bcn_buf.bBcnSntReq = FALSE;

#ifdef CONFIG_STA_SUPPORT
	/* Disable pre-tbtt interrupt */
	AsicSetPreTbtt(pAd, FALSE);

	/*update beacon Sync */
	/*if rausb0 is up => stop beacon */
	/*if rausb0 is down => we will call AsicDisableSync() in usb_rtusb_close_device() */
	if (INFRA_ON(pAd))
		AsicEnableBssSync(pAd, pAd->CommonCfg.BeaconPeriod);
	else if (ADHOC_ON(pAd))
		AsicEnableIbssSync(pAd);
	else
		AsicDisableSync(pAd);
#endif /* CONFIG_STA_SUPPORT */

	pAd->MeshTab.bcn_buf.bBcnSntReq = FALSE;

#ifdef CONFIG_AP_SUPPORT
	APMakeAllBssBeacon(pAd);
	APUpdateAllBeaconFrame(pAd);
#endif /* CONFIG_AP_SUPPORT */
	return 0;
}

#endif /* MESH_SUPPORT */

