Files
Linux_Drivers/osdrv/extdrv/wireless/mediatek/mt7603/common/wnm.c
forum_service 213c880673 add driver of tp、wiegand-gpio and wireless
Change-Id: Ie3c11d9d85cf1a05042f5690ac711856fe8b1ad7
2023-12-22 09:56:05 +08:00

2448 lines
64 KiB
C

/*
***************************************************************************
* Ralink Tech Inc.
* 4F, No. 2 Technology 5th Rd.
* Science-based Industrial Park
* Hsin-chu, Taiwan, R.O.C.
*
* (c) Copyright 2002-2011, 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:
wnm.c
Abstract:
Wireless Network Management(WNM)
Revision History:
Who When What
-------- ---------- ----------------------------------------------
*/
#include "rt_config.h"
static UCHAR ZERO_IP_ADDR[4] = {0x00, 0x00, 0x00, 0x00};
static char SolicitedMulticastAddr[] = {0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0xff};
static char AllNodeLinkLocalMulticastAddr[] = {0xff, 0x02, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01};
static char link_local[] = {0xfe, 0x80};
#define IP_PROTO_HOPOPTS 0 /* IP6 hop-by-hop options - RFC1883 */
#define IP_PROTO_ROUTING 43 /* IP6 routing header */
#define IP_PROTO_FRAGMENT 44 /* IP6 fragmentation header */
#define IP_PROTO_AH 51 /* Authentication Header for IPv6 - RFC2402*/
#define IP_PROTO_DSTOPTS 60 /* IP6 destination options - RFC1883 */
#ifndef MAT_SUPPORT
#define IS_UNSPECIFIED_IPV6_ADDR(_addr) \
(!((_addr).ipv6_addr32[0] | (_addr).ipv6_addr32[1] | (_addr).ipv6_addr32[2] | (_addr).ipv6_addr32[3]))
#endif
#ifdef CONFIG_AP_SUPPORT
void wext_send_btm_query_event(PNET_DEV net_dev, const char *peer_mac_addr,
const char *btm_query, UINT16 btm_query_len)
{
struct btm_query_data *query_data;
UINT16 buflen = 0;
char *buf;
buflen = sizeof(*query_data) + btm_query_len;
os_alloc_mem(NULL, (UCHAR **)&buf, buflen);
NdisZeroMemory(buf, buflen);
query_data = (struct btm_query_data *)buf;
query_data->ifindex = RtmpOsGetNetIfIndex(net_dev);
memcpy(query_data->peer_mac_addr, peer_mac_addr, 6);
query_data->btm_query_len = btm_query_len;
memcpy(query_data->btm_query, btm_query, btm_query_len);
RtmpOSWrielessEventSend(net_dev, RT_WLAN_EVENT_CUSTOM,
OID_802_11_WNM_BTM_QUERY, NULL, (PUCHAR)buf, buflen);
os_free_mem(NULL, buf);
}
void SendBTMQueryEvent(PNET_DEV net_dev, const char *peer_mac_addr,
const char *btm_query, UINT16 btm_query_len, UINT8 ipc_type)
{
if (ipc_type == RA_WEXT) {
wext_send_btm_query_event(net_dev,
peer_mac_addr,
btm_query,
btm_query_len);
}
}
void wext_send_btm_cfm_event(PNET_DEV net_dev, const char *peer_mac_addr,
const char *btm_rsp, UINT16 btm_rsp_len)
{
struct btm_rsp_data *rsp_data;
UINT16 buflen = 0;
char *buf;
buflen = sizeof(*rsp_data) + btm_rsp_len;
os_alloc_mem(NULL, (UCHAR **)&buf, buflen);
NdisZeroMemory(buf, buflen);
rsp_data = (struct btm_rsp_data *)buf;
rsp_data->ifindex = RtmpOsGetNetIfIndex(net_dev);
memcpy(rsp_data->peer_mac_addr, peer_mac_addr, 6);
rsp_data->btm_rsp_len = btm_rsp_len;
memcpy(rsp_data->btm_rsp, btm_rsp, btm_rsp_len);
RtmpOSWrielessEventSend(net_dev, RT_WLAN_EVENT_CUSTOM,
OID_802_11_WNM_BTM_RSP, NULL, (PUCHAR)buf, buflen);
os_free_mem(NULL, buf);
}
void SendBTMConfirmEvent(PNET_DEV net_dev, const char *peer_mac_addr,
const char *btm_rsp, UINT16 btm_rsp_len, UINT8 ipc_type)
{
if (ipc_type == RA_WEXT) {
wext_send_btm_cfm_event(net_dev,
peer_mac_addr,
btm_rsp,
btm_rsp_len);
}
}
void wext_send_proxy_arp_event(PNET_DEV net_dev,
const char *source_mac_addr,
const char *source_ip_addr,
const char *target_mac_addr,
const char *target_ip_addr,
UINT8 ip_type,
UINT8 from_ds,
unsigned char IsDAD)
{
struct proxy_arp_entry *arp_entry;
UINT16 varlen = 0, buflen = 0;
char *buf;
if (ip_type == IPV4)
varlen += 8;
else if (ip_type == IPV6)
varlen += 32;
//for IsDAD, add one more byte
varlen++;
buflen = sizeof(*arp_entry) + varlen;
os_alloc_mem(NULL, (UCHAR **)&buf, buflen);
NdisZeroMemory(buf, buflen);
arp_entry = (struct proxy_arp_entry *)buf;
arp_entry->ifindex = RtmpOsGetNetIfIndex(net_dev);
arp_entry->ip_type = ip_type;
arp_entry->from_ds = from_ds;
arp_entry->IsDAD = IsDAD;
memcpy(arp_entry->source_mac_addr, source_mac_addr, 6);
memcpy(arp_entry->target_mac_addr, target_mac_addr, 6);
if (ip_type == IPV4) {
memcpy(arp_entry->ip_addr, source_ip_addr, 4);
memcpy(arp_entry->ip_addr + 4, target_ip_addr, 4);
} else if (ip_type == IPV6) {
memcpy(arp_entry->ip_addr, source_ip_addr, 16);
memcpy(arp_entry->ip_addr + 16, target_ip_addr, 16);
} else
printk("error not such ip type packet\n");
RtmpOSWrielessEventSend(net_dev, RT_WLAN_EVENT_CUSTOM,
OID_802_11_WNM_PROXY_ARP, NULL, (PUCHAR)buf, buflen);
os_free_mem(NULL, buf);
}
void SendProxyARPEvent(PNET_DEV net_dev,
const char *source_mac_addr,
const char *source_ip_addr,
const char *target_mac_addr,
const char *target_ip_addr,
UINT8 ip_type,
UINT8 from_ds,
unsigned char IsDAD)
{
wext_send_proxy_arp_event(net_dev,
source_mac_addr,
source_ip_addr,
target_mac_addr,
target_ip_addr,
ip_type,
from_ds,
IsDAD);
}
BOOLEAN IsGratuitousARP(IN RTMP_ADAPTER *pAd,
IN UCHAR *pData,
IN UCHAR *DAMacAddr,
IN struct _BSS_STRUCT *pMbss)
{
UCHAR *Pos = pData;
UINT16 ProtoType;
UCHAR *SenderIP;
UCHAR *TargetIP;
UCHAR BroadcastMac[6]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
UINT16 ARPOperation;
PWNM_CTRL pWNMCtrl = &pMbss->WNMCtrl;
PROXY_ARP_IPV4_ENTRY *ProxyARPEntry;
PUCHAR SourceMACAddr;
BOOLEAN IsDrop = FALSE;
INT32 Ret;
NdisMoveMemory(&ProtoType, pData, 2);
ProtoType = OS_NTOHS(ProtoType);
Pos += 2;
if (ProtoType == ETH_P_ARP)
{
/*
* Check if Gratuitous ARP, Sender IP equal Target IP
*/
SourceMACAddr = Pos + 8;
SenderIP = Pos + 14;
TargetIP = Pos + 24;
if ((NdisCmpMemory(SenderIP, TargetIP, 4) == 0) && (NdisCmpMemory(DAMacAddr, BroadcastMac, 6) == 0))
{
DBGPRINT(RT_DEBUG_TRACE, ("The Packet is GratuitousARP\n"));
return TRUE;
}
#ifdef CONFIG_HOTSPOT_R2
Pos += 6;
NdisMoveMemory(&ARPOperation, Pos, 2);
ARPOperation = OS_NTOHS(ARPOperation);
Pos += 2;
if (ARPOperation == 0x0002)
{
RTMP_SEM_EVENT_WAIT(&pWNMCtrl->ProxyARPListLock, Ret);
DlListForEach(ProxyARPEntry, &pWNMCtrl->IPv4ProxyARPList, PROXY_ARP_IPV4_ENTRY, List)
{
if ((IPV4_ADDR_EQUAL(ProxyARPEntry->TargetIPAddr, SenderIP)) && (MAC_ADDR_EQUAL(ProxyARPEntry->TargetMACAddr, SourceMACAddr) == FALSE))
{
IsDrop = TRUE;
break;
}
}
RTMP_SEM_EVENT_UP(&pWNMCtrl->ProxyARPListLock);
if (IsDrop == TRUE)
{
printk("Drop pkt, ip not qeual mac\n");
return TRUE;
}
}
#endif
}
return FALSE;
}
BOOLEAN IsUnsolicitedNeighborAdver(PRTMP_ADAPTER pAd,
PUCHAR pData)
{
UCHAR *Pos = pData;
UINT16 ProtoType;
NdisMoveMemory(&ProtoType, pData, 2);
ProtoType = OS_NTOHS(ProtoType);
Pos += 2;
if (ProtoType == ETH_P_IPV6)
{
Pos += 24;
if (RTMPEqualMemory(Pos, AllNodeLinkLocalMulticastAddr, 16))
{
Pos += 16;
/* Check if neighbor advertisement type */
if (*Pos == 0x88)
{
Pos += 4;
/* Check if solicited flag set to 0 */
if ((*Pos & 0x40) == 0x00)
{
DBGPRINT(RT_DEBUG_OFF, ("The Packet is UnsolicitedNeighborAdver\n"));
Pos += 4;
return TRUE;
}
}
}
}
return FALSE;
}
BOOLEAN IsIPv4ProxyARPCandidate(IN PRTMP_ADAPTER pAd,
IN PUCHAR pData)
{
UCHAR *Pos = pData;
UINT16 ProtoType;
UINT16 ARPOperation;
UCHAR *SenderIP;
UCHAR *TargetIP;
NdisMoveMemory(&ProtoType, pData, 2);
ProtoType = OS_NTOHS(ProtoType);
Pos += 2;
if (ProtoType == ETH_P_ARP)
{
Pos += 6;
NdisMoveMemory(&ARPOperation, Pos, 2);
ARPOperation = OS_NTOHS(ARPOperation);
Pos += 2;
if (ARPOperation == 0x0001)
{
SenderIP = Pos + 6;
TargetIP = Pos + 16;
/* ARP Request */
if (NdisCmpMemory(SenderIP, TargetIP, 4) != 0)
{
DBGPRINT(RT_DEBUG_TRACE, ("IPv4ProxyARPCandidate\n"));
return TRUE;
}
}
}
return FALSE;
}
BOOLEAN IsIpv6DuplicateAddrDetect(PRTMP_ADAPTER pAd,
PUCHAR pData,
PUCHAR pOffset)
{
UCHAR *Pos = pData;
UINT16 ProtoType;
RT_IPV6_ADDR *pIPv6Addr;
UCHAR pData_offset = (UCHAR)Pos;
NdisMoveMemory(&ProtoType, pData, 2);
ProtoType = OS_NTOHS(ProtoType);
Pos += 2;
if (ProtoType == ETH_P_IPV6)
{
INT32 PayloadLen = 0;//((*(Pos+5) & 0xff) << 8) | (*(Pos+4) & 0xff);
UCHAR NextHeader = *(Pos+6);
UCHAR IsExtenHeader = 0;
NdisMoveMemory(&PayloadLen, (Pos+4), 2);
PayloadLen = OS_NTOHS(PayloadLen);
Pos += 8;
pIPv6Addr = (RT_IPV6_ADDR *)Pos;
if (IS_UNSPECIFIED_IPV6_ADDR(*pIPv6Addr))
{
Pos += 16;
if (RTMPEqualMemory(Pos, SolicitedMulticastAddr, 13))
{
Pos += 16;
if ((NextHeader == IP_PROTO_HOPOPTS) || (NextHeader == IP_PROTO_ROUTING) || (NextHeader == IP_PROTO_FRAGMENT) || (NextHeader == IP_PROTO_AH) || (NextHeader == IP_PROTO_DSTOPTS))
{
IsExtenHeader = 1;
do
{
printk("IsIpv6DuplicateAddrDetect: nextheader=0x%x, %d, %d\n", NextHeader, PayloadLen, IsExtenHeader);
switch (NextHeader)
{
case IP_PROTO_HOPOPTS:
case IP_PROTO_ROUTING:
case IP_PROTO_DSTOPTS:
{
UCHAR HdrExtLen = *(Pos+1);
NextHeader = *Pos;
PayloadLen -= ((HdrExtLen+1)<<3);
Pos += ((HdrExtLen+1)<<3);
}
break;
case IP_PROTO_FRAGMENT:
{
NextHeader = *Pos;
PayloadLen -= 8;
Pos += 8;
}
break;
case IP_PROTO_AH:
{
UCHAR AHPayloadLen = *(Pos+1);
UCHAR AHLen = (8+(AHPayloadLen<<2));
NextHeader = *Pos;
PayloadLen -= AHLen;
Pos += AHLen;
}
break;
default:
IsExtenHeader = 0;
break;
}
}
while((PayloadLen > 0) && (IsExtenHeader == 1));
if (PayloadLen <= 0)
return FALSE;
}
/* Check if neighbor solicitation */
if (*Pos == 0x87)
{
DBGPRINT(RT_DEBUG_OFF, ("THe Packet is for Ipv6DuplicateAddrDetect\n"));
*pOffset = Pos-pData_offset+8;
return TRUE;
}
}
}
}
return FALSE;
}
BOOLEAN IsIPv6ProxyARPCandidate(IN PRTMP_ADAPTER pAd,
IN PUCHAR pData)
{
UCHAR *Pos = pData;
UINT16 ProtoType;
RT_IPV6_ADDR *pIPv6Addr;
NdisMoveMemory(&ProtoType, pData, 2);
ProtoType = OS_NTOHS(ProtoType);
Pos += 2;
if (ProtoType == ETH_P_IPV6)
{
INT32 PayloadLen = 0; //((*(Pos+5) & 0xff) << 8) | (*(Pos+4) & 0xff);
UCHAR NextHeader = *(Pos+6);
UCHAR IsExtenHeader = 0;
NdisMoveMemory(&PayloadLen, (Pos+4), 2);
PayloadLen = OS_NTOHS(PayloadLen);
Pos += 8;
pIPv6Addr = (RT_IPV6_ADDR *)Pos;
//if (!IS_UNSPECIFIED_IPV6_ADDR(*pIPv6Addr))
//{
Pos += 16;
if (RTMPEqualMemory(Pos, SolicitedMulticastAddr, 13))
{
Pos+= 16;
if ((NextHeader == IP_PROTO_HOPOPTS) || (NextHeader == IP_PROTO_ROUTING) || (NextHeader == IP_PROTO_FRAGMENT) || (NextHeader == IP_PROTO_AH) || (NextHeader == IP_PROTO_DSTOPTS))
{
IsExtenHeader = 1;
do
{
printk("IsIPv6ProxyARPCandidate: nextheader=0x%x, %d, %d\n", NextHeader, PayloadLen, IsExtenHeader);
switch (NextHeader)
{
case IP_PROTO_HOPOPTS:
case IP_PROTO_ROUTING:
case IP_PROTO_DSTOPTS:
{
UCHAR HdrExtLen = *(Pos+1);
NextHeader = *Pos;
PayloadLen -= ((HdrExtLen+1)<<3);
Pos += ((HdrExtLen+1)<<3);
}
break;
case IP_PROTO_FRAGMENT:
{
NextHeader = *Pos;
PayloadLen -= 8;
Pos += 8;
}
break;
case IP_PROTO_AH:
{
UCHAR AHPayloadLen = *(Pos+1);
UCHAR AHLen = (8+(AHPayloadLen<<2));
NextHeader = *Pos;
PayloadLen -= AHLen;
Pos += AHLen;
}
break;
default:
IsExtenHeader = 0;
break;
}
}
while((PayloadLen > 0) && (IsExtenHeader == 1));
if (PayloadLen <= 0)
return FALSE;
}
/* Check if neighbor solicitation */
if (*Pos == 0x87)
{
DBGPRINT(RT_DEBUG_TRACE, ("The Packet is IPv6ProxyARPCandidate\n"));
return TRUE;
}
}
//}
}
return FALSE;
}
//JERRY
BOOLEAN IsIPv6DHCPv6Solicitation(IN PRTMP_ADAPTER pAd,
IN PUCHAR pData)
{
UCHAR *Pos = pData;
UINT16 ProtoType, SrcPort, DstPort;
NdisMoveMemory(&ProtoType, pData, 2);
ProtoType = OS_NTOHS(ProtoType);
Pos += 2;
if (ProtoType == ETH_P_IPV6)
{
INT32 PayloadLen = 0; //((*(Pos+5) & 0xff) << 8) | (*(Pos+4) & 0xff);
UCHAR NextHeader = *(Pos+6);
UCHAR IsExtenHeader = 0;
NdisMoveMemory(&PayloadLen, (Pos+4), 2);
PayloadLen = OS_NTOHS(PayloadLen);
if ((NextHeader != IP_PROTO_HOPOPTS) && (NextHeader != IP_PROTO_ROUTING) && (NextHeader != IP_PROTO_FRAGMENT) && (NextHeader != IP_PROTO_AH) && (NextHeader != IP_PROTO_DSTOPTS))
{
if (NextHeader == 0x11)
{
Pos += 40;
}
else
return FALSE;
}
else
{
IsExtenHeader = 1;
Pos += 40;
do
{
printk("IsIPv6DHCPv6Solicitation: nextheader=0x%x, %d, %d\n", NextHeader, PayloadLen, IsExtenHeader);
switch (NextHeader)
{
case IP_PROTO_HOPOPTS:
case IP_PROTO_ROUTING:
case IP_PROTO_DSTOPTS:
{
UCHAR HdrExtLen = *(Pos+1);
NextHeader = *Pos;
PayloadLen -= ((HdrExtLen+1)<<3);
Pos += ((HdrExtLen+1)<<3);
}
break;
case IP_PROTO_FRAGMENT:
{
NextHeader = *Pos;
PayloadLen -= 8;
Pos += 8;
}
break;
case IP_PROTO_AH:
{
UCHAR AHPayloadLen = *(Pos+1);
UCHAR AHLen = (8+(AHPayloadLen<<2));
NextHeader = *Pos;
PayloadLen -= AHLen;
Pos += AHLen;
}
break;
default:
IsExtenHeader = 0;
break;
}
}
while((PayloadLen > 0) && (IsExtenHeader == 1));
if (PayloadLen <= 0)
return FALSE;
}
/* Check if DHCPv6 solicitation */
{
unsigned char *type = (unsigned char *)(Pos+8);
if ((*type == 1) || (*type == 4))
{
NdisMoveMemory(&SrcPort, Pos, 2);
SrcPort = OS_NTOHS(SrcPort);
NdisMoveMemory(&DstPort, Pos+2, 2);
DstPort = OS_NTOHS(DstPort);
if ((SrcPort == 546) && (DstPort == 547))
{
DBGPRINT(RT_DEBUG_OFF, ("The Packet is DHCPv6 Solicitation,msg type=%d\n", *type));
return TRUE;
}
}
}
}
return FALSE;
}
BOOLEAN IsIPv6RouterSolicitation(IN PRTMP_ADAPTER pAd,
IN PUCHAR pData)
{
UCHAR *Pos = pData;
UINT16 ProtoType;
NdisMoveMemory(&ProtoType, pData, 2);
ProtoType = OS_NTOHS(ProtoType);
Pos += 2;
if (ProtoType == ETH_P_IPV6)
{
INT32 PayloadLen = 0; //((*(Pos+5) & 0xff) << 8) | (*(Pos+4) & 0xff);
UCHAR NextHeader = *(Pos+6);
UCHAR IsExtenHeader = 0;
NdisMoveMemory(&PayloadLen, (Pos+4), 2);
PayloadLen = OS_NTOHS(PayloadLen);
if ((NextHeader != IP_PROTO_HOPOPTS) && (NextHeader != IP_PROTO_ROUTING) && (NextHeader != IP_PROTO_FRAGMENT) && (NextHeader != IP_PROTO_AH) && (NextHeader != IP_PROTO_DSTOPTS))
{
Pos += 40;
}
else
{
IsExtenHeader = 1;
Pos += 40;
do
{
printk("IsIPv6RouterSolicitation: nextheader=0x%x, %d, %d\n", NextHeader, PayloadLen, IsExtenHeader);
switch (NextHeader)
{
case IP_PROTO_HOPOPTS:
case IP_PROTO_ROUTING:
case IP_PROTO_DSTOPTS:
{
UCHAR HdrExtLen = *(Pos+1);
NextHeader = *Pos;
PayloadLen -= ((HdrExtLen+1)<<3);
Pos += ((HdrExtLen+1)<<3);
}
break;
case IP_PROTO_FRAGMENT:
{
NextHeader = *Pos;
PayloadLen -= 8;
Pos += 8;
}
break;
case IP_PROTO_AH:
{
UCHAR AHPayloadLen = *(Pos+1);
UCHAR AHLen = (8+(AHPayloadLen<<2));
NextHeader = *Pos;
PayloadLen -= AHLen;
Pos += AHLen;
}
break;
default:
IsExtenHeader = 0;
break;
}
}
while((PayloadLen > 0) && (IsExtenHeader == 1));
if (PayloadLen <= 0)
return FALSE;
}
/* Check if router solicitation */
if (*Pos == 0x85)
{
DBGPRINT(RT_DEBUG_OFF, ("The Packet is IPv6 Router Solicitation\n"));
return TRUE;
}
}
return FALSE;
}
BOOLEAN IsIPv6RouterAdvertisement(IN PRTMP_ADAPTER pAd,
IN PUCHAR pData,
IN PUCHAR pOffset)
{
UCHAR *Pos = pData;
UINT16 ProtoType;
UCHAR pData_offset = 0;
NdisMoveMemory(&ProtoType, pData, 2);
ProtoType = OS_NTOHS(ProtoType);
Pos += 2;
if (ProtoType == ETH_P_IPV6)
{
INT32 PayloadLen = 0;
UCHAR NextHeader = *(Pos+6);
UCHAR IsExtenHeader = 0;
NdisMoveMemory(&PayloadLen, (Pos+4), 2);
PayloadLen = OS_NTOHS(PayloadLen);
if ((NextHeader != IP_PROTO_HOPOPTS) &&
(NextHeader != IP_PROTO_ROUTING) &&
(NextHeader != IP_PROTO_FRAGMENT) &&
(NextHeader != IP_PROTO_AH) &&
(NextHeader != IP_PROTO_DSTOPTS))
{
Pos += 40;
pData_offset = (UCHAR)Pos;
}
else
{
IsExtenHeader = 1;
Pos += 40;
pData_offset = (UCHAR)Pos;
do
{
DBGPRINT(RT_DEBUG_TRACE, ("IsIPv6RouterAdvertisement: nextheader=0x%x, %d, %d\n", NextHeader, PayloadLen, IsExtenHeader));
switch (NextHeader)
{
case IP_PROTO_HOPOPTS:
case IP_PROTO_ROUTING:
case IP_PROTO_DSTOPTS:
{
UCHAR HdrExtLen = *(Pos+1);
NextHeader = *Pos;
PayloadLen -= ((HdrExtLen+1)<<3);
Pos += ((HdrExtLen+1)<<3);
}
break;
case IP_PROTO_FRAGMENT:
{
NextHeader = *Pos;
PayloadLen -= 8;
Pos += 8;
}
break;
case IP_PROTO_AH:
{
UCHAR AHPayloadLen = *(Pos+1);
UCHAR AHLen = (8+(AHPayloadLen<<2));
NextHeader = *Pos;
PayloadLen -= AHLen;
Pos += AHLen;
}
break;
default:
IsExtenHeader = 0;
break;
}
}
while((PayloadLen > 0) && (IsExtenHeader == 1));
if (PayloadLen <= 0)
return FALSE;
}
/* Check if router advertisement */
if (*Pos == 0x86)
{
DBGPRINT(RT_DEBUG_TRACE, ("The Packet is IPv6 Router Advertisement\n"));
*pOffset = Pos-pData_offset;
return TRUE;
}
}
return FALSE;
}
BOOLEAN IsTDLSPacket(IN PRTMP_ADAPTER pAd,
IN PUCHAR pData)
{
UCHAR *Pos = pData;
UINT16 ProtoType;
NdisMoveMemory(&ProtoType, pData, 2);
ProtoType = OS_NTOHS(ProtoType);
Pos += 2;
if (ProtoType == 0x890d)
{
DBGPRINT(RT_DEBUG_TRACE, ("THe Packet is TDLS\n"));
return TRUE;
}
return FALSE;
}
UINT32 IPv4ProxyARPTableLen(IN PRTMP_ADAPTER pAd,
IN struct _BSS_STRUCT *pMbss)
{
PWNM_CTRL pWNMCtrl = &pMbss->WNMCtrl;
PROXY_ARP_IPV4_ENTRY *ProxyARPEntry;
UINT32 TableLen = 0;
INT32 Ret;
DBGPRINT(RT_DEBUG_OFF, ("%s\n", __FUNCTION__));
RTMP_SEM_EVENT_WAIT(&pWNMCtrl->ProxyARPListLock, Ret);
DlListForEach(ProxyARPEntry, &pWNMCtrl->IPv4ProxyARPList, PROXY_ARP_IPV4_ENTRY, List)
{
TableLen += sizeof(PROXY_ARP_IPV4_UNIT);
}
RTMP_SEM_EVENT_UP(&pWNMCtrl->ProxyARPListLock);
return TableLen;
}
UINT32 IPv6ProxyARPTableLen(IN PRTMP_ADAPTER pAd,
IN struct _BSS_STRUCT *pMbss)
{
PWNM_CTRL pWNMCtrl = &pMbss->WNMCtrl;
PROXY_ARP_IPV6_ENTRY *ProxyARPEntry;
UINT32 TableLen = 0;
INT32 Ret;
RTMP_SEM_EVENT_WAIT(&pWNMCtrl->ProxyARPIPv6ListLock, Ret);
DlListForEach(ProxyARPEntry, &pWNMCtrl->IPv6ProxyARPList, PROXY_ARP_IPV6_ENTRY, List)
{
TableLen += sizeof(PROXY_ARP_IPV6_UNIT);
}
RTMP_SEM_EVENT_UP(&pWNMCtrl->ProxyARPIPv6ListLock);
return TableLen;
}
BOOLEAN GetIPv4ProxyARPTable(IN PRTMP_ADAPTER pAd,
IN struct _BSS_STRUCT *pMbss,
PUCHAR *ProxyARPTable)
{
PWNM_CTRL pWNMCtrl = &pMbss->WNMCtrl;
PROXY_ARP_IPV4_ENTRY *ProxyARPEntry;
PROXY_ARP_IPV4_UNIT *ProxyARPUnit = (PROXY_ARP_IPV4_UNIT *)(*ProxyARPTable);
INT32 Ret;
DBGPRINT(RT_DEBUG_OFF, ("%s\n", __FUNCTION__));
RTMP_SEM_EVENT_WAIT(&pWNMCtrl->ProxyARPListLock, Ret);
DlListForEach(ProxyARPEntry, &pWNMCtrl->IPv4ProxyARPList, PROXY_ARP_IPV4_ENTRY, List)
{
NdisMoveMemory(ProxyARPUnit->TargetMACAddr, ProxyARPEntry->TargetMACAddr, MAC_ADDR_LEN);
NdisMoveMemory(ProxyARPUnit->TargetIPAddr, ProxyARPEntry->TargetIPAddr, 4);
ProxyARPUnit++;
}
RTMP_SEM_EVENT_UP(&pWNMCtrl->ProxyARPListLock);
return TRUE;
}
BOOLEAN GetIPv6ProxyARPTable(IN PRTMP_ADAPTER pAd,
IN struct _BSS_STRUCT *pMbss,
PUCHAR *ProxyARPTable)
{
PWNM_CTRL pWNMCtrl = &pMbss->WNMCtrl;
PROXY_ARP_IPV6_ENTRY *ProxyARPEntry;
PROXY_ARP_IPV6_UNIT *ProxyARPUnit = (PROXY_ARP_IPV6_UNIT *)(*ProxyARPTable);
INT32 Ret;
DBGPRINT(RT_DEBUG_OFF, ("%s\n", __FUNCTION__));
RTMP_SEM_EVENT_WAIT(&pWNMCtrl->ProxyARPIPv6ListLock, Ret);
DlListForEach(ProxyARPEntry, &pWNMCtrl->IPv6ProxyARPList, PROXY_ARP_IPV6_ENTRY, List)
{
NdisMoveMemory(ProxyARPUnit->TargetMACAddr, ProxyARPEntry->TargetMACAddr, MAC_ADDR_LEN);
ProxyARPUnit->TargetIPType = ProxyARPEntry->TargetIPType;
NdisMoveMemory(ProxyARPUnit->TargetIPAddr, ProxyARPEntry->TargetIPAddr, 16);
ProxyARPUnit++;
}
RTMP_SEM_EVENT_UP(&pWNMCtrl->ProxyARPIPv6ListLock);
return TRUE;
}
UINT32 AddIPv4ProxyARPEntry(IN PRTMP_ADAPTER pAd,
IN BSS_STRUCT *pMbss,
PUCHAR pTargetMACAddr,
PUCHAR pTargetIPAddr)
{
int i = 0, find_list = 0;
PWNM_CTRL pWNMCtrl = &pMbss->WNMCtrl;
PROXY_ARP_IPV4_ENTRY *ProxyARPEntry;
INT32 Ret;
DBGPRINT(RT_DEBUG_OFF, ("%s\n", __FUNCTION__));
if ((pTargetIPAddr[0] == 0) && (pTargetIPAddr[1] == 0)) {
DBGPRINT(RT_DEBUG_ERROR, ("Drop invalid IP Addr:%d.%d.%d.%d\n", pTargetIPAddr[0], pTargetIPAddr[1], pTargetIPAddr[2], pTargetIPAddr[3]));
return FALSE;
}
RTMP_SEM_EVENT_WAIT(&pWNMCtrl->ProxyARPListLock, Ret);
DlListForEach(ProxyARPEntry, &pWNMCtrl->IPv4ProxyARPList, PROXY_ARP_IPV4_ENTRY, List)
{
if (MAC_ADDR_EQUAL(ProxyARPEntry->TargetMACAddr, pTargetMACAddr))
{
//RTMP_SEM_EVENT_UP(&pWNMCtrl->ProxyARPListLock);
//return FALSE;
find_list = 1;
break;
}
}
RTMP_SEM_EVENT_UP(&pWNMCtrl->ProxyARPListLock);
if (find_list == 0)
os_alloc_mem(NULL, (UCHAR **)&ProxyARPEntry, sizeof(*ProxyARPEntry));
if (!ProxyARPEntry)
{
DBGPRINT(RT_DEBUG_ERROR, ("%s Not available memory\n", __FUNCTION__));
return FALSE;
}
NdisMoveMemory(ProxyARPEntry->TargetMACAddr, pTargetMACAddr, 6);
NdisMoveMemory(ProxyARPEntry->TargetIPAddr, pTargetIPAddr, 4);
for (i = 0; i < 4; i++)
printk("pTargetIPv4Addr[%i] = %x\n", i, pTargetIPAddr[i]);
/* Add ProxyARP Entry to list */
if (find_list == 0)
{
RTMP_SEM_EVENT_WAIT(&pWNMCtrl->ProxyARPListLock, Ret);
DlListAddTail(&pWNMCtrl->IPv4ProxyARPList, &ProxyARPEntry->List);
RTMP_SEM_EVENT_UP(&pWNMCtrl->ProxyARPListLock);
}
return TRUE;
}
VOID RemoveIPv4ProxyARPEntry(IN PRTMP_ADAPTER pAd,
IN BSS_STRUCT *pMbss,
PUCHAR pTargetMACAddr)
{
PWNM_CTRL pWNMCtrl = &pMbss->WNMCtrl;
PROXY_ARP_IPV4_ENTRY *ProxyARPEntry, *ProxyARPEntryTmp;
INT32 Ret;
DBGPRINT(RT_DEBUG_OFF, ("%s\n", __FUNCTION__));
RTMP_SEM_EVENT_WAIT(&pWNMCtrl->ProxyARPListLock, Ret);
DlListForEachSafe(ProxyARPEntry, ProxyARPEntryTmp, &pWNMCtrl->IPv4ProxyARPList, PROXY_ARP_IPV4_ENTRY, List)
{
if (!ProxyARPEntry)
break;
if (MAC_ADDR_EQUAL(ProxyARPEntry->TargetMACAddr, pTargetMACAddr))
{
//RTMP_SEM_EVENT_UP(&pWNMCtrl->ProxyARPListLock);
//return FALSE;
DlListDel(&ProxyARPEntry->List);
os_free_mem(NULL, ProxyARPEntry);
break;
}
}
RTMP_SEM_EVENT_UP(&pWNMCtrl->ProxyARPListLock);
}
UINT32 AddIPv6ProxyARPEntry(IN PRTMP_ADAPTER pAd,
IN BSS_STRUCT *pMbss,
PUCHAR pTargetMACAddr,
PUCHAR pTargetIPAddr)
{
PWNM_CTRL pWNMCtrl = &pMbss->WNMCtrl;
PROXY_ARP_IPV6_ENTRY *ProxyARPEntry;
INT32 Ret;
UINT8 i;
BOOLEAN IsDAD = FALSE;
PNET_DEV NetDev = pMbss->wdev.if_dev;
DBGPRINT(RT_DEBUG_OFF, ("%s\n", __FUNCTION__));
RTMP_SEM_EVENT_WAIT(&pWNMCtrl->ProxyARPIPv6ListLock, Ret);
DlListForEach(ProxyARPEntry, &pWNMCtrl->IPv6ProxyARPList, PROXY_ARP_IPV6_ENTRY, List)
{
if (MAC_ADDR_EQUAL(ProxyARPEntry->TargetMACAddr, pTargetMACAddr) &&
IPV6_ADDR_EQUAL(ProxyARPEntry->TargetIPAddr, pTargetIPAddr))
{
DBGPRINT(RT_DEBUG_OFF, ("%s, the Mac address and IPv6 Address exactly same as the one in List already!\n", __FUNCTION__));
RTMP_SEM_EVENT_UP(&pWNMCtrl->ProxyARPIPv6ListLock);
return FALSE;
}
if ((MAC_ADDR_EQUAL(ProxyARPEntry->TargetMACAddr, pTargetMACAddr) == FALSE) &&
IPV6_ADDR_EQUAL(ProxyARPEntry->TargetIPAddr, pTargetIPAddr))
{
DBGPRINT(RT_DEBUG_OFF, ("%s, different Mac address use IPv6 address which already in List!\n", __func__));
RTMP_SEM_EVENT_UP(&pWNMCtrl->ProxyARPIPv6ListLock);
IsDAD = TRUE;
/*we got IPv6 DAD here, AP shall issue Neighbor Advertisement back to sender in below format */
/* SenderMAC is the mac which in List, */
/* DestMAC is multicast address e.g, 33:33:00:00:00:01 */
/* SourceIP = TargetIP = TentativeIP, in this case is the IP which in List */
/* DestIP = FF02::1 */
SendProxyARPEvent(NetDev,
pTargetMACAddr,
ProxyARPEntry->TargetIPAddr,
ProxyARPEntry->TargetMACAddr,
ProxyARPEntry->TargetIPAddr,
IPV6,
FALSE,
IsDAD);
return FALSE;
}
}
RTMP_SEM_EVENT_UP(&pWNMCtrl->ProxyARPIPv6ListLock);
os_alloc_mem(NULL, (UCHAR **)&ProxyARPEntry, sizeof(*ProxyARPEntry));
if (!ProxyARPEntry)
{
DBGPRINT(RT_DEBUG_ERROR, ("%s Not available memory\n", __FUNCTION__));
return FALSE;
}
NdisMoveMemory(ProxyARPEntry->TargetMACAddr, pTargetMACAddr, 6);
if (NdisEqualMemory(link_local, pTargetIPAddr, 2))
ProxyARPEntry->TargetIPType = IPV6_LINK_LOCAL;
else
ProxyARPEntry->TargetIPType = IPV6_GLOBAL;
NdisMoveMemory(ProxyARPEntry->TargetIPAddr, pTargetIPAddr, 16);
for (i = 0; i < 6; i++)
printk("pTargetMACAddr[%i] = %x\n", i, pTargetMACAddr[i]);
for (i = 0; i < 16; i++)
printk("pTargetIPv6Addr[%i] = %x\n", i, pTargetIPAddr[i]);
/* Add ProxyARP Entry to list */
RTMP_SEM_EVENT_WAIT(&pWNMCtrl->ProxyARPIPv6ListLock, Ret);
DlListAddTail(&pWNMCtrl->IPv6ProxyARPList, &ProxyARPEntry->List);
RTMP_SEM_EVENT_UP(&pWNMCtrl->ProxyARPIPv6ListLock);
return TRUE;
}
VOID RemoveIPv6ProxyARPEntry(IN PRTMP_ADAPTER pAd,
IN BSS_STRUCT *pMbss,
PUCHAR pTargetMACAddr)
{
PWNM_CTRL pWNMCtrl = &pMbss->WNMCtrl;
PROXY_ARP_IPV6_ENTRY *ProxyARPEntry, *ProxyARPEntryTmp;
INT32 Ret;
DBGPRINT(RT_DEBUG_OFF, ("%s\n", __FUNCTION__));
RTMP_SEM_EVENT_WAIT(&pWNMCtrl->ProxyARPIPv6ListLock, Ret);
DlListForEachSafe(ProxyARPEntry, ProxyARPEntryTmp, &pWNMCtrl->IPv6ProxyARPList, PROXY_ARP_IPV6_ENTRY, List)
{
if (!ProxyARPEntry)
break;
if (MAC_ADDR_EQUAL(ProxyARPEntry->TargetMACAddr, pTargetMACAddr))
{
DlListDel(&ProxyARPEntry->List);
os_free_mem(NULL, ProxyARPEntry);
}
}
RTMP_SEM_EVENT_UP(&pWNMCtrl->ProxyARPIPv6ListLock);
}
BOOLEAN IPv4ProxyARP(IN PRTMP_ADAPTER pAd,
IN BSS_STRUCT *pMbss,
IN PUCHAR pData,
IN BOOLEAN FromDS)
{
PWNM_CTRL pWNMCtrl = &pMbss->WNMCtrl;
PNET_DEV NetDev = pMbss->wdev.if_dev;
BOOLEAN IsFound = FALSE, InTable = FALSE;
PROXY_ARP_IPV4_ENTRY *ProxyARPEntry;
PROXY_ARP_IPV4_ENTRY *ProxyARPSrcEntry;
PUCHAR SourceMACAddr = pData + 10;
PUCHAR SourceIPAddr = pData + 16;
PUCHAR TargetIPAddr = pData + 26;
INT32 Ret;
BOOLEAN IsDAD = FALSE;
PUCHAR TargetMACAddr = pData + 20;
UCHAR ALL_ZERO_BROADCAST_ADDR[MAC_ADDR_LEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
DBGPRINT(RT_DEBUG_TRACE, ("%s\n", __FUNCTION__));
RTMP_SEM_EVENT_WAIT(&pWNMCtrl->ProxyARPListLock, Ret);
DlListForEach(ProxyARPEntry, &pWNMCtrl->IPv4ProxyARPList, PROXY_ARP_IPV4_ENTRY, List)
{
if (IPV4_ADDR_EQUAL(ProxyARPEntry->TargetIPAddr, TargetIPAddr))
{
IsFound = TRUE;
if (
(MAC_ADDR_EQUAL(ProxyARPEntry->TargetMACAddr, SourceMACAddr) == FALSE) &&
((MAC_ADDR_EQUAL(TargetMACAddr, BROADCAST_ADDR) == TRUE) ||
(MAC_ADDR_EQUAL(TargetMACAddr, ALL_ZERO_BROADCAST_ADDR) == TRUE)) &&
(IPV4_ADDR_EQUAL(SourceIPAddr, ZERO_IP_ADDR) == TRUE)
) {
//Mac address is not equal to the one which already in List.
//it's a DAD arp.
IsDAD = TRUE;
DBGPRINT(RT_DEBUG_TRACE, ("%s, Found DAD!!!!\n", __FUNCTION__));
printk("found dad...\n");
}
break;
}
}
RTMP_SEM_EVENT_UP(&pWNMCtrl->ProxyARPListLock);
if (IsFound)
{
/* ARP Probe and ARP Entry already Build and not DAD */
if ((IsDAD == FALSE) && (IPV4_ADDR_EQUAL(SourceIPAddr, ZERO_IP_ADDR) == TRUE))
return IsFound;
/* Send proxy arp indication to daemon */
SendProxyARPEvent(NetDev,
SourceMACAddr,
SourceIPAddr,
ProxyARPEntry->TargetMACAddr,
ProxyARPEntry->TargetIPAddr,
IPV4,
FromDS,
IsDAD);
if ((IsDAD == FALSE) && (FromDS == FALSE)) {
RTMP_SEM_EVENT_WAIT(&pWNMCtrl->ProxyARPListLock, Ret);
DlListForEach(ProxyARPEntry, &pWNMCtrl->IPv4ProxyARPList, PROXY_ARP_IPV4_ENTRY, List)
{
if (IPV4_ADDR_EQUAL(ProxyARPEntry->TargetIPAddr, SourceIPAddr))
{
InTable = TRUE;
break;
}
}
RTMP_SEM_EVENT_UP(&pWNMCtrl->ProxyARPListLock);
if (InTable == FALSE) {
AddIPv4ProxyARPEntry(pAd, pMbss, SourceMACAddr, SourceIPAddr);
DBGPRINT(RT_DEBUG_ERROR,
("%s, New Station take arp request, Learning ARP Entry from it\n", __func__));
}
}
}
else
{
if (
((MAC_ADDR_EQUAL(TargetMACAddr, BROADCAST_ADDR) == TRUE) ||
(MAC_ADDR_EQUAL(TargetMACAddr, ALL_ZERO_BROADCAST_ADDR) == TRUE)) && (FromDS == FALSE)
) {
//waht if there is a new mac for List, and take BOARDCAST and ZERO_IP,
//it's a station take DAD packet to ask the network.
//In this case, AP shall learn the mac/ip mapping from it.
if (IPV4_ADDR_EQUAL(SourceIPAddr, ZERO_IP_ADDR) == TRUE) {
AddIPv4ProxyARPEntry(pAd, pMbss, SourceMACAddr, TargetIPAddr);
DBGPRINT(RT_DEBUG_ERROR,
("%s, New Station take DAD to detect, Learning ARP Entry from it\n", __func__));
}
else {
RTMP_SEM_EVENT_WAIT(&pWNMCtrl->ProxyARPListLock, Ret);
DlListForEach(ProxyARPEntry, &pWNMCtrl->IPv4ProxyARPList, PROXY_ARP_IPV4_ENTRY, List)
{
if (IPV4_ADDR_EQUAL(ProxyARPEntry->TargetIPAddr, SourceIPAddr))
{
InTable = TRUE;
break;
}
}
RTMP_SEM_EVENT_UP(&pWNMCtrl->ProxyARPListLock);
if (InTable == FALSE) {
AddIPv4ProxyARPEntry(pAd, pMbss, SourceMACAddr, SourceIPAddr);
DBGPRINT(RT_DEBUG_ERROR,
("%s, New Station take arp request to detect, Learning ARP Entry from it\n", __func__));
}
}
}
}
return IsFound;
}
BOOLEAN IPv6ProxyARP(IN PRTMP_ADAPTER pAd,
IN BSS_STRUCT *pMbss,
IN PUCHAR pData,
IN BOOLEAN FromDS)
{
PWNM_CTRL pWNMCtrl = &pMbss->WNMCtrl;
PNET_DEV NetDev = pMbss->wdev.if_dev;
BOOLEAN IsFound = FALSE;
PROXY_ARP_IPV6_ENTRY *ProxyARPEntry;
PUCHAR SourceMACAddr = pData + 68;
PUCHAR SourceIPAddr = pData + 10;
PUCHAR TargetIPAddr = pData + 50;
INT32 Ret;
BOOLEAN IsDAD = FALSE;
//DBGPRINT(RT_DEBUG_OFF, ("%s\n", __FUNCTION__));
RTMP_SEM_EVENT_WAIT(&pWNMCtrl->ProxyARPListLock, Ret);
DlListForEach(ProxyARPEntry, &pWNMCtrl->IPv6ProxyARPList, PROXY_ARP_IPV6_ENTRY, List)
{
if (IPV6_ADDR_EQUAL(ProxyARPEntry->TargetIPAddr, TargetIPAddr))
{
IsFound = TRUE;
break;
}
}
RTMP_SEM_EVENT_UP(&pWNMCtrl->ProxyARPListLock);
if (IsFound)
{
DBGPRINT(RT_DEBUG_OFF, ("%s\n", __FUNCTION__));
/* Send proxy arp indication to daemon */
SendProxyARPEvent(NetDev,
SourceMACAddr,
SourceIPAddr,
ProxyARPEntry->TargetMACAddr,
ProxyARPEntry->TargetIPAddr,
IPV6,
FromDS,
IsDAD);
}
return IsFound;
}
VOID WNMIPv4ProxyARPCheck(
IN PRTMP_ADAPTER pAd,
PNDIS_PACKET pPacket,
USHORT srcPort,
USHORT dstPort,
PUCHAR pSrcBuf)
{
struct wifi_dev *wdev;
UCHAR wdev_idx = RTMP_GET_PACKET_WDEV(pPacket);
BSS_STRUCT *pMbss;
MAC_TABLE_ENTRY *pEntry;
ASSERT(wdev_idx < WDEV_NUM_MAX);
if (wdev_idx >= WDEV_NUM_MAX) {
DBGPRINT(RT_DEBUG_ERROR, ("%s(): Invalid wdev_idx(%d)\n", __FUNCTION__, wdev_idx));
return;
}
wdev = pAd->wdev_list[wdev_idx];
ASSERT(wdev->func_idx < pAd->ApCfg.BssidNum);
pMbss = &pAd->ApCfg.MBSSID[wdev->func_idx];
if (srcPort == 0x43 && dstPort == 0x44)
{
UCHAR *pTargetIPAddr = pSrcBuf + 24;
/* Client hardware address */
UCHAR *pTargetMACAddr = pSrcBuf + 36;
if ((pMbss->WNMCtrl.ProxyARPEnable) && (pEntry = MacTableLookup(pAd, pTargetMACAddr)))
{
printk("entry apidx=%d,%d,%d\n",pEntry->apidx, wdev_idx, pMbss->WNMCtrl.ProxyARPEnable);
if ((pEntry->apidx == wdev_idx) && pMbss->WNMCtrl.ProxyARPEnable)
{
/* Proxy MAC address/IP mapping */
AddIPv4ProxyARPEntry(pAd, pMbss, pTargetMACAddr, pTargetIPAddr);
}
}
}
}
VOID WNMIPv6ProxyARPCheck(
IN PRTMP_ADAPTER pAd,
PNDIS_PACKET pPacket,
PUCHAR pSrcBuf)
{
struct wifi_dev *wdev;
UCHAR wdev_idx = RTMP_GET_PACKET_WDEV(pPacket);
BSS_STRUCT *pMbss;
UCHAR Offset = 0;
ASSERT(wdev_idx < WDEV_NUM_MAX);
if (wdev_idx >= WDEV_NUM_MAX) {
DBGPRINT(RT_DEBUG_ERROR, ("%s(): Invalid wdev_idx(%d)\n", __FUNCTION__, wdev_idx));
return;
}
wdev = pAd->wdev_list[wdev_idx];
ASSERT(wdev->func_idx < pAd->ApCfg.BssidNum);
pMbss = &pAd->ApCfg.MBSSID[wdev->func_idx];
if (pMbss->WNMCtrl.ProxyARPEnable)
{
/* Check if router advertisement, and add proxy entry */
if (IsIPv6RouterAdvertisement(pAd, pSrcBuf - 2, &Offset))
{
UCHAR *Pos = pSrcBuf + 4;
UCHAR TargetIPAddr[16];
INT32 PayloadLen;
DBGPRINT(RT_DEBUG_OFF, ("This packet is router advertisement\n"));
NdisMoveMemory(&PayloadLen, Pos, 2);
PayloadLen = OS_NTOHS(PayloadLen);
printk("WNMIPv6ProxyARPCheck: offset=%d\n", Offset);
/* IPv6 options */
Pos += 52 + Offset;
PayloadLen -= (16 + Offset);
while (PayloadLen > 0)
{
UINT8 OptionsLen = (*(Pos + 1)) * 8;
/* Prefix information */
if (*Pos == 0x03)
{
UCHAR *Prefix;
INT32 Ret;
PROXY_ARP_IPV6_ENTRY *ProxyARPEntry;
PWNM_CTRL pWNMCtrl = &pMbss->WNMCtrl;
/* Prefix */
Prefix = (Pos + 16);
/* Copy global address prefix */
NdisMoveMemory(TargetIPAddr, Prefix, 8);
RTMP_SEM_EVENT_WAIT(&pWNMCtrl->ProxyARPListLock, Ret);
DlListForEach(ProxyARPEntry, &pWNMCtrl->IPv6ProxyARPList,
PROXY_ARP_IPV6_ENTRY, List)
{
if (ProxyARPEntry->TargetIPType == IPV6_LINK_LOCAL)
{
/* Copy host ipv6 interface identifier */
NdisMoveMemory(&TargetIPAddr[8],
&ProxyARPEntry->TargetIPAddr[8], 8);
/* Proxy MAC address/IPv6 mapping for global address */
AddIPv6ProxyARPEntry(pAd, pMbss, ProxyARPEntry->TargetMACAddr,
TargetIPAddr);
}
}
RTMP_SEM_EVENT_UP(&pWNMCtrl->ProxyARPListLock);
}
Pos += OptionsLen;
PayloadLen -= OptionsLen;
}
}
}
}
static VOID ReceiveBTMQuery(IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
BTM_EVENT_DATA *Event;
WNM_FRAME *WNMFrame = (WNM_FRAME *)Elem->Msg;
BTM_PEER_ENTRY *BTMPeerEntry;
PWNM_CTRL pWNMCtrl = NULL;
UCHAR APIndex, *Buf;
UINT16 VarLen;
UINT32 Len = 0;
INT32 Ret;
BOOLEAN IsFound = FALSE;
printk("%s\n", __FUNCTION__);
for (APIndex = 0; APIndex < MAX_MBSSID_NUM(pAd); APIndex++)
{
if (MAC_ADDR_EQUAL(WNMFrame->Hdr.Addr3, pAd->ApCfg.MBSSID[APIndex].wdev.bssid))
{
pWNMCtrl = &pAd->ApCfg.MBSSID[APIndex].WNMCtrl;
break;
}
}
if (!pWNMCtrl)
{
DBGPRINT(RT_DEBUG_ERROR, ("%s Can not find Peer Control\n", __FUNCTION__));
return;
}
RTMP_SEM_EVENT_WAIT(&pWNMCtrl->BTMPeerListLock, Ret);
DlListForEach(BTMPeerEntry, &pWNMCtrl->BTMPeerList, BTM_PEER_ENTRY, List)
{
if (MAC_ADDR_EQUAL(BTMPeerEntry->PeerMACAddr, WNMFrame->Hdr.Addr2))
IsFound = TRUE;
break;
}
RTMP_SEM_EVENT_UP(&pWNMCtrl->BTMPeerListLock);
if (IsFound) {
DBGPRINT(RT_DEBUG_ERROR, ("%s Find peer address in BTMPeerList already\n", __FUNCTION__));
return;
}
os_alloc_mem(NULL, (UCHAR **)&BTMPeerEntry, sizeof(*BTMPeerEntry));
if (!BTMPeerEntry)
{
DBGPRINT(RT_DEBUG_ERROR, ("%s Not available memory\n", __FUNCTION__));
return;
}
NdisZeroMemory(BTMPeerEntry, sizeof(*BTMPeerEntry));
BTMPeerEntry->CurrentState = WAIT_PEER_BTM_QUERY;
NdisMoveMemory(BTMPeerEntry->PeerMACAddr, WNMFrame->Hdr.Addr2, MAC_ADDR_LEN);
BTMPeerEntry->DialogToken = WNMFrame->u.BTM_QUERY.DialogToken;
BTMPeerEntry->Priv = pAd;
RTMPInitTimer(pAd, &BTMPeerEntry->WaitPeerBTMRspTimer,
GET_TIMER_FUNCTION(WaitPeerBTMRspTimeout), BTMPeerEntry, FALSE);
RTMP_SEM_EVENT_WAIT(&pWNMCtrl->BTMPeerListLock, Ret);
DlListAddTail(&pWNMCtrl->BTMPeerList, &BTMPeerEntry->List);
RTMP_SEM_EVENT_UP(&pWNMCtrl->BTMPeerListLock);
VarLen = *(WNMFrame->u.BTM_QUERY.Variable + 2);
VarLen += 3;
os_alloc_mem(NULL, (UCHAR **)&Buf, sizeof(*Event) + VarLen);
if (!Buf)
{
DBGPRINT(RT_DEBUG_ERROR, ("%s Not available memory\n", __FUNCTION__));
goto error;
}
NdisZeroMemory(Buf, sizeof(*Event) + VarLen);
Event = (BTM_EVENT_DATA *)Buf;
Event->ControlIndex = APIndex;
Len += 1;
NdisMoveMemory(Event->PeerMACAddr, WNMFrame->Hdr.Addr2, MAC_ADDR_LEN);
Len += MAC_ADDR_LEN;
Event->EventType = PEER_BTM_QUERY;
Len += 2;
Event->u.PEER_BTM_QUERY_DATA.DialogToken = WNMFrame->u.BTM_QUERY.DialogToken;
Len += 1;
/* FIXME */
Event->u.PEER_BTM_QUERY_DATA.BTMQueryLen;
Len += 2;
NdisMoveMemory(Event->u.PEER_BTM_QUERY_DATA.BTMQuery, WNMFrame->u.BTM_QUERY.Variable,
VarLen);
Len += VarLen;
MlmeEnqueue(pAd, BTM_STATE_MACHINE, PEER_BTM_QUERY, Len, Buf,0);
os_free_mem(NULL, Buf);
return;
error:
DlListDel(&BTMPeerEntry->List);
os_free_mem(NULL, BTMPeerEntry);
}
static VOID ReceiveBTMRsp(IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
BTM_EVENT_DATA *Event;
WNM_FRAME *WNMFrame = (WNM_FRAME *)Elem->Msg;
BTM_PEER_ENTRY *BTMPeerEntry;
PWNM_CTRL pWNMCtrl = NULL;
UCHAR APIndex, *Buf;
UINT16 VarLen = 0;
UINT32 Len = 0;
INT32 Ret;
BOOLEAN IsFound = FALSE, Cancelled;
printk("%s\n", __FUNCTION__);
for (APIndex = 0; APIndex < MAX_MBSSID_NUM(pAd); APIndex++)
{
if (MAC_ADDR_EQUAL(WNMFrame->Hdr.Addr3, pAd->ApCfg.MBSSID[APIndex].wdev.bssid))
{
pWNMCtrl = &pAd->ApCfg.MBSSID[APIndex].WNMCtrl;
break;
}
}
if (!pWNMCtrl)
{
DBGPRINT(RT_DEBUG_ERROR, ("%s Can not find Peer Control\n", __FUNCTION__));
return;
}
RTMP_SEM_EVENT_WAIT(&pWNMCtrl->BTMPeerListLock, Ret);
DlListForEach(BTMPeerEntry, &pWNMCtrl->BTMPeerList, BTM_PEER_ENTRY, List)
{
if (MAC_ADDR_EQUAL(BTMPeerEntry->PeerMACAddr, WNMFrame->Hdr.Addr2))
IsFound = TRUE;
break;
}
RTMP_SEM_EVENT_UP(&pWNMCtrl->BTMPeerListLock);
if (!IsFound) {
DBGPRINT(RT_DEBUG_ERROR, ("Not found peer entry in list\n"));
return;
}
/* Cancel Wait peer wnm response frame */
RTMPCancelTimer(&BTMPeerEntry->WaitPeerBTMRspTimer, &Cancelled);
RTMPReleaseTimer(&BTMPeerEntry->WaitPeerBTMRspTimer, &Cancelled);
VarLen = 2;
if (*WNMFrame->u.BTM_RSP.Variable == 0)
VarLen += 6;
VarLen += *(WNMFrame->u.BTM_RSP.Variable + VarLen + 1);
VarLen += 2;
os_alloc_mem(NULL, (UCHAR **)&Buf, sizeof(*Event) + VarLen);
if (!Buf)
{
DBGPRINT(RT_DEBUG_ERROR, ("%s Not available memory\n", __FUNCTION__));
return;
}
NdisZeroMemory(Buf, sizeof(*Event) + VarLen);
Event = (BTM_EVENT_DATA *)Buf;
Event->ControlIndex = APIndex;
Len += 1;
NdisMoveMemory(Event->PeerMACAddr, WNMFrame->Hdr.Addr2, MAC_ADDR_LEN);
Len += MAC_ADDR_LEN;
Event->EventType = PEER_BTM_RSP;
Len += 2;
Event->u.PEER_BTM_RSP_DATA.DialogToken = WNMFrame->u.BTM_RSP.DialogToken;
Len += 1;
/* FIXME */
Event->u.PEER_BTM_RSP_DATA.BTMRspLen;
Len += 2;
NdisMoveMemory(Event->u.PEER_BTM_RSP_DATA.BTMRsp, WNMFrame->u.BTM_RSP.Variable,
VarLen);
Len += VarLen;
MlmeEnqueue(pAd, BTM_STATE_MACHINE, PEER_BTM_RSP, Len, Buf,0);
os_free_mem(NULL, Buf);
return;
}
VOID BTMSetPeerCurrentState(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem,
IN enum BTM_STATE State)
{
PWNM_CTRL pWNMCtrl;
PBTM_PEER_ENTRY BTMPeerEntry;
PBTM_EVENT_DATA Event = (PBTM_EVENT_DATA)Elem->Msg;
INT32 Ret;
#ifdef CONFIG_AP_SUPPORT
pWNMCtrl = &pAd->ApCfg.MBSSID[Event->ControlIndex].WNMCtrl;
#endif /* CONFIG_AP_SUPPORT */
RTMP_SEM_EVENT_WAIT(&pWNMCtrl->BTMPeerListLock, Ret);
DlListForEach(BTMPeerEntry, &pWNMCtrl->BTMPeerList,
BTM_PEER_ENTRY, List)
{
if (MAC_ADDR_EQUAL(BTMPeerEntry->PeerMACAddr, Event->PeerMACAddr))
{
BTMPeerEntry->CurrentState = State;
break;
}
}
RTMP_SEM_EVENT_UP(&pWNMCtrl->BTMPeerListLock);
}
static VOID SendBTMQueryIndication(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
BTM_EVENT_DATA *Event = (BTM_EVENT_DATA *)Elem->Msg;
PNET_DEV NetDev = pAd->ApCfg.MBSSID[Event->ControlIndex].wdev.if_dev;
printk("%s\n", __FUNCTION__);
/* Send BTM query indication to daemon */
SendBTMQueryEvent(NetDev,
Event->PeerMACAddr,
Event->u.PEER_BTM_QUERY_DATA.BTMQuery,
Event->u.PEER_BTM_QUERY_DATA.BTMQueryLen,
RA_WEXT);
BTMSetPeerCurrentState(pAd, Elem, WAIT_BTM_REQ);
}
VOID WaitPeerBTMRspTimeout(
IN PVOID SystemSpecific1,
IN PVOID FunctionContext,
IN PVOID SystemSpecific2,
IN PVOID SystemSpecific3)
{
BTM_PEER_ENTRY *BTMPeerEntry = (BTM_PEER_ENTRY *)FunctionContext;
PRTMP_ADAPTER pAd;
PWNM_CTRL pWNMCtrl;
INT32 Ret;
BOOLEAN Cancelled;
printk("%s\n", __FUNCTION__);
if (!BTMPeerEntry)
return;
pAd = BTMPeerEntry->Priv;
RTMPReleaseTimer(&BTMPeerEntry->WaitPeerBTMRspTimer, &Cancelled);
if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS
| fRTMP_ADAPTER_NIC_NOT_EXIST))
return;
pWNMCtrl = &pAd->ApCfg.MBSSID[BTMPeerEntry->ControlIndex].WNMCtrl;
RTMP_SEM_EVENT_WAIT(&pWNMCtrl->BTMPeerListLock, Ret);
DlListDel(&BTMPeerEntry->List);
RTMP_SEM_EVENT_UP(&pWNMCtrl->BTMPeerListLock);
os_free_mem(NULL, BTMPeerEntry);
}
BUILD_TIMER_FUNCTION(WaitPeerBTMRspTimeout);
static VOID SendBTMReq(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
BTM_EVENT_DATA *Event = (BTM_EVENT_DATA *)Elem->Msg;
UCHAR *Buf;
WNM_FRAME *WNMFrame;
BTM_PEER_ENTRY *BTMPeerEntry = NULL;
PWNM_CTRL pWNMCtrl = &pAd->ApCfg.MBSSID[Event->ControlIndex].WNMCtrl;
UINT32 FrameLen = 0, VarLen = Event->u.BTM_REQ_DATA.BTMReqLen;
INT32 Ret;
RTMP_SEM_EVENT_WAIT(&pWNMCtrl->BTMPeerListLock, Ret);
DlListForEach(BTMPeerEntry, &pWNMCtrl->BTMPeerList,
BTM_PEER_ENTRY, List)
{
if (MAC_ADDR_EQUAL(BTMPeerEntry->PeerMACAddr, Event->PeerMACAddr))
{
break;
}
}
RTMP_SEM_EVENT_UP(&pWNMCtrl->BTMPeerListLock);
os_alloc_mem(NULL, (UCHAR **)&Buf, sizeof(*WNMFrame) + VarLen);
if (!Buf)
{
DBGPRINT(RT_DEBUG_ERROR, ("%s Not available memory\n", __FUNCTION__));
return;
}
NdisZeroMemory(Buf, sizeof(*WNMFrame) + VarLen);
WNMFrame = (WNM_FRAME *)Buf;
ActHeaderInit(pAd, &WNMFrame->Hdr, Event->PeerMACAddr,
pAd->ApCfg.MBSSID[Event->ControlIndex].wdev.bssid,
pAd->ApCfg.MBSSID[Event->ControlIndex].wdev.bssid);
FrameLen += sizeof(HEADER_802_11);
WNMFrame->Category = CATEGORY_WNM;
FrameLen += 1;
WNMFrame->u.BTM_REQ.Action = BSS_TRANSITION_REQ;
FrameLen += 1;
WNMFrame->u.BTM_REQ.DialogToken = Event->u.BTM_REQ_DATA.DialogToken;
FrameLen += 1;
NdisMoveMemory(WNMFrame->u.BTM_REQ.Variable, Event->u.BTM_REQ_DATA.BTMReq,
Event->u.BTM_REQ_DATA.BTMReqLen);
FrameLen += Event->u.BTM_REQ_DATA.BTMReqLen;
BTMSetPeerCurrentState(pAd, Elem, WAIT_PEER_BTM_RSP);
MiniportMMRequest(pAd, 0, Buf, FrameLen);
RTMPSetTimer(&BTMPeerEntry->WaitPeerBTMRspTimer, WaitPeerBTMRspTimeoutVale);
#ifdef CONFIG_HOTSPOT_R2
{
MAC_TABLE_ENTRY *pEntry;
if ((pEntry = MacTableLookup(pAd, Event->PeerMACAddr)) != NULL)
{
UINT8 *BTMData = (UINT8 *)Event->u.BTM_REQ_DATA.BTMReq;
pEntry->BTMDisassocCount = (((*(BTMData+2) << 8) | (*(BTMData+1)))*pAd->CommonCfg.BeaconPeriod)/1000;
printk("bss discount sec=%d\n", pEntry->BTMDisassocCount);
if (pEntry->BTMDisassocCount < 1)
pEntry->BTMDisassocCount = 1;
}
}
#endif
os_free_mem(NULL, Buf);
}
static VOID SendBTMConfirm(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
PBTM_PEER_ENTRY BTMPeerEntry, BTMPeerEntryTmp;
BTM_EVENT_DATA *Event = (BTM_EVENT_DATA *)Elem->Msg;
PWNM_CTRL pWNMCtrl = &pAd->ApCfg.MBSSID[Event->ControlIndex].WNMCtrl;
PNET_DEV NetDev = pAd->ApCfg.MBSSID[Event->ControlIndex].wdev.if_dev;
INT32 Ret;
printk("%s\n", __FUNCTION__);
/* Send BTM confirm to daemon */
SendBTMConfirmEvent(NetDev,
Event->PeerMACAddr,
Event->u.PEER_BTM_RSP_DATA.BTMRsp,
Event->u.PEER_BTM_RSP_DATA.BTMRspLen,
RA_WEXT);
/* Delete BTM peer entry */
RTMP_SEM_EVENT_WAIT(&pWNMCtrl->BTMPeerListLock, Ret);
DlListForEachSafe(BTMPeerEntry, BTMPeerEntryTmp, &pWNMCtrl->BTMPeerList, BTM_PEER_ENTRY, List)
{
if (MAC_ADDR_EQUAL(BTMPeerEntry->PeerMACAddr, Event->PeerMACAddr))
{
DlListDel(&BTMPeerEntry->List);
os_free_mem(NULL, BTMPeerEntry);
break;
}
}
RTMP_SEM_EVENT_UP(&pWNMCtrl->BTMPeerListLock);
}
#endif /* CONFIG_AP_SUPPORT */
#ifdef CONFIG_STA_SUPPORT
static VOID ReceiveBTMReq(IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
}
static VOID SendBTMQuery(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
}
static VOID SendBTMIndication(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
}
static VOID SendBTMRsp(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
}
#endif /* CONFIG_STA_SUPPORT */
enum BTM_STATE BTMPeerCurrentState(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
PWNM_CTRL pWNMCtrl;
PBTM_PEER_ENTRY BTMPeerEntry;
PBTM_EVENT_DATA Event = (PBTM_EVENT_DATA)Elem->Msg;
INT32 Ret;
#ifdef CONFIG_AP_SUPPORT
pWNMCtrl = &pAd->ApCfg.MBSSID[Event->ControlIndex].WNMCtrl;
#endif /* CONFIG_AP_SUPPORT */
RTMP_SEM_EVENT_WAIT(&pWNMCtrl->BTMPeerListLock, Ret);
DlListForEach(BTMPeerEntry, &pWNMCtrl->BTMPeerList, BTM_PEER_ENTRY, List)
{
if (MAC_ADDR_EQUAL(BTMPeerEntry->PeerMACAddr, Event->PeerMACAddr))
{
RTMP_SEM_EVENT_UP(&pWNMCtrl->BTMPeerListLock);
return BTMPeerEntry->CurrentState;
}
}
RTMP_SEM_EVENT_UP(&pWNMCtrl->BTMPeerListLock);
return BTM_UNKNOWN;
}
void PeerWNMAction(IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
UCHAR Action = Elem->Msg[LENGTH_802_11+1];
switch(Action)
{
#ifdef CONFIG_AP_SUPPORT
case BSS_TRANSITION_QUERY:
ReceiveBTMQuery(pAd, Elem);
break;
case BSS_TRANSITION_RSP:
ReceiveBTMRsp(pAd, Elem);
break;
#ifdef CONFIG_HOTSPOT_R2
case WNM_NOTIFICATION_RSP:
ReceiveWNMNotifyRsp(pAd, Elem);
break;
#endif
#endif /* CONFIG_AP_SUPPORT */
#ifdef CONFIG_STA_SUPPORT
case BSS_TRANSITION_REQ:
ReceiveBTMReq(pAd, Elem);
break;
#endif /* CONFIG_STA_SUPPORT */
default:
DBGPRINT(RT_DEBUG_TRACE, ("Invalid action field = %d\n", Action));
break;
}
}
VOID WNMCtrlInit(IN PRTMP_ADAPTER pAd)
{
PWNM_CTRL pWNMCtrl;
#ifdef CONFIG_AP_SUPPORT
UCHAR APIndex;
#endif /* CONFIG_AP_SUPPORT */
#ifdef CONFIG_AP_SUPPORT
for (APIndex = 0; APIndex < MAX_MBSSID_NUM(pAd); APIndex++)
{
pWNMCtrl = &pAd->ApCfg.MBSSID[APIndex].WNMCtrl;
NdisZeroMemory(pWNMCtrl, sizeof(*pWNMCtrl));
RTMP_SEM_EVENT_INIT(&pWNMCtrl->BTMPeerListLock, &pAd->RscSemMemList);
RTMP_SEM_EVENT_INIT(&pWNMCtrl->ProxyARPListLock, &pAd->RscSemMemList);
RTMP_SEM_EVENT_INIT(&pWNMCtrl->ProxyARPIPv6ListLock, &pAd->RscSemMemList);
DlListInit(&pWNMCtrl->BTMPeerList);
DlListInit(&pWNMCtrl->IPv4ProxyARPList);
DlListInit(&pWNMCtrl->IPv6ProxyARPList);
#ifdef CONFIG_HOTSPOT_R2
RTMP_SEM_EVENT_INIT(&pWNMCtrl->WNMNotifyPeerListLock, &pAd->RscSemMemList);
DlListInit(&pWNMCtrl->WNMNotifyPeerList);
#endif
}
#endif
}
static VOID WNMCtrlRemoveAllIE(PWNM_CTRL pWNMCtrl)
{
if (pWNMCtrl->TimeadvertisementIELen)
{
pWNMCtrl->TimeadvertisementIELen = 0;
os_free_mem(NULL, pWNMCtrl->TimeadvertisementIE);
}
if (pWNMCtrl->TimezoneIELen)
{
pWNMCtrl->TimezoneIELen = 0;
os_free_mem(NULL, pWNMCtrl->TimezoneIE);
}
}
VOID WNMCtrlExit(IN PRTMP_ADAPTER pAd)
{
PWNM_CTRL pWNMCtrl;
UINT32 Ret;
BTM_PEER_ENTRY *BTMPeerEntry, *BTMPeerEntryTmp;
#ifdef CONFIG_AP_SUPPORT
PROXY_ARP_IPV4_ENTRY *ProxyARPIPv4Entry, *ProxyARPIPv4EntryTmp;
PROXY_ARP_IPV6_ENTRY *ProxyARPIPv6Entry, *ProxyARPIPv6EntryTmp;
UCHAR APIndex;
#endif /* CONFIG_AP_SUPPORT */
#ifdef CONFIG_HOTSPOT_R2
WNM_NOTIFY_PEER_ENTRY *WNMNotifyPeerEntry, *WNMNotifyPeerEntryTmp;
#endif
#ifdef CONFIG_AP_SUPPORT
for (APIndex = 0; APIndex < MAX_MBSSID_NUM(pAd); APIndex++)
{
pWNMCtrl = &pAd->ApCfg.MBSSID[APIndex].WNMCtrl;
RTMP_SEM_EVENT_WAIT(&pWNMCtrl->BTMPeerListLock, Ret);
/* Remove all btm peer entry */
DlListForEachSafe(BTMPeerEntry, BTMPeerEntryTmp,
&pWNMCtrl->BTMPeerList, BTM_PEER_ENTRY, List)
{
DlListDel(&BTMPeerEntry->List);
os_free_mem(NULL, BTMPeerEntry);
}
DlListInit(&pWNMCtrl->BTMPeerList);
RTMP_SEM_EVENT_UP(&pWNMCtrl->BTMPeerListLock);
RTMP_SEM_EVENT_DESTORY(&pWNMCtrl->BTMPeerListLock);
RTMP_SEM_EVENT_WAIT(&pWNMCtrl->ProxyARPListLock, Ret);
/* Remove all proxy arp entry */
DlListForEachSafe(ProxyARPIPv4Entry, ProxyARPIPv4EntryTmp,
&pWNMCtrl->IPv4ProxyARPList, PROXY_ARP_IPV4_ENTRY, List)
{
DlListDel(&ProxyARPIPv4Entry->List);
os_free_mem(NULL, ProxyARPIPv4Entry);
}
DlListInit(&pWNMCtrl->IPv4ProxyARPList);
RTMP_SEM_EVENT_UP(&pWNMCtrl->ProxyARPListLock);
RTMP_SEM_EVENT_WAIT(&pWNMCtrl->ProxyARPIPv6ListLock, Ret);
DlListForEachSafe(ProxyARPIPv6Entry, ProxyARPIPv6EntryTmp,
&pWNMCtrl->IPv6ProxyARPList, PROXY_ARP_IPV6_ENTRY, List)
{
DlListDel(&ProxyARPIPv6Entry->List);
os_free_mem(NULL, ProxyARPIPv6Entry);
}
DlListInit(&pWNMCtrl->IPv6ProxyARPList);
RTMP_SEM_EVENT_UP(&pWNMCtrl->ProxyARPIPv6ListLock);
RTMP_SEM_EVENT_DESTORY(&pWNMCtrl->ProxyARPListLock);
RTMP_SEM_EVENT_DESTORY(&pWNMCtrl->ProxyARPIPv6ListLock);
#ifdef CONFIG_HOTSPOT_R2
RTMP_SEM_EVENT_WAIT(&pWNMCtrl->WNMNotifyPeerListLock, Ret);
/* Remove all wnm notify peer entry */
DlListForEachSafe(WNMNotifyPeerEntry, WNMNotifyPeerEntryTmp,
&pWNMCtrl->WNMNotifyPeerList, WNM_NOTIFY_PEER_ENTRY, List)
{
DlListDel(&WNMNotifyPeerEntry->List);
os_free_mem(NULL, WNMNotifyPeerEntry);
}
DlListInit(&pWNMCtrl->WNMNotifyPeerList);
RTMP_SEM_EVENT_UP(&pWNMCtrl->WNMNotifyPeerListLock);
RTMP_SEM_EVENT_DESTORY(&pWNMCtrl->WNMNotifyPeerListLock);
#endif
/* Remove all WNM IEs */
WNMCtrlRemoveAllIE(pWNMCtrl);
}
#endif /* CONFIG_AP_SUPPORT */
}
#ifdef CONFIG_AP_SUPPORT
VOID Clear_All_PROXY_TABLE(IN PRTMP_ADAPTER pAd)
{
POS_COOKIE pObj = (POS_COOKIE)pAd->OS_Cookie;
UCHAR APIndex = pObj->ioctl_if;
PWNM_CTRL pWNMCtrl;
UINT32 Ret;
PROXY_ARP_IPV4_ENTRY *ProxyARPIPv4Entry, *ProxyARPIPv4EntryTmp;
PROXY_ARP_IPV6_ENTRY *ProxyARPIPv6Entry, *ProxyARPIPv6EntryTmp;
pWNMCtrl = &pAd->ApCfg.MBSSID[APIndex].WNMCtrl;
RTMP_SEM_EVENT_WAIT(&pWNMCtrl->ProxyARPListLock, Ret);
/* Remove all proxy arp entry */
DlListForEachSafe(ProxyARPIPv4Entry, ProxyARPIPv4EntryTmp,
&pWNMCtrl->IPv4ProxyARPList, PROXY_ARP_IPV4_ENTRY, List)
{
DlListDel(&ProxyARPIPv4Entry->List);
os_free_mem(NULL, ProxyARPIPv4Entry);
}
DlListInit(&pWNMCtrl->IPv4ProxyARPList);
RTMP_SEM_EVENT_UP(&pWNMCtrl->ProxyARPListLock);
RTMP_SEM_EVENT_WAIT(&pWNMCtrl->ProxyARPIPv6ListLock, Ret);
DlListForEachSafe(ProxyARPIPv6Entry, ProxyARPIPv6EntryTmp,
&pWNMCtrl->IPv6ProxyARPList, PROXY_ARP_IPV6_ENTRY, List)
{
DlListDel(&ProxyARPIPv6Entry->List);
os_free_mem(NULL, ProxyARPIPv6Entry);
}
DlListInit(&pWNMCtrl->IPv6ProxyARPList);
RTMP_SEM_EVENT_UP(&pWNMCtrl->ProxyARPIPv6ListLock);
}
#endif
VOID BTMStateMachineInit(
IN PRTMP_ADAPTER pAd,
IN STATE_MACHINE *S,
OUT STATE_MACHINE_FUNC Trans[])
{
DBGPRINT(RT_DEBUG_TRACE, ("%s\n", __FUNCTION__));
StateMachineInit(S, (STATE_MACHINE_FUNC*)Trans, MAX_BTM_STATE, MAX_BTM_MSG, (STATE_MACHINE_FUNC)Drop, BTM_UNKNOWN, BTM_MACHINE_BASE);
#ifdef CONFIG_AP_SUPPORT
StateMachineSetAction(S, WAIT_PEER_BTM_QUERY, PEER_BTM_QUERY, (STATE_MACHINE_FUNC)SendBTMQueryIndication);
StateMachineSetAction(S, WAIT_BTM_REQ, BTM_REQ, (STATE_MACHINE_FUNC)SendBTMReq);
StateMachineSetAction(S, WAIT_PEER_BTM_RSP, PEER_BTM_RSP, (STATE_MACHINE_FUNC)SendBTMConfirm);
#endif /* CONFIG_AP_SUPPORT */
#ifdef CONFIG_STA_SUPPORT
StateMachineSetAction(S, WAIT_BTM_QUERY, BTM_QUERY, (STATE_MACHINE_FUNC)SendBTMQuery);
StateMachineSetAction(S, WAIT_PEER_BTM_REQ, PEER_BTM_REQ, (STATE_MACHINE_FUNC)SendBTMIndication);
StateMachineSetAction(S, WAIT_BTM_RSP,BTM_RSP, (STATE_MACHINE_FUNC)SendBTMRsp);
#endif /* CONFIG_STA_SUPPORT */
}
#ifdef CONFIG_HOTSPOT_R2
#ifdef CONFIG_AP_SUPPORT
VOID WNMSetPeerCurrentState(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem,
IN enum WNM_NOTIFY_STATE State)
{
PWNM_CTRL pWNMCtrl;
PWNM_NOTIFY_PEER_ENTRY WNMNotifyPeerEntry;
PWNM_NOTIFY_EVENT_DATA Event = (PWNM_NOTIFY_EVENT_DATA)Elem->Msg;
INT32 Ret;
#ifdef CONFIG_AP_SUPPORT
pWNMCtrl = &pAd->ApCfg.MBSSID[Event->ControlIndex].WNMCtrl;
#endif /* CONFIG_AP_SUPPORT */
RTMP_SEM_EVENT_WAIT(&pWNMCtrl->WNMNotifyPeerListLock, Ret);
DlListForEach(WNMNotifyPeerEntry, &pWNMCtrl->WNMNotifyPeerList,
WNM_NOTIFY_PEER_ENTRY, List)
{
if (MAC_ADDR_EQUAL(WNMNotifyPeerEntry->PeerMACAddr, Event->PeerMACAddr))
{
WNMNotifyPeerEntry->CurrentState = State;
break;
}
}
RTMP_SEM_EVENT_UP(&pWNMCtrl->WNMNotifyPeerListLock);
}
enum WNM_NOTIFY_STATE WNMNotifyPeerCurrentState(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
PWNM_CTRL pWNMCtrl;
PWNM_NOTIFY_PEER_ENTRY WNMNotifyPeerEntry;
PWNM_NOTIFY_EVENT_DATA Event = (PWNM_NOTIFY_EVENT_DATA)Elem->Msg;
INT32 Ret;
#ifdef CONFIG_AP_SUPPORT
pWNMCtrl = &pAd->ApCfg.MBSSID[Event->ControlIndex].WNMCtrl;
#endif /* CONFIG_AP_SUPPORT */
RTMP_SEM_EVENT_WAIT(&pWNMCtrl->WNMNotifyPeerListLock, Ret);
DlListForEach(WNMNotifyPeerEntry, &pWNMCtrl->WNMNotifyPeerList, WNM_NOTIFY_PEER_ENTRY, List)
{
if (MAC_ADDR_EQUAL(WNMNotifyPeerEntry->PeerMACAddr, Event->PeerMACAddr))
{
RTMP_SEM_EVENT_UP(&pWNMCtrl->WNMNotifyPeerListLock);
return WNMNotifyPeerEntry->CurrentState;
}
}
RTMP_SEM_EVENT_UP(&pWNMCtrl->WNMNotifyPeerListLock);
return WNM_NOTIFY_UNKNOWN;
}
VOID WaitPeerWNMNotifyRspTimeout(
IN PVOID SystemSpecific1,
IN PVOID FunctionContext,
IN PVOID SystemSpecific2,
IN PVOID SystemSpecific3)
{
WNM_NOTIFY_PEER_ENTRY *WNMNotifyPeerEntry = (WNM_NOTIFY_PEER_ENTRY *)FunctionContext;
PRTMP_ADAPTER pAd;
PWNM_CTRL pWNMCtrl;
INT32 Ret;
BOOLEAN Cancelled;
printk("%s\n", __FUNCTION__);
if (!WNMNotifyPeerEntry)
return;
pAd = WNMNotifyPeerEntry->Priv;
RTMPReleaseTimer(&WNMNotifyPeerEntry->WaitPeerWNMNotifyRspTimer, &Cancelled);
if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS
| fRTMP_ADAPTER_NIC_NOT_EXIST))
return;
pWNMCtrl = &pAd->ApCfg.MBSSID[WNMNotifyPeerEntry->ControlIndex].WNMCtrl;
RTMP_SEM_EVENT_WAIT(&pWNMCtrl->WNMNotifyPeerListLock, Ret);
DlListDel(&WNMNotifyPeerEntry->List);
RTMP_SEM_EVENT_UP(&pWNMCtrl->WNMNotifyPeerListLock);
os_free_mem(NULL, WNMNotifyPeerEntry);
}
BUILD_TIMER_FUNCTION(WaitPeerWNMNotifyRspTimeout);
VOID ReceiveWNMNotifyRsp(IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
WNM_NOTIFY_EVENT_DATA *Event;
WNM_FRAME *WNMFrame = (WNM_FRAME *)Elem->Msg;
WNM_NOTIFY_PEER_ENTRY *WNMNotifyPeerEntry;
PWNM_CTRL pWNMCtrl = NULL;
UCHAR APIndex, *Buf;
UINT16 VarLen = 0;
UINT32 Len = 0;
INT32 Ret;
BOOLEAN IsFound = FALSE, Cancelled;
printk("%s\n", __FUNCTION__);
for (APIndex = 0; APIndex < MAX_MBSSID_NUM(pAd); APIndex++)
{
if (MAC_ADDR_EQUAL(WNMFrame->Hdr.Addr3, pAd->ApCfg.MBSSID[APIndex].wdev.bssid))
{
pWNMCtrl = &pAd->ApCfg.MBSSID[APIndex].WNMCtrl;
break;
}
}
if (!pWNMCtrl)
{
DBGPRINT(RT_DEBUG_ERROR, ("%s Can not find Peer Control\n", __FUNCTION__));
return;
}
RTMP_SEM_EVENT_WAIT(&pWNMCtrl->WNMNotifyPeerListLock, Ret);
DlListForEach(WNMNotifyPeerEntry, &pWNMCtrl->WNMNotifyPeerList, WNM_NOTIFY_PEER_ENTRY, List)
{
if (MAC_ADDR_EQUAL(WNMNotifyPeerEntry->PeerMACAddr, WNMFrame->Hdr.Addr2))
IsFound = TRUE;
break;
}
RTMP_SEM_EVENT_UP(&pWNMCtrl->WNMNotifyPeerListLock);
if (!IsFound) {
DBGPRINT(RT_DEBUG_ERROR, ("Not found peer entry in list\n"));
{
unsigned char *tmp1 = (unsigned char *)WNMFrame->Hdr.Addr2;
unsigned char *tmp2;
printk("client mac:%02x:%02x:%02x:%02x:%02x:%02x\n",*(tmp1),*(tmp1+1),*(tmp1+2),*(tmp1+3),*(tmp1+4),*(tmp1+5));
DlListForEach(WNMNotifyPeerEntry, &pWNMCtrl->WNMNotifyPeerList, WNM_NOTIFY_PEER_ENTRY, List)
{
tmp2 = (unsigned char *)WNMNotifyPeerEntry->PeerMACAddr;
printk("list=> %02x:%02x:%02x:%02x:%02x:%02x\n",*(tmp2),*(tmp2+1),*(tmp2+2),*(tmp2+3),*(tmp2+4),*(tmp2+5));
}
printk("\n");
}
return;
}
/* Cancel Wait peer wnm response frame */
RTMPCancelTimer(&WNMNotifyPeerEntry->WaitPeerWNMNotifyRspTimer, &Cancelled);
RTMPReleaseTimer(&WNMNotifyPeerEntry->WaitPeerWNMNotifyRspTimer, &Cancelled);
VarLen = 1;
os_alloc_mem(NULL, (UCHAR **)&Buf, sizeof(*Event) + VarLen);
if (!Buf)
{
DBGPRINT(RT_DEBUG_ERROR, ("%s Not available memory\n", __FUNCTION__));
return;
}
NdisZeroMemory(Buf, sizeof(*Event) + VarLen);
Event = (WNM_NOTIFY_EVENT_DATA *)Buf;
Event->ControlIndex = APIndex;
Len += 1;
NdisMoveMemory(Event->PeerMACAddr, WNMFrame->Hdr.Addr2, MAC_ADDR_LEN);
Len += MAC_ADDR_LEN;
Event->EventType = WNM_NOTIFY_RSP;
Len += 2;
Event->u.WNM_NOTIFY_RSP_DATA.DialogToken = WNMFrame->u.WNM_NOTIFY_RSP.DialogToken;
Len += 1;
Event->u.WNM_NOTIFY_RSP_DATA.WNMNotifyRspLen = 1;// = WNMFrame->u.WNM_NOTIFY_RSP.DialogToken;
Len += 2;
//NdisMoveMemory(Event->u.WNM_NOTIFY_RSP_DATA.WNMNotifyRsp, WNMFrame->u.WNM_NOTIFY_RSP.Variable,
// VarLen);
Event->u.WNM_NOTIFY_RSP_DATA.WNMNotifyRsp[0] = WNMFrame->u.WNM_NOTIFY_RSP.RespStatus;
Len += VarLen;
MlmeEnqueue(pAd, WNM_NOTIFY_STATE_MACHINE, WNM_NOTIFY_RSP, Len, Buf,0);
os_free_mem(NULL, Buf);
return;
}
static VOID SendWNMNotifyReq(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
WNM_NOTIFY_EVENT_DATA *Event = (WNM_NOTIFY_EVENT_DATA *)Elem->Msg;
UCHAR *Buf;
WNM_FRAME *WNMFrame;
WNM_NOTIFY_PEER_ENTRY *WNMNotifyPeerEntry = NULL;
PWNM_CTRL pWNMCtrl = &pAd->ApCfg.MBSSID[Event->ControlIndex].WNMCtrl;
UINT32 FrameLen = 0, VarLen = Event->u.WNM_NOTIFY_REQ_DATA.WNMNotifyReqLen;
INT32 Ret;
RTMP_SEM_EVENT_WAIT(&pWNMCtrl->WNMNotifyPeerListLock, Ret);
DlListForEach(WNMNotifyPeerEntry, &pWNMCtrl->WNMNotifyPeerList,
WNM_NOTIFY_PEER_ENTRY, List)
{
if (MAC_ADDR_EQUAL(WNMNotifyPeerEntry->PeerMACAddr, Event->PeerMACAddr))
{
break;
}
}
RTMP_SEM_EVENT_UP(&pWNMCtrl->WNMNotifyPeerListLock);
os_alloc_mem(NULL, (UCHAR **)&Buf, sizeof(*WNMFrame) + VarLen + 7);
if (!Buf)
{
DBGPRINT(RT_DEBUG_ERROR, ("%s Not available memory\n", __FUNCTION__));
return;
}
NdisZeroMemory(Buf, sizeof(*WNMFrame) + VarLen);
WNMFrame = (WNM_FRAME *)Buf;
ActHeaderInit(pAd, &WNMFrame->Hdr, Event->PeerMACAddr,
pAd->ApCfg.MBSSID[Event->ControlIndex].wdev.bssid,
pAd->ApCfg.MBSSID[Event->ControlIndex].wdev.bssid);
FrameLen += sizeof(HEADER_802_11);
WNMFrame->Category = CATEGORY_WNM;
FrameLen += 1;
WNMFrame->u.WNM_NOTIFY_REQ.Action = WNM_NOTIFICATION_REQ;
FrameLen += 1;
WNMFrame->u.WNM_NOTIFY_REQ.DialogToken = Event->u.WNM_NOTIFY_REQ_DATA.DialogToken;
FrameLen += 1;
WNMFrame->u.WNM_NOTIFY_REQ.Type = 1;
FrameLen += 1;
if (Event->EventType == 0) //remediation
{
printk("remediation\n");
WNMFrame->u.WNM_NOTIFY_REQ.Variable[0] = 0xdd;
WNMFrame->u.WNM_NOTIFY_REQ.Variable[1] = 5+Event->u.WNM_NOTIFY_REQ_DATA.WNMNotifyReqLen;
WNMFrame->u.WNM_NOTIFY_REQ.Variable[2] = 0x50;
WNMFrame->u.WNM_NOTIFY_REQ.Variable[3] = 0x6f;
WNMFrame->u.WNM_NOTIFY_REQ.Variable[4] = 0x9a;
WNMFrame->u.WNM_NOTIFY_REQ.Variable[5] = 0x00;
WNMFrame->u.WNM_NOTIFY_REQ.Variable[6] = Event->u.WNM_NOTIFY_REQ_DATA.WNMNotifyReqLen;
FrameLen += 7;
NdisMoveMemory(&WNMFrame->u.WNM_NOTIFY_REQ.Variable[7], Event->u.WNM_NOTIFY_REQ_DATA.WNMNotifyReq,
Event->u.WNM_NOTIFY_REQ_DATA.WNMNotifyReqLen);
FrameLen += Event->u.WNM_NOTIFY_REQ_DATA.WNMNotifyReqLen;
}
else if (Event->EventType == 2) //remediation+service method
{
printk("remediation with method\n");
WNMFrame->u.WNM_NOTIFY_REQ.Variable[0] = 0xdd;
WNMFrame->u.WNM_NOTIFY_REQ.Variable[1] = 5+Event->u.WNM_NOTIFY_REQ_DATA.WNMNotifyReqLen;
WNMFrame->u.WNM_NOTIFY_REQ.Variable[2] = 0x50;
WNMFrame->u.WNM_NOTIFY_REQ.Variable[3] = 0x6f;
WNMFrame->u.WNM_NOTIFY_REQ.Variable[4] = 0x9a;
WNMFrame->u.WNM_NOTIFY_REQ.Variable[5] = 0x00;
WNMFrame->u.WNM_NOTIFY_REQ.Variable[6] = Event->u.WNM_NOTIFY_REQ_DATA.WNMNotifyReqLen-1;
FrameLen += 7;
NdisMoveMemory(&WNMFrame->u.WNM_NOTIFY_REQ.Variable[7], Event->u.WNM_NOTIFY_REQ_DATA.WNMNotifyReq,
Event->u.WNM_NOTIFY_REQ_DATA.WNMNotifyReqLen);
FrameLen += Event->u.WNM_NOTIFY_REQ_DATA.WNMNotifyReqLen;
}
else if (Event->EventType == 1) //deauth imminent notice
{
MAC_TABLE_ENTRY *pEntry;
printk("deauth imminent: %d\n", Event->u.WNM_NOTIFY_REQ_DATA.WNMNotifyReqLen);
WNMFrame->u.WNM_NOTIFY_REQ.Variable[0] = 0xdd;
WNMFrame->u.WNM_NOTIFY_REQ.Variable[1] = 5+Event->u.WNM_NOTIFY_REQ_DATA.WNMNotifyReqLen;
WNMFrame->u.WNM_NOTIFY_REQ.Variable[2] = 0x50;
WNMFrame->u.WNM_NOTIFY_REQ.Variable[3] = 0x6f;
WNMFrame->u.WNM_NOTIFY_REQ.Variable[4] = 0x9a;
WNMFrame->u.WNM_NOTIFY_REQ.Variable[5] = 0x01;
NdisMoveMemory(&WNMFrame->u.WNM_NOTIFY_REQ.Variable[6], Event->u.WNM_NOTIFY_REQ_DATA.WNMNotifyReq,
3);
WNMFrame->u.WNM_NOTIFY_REQ.Variable[9] = Event->u.WNM_NOTIFY_REQ_DATA.WNMNotifyReqLen-3;
FrameLen += 10;
if (WNMFrame->u.WNM_NOTIFY_REQ.Variable[9] != 0)
{
NdisMoveMemory(&WNMFrame->u.WNM_NOTIFY_REQ.Variable[10], &Event->u.WNM_NOTIFY_REQ_DATA.WNMNotifyReq[3],
Event->u.WNM_NOTIFY_REQ_DATA.WNMNotifyReqLen-3);
FrameLen += (Event->u.WNM_NOTIFY_REQ_DATA.WNMNotifyReqLen-3);
}
if ((pEntry = MacTableLookup(pAd, Event->PeerMACAddr)) != NULL)
{
pEntry->BTMDisassocCount = 40; //20;
}
}
else
{
printk("no match event type:%d\n", Event->EventType);
os_free_mem(NULL, Buf);
}
WNMSetPeerCurrentState(pAd, Elem, WAIT_WNM_NOTIFY_RSP);
MiniportMMRequest(pAd, 0, Buf, FrameLen);
RTMPSetTimer(&WNMNotifyPeerEntry->WaitPeerWNMNotifyRspTimer, WaitPeerWNMNotifyRspTimeoutVale);
os_free_mem(NULL, Buf);
}
VOID SendWNMNotifyConfirm(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
PWNM_NOTIFY_PEER_ENTRY WNMNotifyPeerEntry, WNMNotifyPeerEntryTmp;
WNM_NOTIFY_EVENT_DATA *Event = (WNM_NOTIFY_EVENT_DATA *)Elem->Msg;
PWNM_CTRL pWNMCtrl = &pAd->ApCfg.MBSSID[Event->ControlIndex].WNMCtrl;
INT32 Ret;
printk("%s\n", __FUNCTION__);
printk("Receive WNM Notify Response Status:%d\n", Event->u.WNM_NOTIFY_RSP_DATA.WNMNotifyRsp[0]);
/* Delete BTM peer entry */
RTMP_SEM_EVENT_WAIT(&pWNMCtrl->WNMNotifyPeerListLock, Ret);
DlListForEachSafe(WNMNotifyPeerEntry, WNMNotifyPeerEntryTmp, &pWNMCtrl->WNMNotifyPeerList, WNM_NOTIFY_PEER_ENTRY, List)
{
if (MAC_ADDR_EQUAL(WNMNotifyPeerEntry->PeerMACAddr, Event->PeerMACAddr))
{
DlListDel(&WNMNotifyPeerEntry->List);
os_free_mem(NULL, WNMNotifyPeerEntry);
break;
}
}
RTMP_SEM_EVENT_UP(&pWNMCtrl->WNMNotifyPeerListLock);
}
#endif /* CONFIG_AP_SUPPORT */
VOID WNMNotifyStateMachineInit(
IN PRTMP_ADAPTER pAd,
IN STATE_MACHINE *S,
OUT STATE_MACHINE_FUNC Trans[])
{
DBGPRINT(RT_DEBUG_TRACE, ("%s\n", __FUNCTION__));
StateMachineInit(S, (STATE_MACHINE_FUNC*)Trans, MAX_WNM_NOTIFY_STATE, MAX_WNM_NOTIFY_MSG, (STATE_MACHINE_FUNC)Drop, WNM_NOTIFY_UNKNOWN, WNM_NOTIFY_MACHINE_BASE);
#ifdef CONFIG_AP_SUPPORT
StateMachineSetAction(S, WAIT_WNM_NOTIFY_REQ, WNM_NOTIFY_REQ, (STATE_MACHINE_FUNC)SendWNMNotifyReq);
StateMachineSetAction(S, WAIT_WNM_NOTIFY_RSP, WNM_NOTIFY_RSP, (STATE_MACHINE_FUNC)SendWNMNotifyConfirm);
#endif /* CONFIG_AP_SUPPORT */
}
#endif /* CONFIG_HOTSPOT_R2 */