Linetkux Wang 41ea46fa15 Revert "Remove leftovers of Intel WIDI and take a general cleanup"
This reverts commit c7f8f6e3633bd91a9f359eb3406beb972e58cd7b.
This commit is reverted because it introduces such issues as
monitor stops working. Before the issue is solved, we should
keep the code on main branch work
2024-07-02 14:10:04 +08:00

5457 lines
163 KiB
C

/******************************************************************************
*
* Copyright(c) 2007 - 2017 Realtek Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*****************************************************************************/
#define _RTW_P2P_C_
#include <drv_types.h>
#ifdef CONFIG_P2P
int rtw_p2p_is_channel_list_ok(u8 desired_ch, u8 *ch_list, u8 ch_cnt)
{
int found = 0, i = 0;
for (i = 0; i < ch_cnt; i++) {
if (ch_list[i] == desired_ch) {
found = 1;
break;
}
}
return found ;
}
int is_any_client_associated(_adapter *padapter)
{
return padapter->stapriv.asoc_list_cnt ? _TRUE : _FALSE;
}
static u32 go_add_group_info_attr(struct wifidirect_info *pwdinfo, u8 *pbuf)
{
_irqL irqL;
_list *phead, *plist;
u32 len = 0;
u16 attr_len = 0;
u8 tmplen, *pdata_attr, *pstart, *pcur;
struct sta_info *psta = NULL;
_adapter *padapter = pwdinfo->padapter;
struct sta_priv *pstapriv = &padapter->stapriv;
RTW_INFO(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter));
pdata_attr = rtw_zmalloc(MAX_P2P_IE_LEN);
if (NULL == pdata_attr) {
RTW_INFO("%s pdata_attr malloc failed\n", __FUNCTION__);
goto _exit;
}
pstart = pdata_attr;
pcur = pdata_attr;
_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
phead = &pstapriv->asoc_list;
plist = get_next(phead);
/* look up sta asoc_queue */
while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) {
psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
plist = get_next(plist);
if (psta->is_p2p_device) {
tmplen = 0;
pcur++;
/* P2P device address */
_rtw_memcpy(pcur, psta->dev_addr, ETH_ALEN);
pcur += ETH_ALEN;
/* P2P interface address */
_rtw_memcpy(pcur, psta->cmn.mac_addr, ETH_ALEN);
pcur += ETH_ALEN;
*pcur = psta->dev_cap;
pcur++;
/* *(u16*)(pcur) = cpu_to_be16(psta->config_methods); */
RTW_PUT_BE16(pcur, psta->config_methods);
pcur += 2;
_rtw_memcpy(pcur, psta->primary_dev_type, 8);
pcur += 8;
*pcur = psta->num_of_secdev_type;
pcur++;
_rtw_memcpy(pcur, psta->secdev_types_list, psta->num_of_secdev_type * 8);
pcur += psta->num_of_secdev_type * 8;
if (psta->dev_name_len > 0) {
/* *(u16*)(pcur) = cpu_to_be16( WPS_ATTR_DEVICE_NAME ); */
RTW_PUT_BE16(pcur, WPS_ATTR_DEVICE_NAME);
pcur += 2;
/* *(u16*)(pcur) = cpu_to_be16( psta->dev_name_len ); */
RTW_PUT_BE16(pcur, psta->dev_name_len);
pcur += 2;
_rtw_memcpy(pcur, psta->dev_name, psta->dev_name_len);
pcur += psta->dev_name_len;
}
tmplen = (u8)(pcur - pstart);
*pstart = (tmplen - 1);
attr_len += tmplen;
/* pstart += tmplen; */
pstart = pcur;
}
}
_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
if (attr_len > 0)
len = rtw_set_p2p_attr_content(pbuf, P2P_ATTR_GROUP_INFO, attr_len, pdata_attr);
rtw_mfree(pdata_attr, MAX_P2P_IE_LEN);
_exit:
return len;
}
static void issue_group_disc_req(struct wifidirect_info *pwdinfo, u8 *da)
{
struct xmit_frame *pmgntframe;
struct pkt_attrib *pattrib;
unsigned char *pframe;
struct rtw_ieee80211_hdr *pwlanhdr;
unsigned short *fctrl;
_adapter *padapter = pwdinfo->padapter;
struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
unsigned char category = RTW_WLAN_CATEGORY_P2P;/* P2P action frame */
u32 p2poui = cpu_to_be32(P2POUI);
u8 oui_subtype = P2P_GO_DISC_REQUEST;
u8 dialogToken = 0;
RTW_INFO("[%s]\n", __FUNCTION__);
pmgntframe = alloc_mgtxmitframe(pxmitpriv);
if (pmgntframe == NULL)
return;
/* update attribute */
pattrib = &pmgntframe->attrib;
update_mgntframe_attrib(padapter, pattrib);
_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
fctrl = &(pwlanhdr->frame_ctl);
*(fctrl) = 0;
_rtw_memcpy(pwlanhdr->addr1, da, ETH_ALEN);
_rtw_memcpy(pwlanhdr->addr2, pwdinfo->interface_addr, ETH_ALEN);
_rtw_memcpy(pwlanhdr->addr3, pwdinfo->interface_addr, ETH_ALEN);
SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
pmlmeext->mgnt_seq++;
set_frame_sub_type(pframe, WIFI_ACTION);
pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
/* Build P2P action frame header */
pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen));
pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *) &(p2poui), &(pattrib->pktlen));
pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen));
pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pattrib->pktlen));
/* there is no IE in this P2P action frame */
pattrib->last_txcmdsz = pattrib->pktlen;
dump_mgntframe(padapter, pmgntframe);
}
static void issue_p2p_devdisc_resp(struct wifidirect_info *pwdinfo, u8 *da, u8 status, u8 dialogToken)
{
struct xmit_frame *pmgntframe;
struct pkt_attrib *pattrib;
unsigned char *pframe;
struct rtw_ieee80211_hdr *pwlanhdr;
unsigned short *fctrl;
_adapter *padapter = pwdinfo->padapter;
struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
unsigned char category = RTW_WLAN_CATEGORY_PUBLIC;
u8 action = P2P_PUB_ACTION_ACTION;
u32 p2poui = cpu_to_be32(P2POUI);
u8 oui_subtype = P2P_DEVDISC_RESP;
u8 p2pie[8] = { 0x00 };
u32 p2pielen = 0;
RTW_INFO("[%s]\n", __FUNCTION__);
pmgntframe = alloc_mgtxmitframe(pxmitpriv);
if (pmgntframe == NULL)
return;
/* update attribute */
pattrib = &pmgntframe->attrib;
update_mgntframe_attrib(padapter, pattrib);
_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
fctrl = &(pwlanhdr->frame_ctl);
*(fctrl) = 0;
_rtw_memcpy(pwlanhdr->addr1, da, ETH_ALEN);
_rtw_memcpy(pwlanhdr->addr2, pwdinfo->device_addr, ETH_ALEN);
_rtw_memcpy(pwlanhdr->addr3, pwdinfo->device_addr, ETH_ALEN);
SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
pmlmeext->mgnt_seq++;
set_frame_sub_type(pframe, WIFI_ACTION);
pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
/* Build P2P public action frame header */
pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen));
pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen));
pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *) &(p2poui), &(pattrib->pktlen));
pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen));
pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pattrib->pktlen));
/* Build P2P IE */
/* P2P OUI */
p2pielen = 0;
p2pie[p2pielen++] = 0x50;
p2pie[p2pielen++] = 0x6F;
p2pie[p2pielen++] = 0x9A;
p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */
/* P2P_ATTR_STATUS */
p2pielen += rtw_set_p2p_attr_content(&p2pie[p2pielen], P2P_ATTR_STATUS, 1, &status);
pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, p2pie, &pattrib->pktlen);
pattrib->last_txcmdsz = pattrib->pktlen;
dump_mgntframe(padapter, pmgntframe);
}
static void issue_p2p_provision_resp(struct wifidirect_info *pwdinfo, u8 *raddr, u8 *frame_body, u16 config_method)
{
_adapter *padapter = pwdinfo->padapter;
unsigned char category = RTW_WLAN_CATEGORY_PUBLIC;
u8 action = P2P_PUB_ACTION_ACTION;
u8 dialogToken = frame_body[7]; /* The Dialog Token of provisioning discovery request frame. */
u32 p2poui = cpu_to_be32(P2POUI);
u8 oui_subtype = P2P_PROVISION_DISC_RESP;
u8 wpsie[100] = { 0x00 };
u8 wpsielen = 0;
#ifdef CONFIG_WFD
u32 wfdielen = 0;
#endif
struct xmit_frame *pmgntframe;
struct pkt_attrib *pattrib;
unsigned char *pframe;
struct rtw_ieee80211_hdr *pwlanhdr;
unsigned short *fctrl;
struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
pmgntframe = alloc_mgtxmitframe(pxmitpriv);
if (pmgntframe == NULL)
return;
/* update attribute */
pattrib = &pmgntframe->attrib;
update_mgntframe_attrib(padapter, pattrib);
_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
fctrl = &(pwlanhdr->frame_ctl);
*(fctrl) = 0;
_rtw_memcpy(pwlanhdr->addr1, raddr, ETH_ALEN);
_rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN);
_rtw_memcpy(pwlanhdr->addr3, adapter_mac_addr(padapter), ETH_ALEN);
SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
pmlmeext->mgnt_seq++;
set_frame_sub_type(pframe, WIFI_ACTION);
pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen));
pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen));
pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *) &(p2poui), &(pattrib->pktlen));
pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen));
pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pattrib->pktlen));
wpsielen = 0;
/* WPS OUI */
/* *(u32*) ( wpsie ) = cpu_to_be32( WPSOUI ); */
RTW_PUT_BE32(wpsie, WPSOUI);
wpsielen += 4;
#if 0
/* WPS version */
/* Type: */
*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1);
wpsielen += 2;
/* Length: */
*(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001);
wpsielen += 2;
/* Value: */
wpsie[wpsielen++] = WPS_VERSION_1; /* Version 1.0 */
#endif
/* Config Method */
/* Type: */
/* *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( WPS_ATTR_CONF_METHOD ); */
RTW_PUT_BE16(wpsie + wpsielen, WPS_ATTR_CONF_METHOD);
wpsielen += 2;
/* Length: */
/* *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( 0x0002 ); */
RTW_PUT_BE16(wpsie + wpsielen, 0x0002);
wpsielen += 2;
/* Value: */
/* *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( config_method ); */
RTW_PUT_BE16(wpsie + wpsielen, config_method);
wpsielen += 2;
pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *) wpsie, &pattrib->pktlen);
#ifdef CONFIG_WFD
wfdielen = build_provdisc_resp_wfd_ie(pwdinfo, pframe);
pframe += wfdielen;
pattrib->pktlen += wfdielen;
#endif
pattrib->last_txcmdsz = pattrib->pktlen;
dump_mgntframe(padapter, pmgntframe);
return;
}
static void issue_p2p_presence_resp(struct wifidirect_info *pwdinfo, u8 *da, u8 status, u8 dialogToken)
{
struct xmit_frame *pmgntframe;
struct pkt_attrib *pattrib;
unsigned char *pframe;
struct rtw_ieee80211_hdr *pwlanhdr;
unsigned short *fctrl;
_adapter *padapter = pwdinfo->padapter;
struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
unsigned char category = RTW_WLAN_CATEGORY_P2P;/* P2P action frame */
u32 p2poui = cpu_to_be32(P2POUI);
u8 oui_subtype = P2P_PRESENCE_RESPONSE;
u8 p2pie[MAX_P2P_IE_LEN] = { 0x00 };
u8 noa_attr_content[32] = { 0x00 };
u32 p2pielen = 0;
RTW_INFO("[%s]\n", __FUNCTION__);
pmgntframe = alloc_mgtxmitframe(pxmitpriv);
if (pmgntframe == NULL)
return;
/* update attribute */
pattrib = &pmgntframe->attrib;
update_mgntframe_attrib(padapter, pattrib);
_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
fctrl = &(pwlanhdr->frame_ctl);
*(fctrl) = 0;
_rtw_memcpy(pwlanhdr->addr1, da, ETH_ALEN);
_rtw_memcpy(pwlanhdr->addr2, pwdinfo->interface_addr, ETH_ALEN);
_rtw_memcpy(pwlanhdr->addr3, pwdinfo->interface_addr, ETH_ALEN);
SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
pmlmeext->mgnt_seq++;
set_frame_sub_type(pframe, WIFI_ACTION);
pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
/* Build P2P action frame header */
pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen));
pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *) &(p2poui), &(pattrib->pktlen));
pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen));
pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pattrib->pktlen));
/* Add P2P IE header */
/* P2P OUI */
p2pielen = 0;
p2pie[p2pielen++] = 0x50;
p2pie[p2pielen++] = 0x6F;
p2pie[p2pielen++] = 0x9A;
p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */
/* Add Status attribute in P2P IE */
p2pielen += rtw_set_p2p_attr_content(&p2pie[p2pielen], P2P_ATTR_STATUS, 1, &status);
/* Add NoA attribute in P2P IE */
noa_attr_content[0] = 0x1;/* index */
noa_attr_content[1] = 0x0;/* CTWindow and OppPS Parameters */
/* todo: Notice of Absence Descriptor(s) */
p2pielen += rtw_set_p2p_attr_content(&p2pie[p2pielen], P2P_ATTR_NOA, 2, noa_attr_content);
pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, p2pie, &(pattrib->pktlen));
pattrib->last_txcmdsz = pattrib->pktlen;
dump_mgntframe(padapter, pmgntframe);
}
u32 build_beacon_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf)
{
u8 p2pie[MAX_P2P_IE_LEN] = { 0x00 };
u16 capability = 0;
u32 len = 0, p2pielen = 0;
/* P2P OUI */
p2pielen = 0;
p2pie[p2pielen++] = 0x50;
p2pie[p2pielen++] = 0x6F;
p2pie[p2pielen++] = 0x9A;
p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */
/* According to the P2P Specification, the beacon frame should contain 3 P2P attributes */
/* 1. P2P Capability */
/* 2. P2P Device ID */
/* 3. Notice of Absence ( NOA ) */
/* P2P Capability ATTR */
/* Type: */
/* Length: */
/* Value: */
/* Device Capability Bitmap, 1 byte */
/* Be able to participate in additional P2P Groups and */
/* support the P2P Invitation Procedure */
/* Group Capability Bitmap, 1 byte */
capability = P2P_DEVCAP_INVITATION_PROC | P2P_DEVCAP_CLIENT_DISCOVERABILITY;
capability |= ((P2P_GRPCAP_GO | P2P_GRPCAP_INTRABSS) << 8);
if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_PROVISIONING_ING))
capability |= (P2P_GRPCAP_GROUP_FORMATION << 8);
capability = cpu_to_le16(capability);
p2pielen += rtw_set_p2p_attr_content(&p2pie[p2pielen], P2P_ATTR_CAPABILITY, 2, (u8 *)&capability);
/* P2P Device ID ATTR */
p2pielen += rtw_set_p2p_attr_content(&p2pie[p2pielen], P2P_ATTR_DEVICE_ID, ETH_ALEN, pwdinfo->device_addr);
/* Notice of Absence ATTR */
/* Type: */
/* Length: */
/* Value: */
/* go_add_noa_attr(pwdinfo); */
pbuf = rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &len);
return len;
}
#ifdef CONFIG_WFD
u32 build_beacon_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf)
{
u8 wfdie[MAX_WFD_IE_LEN] = { 0x00 };
u16 val16 = 0;
u32 len = 0, wfdielen = 0;
_adapter *padapter = pwdinfo->padapter;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct wifi_display_info *pwfd_info = padapter->wdinfo.wfd_info;
if (!hal_chk_wl_func(padapter, WL_FUNC_MIRACAST))
goto exit;
/* WFD OUI */
wfdielen = 0;
wfdie[wfdielen++] = 0x50;
wfdie[wfdielen++] = 0x6F;
wfdie[wfdielen++] = 0x9A;
wfdie[wfdielen++] = 0x0A; /* WFA WFD v1.0 */
/* Commented by Albert 20110812 */
/* According to the WFD Specification, the beacon frame should contain 4 WFD attributes */
/* 1. WFD Device Information */
/* 2. Associated BSSID */
/* 3. Coupled Sink Information */
/* WFD Device Information ATTR */
/* Type: */
wfdie[wfdielen++] = WFD_ATTR_DEVICE_INFO;
/* Length: */
/* Note: In the WFD specification, the size of length field is 2. */
RTW_PUT_BE16(wfdie + wfdielen, 0x0006);
wfdielen += 2;
/* Value1: */
/* WFD device information */
if (P2P_ROLE_GO == pwdinfo->role) {
if (is_any_client_associated(pwdinfo->padapter)) {
/* WFD primary sink + WiFi Direct mode + WSD (WFD Service Discovery) */
val16 = pwfd_info->wfd_device_type | WFD_DEVINFO_WSD;
RTW_PUT_BE16(wfdie + wfdielen, val16);
} else {
/* WFD primary sink + available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) */
val16 = pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD;
RTW_PUT_BE16(wfdie + wfdielen, val16);
}
} else {
/* WFD primary sink + available for WFD session + WiFi Direct mode + WSD ( WFD Service Discovery ) */
val16 = pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD;
RTW_PUT_BE16(wfdie + wfdielen, val16);
}
wfdielen += 2;
/* Value2: */
/* Session Management Control Port */
/* Default TCP port for RTSP messages is 554 */
RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport);
wfdielen += 2;
/* Value3: */
/* WFD Device Maximum Throughput */
/* 300Mbps is the maximum throughput */
RTW_PUT_BE16(wfdie + wfdielen, 300);
wfdielen += 2;
/* Associated BSSID ATTR */
/* Type: */
wfdie[wfdielen++] = WFD_ATTR_ASSOC_BSSID;
/* Length: */
/* Note: In the WFD specification, the size of length field is 2. */
RTW_PUT_BE16(wfdie + wfdielen, 0x0006);
wfdielen += 2;
/* Value: */
/* Associated BSSID */
if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE)
_rtw_memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[0], ETH_ALEN);
else
_rtw_memset(wfdie + wfdielen, 0x00, ETH_ALEN);
wfdielen += ETH_ALEN;
/* Coupled Sink Information ATTR */
/* Type: */
wfdie[wfdielen++] = WFD_ATTR_COUPLED_SINK_INFO;
/* Length: */
/* Note: In the WFD specification, the size of length field is 2. */
RTW_PUT_BE16(wfdie + wfdielen, 0x0007);
wfdielen += 2;
/* Value: */
/* Coupled Sink Status bitmap */
/* Not coupled/available for Coupling */
wfdie[wfdielen++] = 0;
/* MAC Addr. */
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len);
exit:
return len;
}
u32 build_probe_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf)
{
u8 wfdie[MAX_WFD_IE_LEN] = { 0x00 };
u16 val16 = 0;
u32 len = 0, wfdielen = 0;
_adapter *padapter = pwdinfo->padapter;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct wifi_display_info *pwfd_info = padapter->wdinfo.wfd_info;
if (!hal_chk_wl_func(padapter, WL_FUNC_MIRACAST))
goto exit;
/* WFD OUI */
wfdielen = 0;
wfdie[wfdielen++] = 0x50;
wfdie[wfdielen++] = 0x6F;
wfdie[wfdielen++] = 0x9A;
wfdie[wfdielen++] = 0x0A; /* WFA WFD v1.0 */
/* Commented by Albert 20110812 */
/* According to the WFD Specification, the probe request frame should contain 4 WFD attributes */
/* 1. WFD Device Information */
/* 2. Associated BSSID */
/* 3. Coupled Sink Information */
/* WFD Device Information ATTR */
/* Type: */
wfdie[wfdielen++] = WFD_ATTR_DEVICE_INFO;
/* Length: */
/* Note: In the WFD specification, the size of length field is 2. */
RTW_PUT_BE16(wfdie + wfdielen, 0x0006);
wfdielen += 2;
/* Value1: */
/* WFD device information */
if (1 == pwdinfo->wfd_tdls_enable) {
/* WFD primary sink + available for WFD session + WiFi TDLS mode + WSC ( WFD Service Discovery ) */
val16 = pwfd_info->wfd_device_type |
WFD_DEVINFO_SESSION_AVAIL |
WFD_DEVINFO_WSD |
WFD_DEVINFO_PC_TDLS;
RTW_PUT_BE16(wfdie + wfdielen, val16);
} else {
/* WFD primary sink + available for WFD session + WiFi Direct mode + WSC ( WFD Service Discovery ) */
val16 = pwfd_info->wfd_device_type |
WFD_DEVINFO_SESSION_AVAIL |
WFD_DEVINFO_WSD;
RTW_PUT_BE16(wfdie + wfdielen, val16);
}
wfdielen += 2;
/* Value2: */
/* Session Management Control Port */
/* Default TCP port for RTSP messages is 554 */
RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport);
wfdielen += 2;
/* Value3: */
/* WFD Device Maximum Throughput */
/* 300Mbps is the maximum throughput */
RTW_PUT_BE16(wfdie + wfdielen, 300);
wfdielen += 2;
/* Associated BSSID ATTR */
/* Type: */
wfdie[wfdielen++] = WFD_ATTR_ASSOC_BSSID;
/* Length: */
/* Note: In the WFD specification, the size of length field is 2. */
RTW_PUT_BE16(wfdie + wfdielen, 0x0006);
wfdielen += 2;
/* Value: */
/* Associated BSSID */
if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE)
_rtw_memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[0], ETH_ALEN);
else
_rtw_memset(wfdie + wfdielen, 0x00, ETH_ALEN);
wfdielen += ETH_ALEN;
/* Coupled Sink Information ATTR */
/* Type: */
wfdie[wfdielen++] = WFD_ATTR_COUPLED_SINK_INFO;
/* Length: */
/* Note: In the WFD specification, the size of length field is 2. */
RTW_PUT_BE16(wfdie + wfdielen, 0x0007);
wfdielen += 2;
/* Value: */
/* Coupled Sink Status bitmap */
/* Not coupled/available for Coupling */
wfdie[wfdielen++] = 0;
/* MAC Addr. */
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len);
exit:
return len;
}
u32 build_probe_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf, u8 tunneled)
{
u8 wfdie[MAX_WFD_IE_LEN] = { 0x00 };
u32 len = 0, wfdielen = 0;
_adapter *padapter = pwdinfo->padapter;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct wifi_display_info *pwfd_info = padapter->wdinfo.wfd_info;
u16 v16 = 0;
if (!hal_chk_wl_func(padapter, WL_FUNC_MIRACAST))
goto exit;
/* WFD OUI */
wfdielen = 0;
wfdie[wfdielen++] = 0x50;
wfdie[wfdielen++] = 0x6F;
wfdie[wfdielen++] = 0x9A;
wfdie[wfdielen++] = 0x0A; /* WFA WFD v1.0 */
/* Commented by Albert 20110812 */
/* According to the WFD Specification, the probe response frame should contain 4 WFD attributes */
/* 1. WFD Device Information */
/* 2. Associated BSSID */
/* 3. Coupled Sink Information */
/* 4. WFD Session Information */
/* WFD Device Information ATTR */
/* Type: */
wfdie[wfdielen++] = WFD_ATTR_DEVICE_INFO;
/* Length: */
/* Note: In the WFD specification, the size of length field is 2. */
RTW_PUT_BE16(wfdie + wfdielen, 0x0006);
wfdielen += 2;
/* Value1: */
/* WFD device information */
/* WFD primary sink + available for WFD session + WiFi Direct mode */
if (_TRUE == pwdinfo->session_available) {
if (P2P_ROLE_GO == pwdinfo->role) {
if (is_any_client_associated(pwdinfo->padapter)) {
if (pwdinfo->wfd_tdls_enable) {
/* TDLS mode + WSD ( WFD Service Discovery ) */
v16 = pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | WFD_DEVINFO_PC_TDLS | WFD_DEVINFO_HDCP_SUPPORT;
RTW_PUT_BE16(wfdie + wfdielen, v16);
} else {
/* WiFi Direct mode + WSD ( WFD Service Discovery ) */
v16 = pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | WFD_DEVINFO_HDCP_SUPPORT;
RTW_PUT_BE16(wfdie + wfdielen, v16);
}
} else {
if (pwdinfo->wfd_tdls_enable) {
/* available for WFD session + TDLS mode + WSD ( WFD Service Discovery ) */
v16 = pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD | WFD_DEVINFO_PC_TDLS | WFD_DEVINFO_HDCP_SUPPORT;
RTW_PUT_BE16(wfdie + wfdielen, v16);
} else {
/* available for WFD session + WiFi Direct mode + WSD ( WFD Service Discovery ) */
v16 = pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD | WFD_DEVINFO_HDCP_SUPPORT;
RTW_PUT_BE16(wfdie + wfdielen, v16);
}
}
} else {
if (pwdinfo->wfd_tdls_enable) {
/* available for WFD session + WiFi Direct mode + WSD ( WFD Service Discovery ) */
v16 = pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD | WFD_DEVINFO_PC_TDLS | WFD_DEVINFO_HDCP_SUPPORT;
RTW_PUT_BE16(wfdie + wfdielen, v16);
} else {
/* available for WFD session + WiFi Direct mode + WSD ( WFD Service Discovery ) */
v16 = pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD | WFD_DEVINFO_HDCP_SUPPORT;
RTW_PUT_BE16(wfdie + wfdielen, v16);
}
}
} else {
if (pwdinfo->wfd_tdls_enable) {
v16 = pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | WFD_DEVINFO_PC_TDLS | WFD_DEVINFO_HDCP_SUPPORT;
RTW_PUT_BE16(wfdie + wfdielen, v16);
} else {
v16 = pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | WFD_DEVINFO_HDCP_SUPPORT;
RTW_PUT_BE16(wfdie + wfdielen, v16);
}
}
wfdielen += 2;
/* Value2: */
/* Session Management Control Port */
/* Default TCP port for RTSP messages is 554 */
RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport);
wfdielen += 2;
/* Value3: */
/* WFD Device Maximum Throughput */
/* 300Mbps is the maximum throughput */
RTW_PUT_BE16(wfdie + wfdielen, 300);
wfdielen += 2;
/* Associated BSSID ATTR */
/* Type: */
wfdie[wfdielen++] = WFD_ATTR_ASSOC_BSSID;
/* Length: */
/* Note: In the WFD specification, the size of length field is 2. */
RTW_PUT_BE16(wfdie + wfdielen, 0x0006);
wfdielen += 2;
/* Value: */
/* Associated BSSID */
if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE)
_rtw_memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[0], ETH_ALEN);
else
_rtw_memset(wfdie + wfdielen, 0x00, ETH_ALEN);
wfdielen += ETH_ALEN;
/* Coupled Sink Information ATTR */
/* Type: */
wfdie[wfdielen++] = WFD_ATTR_COUPLED_SINK_INFO;
/* Length: */
/* Note: In the WFD specification, the size of length field is 2. */
RTW_PUT_BE16(wfdie + wfdielen, 0x0007);
wfdielen += 2;
/* Value: */
/* Coupled Sink Status bitmap */
/* Not coupled/available for Coupling */
wfdie[wfdielen++] = 0;
/* MAC Addr. */
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
/* WFD Session Information ATTR */
/* Type: */
wfdie[wfdielen++] = WFD_ATTR_SESSION_INFO;
/* Length: */
/* Note: In the WFD specification, the size of length field is 2. */
RTW_PUT_BE16(wfdie + wfdielen, 0x0000);
wfdielen += 2;
/* Todo: to add the list of WFD device info descriptor in WFD group. */
}
#ifdef CONFIG_CONCURRENT_MODE
#ifdef CONFIG_TDLS
{
int i;
_adapter *iface = NULL;
struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
for (i = 0; i < dvobj->iface_nums; i++) {
iface = dvobj->padapters[i];
if ((iface) && rtw_is_adapter_up(iface)) {
if (iface == padapter)
continue;
if ((tunneled == 0) && (iface->wdinfo.wfd_tdls_enable == 1)) {
/* Alternative MAC Address ATTR
Type: */
wfdie[wfdielen++] = WFD_ATTR_ALTER_MAC;
/* Length:
Note: In the WFD specification, the size of length field is 2.*/
RTW_PUT_BE16(wfdie + wfdielen, ETH_ALEN);
wfdielen += 2;
/* Value:
Alternative MAC Address*/
_rtw_memcpy(wfdie + wfdielen, adapter_mac_addr(iface), ETH_ALEN);
wfdielen += ETH_ALEN;
}
}
}
}
#endif /* CONFIG_TDLS*/
#endif /* CONFIG_CONCURRENT_MODE */
pbuf = rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len);
exit:
return len;
}
u32 build_assoc_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf)
{
u8 wfdie[MAX_WFD_IE_LEN] = { 0x00 };
u16 val16 = 0;
u32 len = 0, wfdielen = 0;
_adapter *padapter = NULL;
struct mlme_priv *pmlmepriv = NULL;
struct wifi_display_info *pwfd_info = NULL;
padapter = pwdinfo->padapter;
pmlmepriv = &padapter->mlmepriv;
pwfd_info = padapter->wdinfo.wfd_info;
if (!hal_chk_wl_func(padapter, WL_FUNC_MIRACAST))
goto exit;
if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE))
goto exit;
/* WFD OUI */
wfdielen = 0;
wfdie[wfdielen++] = 0x50;
wfdie[wfdielen++] = 0x6F;
wfdie[wfdielen++] = 0x9A;
wfdie[wfdielen++] = 0x0A; /* WFA WFD v1.0 */
/* Commented by Albert 20110812 */
/* According to the WFD Specification, the probe request frame should contain 4 WFD attributes */
/* 1. WFD Device Information */
/* 2. Associated BSSID */
/* 3. Coupled Sink Information */
/* WFD Device Information ATTR */
/* Type: */
wfdie[wfdielen++] = WFD_ATTR_DEVICE_INFO;
/* Length: */
/* Note: In the WFD specification, the size of length field is 2. */
RTW_PUT_BE16(wfdie + wfdielen, 0x0006);
wfdielen += 2;
/* Value1: */
/* WFD device information */
/* WFD primary sink + available for WFD session + WiFi Direct mode + WSD ( WFD Service Discovery ) */
val16 = pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD;
RTW_PUT_BE16(wfdie + wfdielen, val16);
wfdielen += 2;
/* Value2: */
/* Session Management Control Port */
/* Default TCP port for RTSP messages is 554 */
RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport);
wfdielen += 2;
/* Value3: */
/* WFD Device Maximum Throughput */
/* 300Mbps is the maximum throughput */
RTW_PUT_BE16(wfdie + wfdielen, 300);
wfdielen += 2;
/* Associated BSSID ATTR */
/* Type: */
wfdie[wfdielen++] = WFD_ATTR_ASSOC_BSSID;
/* Length: */
/* Note: In the WFD specification, the size of length field is 2. */
RTW_PUT_BE16(wfdie + wfdielen, 0x0006);
wfdielen += 2;
/* Value: */
/* Associated BSSID */
if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE)
_rtw_memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[0], ETH_ALEN);
else
_rtw_memset(wfdie + wfdielen, 0x00, ETH_ALEN);
wfdielen += ETH_ALEN;
/* Coupled Sink Information ATTR */
/* Type: */
wfdie[wfdielen++] = WFD_ATTR_COUPLED_SINK_INFO;
/* Length: */
/* Note: In the WFD specification, the size of length field is 2. */
RTW_PUT_BE16(wfdie + wfdielen, 0x0007);
wfdielen += 2;
/* Value: */
/* Coupled Sink Status bitmap */
/* Not coupled/available for Coupling */
wfdie[wfdielen++] = 0;
/* MAC Addr. */
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len);
exit:
return len;
}
u32 build_assoc_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf)
{
u8 wfdie[MAX_WFD_IE_LEN] = { 0x00 };
u32 len = 0, wfdielen = 0;
u16 val16 = 0;
_adapter *padapter = pwdinfo->padapter;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct wifi_display_info *pwfd_info = padapter->wdinfo.wfd_info;
if (!hal_chk_wl_func(padapter, WL_FUNC_MIRACAST))
goto exit;
/* WFD OUI */
wfdielen = 0;
wfdie[wfdielen++] = 0x50;
wfdie[wfdielen++] = 0x6F;
wfdie[wfdielen++] = 0x9A;
wfdie[wfdielen++] = 0x0A; /* WFA WFD v1.0 */
/* Commented by Albert 20110812 */
/* According to the WFD Specification, the probe request frame should contain 4 WFD attributes */
/* 1. WFD Device Information */
/* 2. Associated BSSID */
/* 3. Coupled Sink Information */
/* WFD Device Information ATTR */
/* Type: */
wfdie[wfdielen++] = WFD_ATTR_DEVICE_INFO;
/* Length: */
/* Note: In the WFD specification, the size of length field is 2. */
RTW_PUT_BE16(wfdie + wfdielen, 0x0006);
wfdielen += 2;
/* Value1: */
/* WFD device information */
/* WFD primary sink + available for WFD session + WiFi Direct mode + WSD ( WFD Service Discovery ) */
val16 = pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD;
RTW_PUT_BE16(wfdie + wfdielen, val16);
wfdielen += 2;
/* Value2: */
/* Session Management Control Port */
/* Default TCP port for RTSP messages is 554 */
RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport);
wfdielen += 2;
/* Value3: */
/* WFD Device Maximum Throughput */
/* 300Mbps is the maximum throughput */
RTW_PUT_BE16(wfdie + wfdielen, 300);
wfdielen += 2;
/* Associated BSSID ATTR */
/* Type: */
wfdie[wfdielen++] = WFD_ATTR_ASSOC_BSSID;
/* Length: */
/* Note: In the WFD specification, the size of length field is 2. */
RTW_PUT_BE16(wfdie + wfdielen, 0x0006);
wfdielen += 2;
/* Value: */
/* Associated BSSID */
if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE)
_rtw_memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[0], ETH_ALEN);
else
_rtw_memset(wfdie + wfdielen, 0x00, ETH_ALEN);
wfdielen += ETH_ALEN;
/* Coupled Sink Information ATTR */
/* Type: */
wfdie[wfdielen++] = WFD_ATTR_COUPLED_SINK_INFO;
/* Length: */
/* Note: In the WFD specification, the size of length field is 2. */
RTW_PUT_BE16(wfdie + wfdielen, 0x0007);
wfdielen += 2;
/* Value: */
/* Coupled Sink Status bitmap */
/* Not coupled/available for Coupling */
wfdie[wfdielen++] = 0;
/* MAC Addr. */
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len);
exit:
return len;
}
u32 build_nego_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf)
{
u8 wfdie[MAX_WFD_IE_LEN] = { 0x00 };
u32 len = 0, wfdielen = 0;
u16 val16 = 0;
_adapter *padapter = pwdinfo->padapter;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct wifi_display_info *pwfd_info = padapter->wdinfo.wfd_info;
if (!hal_chk_wl_func(padapter, WL_FUNC_MIRACAST))
goto exit;
/* WFD OUI */
wfdielen = 0;
wfdie[wfdielen++] = 0x50;
wfdie[wfdielen++] = 0x6F;
wfdie[wfdielen++] = 0x9A;
wfdie[wfdielen++] = 0x0A; /* WFA WFD v1.0 */
/* Commented by Albert 20110825 */
/* According to the WFD Specification, the negotiation request frame should contain 3 WFD attributes */
/* 1. WFD Device Information */
/* 2. Associated BSSID ( Optional ) */
/* 3. Local IP Adress ( Optional ) */
/* WFD Device Information ATTR */
/* Type: */
wfdie[wfdielen++] = WFD_ATTR_DEVICE_INFO;
/* Length: */
/* Note: In the WFD specification, the size of length field is 2. */
RTW_PUT_BE16(wfdie + wfdielen, 0x0006);
wfdielen += 2;
/* Value1: */
/* WFD device information */
/* WFD primary sink + WiFi Direct mode + WSD ( WFD Service Discovery ) + WFD Session Available */
val16 = pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | WFD_DEVINFO_SESSION_AVAIL;
RTW_PUT_BE16(wfdie + wfdielen, val16);
wfdielen += 2;
/* Value2: */
/* Session Management Control Port */
/* Default TCP port for RTSP messages is 554 */
RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport);
wfdielen += 2;
/* Value3: */
/* WFD Device Maximum Throughput */
/* 300Mbps is the maximum throughput */
RTW_PUT_BE16(wfdie + wfdielen, 300);
wfdielen += 2;
/* Associated BSSID ATTR */
/* Type: */
wfdie[wfdielen++] = WFD_ATTR_ASSOC_BSSID;
/* Length: */
/* Note: In the WFD specification, the size of length field is 2. */
RTW_PUT_BE16(wfdie + wfdielen, 0x0006);
wfdielen += 2;
/* Value: */
/* Associated BSSID */
if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE)
_rtw_memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[0], ETH_ALEN);
else
_rtw_memset(wfdie + wfdielen, 0x00, ETH_ALEN);
wfdielen += ETH_ALEN;
/* Coupled Sink Information ATTR */
/* Type: */
wfdie[wfdielen++] = WFD_ATTR_COUPLED_SINK_INFO;
/* Length: */
/* Note: In the WFD specification, the size of length field is 2. */
RTW_PUT_BE16(wfdie + wfdielen, 0x0007);
wfdielen += 2;
/* Value: */
/* Coupled Sink Status bitmap */
/* Not coupled/available for Coupling */
wfdie[wfdielen++] = 0;
/* MAC Addr. */
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len);
exit:
return len;
}
u32 build_nego_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf)
{
u8 wfdie[MAX_WFD_IE_LEN] = { 0x00 };
u32 len = 0, wfdielen = 0;
u16 val16 = 0;
_adapter *padapter = pwdinfo->padapter;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct wifi_display_info *pwfd_info = padapter->wdinfo.wfd_info;
if (!hal_chk_wl_func(padapter, WL_FUNC_MIRACAST))
goto exit;
/* WFD OUI */
wfdielen = 0;
wfdie[wfdielen++] = 0x50;
wfdie[wfdielen++] = 0x6F;
wfdie[wfdielen++] = 0x9A;
wfdie[wfdielen++] = 0x0A; /* WFA WFD v1.0 */
/* Commented by Albert 20110825 */
/* According to the WFD Specification, the negotiation request frame should contain 3 WFD attributes */
/* 1. WFD Device Information */
/* 2. Associated BSSID ( Optional ) */
/* 3. Local IP Adress ( Optional ) */
/* WFD Device Information ATTR */
/* Type: */
wfdie[wfdielen++] = WFD_ATTR_DEVICE_INFO;
/* Length: */
/* Note: In the WFD specification, the size of length field is 2. */
RTW_PUT_BE16(wfdie + wfdielen, 0x0006);
wfdielen += 2;
/* Value1: */
/* WFD device information */
/* WFD primary sink + WiFi Direct mode + WSD ( WFD Service Discovery ) + WFD Session Available */
val16 = pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | WFD_DEVINFO_SESSION_AVAIL;
RTW_PUT_BE16(wfdie + wfdielen, val16);
wfdielen += 2;
/* Value2: */
/* Session Management Control Port */
/* Default TCP port for RTSP messages is 554 */
RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport);
wfdielen += 2;
/* Value3: */
/* WFD Device Maximum Throughput */
/* 300Mbps is the maximum throughput */
RTW_PUT_BE16(wfdie + wfdielen, 300);
wfdielen += 2;
/* Associated BSSID ATTR */
/* Type: */
wfdie[wfdielen++] = WFD_ATTR_ASSOC_BSSID;
/* Length: */
/* Note: In the WFD specification, the size of length field is 2. */
RTW_PUT_BE16(wfdie + wfdielen, 0x0006);
wfdielen += 2;
/* Value: */
/* Associated BSSID */
if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE)
_rtw_memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[0], ETH_ALEN);
else
_rtw_memset(wfdie + wfdielen, 0x00, ETH_ALEN);
wfdielen += ETH_ALEN;
/* Coupled Sink Information ATTR */
/* Type: */
wfdie[wfdielen++] = WFD_ATTR_COUPLED_SINK_INFO;
/* Length: */
/* Note: In the WFD specification, the size of length field is 2. */
RTW_PUT_BE16(wfdie + wfdielen, 0x0007);
wfdielen += 2;
/* Value: */
/* Coupled Sink Status bitmap */
/* Not coupled/available for Coupling */
wfdie[wfdielen++] = 0;
/* MAC Addr. */
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len);
exit:
return len;
}
u32 build_nego_confirm_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf)
{
u8 wfdie[MAX_WFD_IE_LEN] = { 0x00 };
u32 len = 0, wfdielen = 0;
u16 val16 = 0;
_adapter *padapter = pwdinfo->padapter;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct wifi_display_info *pwfd_info = padapter->wdinfo.wfd_info;
if (!hal_chk_wl_func(padapter, WL_FUNC_MIRACAST))
goto exit;
/* WFD OUI */
wfdielen = 0;
wfdie[wfdielen++] = 0x50;
wfdie[wfdielen++] = 0x6F;
wfdie[wfdielen++] = 0x9A;
wfdie[wfdielen++] = 0x0A; /* WFA WFD v1.0 */
/* Commented by Albert 20110825 */
/* According to the WFD Specification, the negotiation request frame should contain 3 WFD attributes */
/* 1. WFD Device Information */
/* 2. Associated BSSID ( Optional ) */
/* 3. Local IP Adress ( Optional ) */
/* WFD Device Information ATTR */
/* Type: */
wfdie[wfdielen++] = WFD_ATTR_DEVICE_INFO;
/* Length: */
/* Note: In the WFD specification, the size of length field is 2. */
RTW_PUT_BE16(wfdie + wfdielen, 0x0006);
wfdielen += 2;
/* Value1: */
/* WFD device information */
/* WFD primary sink + WiFi Direct mode + WSD ( WFD Service Discovery ) + WFD Session Available */
val16 = pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | WFD_DEVINFO_SESSION_AVAIL;
RTW_PUT_BE16(wfdie + wfdielen, val16);
wfdielen += 2;
/* Value2: */
/* Session Management Control Port */
/* Default TCP port for RTSP messages is 554 */
RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport);
wfdielen += 2;
/* Value3: */
/* WFD Device Maximum Throughput */
/* 300Mbps is the maximum throughput */
RTW_PUT_BE16(wfdie + wfdielen, 300);
wfdielen += 2;
/* Associated BSSID ATTR */
/* Type: */
wfdie[wfdielen++] = WFD_ATTR_ASSOC_BSSID;
/* Length: */
/* Note: In the WFD specification, the size of length field is 2. */
RTW_PUT_BE16(wfdie + wfdielen, 0x0006);
wfdielen += 2;
/* Value: */
/* Associated BSSID */
if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE)
_rtw_memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[0], ETH_ALEN);
else
_rtw_memset(wfdie + wfdielen, 0x00, ETH_ALEN);
wfdielen += ETH_ALEN;
/* Coupled Sink Information ATTR */
/* Type: */
wfdie[wfdielen++] = WFD_ATTR_COUPLED_SINK_INFO;
/* Length: */
/* Note: In the WFD specification, the size of length field is 2. */
RTW_PUT_BE16(wfdie + wfdielen, 0x0007);
wfdielen += 2;
/* Value: */
/* Coupled Sink Status bitmap */
/* Not coupled/available for Coupling */
wfdie[wfdielen++] = 0;
/* MAC Addr. */
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
pbuf = rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len);
exit:
return len;
}
u32 build_invitation_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf)
{
u8 wfdie[MAX_WFD_IE_LEN] = { 0x00 };
u32 len = 0, wfdielen = 0;
u16 val16 = 0;
_adapter *padapter = pwdinfo->padapter;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct wifi_display_info *pwfd_info = padapter->wdinfo.wfd_info;
if (!hal_chk_wl_func(padapter, WL_FUNC_MIRACAST))
goto exit;
/* WFD OUI */
wfdielen = 0;
wfdie[wfdielen++] = 0x50;
wfdie[wfdielen++] = 0x6F;
wfdie[wfdielen++] = 0x9A;
wfdie[wfdielen++] = 0x0A; /* WFA WFD v1.0 */
/* Commented by Albert 20110825 */
/* According to the WFD Specification, the provision discovery request frame should contain 3 WFD attributes */
/* 1. WFD Device Information */
/* 2. Associated BSSID ( Optional ) */
/* 3. Local IP Adress ( Optional ) */
/* WFD Device Information ATTR */
/* Type: */
wfdie[wfdielen++] = WFD_ATTR_DEVICE_INFO;
/* Length: */
/* Note: In the WFD specification, the size of length field is 2. */
RTW_PUT_BE16(wfdie + wfdielen, 0x0006);
wfdielen += 2;
/* Value1: */
/* WFD device information */
/* WFD primary sink + available for WFD session + WiFi Direct mode + WSD ( WFD Service Discovery ) */
val16 = pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD;
RTW_PUT_BE16(wfdie + wfdielen, val16);
wfdielen += 2;
/* Value2: */
/* Session Management Control Port */
/* Default TCP port for RTSP messages is 554 */
RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport);
wfdielen += 2;
/* Value3: */
/* WFD Device Maximum Throughput */
/* 300Mbps is the maximum throughput */
RTW_PUT_BE16(wfdie + wfdielen, 300);
wfdielen += 2;
/* Associated BSSID ATTR */
/* Type: */
wfdie[wfdielen++] = WFD_ATTR_ASSOC_BSSID;
/* Length: */
/* Note: In the WFD specification, the size of length field is 2. */
RTW_PUT_BE16(wfdie + wfdielen, 0x0006);
wfdielen += 2;
/* Value: */
/* Associated BSSID */
if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE)
_rtw_memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[0], ETH_ALEN);
else
_rtw_memset(wfdie + wfdielen, 0x00, ETH_ALEN);
wfdielen += ETH_ALEN;
/* Coupled Sink Information ATTR */
/* Type: */
wfdie[wfdielen++] = WFD_ATTR_COUPLED_SINK_INFO;
/* Length: */
/* Note: In the WFD specification, the size of length field is 2. */
RTW_PUT_BE16(wfdie + wfdielen, 0x0007);
wfdielen += 2;
/* Value: */
/* Coupled Sink Status bitmap */
/* Not coupled/available for Coupling */
wfdie[wfdielen++] = 0;
/* MAC Addr. */
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
if (P2P_ROLE_GO == pwdinfo->role) {
/* WFD Session Information ATTR */
/* Type: */
wfdie[wfdielen++] = WFD_ATTR_SESSION_INFO;
/* Length: */
/* Note: In the WFD specification, the size of length field is 2. */
RTW_PUT_BE16(wfdie + wfdielen, 0x0000);
wfdielen += 2;
/* Todo: to add the list of WFD device info descriptor in WFD group. */
}
rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len);
exit:
return len;
}
u32 build_invitation_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf)
{
u8 wfdie[MAX_WFD_IE_LEN] = { 0x00 };
u16 val16 = 0;
u32 len = 0, wfdielen = 0;
_adapter *padapter = pwdinfo->padapter;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct wifi_display_info *pwfd_info = padapter->wdinfo.wfd_info;
if (!hal_chk_wl_func(padapter, WL_FUNC_MIRACAST))
goto exit;
/* WFD OUI */
wfdielen = 0;
wfdie[wfdielen++] = 0x50;
wfdie[wfdielen++] = 0x6F;
wfdie[wfdielen++] = 0x9A;
wfdie[wfdielen++] = 0x0A; /* WFA WFD v1.0 */
/* Commented by Albert 20110825 */
/* According to the WFD Specification, the provision discovery request frame should contain 3 WFD attributes */
/* 1. WFD Device Information */
/* 2. Associated BSSID ( Optional ) */
/* 3. Local IP Adress ( Optional ) */
/* WFD Device Information ATTR */
/* Type: */
wfdie[wfdielen++] = WFD_ATTR_DEVICE_INFO;
/* Length: */
/* Note: In the WFD specification, the size of length field is 2. */
RTW_PUT_BE16(wfdie + wfdielen, 0x0006);
wfdielen += 2;
/* Value1: */
/* WFD device information */
/* WFD primary sink + available for WFD session + WiFi Direct mode + WSD ( WFD Service Discovery ) */
val16 = pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD;
RTW_PUT_BE16(wfdie + wfdielen, val16);
wfdielen += 2;
/* Value2: */
/* Session Management Control Port */
/* Default TCP port for RTSP messages is 554 */
RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport);
wfdielen += 2;
/* Value3: */
/* WFD Device Maximum Throughput */
/* 300Mbps is the maximum throughput */
RTW_PUT_BE16(wfdie + wfdielen, 300);
wfdielen += 2;
/* Associated BSSID ATTR */
/* Type: */
wfdie[wfdielen++] = WFD_ATTR_ASSOC_BSSID;
/* Length: */
/* Note: In the WFD specification, the size of length field is 2. */
RTW_PUT_BE16(wfdie + wfdielen, 0x0006);
wfdielen += 2;
/* Value: */
/* Associated BSSID */
if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE)
_rtw_memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[0], ETH_ALEN);
else
_rtw_memset(wfdie + wfdielen, 0x00, ETH_ALEN);
wfdielen += ETH_ALEN;
/* Coupled Sink Information ATTR */
/* Type: */
wfdie[wfdielen++] = WFD_ATTR_COUPLED_SINK_INFO;
/* Length: */
/* Note: In the WFD specification, the size of length field is 2. */
RTW_PUT_BE16(wfdie + wfdielen, 0x0007);
wfdielen += 2;
/* Value: */
/* Coupled Sink Status bitmap */
/* Not coupled/available for Coupling */
wfdie[wfdielen++] = 0;
/* MAC Addr. */
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
if (P2P_ROLE_GO == pwdinfo->role) {
/* WFD Session Information ATTR */
/* Type: */
wfdie[wfdielen++] = WFD_ATTR_SESSION_INFO;
/* Length: */
/* Note: In the WFD specification, the size of length field is 2. */
RTW_PUT_BE16(wfdie + wfdielen, 0x0000);
wfdielen += 2;
/* Todo: to add the list of WFD device info descriptor in WFD group. */
}
rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len);
exit:
return len;
}
u32 build_provdisc_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf)
{
u8 wfdie[MAX_WFD_IE_LEN] = { 0x00 };
u32 len = 0, wfdielen = 0;
u16 val16 = 0;
_adapter *padapter = pwdinfo->padapter;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct wifi_display_info *pwfd_info = padapter->wdinfo.wfd_info;
if (!hal_chk_wl_func(padapter, WL_FUNC_MIRACAST))
goto exit;
/* WFD OUI */
wfdielen = 0;
wfdie[wfdielen++] = 0x50;
wfdie[wfdielen++] = 0x6F;
wfdie[wfdielen++] = 0x9A;
wfdie[wfdielen++] = 0x0A; /* WFA WFD v1.0 */
/* Commented by Albert 20110825 */
/* According to the WFD Specification, the provision discovery request frame should contain 3 WFD attributes */
/* 1. WFD Device Information */
/* 2. Associated BSSID ( Optional ) */
/* 3. Local IP Adress ( Optional ) */
/* WFD Device Information ATTR */
/* Type: */
wfdie[wfdielen++] = WFD_ATTR_DEVICE_INFO;
/* Length: */
/* Note: In the WFD specification, the size of length field is 2. */
RTW_PUT_BE16(wfdie + wfdielen, 0x0006);
wfdielen += 2;
/* Value1: */
/* WFD device information */
/* WFD primary sink + available for WFD session + WiFi Direct mode + WSD ( WFD Service Discovery ) */
val16 = pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD;
RTW_PUT_BE16(wfdie + wfdielen, val16);
wfdielen += 2;
/* Value2: */
/* Session Management Control Port */
/* Default TCP port for RTSP messages is 554 */
RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport);
wfdielen += 2;
/* Value3: */
/* WFD Device Maximum Throughput */
/* 300Mbps is the maximum throughput */
RTW_PUT_BE16(wfdie + wfdielen, 300);
wfdielen += 2;
/* Associated BSSID ATTR */
/* Type: */
wfdie[wfdielen++] = WFD_ATTR_ASSOC_BSSID;
/* Length: */
/* Note: In the WFD specification, the size of length field is 2. */
RTW_PUT_BE16(wfdie + wfdielen, 0x0006);
wfdielen += 2;
/* Value: */
/* Associated BSSID */
if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE)
_rtw_memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[0], ETH_ALEN);
else
_rtw_memset(wfdie + wfdielen, 0x00, ETH_ALEN);
wfdielen += ETH_ALEN;
/* Coupled Sink Information ATTR */
/* Type: */
wfdie[wfdielen++] = WFD_ATTR_COUPLED_SINK_INFO;
/* Length: */
/* Note: In the WFD specification, the size of length field is 2. */
RTW_PUT_BE16(wfdie + wfdielen, 0x0007);
wfdielen += 2;
/* Value: */
/* Coupled Sink Status bitmap */
/* Not coupled/available for Coupling */
wfdie[wfdielen++] = 0;
/* MAC Addr. */
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len);
exit:
return len;
}
u32 build_provdisc_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf)
{
u8 wfdie[MAX_WFD_IE_LEN] = { 0x00 };
u32 len = 0, wfdielen = 0;
u16 val16 = 0;
_adapter *padapter = pwdinfo->padapter;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct wifi_display_info *pwfd_info = padapter->wdinfo.wfd_info;
if (!hal_chk_wl_func(padapter, WL_FUNC_MIRACAST))
goto exit;
/* WFD OUI */
wfdielen = 0;
wfdie[wfdielen++] = 0x50;
wfdie[wfdielen++] = 0x6F;
wfdie[wfdielen++] = 0x9A;
wfdie[wfdielen++] = 0x0A; /* WFA WFD v1.0 */
/* Commented by Albert 20110825 */
/* According to the WFD Specification, the provision discovery response frame should contain 3 WFD attributes */
/* 1. WFD Device Information */
/* 2. Associated BSSID ( Optional ) */
/* 3. Local IP Adress ( Optional ) */
/* WFD Device Information ATTR */
/* Type: */
wfdie[wfdielen++] = WFD_ATTR_DEVICE_INFO;
/* Length: */
/* Note: In the WFD specification, the size of length field is 2. */
RTW_PUT_BE16(wfdie + wfdielen, 0x0006);
wfdielen += 2;
/* Value1: */
/* WFD device information */
/* WFD primary sink + available for WFD session + WiFi Direct mode + WSD ( WFD Service Discovery ) */
val16 = pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD;
RTW_PUT_BE16(wfdie + wfdielen, val16);
wfdielen += 2;
/* Value2: */
/* Session Management Control Port */
/* Default TCP port for RTSP messages is 554 */
RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport);
wfdielen += 2;
/* Value3: */
/* WFD Device Maximum Throughput */
/* 300Mbps is the maximum throughput */
RTW_PUT_BE16(wfdie + wfdielen, 300);
wfdielen += 2;
/* Associated BSSID ATTR */
/* Type: */
wfdie[wfdielen++] = WFD_ATTR_ASSOC_BSSID;
/* Length: */
/* Note: In the WFD specification, the size of length field is 2. */
RTW_PUT_BE16(wfdie + wfdielen, 0x0006);
wfdielen += 2;
/* Value: */
/* Associated BSSID */
if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE)
_rtw_memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[0], ETH_ALEN);
else
_rtw_memset(wfdie + wfdielen, 0x00, ETH_ALEN);
wfdielen += ETH_ALEN;
/* Coupled Sink Information ATTR */
/* Type: */
wfdie[wfdielen++] = WFD_ATTR_COUPLED_SINK_INFO;
/* Length: */
/* Note: In the WFD specification, the size of length field is 2. */
RTW_PUT_BE16(wfdie + wfdielen, 0x0007);
wfdielen += 2;
/* Value: */
/* Coupled Sink Status bitmap */
/* Not coupled/available for Coupling */
wfdie[wfdielen++] = 0;
/* MAC Addr. */
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
wfdie[wfdielen++] = 0;
rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len);
exit:
return len;
}
#endif /* CONFIG_WFD */
u32 build_probe_resp_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf)
{
u8 p2pie[MAX_P2P_IE_LEN] = { 0x00 };
u32 len = 0, p2pielen = 0;
#ifdef CONFIG_INTEL_WIDI
struct mlme_priv *pmlmepriv = &(pwdinfo->padapter->mlmepriv);
u8 zero_array_check[L2SDTA_SERVICE_VE_LEN] = { 0x00 };
u8 widi_version = 0, i = 0;
if (_rtw_memcmp(pmlmepriv->sa_ext, zero_array_check, L2SDTA_SERVICE_VE_LEN) == _FALSE)
widi_version = 35;
else if (pmlmepriv->num_p2p_sdt != 0)
widi_version = 40;
#endif /* CONFIG_INTEL_WIDI */
/* P2P OUI */
p2pielen = 0;
p2pie[p2pielen++] = 0x50;
p2pie[p2pielen++] = 0x6F;
p2pie[p2pielen++] = 0x9A;
p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */
/* Commented by Albert 20100907 */
/* According to the P2P Specification, the probe response frame should contain 5 P2P attributes */
/* 1. P2P Capability */
/* 2. Extended Listen Timing */
/* 3. Notice of Absence ( NOA ) ( Only GO needs this ) */
/* 4. Device Info */
/* 5. Group Info ( Only GO need this ) */
/* P2P Capability ATTR */
/* Type: */
p2pie[p2pielen++] = P2P_ATTR_CAPABILITY;
/* Length: */
/* *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0x0002 ); */
RTW_PUT_LE16(p2pie + p2pielen, 0x0002);
p2pielen += 2;
/* Value: */
/* Device Capability Bitmap, 1 byte */
p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT;
/* Group Capability Bitmap, 1 byte */
if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
p2pie[p2pielen] = (P2P_GRPCAP_GO | P2P_GRPCAP_INTRABSS);
if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_PROVISIONING_ING))
p2pie[p2pielen] |= P2P_GRPCAP_GROUP_FORMATION;
p2pielen++;
} else if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE)) {
/* Group Capability Bitmap, 1 byte */
if (pwdinfo->persistent_supported)
p2pie[p2pielen++] = P2P_GRPCAP_PERSISTENT_GROUP | DMP_P2P_GRPCAP_SUPPORT;
else
p2pie[p2pielen++] = DMP_P2P_GRPCAP_SUPPORT;
}
/* Extended Listen Timing ATTR */
/* Type: */
p2pie[p2pielen++] = P2P_ATTR_EX_LISTEN_TIMING;
/* Length: */
/* *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0x0004 ); */
RTW_PUT_LE16(p2pie + p2pielen, 0x0004);
p2pielen += 2;
/* Value: */
/* Availability Period */
/* *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0xFFFF ); */
RTW_PUT_LE16(p2pie + p2pielen, 0xFFFF);
p2pielen += 2;
/* Availability Interval */
/* *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0xFFFF ); */
RTW_PUT_LE16(p2pie + p2pielen, 0xFFFF);
p2pielen += 2;
/* Notice of Absence ATTR */
/* Type: */
/* Length: */
/* Value: */
if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
/* go_add_noa_attr(pwdinfo); */
}
/* Device Info ATTR */
/* Type: */
p2pie[p2pielen++] = P2P_ATTR_DEVICE_INFO;
/* Length: */
/* 21->P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) */
/* + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) */
/* *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 21 + pwdinfo->device_name_len ); */
#ifdef CONFIG_INTEL_WIDI
if (widi_version == 35)
RTW_PUT_LE16(p2pie + p2pielen, 21 + 8 + pwdinfo->device_name_len);
else if (widi_version == 40)
RTW_PUT_LE16(p2pie + p2pielen, 21 + 8 * pmlmepriv->num_p2p_sdt + pwdinfo->device_name_len);
else
#endif /* CONFIG_INTEL_WIDI */
RTW_PUT_LE16(p2pie + p2pielen, 21 + pwdinfo->device_name_len);
p2pielen += 2;
/* Value: */
/* P2P Device Address */
_rtw_memcpy(p2pie + p2pielen, pwdinfo->device_addr, ETH_ALEN);
p2pielen += ETH_ALEN;
/* Config Method */
/* This field should be big endian. Noted by P2P specification. */
/* *(u16*) ( p2pie + p2pielen ) = cpu_to_be16( pwdinfo->supported_wps_cm ); */
RTW_PUT_BE16(p2pie + p2pielen, pwdinfo->supported_wps_cm);
p2pielen += 2;
#ifdef CONFIG_INTEL_WIDI
if (widi_version == 40) {
/* Primary Device Type */
/* Category ID */
/* *(u16*) ( p2pie + p2pielen ) = cpu_to_be16( WPS_PDT_CID_MULIT_MEDIA ); */
RTW_PUT_BE16(p2pie + p2pielen, pmlmepriv->p2p_pdt_cid);
p2pielen += 2;
/* OUI */
/* *(u32*) ( p2pie + p2pielen ) = cpu_to_be32( WPSOUI ); */
RTW_PUT_BE32(p2pie + p2pielen, WPSOUI);
p2pielen += 4;
/* Sub Category ID */
/* *(u16*) ( p2pie + p2pielen ) = cpu_to_be16( WPS_PDT_SCID_MEDIA_SERVER ); */
RTW_PUT_BE16(p2pie + p2pielen, pmlmepriv->p2p_pdt_scid);
p2pielen += 2;
} else
#endif /* CONFIG_INTEL_WIDI */
{
/* Primary Device Type */
/* Category ID */
/* *(u16*) ( p2pie + p2pielen ) = cpu_to_be16( WPS_PDT_CID_MULIT_MEDIA ); */
RTW_PUT_BE16(p2pie + p2pielen, WPS_PDT_CID_MULIT_MEDIA);
p2pielen += 2;
/* OUI */
/* *(u32*) ( p2pie + p2pielen ) = cpu_to_be32( WPSOUI ); */
RTW_PUT_BE32(p2pie + p2pielen, WPSOUI);
p2pielen += 4;
/* Sub Category ID */
/* *(u16*) ( p2pie + p2pielen ) = cpu_to_be16( WPS_PDT_SCID_MEDIA_SERVER ); */
RTW_PUT_BE16(p2pie + p2pielen, WPS_PDT_SCID_MEDIA_SERVER);
p2pielen += 2;
}
/* Number of Secondary Device Types */
#ifdef CONFIG_INTEL_WIDI
if (widi_version == 35) {
p2pie[p2pielen++] = 0x01;
RTW_PUT_BE16(p2pie + p2pielen, WPS_PDT_CID_DISPLAYS);
p2pielen += 2;
RTW_PUT_BE32(p2pie + p2pielen, INTEL_DEV_TYPE_OUI);
p2pielen += 4;
RTW_PUT_BE16(p2pie + p2pielen, P2P_SCID_WIDI_CONSUMER_SINK);
p2pielen += 2;
} else if (widi_version == 40) {
p2pie[p2pielen++] = pmlmepriv->num_p2p_sdt;
for (; i < pmlmepriv->num_p2p_sdt; i++) {
RTW_PUT_BE16(p2pie + p2pielen, pmlmepriv->p2p_sdt_cid[i]);
p2pielen += 2;
RTW_PUT_BE32(p2pie + p2pielen, INTEL_DEV_TYPE_OUI);
p2pielen += 4;
RTW_PUT_BE16(p2pie + p2pielen, pmlmepriv->p2p_sdt_scid[i]);
p2pielen += 2;
}
} else
#endif /* CONFIG_INTEL_WIDI */
p2pie[p2pielen++] = 0x00; /* No Secondary Device Type List */
/* Device Name */
/* Type: */
/* *(u16*) ( p2pie + p2pielen ) = cpu_to_be16( WPS_ATTR_DEVICE_NAME ); */
RTW_PUT_BE16(p2pie + p2pielen, WPS_ATTR_DEVICE_NAME);
p2pielen += 2;
/* Length: */
/* *(u16*) ( p2pie + p2pielen ) = cpu_to_be16( pwdinfo->device_name_len ); */
RTW_PUT_BE16(p2pie + p2pielen, pwdinfo->device_name_len);
p2pielen += 2;
/* Value: */
_rtw_memcpy(p2pie + p2pielen, pwdinfo->device_name, pwdinfo->device_name_len);
p2pielen += pwdinfo->device_name_len;
/* Group Info ATTR */
/* Type: */
/* Length: */
/* Value: */
if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO))
p2pielen += go_add_group_info_attr(pwdinfo, p2pie + p2pielen);
pbuf = rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &len);
return len;
}
u32 build_prov_disc_request_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf, u8 *pssid, u8 ussidlen, u8 *pdev_raddr)
{
u8 p2pie[MAX_P2P_IE_LEN] = { 0x00 };
u32 len = 0, p2pielen = 0;
/* P2P OUI */
p2pielen = 0;
p2pie[p2pielen++] = 0x50;
p2pie[p2pielen++] = 0x6F;
p2pie[p2pielen++] = 0x9A;
p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */
/* Commented by Albert 20110301 */
/* According to the P2P Specification, the provision discovery request frame should contain 3 P2P attributes */
/* 1. P2P Capability */
/* 2. Device Info */
/* 3. Group ID ( When joining an operating P2P Group ) */
/* P2P Capability ATTR */
/* Type: */
p2pie[p2pielen++] = P2P_ATTR_CAPABILITY;
/* Length: */
/* *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0x0002 ); */
RTW_PUT_LE16(p2pie + p2pielen, 0x0002);
p2pielen += 2;
/* Value: */
/* Device Capability Bitmap, 1 byte */
p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT;
/* Group Capability Bitmap, 1 byte */
if (pwdinfo->persistent_supported)
p2pie[p2pielen++] = P2P_GRPCAP_PERSISTENT_GROUP | DMP_P2P_GRPCAP_SUPPORT;
else
p2pie[p2pielen++] = DMP_P2P_GRPCAP_SUPPORT;
/* Device Info ATTR */
/* Type: */
p2pie[p2pielen++] = P2P_ATTR_DEVICE_INFO;
/* Length: */
/* 21->P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) */
/* + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) */
/* *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 21 + pwdinfo->device_name_len ); */
RTW_PUT_LE16(p2pie + p2pielen, 21 + pwdinfo->device_name_len);
p2pielen += 2;
/* Value: */
/* P2P Device Address */
_rtw_memcpy(p2pie + p2pielen, pwdinfo->device_addr, ETH_ALEN);
p2pielen += ETH_ALEN;
/* Config Method */
/* This field should be big endian. Noted by P2P specification. */
if (pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_PBC) {
/* *(u16*) ( p2pie + p2pielen ) = cpu_to_be16( WPS_CONFIG_METHOD_PBC ); */
RTW_PUT_BE16(p2pie + p2pielen, WPS_CONFIG_METHOD_PBC);
} else {
/* *(u16*) ( p2pie + p2pielen ) = cpu_to_be16( WPS_CONFIG_METHOD_DISPLAY ); */
RTW_PUT_BE16(p2pie + p2pielen, WPS_CONFIG_METHOD_DISPLAY);
}
p2pielen += 2;
/* Primary Device Type */
/* Category ID */
/* *(u16*) ( p2pie + p2pielen ) = cpu_to_be16( WPS_PDT_CID_MULIT_MEDIA ); */
RTW_PUT_BE16(p2pie + p2pielen, WPS_PDT_CID_MULIT_MEDIA);
p2pielen += 2;
/* OUI */
/* *(u32*) ( p2pie + p2pielen ) = cpu_to_be32( WPSOUI ); */
RTW_PUT_BE32(p2pie + p2pielen, WPSOUI);
p2pielen += 4;
/* Sub Category ID */
/* *(u16*) ( p2pie + p2pielen ) = cpu_to_be16( WPS_PDT_SCID_MEDIA_SERVER ); */
RTW_PUT_BE16(p2pie + p2pielen, WPS_PDT_SCID_MEDIA_SERVER);
p2pielen += 2;
/* Number of Secondary Device Types */
p2pie[p2pielen++] = 0x00; /* No Secondary Device Type List */
/* Device Name */
/* Type: */
/* *(u16*) ( p2pie + p2pielen ) = cpu_to_be16( WPS_ATTR_DEVICE_NAME ); */
RTW_PUT_BE16(p2pie + p2pielen, WPS_ATTR_DEVICE_NAME);
p2pielen += 2;
/* Length: */
/* *(u16*) ( p2pie + p2pielen ) = cpu_to_be16( pwdinfo->device_name_len ); */
RTW_PUT_BE16(p2pie + p2pielen, pwdinfo->device_name_len);
p2pielen += 2;
/* Value: */
_rtw_memcpy(p2pie + p2pielen, pwdinfo->device_name, pwdinfo->device_name_len);
p2pielen += pwdinfo->device_name_len;
if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT)) {
/* Added by Albert 2011/05/19 */
/* In this case, the pdev_raddr is the device address of the group owner. */
/* P2P Group ID ATTR */
/* Type: */
p2pie[p2pielen++] = P2P_ATTR_GROUP_ID;
/* Length: */
/* *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( ETH_ALEN + ussidlen ); */
RTW_PUT_LE16(p2pie + p2pielen, ETH_ALEN + ussidlen);
p2pielen += 2;
/* Value: */
_rtw_memcpy(p2pie + p2pielen, pdev_raddr, ETH_ALEN);
p2pielen += ETH_ALEN;
_rtw_memcpy(p2pie + p2pielen, pssid, ussidlen);
p2pielen += ussidlen;
}
pbuf = rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &len);
return len;
}
u32 build_assoc_resp_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf, u8 status_code)
{
u8 p2pie[MAX_P2P_IE_LEN] = { 0x00 };
u32 len = 0, p2pielen = 0;
/* P2P OUI */
p2pielen = 0;
p2pie[p2pielen++] = 0x50;
p2pie[p2pielen++] = 0x6F;
p2pie[p2pielen++] = 0x9A;
p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */
/* According to the P2P Specification, the Association response frame should contain 2 P2P attributes */
/* 1. Status */
/* 2. Extended Listen Timing (optional) */
/* Status ATTR */
p2pielen += rtw_set_p2p_attr_content(&p2pie[p2pielen], P2P_ATTR_STATUS, 1, &status_code);
/* Extended Listen Timing ATTR */
/* Type: */
/* Length: */
/* Value: */
pbuf = rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &len);
return len;
}
u32 build_deauth_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf)
{
u32 len = 0;
return len;
}
u32 process_probe_req_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pframe, uint len)
{
u8 *p;
u32 ret = _FALSE;
u8 *p2pie;
u32 p2pielen = 0;
int ssid_len = 0, rate_cnt = 0;
p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + _PROBEREQ_IE_OFFSET_, _SUPPORTEDRATES_IE_, (int *)&rate_cnt,
len - WLAN_HDR_A3_LEN - _PROBEREQ_IE_OFFSET_);
if (rate_cnt <= 4) {
int i, g_rate = 0;
for (i = 0; i < rate_cnt; i++) {
if (((*(p + 2 + i) & 0xff) != 0x02) &&
((*(p + 2 + i) & 0xff) != 0x04) &&
((*(p + 2 + i) & 0xff) != 0x0B) &&
((*(p + 2 + i) & 0xff) != 0x16))
g_rate = 1;
}
if (g_rate == 0) {
/* There is no OFDM rate included in SupportedRates IE of this probe request frame */
/* The driver should response this probe request. */
return ret;
}
} else {
/* rate_cnt > 4 means the SupportRates IE contains the OFDM rate because the count of CCK rates are 4. */
/* We should proceed the following check for this probe request. */
}
/* Added comments by Albert 20100906 */
/* There are several items we should check here. */
/* 1. This probe request frame must contain the P2P IE. (Done) */
/* 2. This probe request frame must contain the wildcard SSID. (Done) */
/* 3. Wildcard BSSID. (Todo) */
/* 4. Destination Address. ( Done in mgt_dispatcher function ) */
/* 5. Requested Device Type in WSC IE. (Todo) */
/* 6. Device ID attribute in P2P IE. (Todo) */
p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + _PROBEREQ_IE_OFFSET_, _SSID_IE_, (int *)&ssid_len,
len - WLAN_HDR_A3_LEN - _PROBEREQ_IE_OFFSET_);
ssid_len &= 0xff; /* Just last 1 byte is valid for ssid len of the probe request */
if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE) || rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
p2pie = rtw_get_p2p_ie(pframe + WLAN_HDR_A3_LEN + _PROBEREQ_IE_OFFSET_ , len - WLAN_HDR_A3_LEN - _PROBEREQ_IE_OFFSET_ , NULL, &p2pielen);
if (p2pie) {
if ((p != NULL) && _rtw_memcmp((void *)(p + 2), (void *) pwdinfo->p2p_wildcard_ssid , 7)) {
/* todo: */
/* Check Requested Device Type attributes in WSC IE. */
/* Check Device ID attribute in P2P IE */
ret = _TRUE;
} else if ((p != NULL) && (ssid_len == 0))
ret = _TRUE;
} else {
/* non -p2p device */
}
}
return ret;
}
u32 process_assoc_req_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pframe, uint len, struct sta_info *psta)
{
u8 status_code = P2P_STATUS_SUCCESS;
u8 *pbuf, *pattr_content = NULL;
u32 attr_contentlen = 0;
u16 cap_attr = 0;
unsigned short frame_type, ie_offset = 0;
u8 *ies;
u32 ies_len;
u8 *p2p_ie;
u32 p2p_ielen = 0;
if (!rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO))
return P2P_STATUS_FAIL_REQUEST_UNABLE;
frame_type = get_frame_sub_type(pframe);
if (frame_type == WIFI_ASSOCREQ)
ie_offset = _ASOCREQ_IE_OFFSET_;
else /* WIFI_REASSOCREQ */
ie_offset = _REASOCREQ_IE_OFFSET_;
ies = pframe + WLAN_HDR_A3_LEN + ie_offset;
ies_len = len - WLAN_HDR_A3_LEN - ie_offset;
p2p_ie = rtw_get_p2p_ie(ies , ies_len , NULL, &p2p_ielen);
if (!p2p_ie) {
RTW_INFO("[%s] P2P IE not Found!!\n", __FUNCTION__);
status_code = P2P_STATUS_FAIL_INVALID_PARAM;
} else
RTW_INFO("[%s] P2P IE Found!!\n", __FUNCTION__);
while (p2p_ie) {
/* Check P2P Capability ATTR */
if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_CAPABILITY, (u8 *)&cap_attr, (uint *) &attr_contentlen)) {
RTW_INFO("[%s] Got P2P Capability Attr!!\n", __FUNCTION__);
cap_attr = le16_to_cpu(cap_attr);
psta->dev_cap = cap_attr & 0xff;
}
/* Check Extended Listen Timing ATTR */
/* Check P2P Device Info ATTR */
if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_DEVICE_INFO, NULL, (uint *)&attr_contentlen)) {
RTW_INFO("[%s] Got P2P DEVICE INFO Attr!!\n", __FUNCTION__);
pattr_content = pbuf = rtw_zmalloc(attr_contentlen);
if (pattr_content) {
u8 num_of_secdev_type;
u16 dev_name_len;
rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_DEVICE_INFO , pattr_content, (uint *)&attr_contentlen);
_rtw_memcpy(psta->dev_addr, pattr_content, ETH_ALEN);/* P2P Device Address */
pattr_content += ETH_ALEN;
_rtw_memcpy(&psta->config_methods, pattr_content, 2);/* Config Methods */
psta->config_methods = be16_to_cpu(psta->config_methods);
pattr_content += 2;
_rtw_memcpy(psta->primary_dev_type, pattr_content, 8);
pattr_content += 8;
num_of_secdev_type = *pattr_content;
pattr_content += 1;
if (num_of_secdev_type == 0)
psta->num_of_secdev_type = 0;
else {
u32 len;
psta->num_of_secdev_type = num_of_secdev_type;
len = (sizeof(psta->secdev_types_list) < (num_of_secdev_type * 8)) ? (sizeof(psta->secdev_types_list)) : (num_of_secdev_type * 8);
_rtw_memcpy(psta->secdev_types_list, pattr_content, len);
pattr_content += (num_of_secdev_type * 8);
}
/* dev_name_len = attr_contentlen - ETH_ALEN - 2 - 8 - 1 - (num_of_secdev_type*8); */
psta->dev_name_len = 0;
if (WPS_ATTR_DEVICE_NAME == be16_to_cpu(*(u16 *)pattr_content)) {
dev_name_len = be16_to_cpu(*(u16 *)(pattr_content + 2));
psta->dev_name_len = (sizeof(psta->dev_name) < dev_name_len) ? sizeof(psta->dev_name) : dev_name_len;
_rtw_memcpy(psta->dev_name, pattr_content + 4, psta->dev_name_len);
}
rtw_mfree(pbuf, attr_contentlen);
}
}
/* Get the next P2P IE */
p2p_ie = rtw_get_p2p_ie(p2p_ie + p2p_ielen, ies_len - (p2p_ie - ies + p2p_ielen), NULL, &p2p_ielen);
}
return status_code;
}
u32 process_p2p_devdisc_req(struct wifidirect_info *pwdinfo, u8 *pframe, uint len)
{
u8 *frame_body;
u8 status, dialogToken;
struct sta_info *psta = NULL;
_adapter *padapter = pwdinfo->padapter;
struct sta_priv *pstapriv = &padapter->stapriv;
u8 *p2p_ie;
u32 p2p_ielen = 0;
frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr));
dialogToken = frame_body[7];
status = P2P_STATUS_FAIL_UNKNOWN_P2PGROUP;
p2p_ie = rtw_get_p2p_ie(frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, NULL, &p2p_ielen);
if (p2p_ie) {
u8 groupid[38] = { 0x00 };
u8 dev_addr[ETH_ALEN] = { 0x00 };
u32 attr_contentlen = 0;
if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, groupid, &attr_contentlen)) {
if (_rtw_memcmp(pwdinfo->device_addr, groupid, ETH_ALEN) &&
_rtw_memcmp(pwdinfo->p2p_group_ssid, groupid + ETH_ALEN, pwdinfo->p2p_group_ssid_len)) {
attr_contentlen = 0;
if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_DEVICE_ID, dev_addr, &attr_contentlen)) {
_irqL irqL;
_list *phead, *plist;
_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
phead = &pstapriv->asoc_list;
plist = get_next(phead);
/* look up sta asoc_queue */
while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) {
psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
plist = get_next(plist);
if (psta->is_p2p_device && (psta->dev_cap & P2P_DEVCAP_CLIENT_DISCOVERABILITY) &&
_rtw_memcmp(psta->dev_addr, dev_addr, ETH_ALEN)) {
/* _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL); */
/* issue GO Discoverability Request */
issue_group_disc_req(pwdinfo, psta->cmn.mac_addr);
/* _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL); */
status = P2P_STATUS_SUCCESS;
break;
} else
status = P2P_STATUS_FAIL_INFO_UNAVAILABLE;
}
_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
} else
status = P2P_STATUS_FAIL_INVALID_PARAM;
} else
status = P2P_STATUS_FAIL_INVALID_PARAM;
}
}
/* issue Device Discoverability Response */
issue_p2p_devdisc_resp(pwdinfo, get_addr2_ptr(pframe), status, dialogToken);
return (status == P2P_STATUS_SUCCESS) ? _TRUE : _FALSE;
}
u32 process_p2p_devdisc_resp(struct wifidirect_info *pwdinfo, u8 *pframe, uint len)
{
return _TRUE;
}
u8 process_p2p_provdisc_req(struct wifidirect_info *pwdinfo, u8 *pframe, uint len)
{
u8 *frame_body;
u8 *wpsie;
uint wps_ielen = 0, attr_contentlen = 0;
u16 uconfig_method = 0;
frame_body = (pframe + sizeof(struct rtw_ieee80211_hdr_3addr));
wpsie = rtw_get_wps_ie(frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, NULL, &wps_ielen);
if (wpsie) {
if (rtw_get_wps_attr_content(wpsie, wps_ielen, WPS_ATTR_CONF_METHOD , (u8 *) &uconfig_method, &attr_contentlen)) {
uconfig_method = be16_to_cpu(uconfig_method);
switch (uconfig_method) {
case WPS_CM_DISPLYA: {
_rtw_memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "dis", 3);
break;
}
case WPS_CM_LABEL: {
_rtw_memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "lab", 3);
break;
}
case WPS_CM_PUSH_BUTTON: {
_rtw_memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pbc", 3);
break;
}
case WPS_CM_KEYPAD: {
_rtw_memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pad", 3);
break;
}
}
issue_p2p_provision_resp(pwdinfo, get_addr2_ptr(pframe), frame_body, uconfig_method);
}
}
RTW_INFO("[%s] config method = %s\n", __FUNCTION__, pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req);
return _TRUE;
}
u8 process_p2p_provdisc_resp(struct wifidirect_info *pwdinfo, u8 *pframe)
{
return _TRUE;
}
u8 rtw_p2p_get_peer_ch_list(struct wifidirect_info *pwdinfo, u8 *ch_content, u8 ch_cnt, u8 *peer_ch_list)
{
u8 i = 0, j = 0;
u8 temp = 0;
u8 ch_no = 0;
ch_content += 3;
ch_cnt -= 3;
while (ch_cnt > 0) {
ch_content += 1;
ch_cnt -= 1;
temp = *ch_content;
for (i = 0 ; i < temp ; i++, j++)
peer_ch_list[j] = *(ch_content + 1 + i);
ch_content += (temp + 1);
ch_cnt -= (temp + 1);
ch_no += temp ;
}
return ch_no;
}
u8 rtw_p2p_ch_inclusion(_adapter *adapter, u8 *peer_ch_list, u8 peer_ch_num, u8 *ch_list_inclusioned)
{
struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter);
int i = 0, j = 0, temp = 0;
u8 ch_no = 0;
for (i = 0; i < peer_ch_num; i++) {
for (j = temp; j < rfctl->max_chan_nums; j++) {
if (*(peer_ch_list + i) == rfctl->channel_set[j].ChannelNum) {
ch_list_inclusioned[ch_no++] = *(peer_ch_list + i);
temp = j;
break;
}
}
}
return ch_no;
}
u8 process_p2p_group_negotation_req(struct wifidirect_info *pwdinfo, u8 *pframe, uint len)
{
_adapter *padapter = pwdinfo->padapter;
u8 result = P2P_STATUS_SUCCESS;
u32 p2p_ielen = 0, wps_ielen = 0;
u8 *ies;
u32 ies_len;
u8 *p2p_ie;
u8 *wpsie;
u16 wps_devicepassword_id = 0x0000;
uint wps_devicepassword_id_len = 0;
#ifdef CONFIG_WFD
#ifdef CONFIG_TDLS
struct tdls_info *ptdlsinfo = &padapter->tdlsinfo;
#endif /* CONFIG_TDLS */
#endif /* CONFIG_WFD */
wpsie = rtw_get_wps_ie(pframe + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, NULL, &wps_ielen);
if (wpsie) {
/* Commented by Kurt 20120113 */
/* If some device wants to do p2p handshake without sending prov_disc_req */
/* We have to get peer_req_cm from here. */
if (_rtw_memcmp(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "000", 3)) {
rtw_get_wps_attr_content(wpsie, wps_ielen, WPS_ATTR_DEVICE_PWID, (u8 *) &wps_devicepassword_id, &wps_devicepassword_id_len);
wps_devicepassword_id = be16_to_cpu(wps_devicepassword_id);
if (wps_devicepassword_id == WPS_DPID_USER_SPEC)
_rtw_memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "dis", 3);
else if (wps_devicepassword_id == WPS_DPID_REGISTRAR_SPEC)
_rtw_memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pad", 3);
else
_rtw_memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pbc", 3);
}
} else {
RTW_INFO("[%s] WPS IE not Found!!\n", __FUNCTION__);
result = P2P_STATUS_FAIL_INCOMPATIBLE_PARAM;
rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL);
return result ;
}
ies = pframe + _PUBLIC_ACTION_IE_OFFSET_;
ies_len = len - _PUBLIC_ACTION_IE_OFFSET_;
p2p_ie = rtw_get_p2p_ie(ies, ies_len, NULL, &p2p_ielen);
if (!p2p_ie) {
RTW_INFO("[%s] P2P IE not Found!!\n", __FUNCTION__);
result = P2P_STATUS_FAIL_INCOMPATIBLE_PARAM;
rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL);
}
while (p2p_ie) {
u8 attr_content = 0x00;
u32 attr_contentlen = 0;
u8 ch_content[100] = { 0x00 };
uint ch_cnt = 0;
u8 peer_ch_list[100] = { 0x00 };
u8 peer_ch_num = 0;
u8 ch_list_inclusioned[100] = { 0x00 };
u8 ch_num_inclusioned = 0;
u16 cap_attr;
u8 listen_ch_attr[5] = { 0x00 };
rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_ING);
/* Check P2P Capability ATTR */
if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_CAPABILITY, (u8 *)&cap_attr, (uint *)&attr_contentlen)) {
cap_attr = le16_to_cpu(cap_attr);
#if defined(CONFIG_WFD) && defined(CONFIG_TDLS)
if (!(cap_attr & P2P_GRPCAP_INTRABSS))
ptdlsinfo->ap_prohibited = _TRUE;
#endif /* defined(CONFIG_WFD) && defined(CONFIG_TDLS) */
}
if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GO_INTENT , &attr_content, &attr_contentlen)) {
RTW_INFO("[%s] GO Intent = %d, tie = %d\n", __FUNCTION__, attr_content >> 1, attr_content & 0x01);
pwdinfo->peer_intent = attr_content; /* include both intent and tie breaker values. */
if (pwdinfo->intent == (pwdinfo->peer_intent >> 1)) {
/* Try to match the tie breaker value */
if (pwdinfo->intent == P2P_MAX_INTENT) {
rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE);
result = P2P_STATUS_FAIL_BOTH_GOINTENT_15;
} else {
if (attr_content & 0x01)
rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT);
else
rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO);
}
} else if (pwdinfo->intent > (pwdinfo->peer_intent >> 1))
rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO);
else
rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT);
if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
/* Store the group id information. */
_rtw_memcpy(pwdinfo->groupid_info.go_device_addr, pwdinfo->device_addr, ETH_ALEN);
_rtw_memcpy(pwdinfo->groupid_info.ssid, pwdinfo->nego_ssid, pwdinfo->nego_ssidlen);
}
}
if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_LISTEN_CH, (u8 *)listen_ch_attr, (uint *) &attr_contentlen) && attr_contentlen == 5)
pwdinfo->nego_req_info.peer_ch = listen_ch_attr[4];
RTW_INFO(FUNC_ADPT_FMT" listen channel :%u\n", FUNC_ADPT_ARG(padapter), pwdinfo->nego_req_info.peer_ch);
attr_contentlen = 0;
if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_INTENDED_IF_ADDR, pwdinfo->p2p_peer_interface_addr, &attr_contentlen)) {
if (attr_contentlen != ETH_ALEN)
_rtw_memset(pwdinfo->p2p_peer_interface_addr, 0x00, ETH_ALEN);
}
if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_CH_LIST, ch_content, &ch_cnt)) {
peer_ch_num = rtw_p2p_get_peer_ch_list(pwdinfo, ch_content, ch_cnt, peer_ch_list);
ch_num_inclusioned = rtw_p2p_ch_inclusion(padapter, peer_ch_list, peer_ch_num, ch_list_inclusioned);
if (ch_num_inclusioned == 0) {
RTW_INFO("[%s] No common channel in channel list!\n", __FUNCTION__);
result = P2P_STATUS_FAIL_NO_COMMON_CH;
rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL);
break;
}
if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
if (!rtw_p2p_is_channel_list_ok(pwdinfo->operating_channel,
ch_list_inclusioned, ch_num_inclusioned)) {
#ifdef CONFIG_CONCURRENT_MODE
if (rtw_mi_check_status(padapter, MI_LINKED)
&& padapter->registrypriv.full_ch_in_p2p_handshake == 0) {
RTW_INFO("[%s] desired channel NOT Found!\n", __FUNCTION__);
result = P2P_STATUS_FAIL_NO_COMMON_CH;
rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL);
break;
} else
#endif /* CONFIG_CONCURRENT_MODE */
{
u8 operatingch_info[5] = { 0x00 }, peer_operating_ch = 0;
attr_contentlen = 0;
if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen))
peer_operating_ch = operatingch_info[4];
if (rtw_p2p_is_channel_list_ok(peer_operating_ch,
ch_list_inclusioned, ch_num_inclusioned)) {
/**
* Change our operating channel as peer's for compatibility.
*/
pwdinfo->operating_channel = peer_operating_ch;
RTW_INFO("[%s] Change op ch to %02x as peer's\n", __FUNCTION__, pwdinfo->operating_channel);
} else {
/* Take first channel of ch_list_inclusioned as operating channel */
pwdinfo->operating_channel = ch_list_inclusioned[0];
RTW_INFO("[%s] Change op ch to %02x\n", __FUNCTION__, pwdinfo->operating_channel);
}
}
}
}
}
/* Get the next P2P IE */
p2p_ie = rtw_get_p2p_ie(p2p_ie + p2p_ielen, ies_len - (p2p_ie - ies + p2p_ielen), NULL, &p2p_ielen);
}
if (pwdinfo->ui_got_wps_info == P2P_NO_WPSINFO) {
result = P2P_STATUS_FAIL_INFO_UNAVAILABLE;
rtw_p2p_set_state(pwdinfo, P2P_STATE_TX_INFOR_NOREADY);
return result;
}
#ifdef CONFIG_WFD
rtw_process_wfd_ies(padapter, pframe + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, __func__);
#endif
return result ;
}
u8 process_p2p_group_negotation_resp(struct wifidirect_info *pwdinfo, u8 *pframe, uint len)
{
_adapter *padapter = pwdinfo->padapter;
u8 result = P2P_STATUS_SUCCESS;
u32 p2p_ielen, wps_ielen;
u8 *ies;
u32 ies_len;
u8 *p2p_ie;
#ifdef CONFIG_WFD
#ifdef CONFIG_TDLS
struct tdls_info *ptdlsinfo = &padapter->tdlsinfo;
#endif /* CONFIG_TDLS */
#endif /* CONFIG_WFD */
ies = pframe + _PUBLIC_ACTION_IE_OFFSET_;
ies_len = len - _PUBLIC_ACTION_IE_OFFSET_;
/* Be able to know which one is the P2P GO and which one is P2P client. */
if (rtw_get_wps_ie(ies, ies_len, NULL, &wps_ielen)) {
} else {
RTW_INFO("[%s] WPS IE not Found!!\n", __FUNCTION__);
result = P2P_STATUS_FAIL_INCOMPATIBLE_PARAM;
rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL);
}
p2p_ie = rtw_get_p2p_ie(ies, ies_len, NULL, &p2p_ielen);
if (!p2p_ie) {
rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE);
rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL);
result = P2P_STATUS_FAIL_INCOMPATIBLE_PARAM;
} else {
u8 attr_content = 0x00;
u32 attr_contentlen = 0;
u8 operatingch_info[5] = { 0x00 };
u8 groupid[38];
u16 cap_attr;
u8 peer_ch_list[100] = { 0x00 };
u8 peer_ch_num = 0;
u8 ch_list_inclusioned[100] = { 0x00 };
u8 ch_num_inclusioned = 0;
while (p2p_ie) { /* Found the P2P IE. */
/* Check P2P Capability ATTR */
if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_CAPABILITY, (u8 *)&cap_attr, (uint *)&attr_contentlen)) {
cap_attr = le16_to_cpu(cap_attr);
#ifdef CONFIG_TDLS
if (!(cap_attr & P2P_GRPCAP_INTRABSS))
ptdlsinfo->ap_prohibited = _TRUE;
#endif /* CONFIG_TDLS */
}
rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, &attr_content, &attr_contentlen);
if (attr_contentlen == 1) {
RTW_INFO("[%s] Status = %d\n", __FUNCTION__, attr_content);
if (attr_content == P2P_STATUS_SUCCESS) {
/* Do nothing. */
} else {
if (P2P_STATUS_FAIL_INFO_UNAVAILABLE == attr_content)
rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_INFOR_NOREADY);
else
rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL);
rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE);
result = attr_content;
break;
}
}
/* Try to get the peer's interface address */
attr_contentlen = 0;
if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_INTENDED_IF_ADDR, pwdinfo->p2p_peer_interface_addr, &attr_contentlen)) {
if (attr_contentlen != ETH_ALEN)
_rtw_memset(pwdinfo->p2p_peer_interface_addr, 0x00, ETH_ALEN);
}
/* Try to get the peer's intent and tie breaker value. */
attr_content = 0x00;
attr_contentlen = 0;
if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GO_INTENT , &attr_content, &attr_contentlen)) {
RTW_INFO("[%s] GO Intent = %d, tie = %d\n", __FUNCTION__, attr_content >> 1, attr_content & 0x01);
pwdinfo->peer_intent = attr_content; /* include both intent and tie breaker values. */
if (pwdinfo->intent == (pwdinfo->peer_intent >> 1)) {
/* Try to match the tie breaker value */
if (pwdinfo->intent == P2P_MAX_INTENT) {
rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE);
result = P2P_STATUS_FAIL_BOTH_GOINTENT_15;
rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL);
} else {
rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK);
rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK);
if (attr_content & 0x01)
rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT);
else
rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO);
}
} else if (pwdinfo->intent > (pwdinfo->peer_intent >> 1)) {
rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK);
rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK);
rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO);
} else {
rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK);
rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK);
rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT);
}
if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
/* Store the group id information. */
_rtw_memcpy(pwdinfo->groupid_info.go_device_addr, pwdinfo->device_addr, ETH_ALEN);
_rtw_memcpy(pwdinfo->groupid_info.ssid, pwdinfo->nego_ssid, pwdinfo->nego_ssidlen);
}
}
/* Try to get the operation channel information */
attr_contentlen = 0;
if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen)) {
RTW_INFO("[%s] Peer's operating channel = %d\n", __FUNCTION__, operatingch_info[4]);
pwdinfo->peer_operating_ch = operatingch_info[4];
}
/* Try to get the channel list information */
if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_CH_LIST, pwdinfo->channel_list_attr, &pwdinfo->channel_list_attr_len)) {
RTW_INFO("[%s] channel list attribute found, len = %d\n", __FUNCTION__, pwdinfo->channel_list_attr_len);
peer_ch_num = rtw_p2p_get_peer_ch_list(pwdinfo, pwdinfo->channel_list_attr, pwdinfo->channel_list_attr_len, peer_ch_list);
ch_num_inclusioned = rtw_p2p_ch_inclusion(padapter, peer_ch_list, peer_ch_num, ch_list_inclusioned);
if (ch_num_inclusioned == 0) {
RTW_INFO("[%s] No common channel in channel list!\n", __FUNCTION__);
result = P2P_STATUS_FAIL_NO_COMMON_CH;
rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL);
break;
}
if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
if (!rtw_p2p_is_channel_list_ok(pwdinfo->operating_channel,
ch_list_inclusioned, ch_num_inclusioned)) {
#ifdef CONFIG_CONCURRENT_MODE
if (rtw_mi_check_status(padapter, MI_LINKED)
&& padapter->registrypriv.full_ch_in_p2p_handshake == 0) {
RTW_INFO("[%s] desired channel NOT Found!\n", __FUNCTION__);
result = P2P_STATUS_FAIL_NO_COMMON_CH;
rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL);
break;
} else
#endif /* CONFIG_CONCURRENT_MODE */
{
u8 operatingch_info[5] = { 0x00 }, peer_operating_ch = 0;
attr_contentlen = 0;
if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen))
peer_operating_ch = operatingch_info[4];
if (rtw_p2p_is_channel_list_ok(peer_operating_ch,
ch_list_inclusioned, ch_num_inclusioned)) {
/**
* Change our operating channel as peer's for compatibility.
*/
pwdinfo->operating_channel = peer_operating_ch;
RTW_INFO("[%s] Change op ch to %02x as peer's\n", __FUNCTION__, pwdinfo->operating_channel);
} else {
/* Take first channel of ch_list_inclusioned as operating channel */
pwdinfo->operating_channel = ch_list_inclusioned[0];
RTW_INFO("[%s] Change op ch to %02x\n", __FUNCTION__, pwdinfo->operating_channel);
}
}
}
}
} else
RTW_INFO("[%s] channel list attribute not found!\n", __FUNCTION__);
/* Try to get the group id information if peer is GO */
attr_contentlen = 0;
_rtw_memset(groupid, 0x00, 38);
if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, groupid, &attr_contentlen)) {
_rtw_memcpy(pwdinfo->groupid_info.go_device_addr, &groupid[0], ETH_ALEN);
_rtw_memcpy(pwdinfo->groupid_info.ssid, &groupid[6], attr_contentlen - ETH_ALEN);
}
/* Get the next P2P IE */
p2p_ie = rtw_get_p2p_ie(p2p_ie + p2p_ielen, ies_len - (p2p_ie - ies + p2p_ielen), NULL, &p2p_ielen);
}
}
#ifdef CONFIG_WFD
rtw_process_wfd_ies(padapter, pframe + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, __func__);
#endif
return result ;
}
u8 process_p2p_group_negotation_confirm(struct wifidirect_info *pwdinfo, u8 *pframe, uint len)
{
#ifdef CONFIG_CONCURRENT_MODE
_adapter *padapter = pwdinfo->padapter;
#endif
u8 *ies;
u32 ies_len;
u8 *p2p_ie;
u32 p2p_ielen = 0;
u8 result = P2P_STATUS_SUCCESS;
ies = pframe + _PUBLIC_ACTION_IE_OFFSET_;
ies_len = len - _PUBLIC_ACTION_IE_OFFSET_;
p2p_ie = rtw_get_p2p_ie(ies, ies_len, NULL, &p2p_ielen);
while (p2p_ie) { /* Found the P2P IE. */
u8 attr_content = 0x00, operatingch_info[5] = { 0x00 };
u8 groupid[38] = { 0x00 };
u32 attr_contentlen = 0;
pwdinfo->negotiation_dialog_token = 1;
rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, &attr_content, &attr_contentlen);
if (attr_contentlen == 1) {
RTW_INFO("[%s] Status = %d\n", __FUNCTION__, attr_content);
result = attr_content;
if (attr_content == P2P_STATUS_SUCCESS) {
_cancel_timer_ex(&pwdinfo->restore_p2p_state_timer);
/* Commented by Albert 20100911 */
/* Todo: Need to handle the case which both Intents are the same. */
rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK);
rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK);
if ((pwdinfo->intent) > (pwdinfo->peer_intent >> 1))
rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO);
else if ((pwdinfo->intent) < (pwdinfo->peer_intent >> 1))
rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT);
else {
/* Have to compare the Tie Breaker */
if (pwdinfo->peer_intent & 0x01)
rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT);
else
rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO);
}
#ifdef CONFIG_CONCURRENT_MODE
if (rtw_mi_check_status(padapter, MI_LINKED)
&& padapter->registrypriv.full_ch_in_p2p_handshake == 0) {
/* Switch back to the AP channel soon. */
_set_timer(&pwdinfo->ap_p2p_switch_timer, 100);
}
#endif
} else {
rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE);
rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL);
break;
}
}
/* Try to get the group id information */
attr_contentlen = 0;
_rtw_memset(groupid, 0x00, 38);
if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, groupid, &attr_contentlen)) {
RTW_INFO("[%s] Ssid = %s, ssidlen = %zu\n", __FUNCTION__, &groupid[ETH_ALEN], strlen(&groupid[ETH_ALEN]));
_rtw_memcpy(pwdinfo->groupid_info.go_device_addr, &groupid[0], ETH_ALEN);
_rtw_memcpy(pwdinfo->groupid_info.ssid, &groupid[6], attr_contentlen - ETH_ALEN);
}
attr_contentlen = 0;
if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen)) {
RTW_INFO("[%s] Peer's operating channel = %d\n", __FUNCTION__, operatingch_info[4]);
pwdinfo->peer_operating_ch = operatingch_info[4];
}
/* Get the next P2P IE */
p2p_ie = rtw_get_p2p_ie(p2p_ie + p2p_ielen, ies_len - (p2p_ie - ies + p2p_ielen), NULL, &p2p_ielen);
}
return result ;
}
u8 process_p2p_presence_req(struct wifidirect_info *pwdinfo, u8 *pframe, uint len)
{
u8 *frame_body;
u8 dialogToken = 0;
u8 status = P2P_STATUS_SUCCESS;
frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr));
dialogToken = frame_body[6];
/* todo: check NoA attribute */
issue_p2p_presence_resp(pwdinfo, get_addr2_ptr(pframe), status, dialogToken);
return _TRUE;
}
void find_phase_handler(_adapter *padapter)
{
struct wifidirect_info *pwdinfo = &padapter->wdinfo;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct sitesurvey_parm parm;
_irqL irqL;
u8 _status = 0;
rtw_init_sitesurvey_parm(padapter, &parm);
_rtw_memcpy(&parm.ssid[0].Ssid, pwdinfo->p2p_wildcard_ssid, P2P_WILDCARD_SSID_LEN);
parm.ssid[0].SsidLength = P2P_WILDCARD_SSID_LEN;
parm.ssid_num = 1;
rtw_p2p_set_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH);
_enter_critical_bh(&pmlmepriv->lock, &irqL);
_status = rtw_sitesurvey_cmd(padapter, &parm);
_exit_critical_bh(&pmlmepriv->lock, &irqL);
}
void p2p_concurrent_handler(_adapter *padapter);
void restore_p2p_state_handler(_adapter *padapter)
{
struct wifidirect_info *pwdinfo = &padapter->wdinfo;
if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_FAIL))
rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE);
#ifdef CONFIG_CONCURRENT_MODE
if (rtw_mi_check_status(padapter, MI_LINKED)) {
u8 union_ch = rtw_mi_get_union_chan(padapter);
u8 union_bw = rtw_mi_get_union_bw(padapter);
u8 union_offset = rtw_mi_get_union_offset(padapter);
if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_PROVISION_DIS_REQ) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_RSP)) {
set_channel_bwmode(padapter, union_ch, union_offset, union_bw);
rtw_back_opch(padapter);
}
}
#endif
rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo));
if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE)) {
#ifdef CONFIG_CONCURRENT_MODE
p2p_concurrent_handler(padapter);
#else
/* In the P2P client mode, the driver should not switch back to its listen channel */
/* because this P2P client should stay at the operating channel of P2P GO. */
set_channel_bwmode(padapter, pwdinfo->listen_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20);
#endif
}
}
void pre_tx_invitereq_handler(_adapter *padapter)
{
struct wifidirect_info *pwdinfo = &padapter->wdinfo;
u8 val8 = 1;
set_channel_bwmode(padapter, pwdinfo->invitereq_info.peer_ch, HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20);
rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8));
issue_probereq_p2p(padapter, NULL);
_set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT);
}
void pre_tx_provdisc_handler(_adapter *padapter)
{
struct wifidirect_info *pwdinfo = &padapter->wdinfo;
u8 val8 = 1;
set_channel_bwmode(padapter, pwdinfo->tx_prov_disc_info.peer_channel_num[0], HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20);
rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8));
issue_probereq_p2p(padapter, NULL);
_set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT);
}
void pre_tx_negoreq_handler(_adapter *padapter)
{
struct wifidirect_info *pwdinfo = &padapter->wdinfo;
u8 val8 = 1;
set_channel_bwmode(padapter, pwdinfo->nego_req_info.peer_channel_num[0], HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20);
rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8));
issue_probereq_p2p(padapter , NULL);
/* WIN Phone only accept unicast probe request when nego back */
issue_probereq_p2p(padapter , pwdinfo->nego_req_info.peerDevAddr);
_set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT);
}
#ifdef CONFIG_CONCURRENT_MODE
void p2p_concurrent_handler(_adapter *padapter)
{
struct wifidirect_info *pwdinfo = &padapter->wdinfo;
struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
u8 val8;
#ifdef CONFIG_IOCTL_CFG80211
if (pwdinfo->driver_interface == DRIVER_CFG80211
&& !rtw_cfg80211_get_is_roch(padapter))
return;
#endif
if (rtw_mi_check_status(padapter, MI_LINKED)) {
u8 union_ch = rtw_mi_get_union_chan(padapter);
u8 union_bw = rtw_mi_get_union_bw(padapter);
u8 union_offset = rtw_mi_get_union_offset(padapter);
pwdinfo->operating_channel = union_ch;
if (pwdinfo->driver_interface == DRIVER_CFG80211) {
RTW_INFO("%s, switch ch back to union=%u,%u, %u\n"
, __func__, union_ch, union_bw, union_offset);
set_channel_bwmode(padapter, union_ch, union_offset, union_bw);
rtw_back_opch(padapter);
} else if (pwdinfo->driver_interface == DRIVER_WEXT) {
if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE)) {
/* Now, the driver stays on the AP's channel. */
/* If the pwdinfo->ext_listen_period = 0, that means the P2P listen state is not available on listen channel. */
if (pwdinfo->ext_listen_period > 0) {
RTW_INFO("[%s] P2P_STATE_IDLE, ext_listen_period = %d\n", __FUNCTION__, pwdinfo->ext_listen_period);
if (union_ch != pwdinfo->listen_channel) {
rtw_leave_opch(padapter);
set_channel_bwmode(padapter, pwdinfo->listen_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20);
}
rtw_p2p_set_state(pwdinfo, P2P_STATE_LISTEN);
if (!rtw_mi_check_mlmeinfo_state(padapter, WIFI_FW_AP_STATE)) {
val8 = 1;
rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8));
}
/* Todo: To check the value of pwdinfo->ext_listen_period is equal to 0 or not. */
_set_timer(&pwdinfo->ap_p2p_switch_timer, pwdinfo->ext_listen_period);
}
} else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_LISTEN) ||
rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_FAIL) ||
(rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING) && pwdinfo->nego_req_info.benable == _FALSE) ||
rtw_p2p_chk_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_REQ)) {
/* Now, the driver is in the listen state of P2P mode. */
RTW_INFO("[%s] P2P_STATE_IDLE, ext_listen_interval = %d\n", __FUNCTION__, pwdinfo->ext_listen_interval);
/* Commented by Albert 2012/11/01 */
/* If the AP's channel is the same as the listen channel, we should still be in the listen state */
/* Other P2P device is still able to find this device out even this device is in the AP's channel. */
/* So, configure this device to be able to receive the probe request frame and set it to listen state. */
if (union_ch != pwdinfo->listen_channel) {
set_channel_bwmode(padapter, union_ch, union_offset, union_bw);
if (!rtw_mi_check_status(padapter, MI_AP_MODE)) {
val8 = 0;
rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8));
}
rtw_p2p_set_state(pwdinfo, P2P_STATE_IDLE);
rtw_back_opch(padapter);
}
/* Todo: To check the value of pwdinfo->ext_listen_interval is equal to 0 or not. */
_set_timer(&pwdinfo->ap_p2p_switch_timer, pwdinfo->ext_listen_interval);
} else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_OK)) {
/* The driver had finished the P2P handshake successfully. */
val8 = 0;
rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8));
set_channel_bwmode(padapter, union_ch, union_offset, union_bw);
rtw_back_opch(padapter);
} else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_PROVISION_DIS_REQ)) {
val8 = 1;
set_channel_bwmode(padapter, pwdinfo->tx_prov_disc_info.peer_channel_num[0], HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20);
rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8));
issue_probereq_p2p(padapter, NULL);
_set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT);
} else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING) && pwdinfo->nego_req_info.benable == _TRUE) {
val8 = 1;
set_channel_bwmode(padapter, pwdinfo->nego_req_info.peer_channel_num[0], HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20);
rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8));
issue_probereq_p2p(padapter, NULL);
_set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT);
} else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_INVITE_REQ) && pwdinfo->invitereq_info.benable == _TRUE) {
/*
val8 = 1;
set_channel_bwmode(padapter, , HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20);
rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8));
issue_probereq_p2p(padapter, NULL);
_set_timer( &pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT );
*/
}
}
} else {
/* In p2p+softap. When in P2P_STATE_GONEGO_OK, not back to listen channel.*/
if (!rtw_p2p_chk_state(pwdinfo , P2P_STATE_GONEGO_OK) || padapter->registrypriv.full_ch_in_p2p_handshake == 0)
set_channel_bwmode(padapter, pwdinfo->listen_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20);
else
RTW_INFO("%s, buddy not linked, go nego ok, not back to listen channel\n", __func__);
}
}
#endif
#ifdef CONFIG_IOCTL_CFG80211
u8 roch_stay_in_cur_chan(_adapter *padapter)
{
int i;
_adapter *iface;
struct mlme_priv *pmlmepriv;
struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
u8 rst = _FALSE;
for (i = 0; i < dvobj->iface_nums; i++) {
iface = dvobj->padapters[i];
if (iface) {
pmlmepriv = &iface->mlmepriv;
if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING | WIFI_UNDER_WPS | WIFI_UNDER_KEY_HANDSHAKE) == _TRUE) {
RTW_INFO(ADPT_FMT"- _FW_UNDER_LINKING |WIFI_UNDER_WPS | WIFI_UNDER_KEY_HANDSHAKE (mlme state:0x%x)\n",
ADPT_ARG(iface), get_fwstate(&iface->mlmepriv));
rst = _TRUE;
break;
}
#ifdef CONFIG_AP_MODE
if (MLME_IS_AP(iface) || MLME_IS_MESH(iface)) {
if (rtw_ap_sta_states_check(iface) == _TRUE) {
rst = _TRUE;
break;
}
}
#endif
}
}
return rst;
}
static int ro_ch_handler(_adapter *adapter, u8 *buf)
{
int ret = H2C_SUCCESS;
struct p2p_roch_parm *roch_parm = (struct p2p_roch_parm *)buf;
struct rtw_wdev_priv *pwdev_priv = adapter_wdev_data(adapter);
struct cfg80211_wifidirect_info *pcfg80211_wdinfo = &adapter->cfg80211_wdinfo;
#ifdef CONFIG_CONCURRENT_MODE
struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv;
#ifdef RTW_ROCH_BACK_OP
struct wifidirect_info *pwdinfo = &adapter->wdinfo;
#endif
#endif
u8 ready_on_channel = _FALSE;
u8 remain_ch;
unsigned int duration;
_enter_critical_mutex(&pwdev_priv->roch_mutex, NULL);
if (rtw_cfg80211_get_is_roch(adapter) != _TRUE)
goto exit;
remain_ch = (u8)ieee80211_frequency_to_channel(roch_parm->ch.center_freq);
duration = roch_parm->duration;
RTW_INFO(FUNC_ADPT_FMT" ch:%u duration:%d, cookie:0x%llx\n"
, FUNC_ADPT_ARG(adapter), remain_ch, roch_parm->duration, roch_parm->cookie);
if (roch_parm->wdev && roch_parm->cookie) {
if (pcfg80211_wdinfo->ro_ch_wdev != roch_parm->wdev) {
RTW_WARN(FUNC_ADPT_FMT" ongoing wdev:%p, wdev:%p\n"
, FUNC_ADPT_ARG(adapter), pcfg80211_wdinfo->ro_ch_wdev, roch_parm->wdev);
rtw_warn_on(1);
}
if (pcfg80211_wdinfo->remain_on_ch_cookie != roch_parm->cookie) {
RTW_WARN(FUNC_ADPT_FMT" ongoing cookie:0x%llx, cookie:0x%llx\n"
, FUNC_ADPT_ARG(adapter), pcfg80211_wdinfo->remain_on_ch_cookie, roch_parm->cookie);
rtw_warn_on(1);
}
}
if (roch_stay_in_cur_chan(adapter) == _TRUE) {
remain_ch = rtw_mi_get_union_chan(adapter);
RTW_INFO(FUNC_ADPT_FMT" stay in union ch:%d\n", FUNC_ADPT_ARG(adapter), remain_ch);
}
#ifdef CONFIG_CONCURRENT_MODE
if (rtw_mi_check_status(adapter, MI_LINKED) && (0 != rtw_mi_get_union_chan(adapter))) {
if ((remain_ch != rtw_mi_get_union_chan(adapter)) && !check_fwstate(&adapter->mlmepriv, _FW_LINKED)) {
if (remain_ch != pmlmeext->cur_channel
#ifdef RTW_ROCH_BACK_OP
|| ATOMIC_READ(&pwdev_priv->switch_ch_to) == 1
#endif
) {
rtw_leave_opch(adapter);
#ifdef RTW_ROCH_BACK_OP
RTW_INFO("%s, set switch ch timer, duration=%d\n", __func__, duration - pwdinfo->ext_listen_interval);
ATOMIC_SET(&pwdev_priv->switch_ch_to, 0);
_set_timer(&pwdinfo->ap_p2p_switch_timer, duration - pwdinfo->ext_listen_interval);
#endif
}
}
ready_on_channel = _TRUE;
} else
#endif /* CONFIG_CONCURRENT_MODE */
{
if (remain_ch != rtw_get_oper_ch(adapter))
ready_on_channel = _TRUE;
}
if (ready_on_channel == _TRUE) {
#ifndef RTW_SINGLE_WIPHY
if (!check_fwstate(&adapter->mlmepriv, _FW_LINKED))
#endif
{
#ifdef CONFIG_CONCURRENT_MODE
if (rtw_get_oper_ch(adapter) != remain_ch)
#endif
{
/* if (!padapter->mlmepriv.LinkDetectInfo.bBusyTraffic) */
set_channel_bwmode(adapter, remain_ch, HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20);
}
}
}
#ifdef CONFIG_BT_COEXIST
rtw_btcoex_ScanNotify(adapter, _TRUE);
#endif
RTW_INFO("%s, set ro ch timer, duration=%d\n", __func__, duration);
_set_timer(&pcfg80211_wdinfo->remain_on_ch_timer, duration);
exit:
_exit_critical_mutex(&pwdev_priv->roch_mutex, NULL);
return ret;
}
static int cancel_ro_ch_handler(_adapter *padapter, u8 *buf)
{
int ret = H2C_SUCCESS;
struct p2p_roch_parm *roch_parm = (struct p2p_roch_parm *)buf;
struct rtw_wdev_priv *pwdev_priv = adapter_wdev_data(padapter);
struct cfg80211_wifidirect_info *pcfg80211_wdinfo = &padapter->cfg80211_wdinfo;
struct wireless_dev *wdev;
struct wifidirect_info *pwdinfo = &padapter->wdinfo;
u8 ch, bw, offset;
_enter_critical_mutex(&pwdev_priv->roch_mutex, NULL);
if (rtw_cfg80211_get_is_roch(padapter) != _TRUE)
goto exit;
if (roch_parm->wdev && roch_parm->cookie) {
if (pcfg80211_wdinfo->ro_ch_wdev != roch_parm->wdev) {
RTW_WARN(FUNC_ADPT_FMT" ongoing wdev:%p, wdev:%p\n"
, FUNC_ADPT_ARG(padapter), pcfg80211_wdinfo->ro_ch_wdev, roch_parm->wdev);
rtw_warn_on(1);
}
if (pcfg80211_wdinfo->remain_on_ch_cookie != roch_parm->cookie) {
RTW_WARN(FUNC_ADPT_FMT" ongoing cookie:0x%llx, cookie:0x%llx\n"
, FUNC_ADPT_ARG(padapter), pcfg80211_wdinfo->remain_on_ch_cookie, roch_parm->cookie);
rtw_warn_on(1);
}
}
#if defined(RTW_ROCH_BACK_OP) && defined(CONFIG_CONCURRENT_MODE)
_cancel_timer_ex(&pwdinfo->ap_p2p_switch_timer);
ATOMIC_SET(&pwdev_priv->switch_ch_to, 1);
#endif
if (rtw_mi_get_ch_setting_union(padapter, &ch, &bw, &offset) != 0) {
if (0)
RTW_INFO(FUNC_ADPT_FMT" back to linked/linking union - ch:%u, bw:%u, offset:%u\n",
FUNC_ADPT_ARG(padapter), ch, bw, offset);
} else if (adapter_wdev_data(padapter)->p2p_enabled && pwdinfo->listen_channel) {
ch = pwdinfo->listen_channel;
bw = CHANNEL_WIDTH_20;
offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
if (0)
RTW_INFO(FUNC_ADPT_FMT" back to listen ch - ch:%u, bw:%u, offset:%u\n",
FUNC_ADPT_ARG(padapter), ch, bw, offset);
} else {
ch = pcfg80211_wdinfo->restore_channel;
bw = CHANNEL_WIDTH_20;
offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
if (0)
RTW_INFO(FUNC_ADPT_FMT" back to restore ch - ch:%u, bw:%u, offset:%u\n",
FUNC_ADPT_ARG(padapter), ch, bw, offset);
}
set_channel_bwmode(padapter, ch, offset, bw);
rtw_back_opch(padapter);
rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo));
#ifdef CONFIG_DEBUG_CFG80211
RTW_INFO("%s, role=%d, p2p_state=%d\n", __func__, rtw_p2p_role(pwdinfo), rtw_p2p_state(pwdinfo));
#endif
wdev = pcfg80211_wdinfo->ro_ch_wdev;
rtw_cfg80211_set_is_roch(padapter, _FALSE);
pcfg80211_wdinfo->ro_ch_wdev = NULL;
rtw_cfg80211_set_last_ro_ch_time(padapter);
rtw_cfg80211_remain_on_channel_expired(wdev
, pcfg80211_wdinfo->remain_on_ch_cookie
, &pcfg80211_wdinfo->remain_on_ch_channel
, pcfg80211_wdinfo->remain_on_ch_type, GFP_KERNEL);
RTW_INFO("cfg80211_remain_on_channel_expired cookie:0x%llx\n"
, pcfg80211_wdinfo->remain_on_ch_cookie);
#ifdef CONFIG_BT_COEXIST
rtw_btcoex_ScanNotify(padapter, _FALSE);
#endif
exit:
_exit_critical_mutex(&pwdev_priv->roch_mutex, NULL);
return ret;
}
static void ro_ch_timer_process(void *FunctionContext)
{
_adapter *adapter = (_adapter *)FunctionContext;
p2p_cancel_roch_cmd(adapter, 0, NULL, 0);
}
#if 0
static void rtw_change_p2pie_op_ch(_adapter *padapter, const u8 *frame_body, u32 len, u8 ch)
{
u8 *ies, *p2p_ie;
u32 ies_len, p2p_ielen;
#ifdef CONFIG_MCC_MODE
if (MCC_EN(padapter))
return;
#endif /* CONFIG_MCC_MODE */
ies = (u8 *)(frame_body + _PUBLIC_ACTION_IE_OFFSET_);
ies_len = len - _PUBLIC_ACTION_IE_OFFSET_;
p2p_ie = rtw_get_p2p_ie(ies, ies_len, NULL, &p2p_ielen);
while (p2p_ie) {
u32 attr_contentlen = 0;
u8 *pattr = NULL;
/* Check P2P_ATTR_OPERATING_CH */
attr_contentlen = 0;
pattr = NULL;
pattr = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, NULL, (uint *)&attr_contentlen);
if (pattr != NULL)
*(pattr + 4) = ch;
/* Get the next P2P IE */
p2p_ie = rtw_get_p2p_ie(p2p_ie + p2p_ielen, ies_len - (p2p_ie - ies + p2p_ielen), NULL, &p2p_ielen);
}
}
#endif
#if defined(CONFIG_CONCURRENT_MODE) && defined(CONFIG_CFG80211_ONECHANNEL_UNDER_CONCURRENT)
static void rtw_change_p2pie_ch_list(_adapter *padapter, const u8 *frame_body, u32 len, u8 ch)
{
u8 *ies, *p2p_ie;
u32 ies_len, p2p_ielen;
#ifdef CONFIG_MCC_MODE
if (MCC_EN(padapter))
return;
#endif /* CONFIG_MCC_MODE */
ies = (u8 *)(frame_body + _PUBLIC_ACTION_IE_OFFSET_);
ies_len = len - _PUBLIC_ACTION_IE_OFFSET_;
p2p_ie = rtw_get_p2p_ie(ies, ies_len, NULL, &p2p_ielen);
while (p2p_ie) {
u32 attr_contentlen = 0;
u8 *pattr = NULL;
/* Check P2P_ATTR_CH_LIST */
pattr = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_CH_LIST, NULL, (uint *)&attr_contentlen);
if (pattr != NULL) {
int i;
u32 num_of_ch;
u8 *pattr_temp = pattr + 3 ;
attr_contentlen -= 3;
while (attr_contentlen > 0) {
num_of_ch = *(pattr_temp + 1);
for (i = 0; i < num_of_ch; i++)
*(pattr_temp + 2 + i) = ch;
pattr_temp += (2 + num_of_ch);
attr_contentlen -= (2 + num_of_ch);
}
}
/* Get the next P2P IE */
p2p_ie = rtw_get_p2p_ie(p2p_ie + p2p_ielen, ies_len - (p2p_ie - ies + p2p_ielen), NULL, &p2p_ielen);
}
}
#endif
#if defined(CONFIG_CONCURRENT_MODE) && defined(CONFIG_CFG80211_ONECHANNEL_UNDER_CONCURRENT)
static bool rtw_chk_p2pie_ch_list_with_buddy(_adapter *padapter, const u8 *frame_body, u32 len)
{
bool fit = _FALSE;
u8 *ies, *p2p_ie;
u32 ies_len, p2p_ielen;
u8 union_ch = rtw_mi_get_union_chan(padapter);
ies = (u8 *)(frame_body + _PUBLIC_ACTION_IE_OFFSET_);
ies_len = len - _PUBLIC_ACTION_IE_OFFSET_;
p2p_ie = rtw_get_p2p_ie(ies, ies_len, NULL, &p2p_ielen);
while (p2p_ie) {
u32 attr_contentlen = 0;
u8 *pattr = NULL;
/* Check P2P_ATTR_CH_LIST */
pattr = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_CH_LIST, NULL, (uint *)&attr_contentlen);
if (pattr != NULL) {
int i;
u32 num_of_ch;
u8 *pattr_temp = pattr + 3 ;
attr_contentlen -= 3;
while (attr_contentlen > 0) {
num_of_ch = *(pattr_temp + 1);
for (i = 0; i < num_of_ch; i++) {
if (*(pattr_temp + 2 + i) == union_ch) {
RTW_INFO(FUNC_ADPT_FMT" ch_list fit buddy_ch:%u\n", FUNC_ADPT_ARG(padapter), union_ch);
fit = _TRUE;
break;
}
}
pattr_temp += (2 + num_of_ch);
attr_contentlen -= (2 + num_of_ch);
}
}
/* Get the next P2P IE */
p2p_ie = rtw_get_p2p_ie(p2p_ie + p2p_ielen, ies_len - (p2p_ie - ies + p2p_ielen), NULL, &p2p_ielen);
}
return fit;
}
#if defined(CONFIG_P2P_INVITE_IOT)
static bool rtw_chk_p2pie_op_ch_with_buddy(_adapter *padapter, const u8 *frame_body, u32 len)
{
bool fit = _FALSE;
u8 *ies, *p2p_ie;
u32 ies_len, p2p_ielen;
u8 union_ch = rtw_mi_get_union_chan(padapter);
ies = (u8 *)(frame_body + _PUBLIC_ACTION_IE_OFFSET_);
ies_len = len - _PUBLIC_ACTION_IE_OFFSET_;
p2p_ie = rtw_get_p2p_ie(ies, ies_len, NULL, &p2p_ielen);
while (p2p_ie) {
u32 attr_contentlen = 0;
u8 *pattr = NULL;
/* Check P2P_ATTR_OPERATING_CH */
attr_contentlen = 0;
pattr = NULL;
pattr = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, NULL, (uint *)&attr_contentlen);
if (pattr != NULL) {
if (*(pattr + 4) == union_ch) {
RTW_INFO(FUNC_ADPT_FMT" op_ch fit buddy_ch:%u\n", FUNC_ADPT_ARG(padapter), union_ch);
fit = _TRUE;
break;
}
}
/* Get the next P2P IE */
p2p_ie = rtw_get_p2p_ie(p2p_ie + p2p_ielen, ies_len - (p2p_ie - ies + p2p_ielen), NULL, &p2p_ielen);
}
return fit;
}
#endif
static void rtw_cfg80211_adjust_p2pie_channel(_adapter *padapter, const u8 *frame_body, u32 len)
{
u8 *ies, *p2p_ie;
u32 ies_len, p2p_ielen;
u8 union_ch = rtw_mi_get_union_chan(padapter);
#ifdef CONFIG_MCC_MODE
if (MCC_EN(padapter))
return;
#endif /* CONFIG_MCC_MODE */
ies = (u8 *)(frame_body + _PUBLIC_ACTION_IE_OFFSET_);
ies_len = len - _PUBLIC_ACTION_IE_OFFSET_;
p2p_ie = rtw_get_p2p_ie(ies, ies_len, NULL, &p2p_ielen);
while (p2p_ie) {
u32 attr_contentlen = 0;
u8 *pattr = NULL;
/* Check P2P_ATTR_CH_LIST */
pattr = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_CH_LIST, NULL, (uint *)&attr_contentlen);
if (pattr != NULL) {
int i;
u32 num_of_ch;
u8 *pattr_temp = pattr + 3 ;
attr_contentlen -= 3;
while (attr_contentlen > 0) {
num_of_ch = *(pattr_temp + 1);
for (i = 0; i < num_of_ch; i++) {
if (*(pattr_temp + 2 + i) && *(pattr_temp + 2 + i) != union_ch) {
#ifdef RTW_SINGLE_WIPHY
RTW_ERR("replace ch_list:%u with:%u\n", *(pattr_temp + 2 + i), union_ch);
#endif
*(pattr_temp + 2 + i) = union_ch; /*forcing to the same channel*/
}
}
pattr_temp += (2 + num_of_ch);
attr_contentlen -= (2 + num_of_ch);
}
}
/* Check P2P_ATTR_OPERATING_CH */
attr_contentlen = 0;
pattr = NULL;
pattr = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, NULL, (uint *)&attr_contentlen);
if (pattr != NULL) {
if (*(pattr + 4) && *(pattr + 4) != union_ch) {
#ifdef RTW_SINGLE_WIPHY
RTW_ERR("replace op_ch:%u with:%u\n", *(pattr + 4), union_ch);
#endif
*(pattr + 4) = union_ch; /*forcing to the same channel */
}
}
/* Get the next P2P IE */
p2p_ie = rtw_get_p2p_ie(p2p_ie + p2p_ielen, ies_len - (p2p_ie - ies + p2p_ielen), NULL, &p2p_ielen);
}
}
#endif
#ifdef CONFIG_WFD
u32 rtw_xframe_build_wfd_ie(struct xmit_frame *xframe)
{
_adapter *adapter = xframe->padapter;
struct wifidirect_info *wdinfo = &adapter->wdinfo;
u8 *frame = xframe->buf_addr + TXDESC_OFFSET;
u8 *frame_body = frame + sizeof(struct rtw_ieee80211_hdr_3addr);
u8 *frame_tail = frame + xframe->attrib.pktlen;
u8 category, action, OUI_Subtype, dialogToken = 0;
u32 wfdielen = 0;
category = frame_body[0];
if (category == RTW_WLAN_CATEGORY_PUBLIC) {
action = frame_body[1];
if (action == ACT_PUBLIC_VENDOR
&& _rtw_memcmp(frame_body + 2, P2P_OUI, 4) == _TRUE
) {
OUI_Subtype = frame_body[6];
dialogToken = frame_body[7];
switch (OUI_Subtype) {
case P2P_GO_NEGO_REQ:
wfdielen = build_nego_req_wfd_ie(wdinfo, frame_tail);
break;
case P2P_GO_NEGO_RESP:
wfdielen = build_nego_resp_wfd_ie(wdinfo, frame_tail);
break;
case P2P_GO_NEGO_CONF:
wfdielen = build_nego_confirm_wfd_ie(wdinfo, frame_tail);
break;
case P2P_INVIT_REQ:
wfdielen = build_invitation_req_wfd_ie(wdinfo, frame_tail);
break;
case P2P_INVIT_RESP:
wfdielen = build_invitation_resp_wfd_ie(wdinfo, frame_tail);
break;
case P2P_PROVISION_DISC_REQ:
wfdielen = build_provdisc_req_wfd_ie(wdinfo, frame_tail);
break;
case P2P_PROVISION_DISC_RESP:
wfdielen = build_provdisc_resp_wfd_ie(wdinfo, frame_tail);
break;
case P2P_DEVDISC_REQ:
case P2P_DEVDISC_RESP:
default:
break;
}
}
} else if (category == RTW_WLAN_CATEGORY_P2P) {
OUI_Subtype = frame_body[5];
dialogToken = frame_body[6];
#ifdef CONFIG_DEBUG_CFG80211
RTW_INFO("ACTION_CATEGORY_P2P: OUI=0x%x, OUI_Subtype=%d, dialogToken=%d\n"
, cpu_to_be32(*((u32 *)(frame_body + 1))), OUI_Subtype, dialogToken);
#endif
switch (OUI_Subtype) {
case P2P_NOTICE_OF_ABSENCE:
break;
case P2P_PRESENCE_REQUEST:
break;
case P2P_PRESENCE_RESPONSE:
break;
case P2P_GO_DISC_REQUEST:
break;
default:
break;
}
} else
RTW_INFO("%s, action frame category=%d\n", __func__, category);
xframe->attrib.pktlen += wfdielen;
return wfdielen;
}
#endif /* CONFIG_WFD */
bool rtw_xframe_del_wfd_ie(struct xmit_frame *xframe)
{
#define DBG_XFRAME_DEL_WFD_IE 0
u8 *frame = xframe->buf_addr + TXDESC_OFFSET;
u8 *frame_body = frame + sizeof(struct rtw_ieee80211_hdr_3addr);
u8 *frame_tail = frame + xframe->attrib.pktlen;
u8 category, action, OUI_Subtype;
u8 *ies = NULL;
uint ies_len_ori = 0;
uint ies_len = 0;
category = frame_body[0];
if (category == RTW_WLAN_CATEGORY_PUBLIC) {
action = frame_body[1];
if (action == ACT_PUBLIC_VENDOR
&& _rtw_memcmp(frame_body + 2, P2P_OUI, 4) == _TRUE
) {
OUI_Subtype = frame_body[6];
switch (OUI_Subtype) {
case P2P_GO_NEGO_REQ:
case P2P_GO_NEGO_RESP:
case P2P_GO_NEGO_CONF:
case P2P_INVIT_REQ:
case P2P_INVIT_RESP:
case P2P_PROVISION_DISC_REQ:
case P2P_PROVISION_DISC_RESP:
ies = frame_body + 8;
ies_len_ori = frame_tail - (frame_body + 8);
break;
}
}
}
if (ies && ies_len_ori) {
ies_len = rtw_del_wfd_ie(ies, ies_len_ori, DBG_XFRAME_DEL_WFD_IE ? __func__ : NULL);
xframe->attrib.pktlen -= (ies_len_ori - ies_len);
}
return ies_len_ori != ies_len;
}
/*
* rtw_xframe_chk_wfd_ie -
*
*/
void rtw_xframe_chk_wfd_ie(struct xmit_frame *xframe)
{
_adapter *adapter = xframe->padapter;
#ifdef CONFIG_IOCTL_CFG80211
struct wifidirect_info *wdinfo = &adapter->wdinfo;
#endif
u8 build = 0;
u8 del = 0;
if (!hal_chk_wl_func(adapter, WL_FUNC_MIRACAST))
del = 1;
#ifdef CONFIG_IOCTL_CFG80211
if (wdinfo->wfd_info->wfd_enable == _TRUE)
#endif
del = build = 1;
if (del)
rtw_xframe_del_wfd_ie(xframe);
#ifdef CONFIG_WFD
if (build)
rtw_xframe_build_wfd_ie(xframe);
#endif
}
u8 *dump_p2p_attr_ch_list(u8 *p2p_ie, uint p2p_ielen, u8 *buf, u32 buf_len)
{
uint attr_contentlen = 0;
u8 *pattr = NULL;
int w_sz = 0;
u8 ch_cnt = 0;
u8 ch_list[40];
pattr = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_CH_LIST, NULL, &attr_contentlen);
if (pattr != NULL) {
int i, j;
u32 num_of_ch;
u8 *pattr_temp = pattr + 3 ;
attr_contentlen -= 3;
_rtw_memset(ch_list, 0, 40);
while (attr_contentlen > 0) {
num_of_ch = *(pattr_temp + 1);
for (i = 0; i < num_of_ch; i++) {
for (j = 0; j < ch_cnt; j++) {
if (ch_list[j] == *(pattr_temp + 2 + i))
break;
}
if (j >= ch_cnt)
ch_list[ch_cnt++] = *(pattr_temp + 2 + i);
}
pattr_temp += (2 + num_of_ch);
attr_contentlen -= (2 + num_of_ch);
}
for (j = 0; j < ch_cnt; j++) {
if (j == 0)
w_sz += snprintf(buf + w_sz, buf_len - w_sz, "%u", ch_list[j]);
else if (ch_list[j] - ch_list[j - 1] != 1)
w_sz += snprintf(buf + w_sz, buf_len - w_sz, ", %u", ch_list[j]);
else if (j != ch_cnt - 1 && ch_list[j + 1] - ch_list[j] == 1) {
/* empty */
} else
w_sz += snprintf(buf + w_sz, buf_len - w_sz, "-%u", ch_list[j]);
}
}
return buf;
}
/*
* return _TRUE if requester is GO, _FALSE if responder is GO
*/
bool rtw_p2p_nego_intent_compare(u8 req, u8 resp)
{
if (req >> 1 == resp >> 1)
return req & 0x01 ? _TRUE : _FALSE;
else if (req >> 1 > resp >> 1)
return _TRUE;
else
return _FALSE;
}
int rtw_p2p_check_frames(_adapter *padapter, const u8 *buf, u32 len, u8 tx)
{
int is_p2p_frame = (-1);
unsigned char *frame_body;
u8 category, action, OUI_Subtype, dialogToken = 0;
u8 *p2p_ie = NULL;
uint p2p_ielen = 0;
struct rtw_wdev_priv *pwdev_priv = adapter_wdev_data(padapter);
int status = -1;
u8 ch_list_buf[128] = {'\0'};
int op_ch = -1;
int listen_ch = -1;
u8 intent = 0;
u8 *iaddr = NULL;
u8 *gbssid = NULL;
frame_body = (unsigned char *)(buf + sizeof(struct rtw_ieee80211_hdr_3addr));
category = frame_body[0];
/* just for check */
if (category == RTW_WLAN_CATEGORY_PUBLIC) {
action = frame_body[1];
if (action == ACT_PUBLIC_VENDOR
&& _rtw_memcmp(frame_body + 2, P2P_OUI, 4) == _TRUE
) {
OUI_Subtype = frame_body[6];
dialogToken = frame_body[7];
is_p2p_frame = OUI_Subtype;
#ifdef CONFIG_DEBUG_CFG80211
RTW_INFO("ACTION_CATEGORY_PUBLIC: ACT_PUBLIC_VENDOR, OUI=0x%x, OUI_Subtype=%d, dialogToken=%d\n",
cpu_to_be32(*((u32 *)(frame_body + 2))), OUI_Subtype, dialogToken);
#endif
p2p_ie = rtw_get_p2p_ie(
(u8 *)buf + sizeof(struct rtw_ieee80211_hdr_3addr) + _PUBLIC_ACTION_IE_OFFSET_
, len - sizeof(struct rtw_ieee80211_hdr_3addr) - _PUBLIC_ACTION_IE_OFFSET_
, NULL, &p2p_ielen);
switch (OUI_Subtype) { /* OUI Subtype */
u8 *cont;
uint cont_len;
case P2P_GO_NEGO_REQ: {
struct rtw_wdev_nego_info *nego_info = &pwdev_priv->nego_info;
if (tx) {
#ifdef CONFIG_DRV_ISSUE_PROV_REQ /* IOT FOR S2 */
if (pwdev_priv->provdisc_req_issued == _FALSE)
rtw_cfg80211_issue_p2p_provision_request(padapter, buf, len);
#endif /* CONFIG_DRV_ISSUE_PROV_REQ */
/* pwdev_priv->provdisc_req_issued = _FALSE; */
#if defined(CONFIG_CONCURRENT_MODE) && defined(CONFIG_CFG80211_ONECHANNEL_UNDER_CONCURRENT)
if (rtw_mi_check_status(padapter, MI_LINKED) && padapter->registrypriv.full_ch_in_p2p_handshake == 0)
rtw_cfg80211_adjust_p2pie_channel(padapter, frame_body, len - sizeof(struct rtw_ieee80211_hdr_3addr));
#endif
}
cont = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, NULL, &cont_len);
if (cont)
op_ch = *(cont + 4);
cont = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_LISTEN_CH, NULL, &cont_len);
if (cont)
listen_ch = *(cont + 4);
cont = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GO_INTENT, NULL, &cont_len);
if (cont)
intent = *cont;
cont = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_INTENDED_IF_ADDR, NULL, &cont_len);
if (cont && cont_len == 6)
iaddr = cont;
if (nego_info->token != dialogToken)
rtw_wdev_nego_info_init(nego_info);
_rtw_memcpy(nego_info->peer_mac, tx ? GetAddr1Ptr(buf) : get_addr2_ptr(buf), ETH_ALEN);
if (iaddr)
_rtw_memcpy(tx ? nego_info->iface_addr : nego_info->peer_iface_addr, iaddr, ETH_ALEN);
nego_info->active = tx ? 1 : 0;
nego_info->token = dialogToken;
nego_info->req_op_ch = op_ch;
nego_info->req_listen_ch = listen_ch;
nego_info->req_intent = intent;
nego_info->state = 0;
dump_p2p_attr_ch_list(p2p_ie, p2p_ielen, ch_list_buf, 128);
RTW_INFO("RTW_%s:P2P_GO_NEGO_REQ, dialogToken=%d, intent:%u%s, listen_ch:%d, op_ch:%d, ch_list:%s"
, (tx == _TRUE) ? "Tx" : "Rx" , dialogToken , (intent >> 1) , intent & 0x1 ? "+" : "-" , listen_ch , op_ch , ch_list_buf);
if (iaddr)
_RTW_INFO(", iaddr:"MAC_FMT, MAC_ARG(iaddr));
_RTW_INFO("\n");
if (!tx) {
#if defined(CONFIG_CONCURRENT_MODE) && defined(CONFIG_CFG80211_ONECHANNEL_UNDER_CONCURRENT)
if (rtw_mi_check_status(padapter, MI_LINKED)
&& rtw_chk_p2pie_ch_list_with_buddy(padapter, frame_body, len - sizeof(struct rtw_ieee80211_hdr_3addr)) == _FALSE
&& padapter->registrypriv.full_ch_in_p2p_handshake == 0) {
RTW_INFO(FUNC_ADPT_FMT" ch_list has no intersect with buddy\n", FUNC_ADPT_ARG(padapter));
rtw_change_p2pie_ch_list(padapter, frame_body, len - sizeof(struct rtw_ieee80211_hdr_3addr), 0);
}
#endif
}
break;
}
case P2P_GO_NEGO_RESP: {
struct rtw_wdev_nego_info *nego_info = &pwdev_priv->nego_info;
if (tx) {
#if defined(CONFIG_CONCURRENT_MODE) && defined(CONFIG_CFG80211_ONECHANNEL_UNDER_CONCURRENT)
if (rtw_mi_check_status(padapter, MI_LINKED) && padapter->registrypriv.full_ch_in_p2p_handshake == 0)
rtw_cfg80211_adjust_p2pie_channel(padapter, frame_body, len - sizeof(struct rtw_ieee80211_hdr_3addr));
#endif
}
cont = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, NULL, &cont_len);
if (cont)
op_ch = *(cont + 4);
cont = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GO_INTENT, NULL, &cont_len);
if (cont)
intent = *cont;
cont = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, NULL, &cont_len);
if (cont)
status = *cont;
cont = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_INTENDED_IF_ADDR, NULL, &cont_len);
if (cont && cont_len == 6)
iaddr = cont;
if (nego_info->token == dialogToken && nego_info->state == 0
&& _rtw_memcmp(nego_info->peer_mac, tx ? GetAddr1Ptr(buf) : get_addr2_ptr(buf), ETH_ALEN) == _TRUE
) {
if (iaddr)
_rtw_memcpy(tx ? nego_info->iface_addr : nego_info->peer_iface_addr, iaddr, ETH_ALEN);
nego_info->status = (status == -1) ? 0xff : status;
nego_info->rsp_op_ch = op_ch;
nego_info->rsp_intent = intent;
nego_info->state = 1;
if (status != 0)
nego_info->token = 0; /* init */
}
dump_p2p_attr_ch_list(p2p_ie, p2p_ielen, ch_list_buf, 128);
RTW_INFO("RTW_%s:P2P_GO_NEGO_RESP, dialogToken=%d, intent:%u%s, status:%d, op_ch:%d, ch_list:%s"
, (tx == _TRUE) ? "Tx" : "Rx", dialogToken, (intent >> 1), intent & 0x1 ? "+" : "-", status, op_ch, ch_list_buf);
if (iaddr)
_RTW_INFO(", iaddr:"MAC_FMT, MAC_ARG(iaddr));
_RTW_INFO("\n");
if (!tx) {
pwdev_priv->provdisc_req_issued = _FALSE;
#if defined(CONFIG_CONCURRENT_MODE) && defined(CONFIG_CFG80211_ONECHANNEL_UNDER_CONCURRENT)
if (rtw_mi_check_status(padapter, MI_LINKED)
&& rtw_chk_p2pie_ch_list_with_buddy(padapter, frame_body, len - sizeof(struct rtw_ieee80211_hdr_3addr)) == _FALSE
&& padapter->registrypriv.full_ch_in_p2p_handshake == 0) {
RTW_INFO(FUNC_ADPT_FMT" ch_list has no intersect with buddy\n", FUNC_ADPT_ARG(padapter));
rtw_change_p2pie_ch_list(padapter, frame_body, len - sizeof(struct rtw_ieee80211_hdr_3addr), 0);
}
#endif
}
break;
}
case P2P_GO_NEGO_CONF: {
struct rtw_wdev_nego_info *nego_info = &pwdev_priv->nego_info;
bool is_go = _FALSE;
if (tx) {
#if defined(CONFIG_CONCURRENT_MODE) && defined(CONFIG_CFG80211_ONECHANNEL_UNDER_CONCURRENT)
if (rtw_mi_check_status(padapter, MI_LINKED) && padapter->registrypriv.full_ch_in_p2p_handshake == 0)
rtw_cfg80211_adjust_p2pie_channel(padapter, frame_body, len - sizeof(struct rtw_ieee80211_hdr_3addr));
#endif
}
cont = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, NULL, &cont_len);
if (cont)
op_ch = *(cont + 4);
cont = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, NULL, &cont_len);
if (cont)
status = *cont;
if (nego_info->token == dialogToken && nego_info->state == 1
&& _rtw_memcmp(nego_info->peer_mac, tx ? GetAddr1Ptr(buf) : get_addr2_ptr(buf), ETH_ALEN) == _TRUE
) {
nego_info->status = (status == -1) ? 0xff : status;
nego_info->conf_op_ch = (op_ch == -1) ? 0 : op_ch;
nego_info->state = 2;
if (status == 0) {
if (rtw_p2p_nego_intent_compare(nego_info->req_intent, nego_info->rsp_intent) ^ !tx)
is_go = _TRUE;
}
nego_info->token = 0; /* init */
}
dump_p2p_attr_ch_list(p2p_ie, p2p_ielen, ch_list_buf, 128);
RTW_INFO("RTW_%s:P2P_GO_NEGO_CONF, dialogToken=%d, status:%d, op_ch:%d, ch_list:%s\n"
, (tx == _TRUE) ? "Tx" : "Rx", dialogToken, status, op_ch, ch_list_buf);
if (!tx) {
}
break;
}
case P2P_INVIT_REQ: {
struct rtw_wdev_invit_info *invit_info = &pwdev_priv->invit_info;
int flags = -1;
if (tx) {
#if defined(CONFIG_CONCURRENT_MODE) && defined(CONFIG_CFG80211_ONECHANNEL_UNDER_CONCURRENT)
if (rtw_mi_check_status(padapter, MI_LINKED)
&& padapter->registrypriv.full_ch_in_p2p_handshake == 0)
rtw_cfg80211_adjust_p2pie_channel(padapter, frame_body, len - sizeof(struct rtw_ieee80211_hdr_3addr));
#endif
}
cont = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_INVITATION_FLAGS, NULL, &cont_len);
if (cont)
flags = *cont;
cont = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, NULL, &cont_len);
if (cont)
op_ch = *(cont + 4);
cont = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_BSSID, NULL, &cont_len);
if (cont && cont_len == 6)
gbssid = cont;
if (invit_info->token != dialogToken)
rtw_wdev_invit_info_init(invit_info);
_rtw_memcpy(invit_info->peer_mac, tx ? GetAddr1Ptr(buf) : get_addr2_ptr(buf), ETH_ALEN);
if (gbssid)
_rtw_memcpy(invit_info->group_bssid, gbssid, ETH_ALEN);
invit_info->active = tx ? 1 : 0;
invit_info->token = dialogToken;
invit_info->flags = (flags == -1) ? 0x0 : flags;
invit_info->req_op_ch = op_ch;
invit_info->state = 0;
dump_p2p_attr_ch_list(p2p_ie, p2p_ielen, ch_list_buf, 128);
RTW_INFO("RTW_%s:P2P_INVIT_REQ, dialogToken=%d, flags:0x%02x, op_ch:%d, ch_list:%s"
, (tx == _TRUE) ? "Tx" : "Rx", dialogToken, flags, op_ch, ch_list_buf);
if (gbssid)
_RTW_INFO(", gbssid:"MAC_FMT, MAC_ARG(gbssid));
_RTW_INFO("\n");
if (!tx) {
#if defined(CONFIG_CONCURRENT_MODE) && defined(CONFIG_CFG80211_ONECHANNEL_UNDER_CONCURRENT)
if (rtw_mi_check_status(padapter, MI_LINKED) && padapter->registrypriv.full_ch_in_p2p_handshake == 0) {
#if defined(CONFIG_P2P_INVITE_IOT)
if (op_ch != -1 && rtw_chk_p2pie_op_ch_with_buddy(padapter, frame_body, len - sizeof(struct rtw_ieee80211_hdr_3addr)) == _FALSE) {
RTW_INFO(FUNC_ADPT_FMT" op_ch:%u has no intersect with buddy\n", FUNC_ADPT_ARG(padapter), op_ch);
rtw_change_p2pie_ch_list(padapter, frame_body, len - sizeof(struct rtw_ieee80211_hdr_3addr), 0);
} else
#endif
if (rtw_chk_p2pie_ch_list_with_buddy(padapter, frame_body, len - sizeof(struct rtw_ieee80211_hdr_3addr)) == _FALSE) {
RTW_INFO(FUNC_ADPT_FMT" ch_list has no intersect with buddy\n", FUNC_ADPT_ARG(padapter));
rtw_change_p2pie_ch_list(padapter, frame_body, len - sizeof(struct rtw_ieee80211_hdr_3addr), 0);
}
}
#endif
}
break;
}
case P2P_INVIT_RESP: {
struct rtw_wdev_invit_info *invit_info = &pwdev_priv->invit_info;
if (tx) {
#if defined(CONFIG_CONCURRENT_MODE) && defined(CONFIG_CFG80211_ONECHANNEL_UNDER_CONCURRENT)
if (rtw_mi_check_status(padapter, MI_LINKED) && padapter->registrypriv.full_ch_in_p2p_handshake == 0)
rtw_cfg80211_adjust_p2pie_channel(padapter, frame_body, len - sizeof(struct rtw_ieee80211_hdr_3addr));
#endif
}
cont = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, NULL, &cont_len);
if (cont) {
#ifdef CONFIG_P2P_INVITE_IOT
if (tx && *cont == 7) {
RTW_INFO("TX_P2P_INVITE_RESP, status is no common channel, change to unknown group\n");
*cont = 8; /* unknow group status */
}
#endif /* CONFIG_P2P_INVITE_IOT */
status = *cont;
}
cont = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, NULL, &cont_len);
if (cont)
op_ch = *(cont + 4);
cont = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_BSSID, NULL, &cont_len);
if (cont && cont_len == 6)
gbssid = cont;
if (invit_info->token == dialogToken && invit_info->state == 0
&& _rtw_memcmp(invit_info->peer_mac, tx ? GetAddr1Ptr(buf) : get_addr2_ptr(buf), ETH_ALEN) == _TRUE
) {
invit_info->status = (status == -1) ? 0xff : status;
invit_info->rsp_op_ch = op_ch;
invit_info->state = 1;
invit_info->token = 0; /* init */
}
dump_p2p_attr_ch_list(p2p_ie, p2p_ielen, ch_list_buf, 128);
RTW_INFO("RTW_%s:P2P_INVIT_RESP, dialogToken=%d, status:%d, op_ch:%d, ch_list:%s"
, (tx == _TRUE) ? "Tx" : "Rx", dialogToken, status, op_ch, ch_list_buf);
if (gbssid)
_RTW_INFO(", gbssid:"MAC_FMT, MAC_ARG(gbssid));
_RTW_INFO("\n");
if (!tx) {
}
break;
}
case P2P_DEVDISC_REQ:
RTW_INFO("RTW_%s:P2P_DEVDISC_REQ, dialogToken=%d\n", (tx == _TRUE) ? "Tx" : "Rx", dialogToken);
break;
case P2P_DEVDISC_RESP:
cont = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, NULL, &cont_len);
RTW_INFO("RTW_%s:P2P_DEVDISC_RESP, dialogToken=%d, status:%d\n", (tx == _TRUE) ? "Tx" : "Rx", dialogToken, cont ? *cont : -1);
break;
case P2P_PROVISION_DISC_REQ: {
size_t frame_body_len = len - sizeof(struct rtw_ieee80211_hdr_3addr);
u8 *p2p_ie;
uint p2p_ielen = 0;
uint contentlen = 0;
RTW_INFO("RTW_%s:P2P_PROVISION_DISC_REQ, dialogToken=%d\n", (tx == _TRUE) ? "Tx" : "Rx", dialogToken);
/* if(tx) */
{
pwdev_priv->provdisc_req_issued = _FALSE;
p2p_ie = rtw_get_p2p_ie(frame_body + _PUBLIC_ACTION_IE_OFFSET_, frame_body_len - _PUBLIC_ACTION_IE_OFFSET_, NULL, &p2p_ielen);
if (p2p_ie) {
if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, NULL, &contentlen)) {
pwdev_priv->provdisc_req_issued = _FALSE;/* case: p2p_client join p2p GO */
} else {
#ifdef CONFIG_DEBUG_CFG80211
RTW_INFO("provdisc_req_issued is _TRUE\n");
#endif /*CONFIG_DEBUG_CFG80211*/
pwdev_priv->provdisc_req_issued = _TRUE;/* case: p2p_devices connection before Nego req. */
}
}
}
}
break;
case P2P_PROVISION_DISC_RESP:
RTW_INFO("RTW_%s:P2P_PROVISION_DISC_RESP, dialogToken=%d\n", (tx == _TRUE) ? "Tx" : "Rx", dialogToken);
break;
default:
RTW_INFO("RTW_%s:OUI_Subtype=%d, dialogToken=%d\n", (tx == _TRUE) ? "Tx" : "Rx", OUI_Subtype, dialogToken);
break;
}
}
} else if (category == RTW_WLAN_CATEGORY_P2P) {
OUI_Subtype = frame_body[5];
dialogToken = frame_body[6];
#ifdef CONFIG_DEBUG_CFG80211
RTW_INFO("ACTION_CATEGORY_P2P: OUI=0x%x, OUI_Subtype=%d, dialogToken=%d\n",
cpu_to_be32(*((u32 *)(frame_body + 1))), OUI_Subtype, dialogToken);
#endif
is_p2p_frame = OUI_Subtype;
switch (OUI_Subtype) {
case P2P_NOTICE_OF_ABSENCE:
RTW_INFO("RTW_%s:P2P_NOTICE_OF_ABSENCE, dialogToken=%d\n", (tx == _TRUE) ? "Tx" : "Rx", dialogToken);
break;
case P2P_PRESENCE_REQUEST:
RTW_INFO("RTW_%s:P2P_PRESENCE_REQUEST, dialogToken=%d\n", (tx == _TRUE) ? "Tx" : "Rx", dialogToken);
break;
case P2P_PRESENCE_RESPONSE:
RTW_INFO("RTW_%s:P2P_PRESENCE_RESPONSE, dialogToken=%d\n", (tx == _TRUE) ? "Tx" : "Rx", dialogToken);
break;
case P2P_GO_DISC_REQUEST:
RTW_INFO("RTW_%s:P2P_GO_DISC_REQUEST, dialogToken=%d\n", (tx == _TRUE) ? "Tx" : "Rx", dialogToken);
break;
default:
RTW_INFO("RTW_%s:OUI_Subtype=%d, dialogToken=%d\n", (tx == _TRUE) ? "Tx" : "Rx", OUI_Subtype, dialogToken);
break;
}
}
return is_p2p_frame;
}
void rtw_init_cfg80211_wifidirect_info(_adapter *padapter)
{
struct cfg80211_wifidirect_info *pcfg80211_wdinfo = &padapter->cfg80211_wdinfo;
_rtw_memset(pcfg80211_wdinfo, 0x00, sizeof(struct cfg80211_wifidirect_info));
rtw_init_timer(&pcfg80211_wdinfo->remain_on_ch_timer, padapter, ro_ch_timer_process, padapter);
}
#endif /* CONFIG_IOCTL_CFG80211 */
s32 p2p_protocol_wk_hdl(_adapter *padapter, int intCmdType, u8 *buf)
{
int ret = H2C_SUCCESS;
switch (intCmdType) {
case P2P_FIND_PHASE_WK:
find_phase_handler(padapter);
break;
case P2P_RESTORE_STATE_WK:
restore_p2p_state_handler(padapter);
break;
case P2P_PRE_TX_PROVDISC_PROCESS_WK:
#ifdef CONFIG_CONCURRENT_MODE
if (rtw_mi_check_status(padapter, MI_LINKED))
p2p_concurrent_handler(padapter);
else
pre_tx_provdisc_handler(padapter);
#else
pre_tx_provdisc_handler(padapter);
#endif
break;
case P2P_PRE_TX_INVITEREQ_PROCESS_WK:
#ifdef CONFIG_CONCURRENT_MODE
if (rtw_mi_check_status(padapter, MI_LINKED))
p2p_concurrent_handler(padapter);
else
pre_tx_invitereq_handler(padapter);
#else
pre_tx_invitereq_handler(padapter);
#endif
break;
case P2P_PRE_TX_NEGOREQ_PROCESS_WK:
#ifdef CONFIG_CONCURRENT_MODE
if (rtw_mi_check_status(padapter, MI_LINKED))
p2p_concurrent_handler(padapter);
else
pre_tx_negoreq_handler(padapter);
#else
pre_tx_negoreq_handler(padapter);
#endif
break;
#ifdef CONFIG_CONCURRENT_MODE
case P2P_AP_P2P_CH_SWITCH_PROCESS_WK:
p2p_concurrent_handler(padapter);
break;
#endif
#ifdef CONFIG_IOCTL_CFG80211
case P2P_RO_CH_WK:
ret = ro_ch_handler(padapter, buf);
break;
case P2P_CANCEL_RO_CH_WK:
ret = cancel_ro_ch_handler(padapter, buf);
break;
#endif
default:
rtw_warn_on(1);
break;
}
return ret;
}
int process_p2p_cross_connect_ie(PADAPTER padapter, u8 *IEs, u32 IELength)
{
int ret = _TRUE;
u8 *ies;
u32 ies_len;
u8 *p2p_ie;
u32 p2p_ielen = 0;
u8 p2p_attr[MAX_P2P_IE_LEN] = { 0x00 };/* NoA length should be n*(13) + 2 */
u32 attr_contentlen = 0;
if (IELength <= _BEACON_IE_OFFSET_)
return ret;
ies = IEs + _BEACON_IE_OFFSET_;
ies_len = IELength - _BEACON_IE_OFFSET_;
p2p_ie = rtw_get_p2p_ie(ies, ies_len, NULL, &p2p_ielen);
while (p2p_ie) {
/* Get P2P Manageability IE. */
if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_MANAGEABILITY, p2p_attr, &attr_contentlen)) {
if ((p2p_attr[0] & (BIT(0) | BIT(1))) == 0x01)
ret = _FALSE;
break;
}
/* Get the next P2P IE */
p2p_ie = rtw_get_p2p_ie(p2p_ie + p2p_ielen, ies_len - (p2p_ie - ies + p2p_ielen), NULL, &p2p_ielen);
}
return ret;
}
#ifdef CONFIG_P2P_PS
void process_p2p_ps_ie(PADAPTER padapter, u8 *IEs, u32 IELength)
{
u8 *ies;
u32 ies_len;
u8 *p2p_ie;
u32 p2p_ielen = 0;
u8 *noa_attr; /* NoA length should be n*(13) + 2 */
u32 attr_contentlen = 0;
struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
u8 find_p2p = _FALSE, find_p2p_ps = _FALSE;
u8 noa_offset, noa_num, noa_index;
if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
return;
#ifdef CONFIG_CONCURRENT_MODE
#ifndef CONFIG_FW_MULTI_PORT_SUPPORT
if (padapter->hw_port != HW_PORT0)
return;
#endif
#endif
if (IELength <= _BEACON_IE_OFFSET_)
return;
ies = IEs + _BEACON_IE_OFFSET_;
ies_len = IELength - _BEACON_IE_OFFSET_;
p2p_ie = rtw_get_p2p_ie(ies, ies_len, NULL, &p2p_ielen);
while (p2p_ie) {
find_p2p = _TRUE;
/* Get Notice of Absence IE. */
noa_attr = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_NOA, NULL, &attr_contentlen);
if (noa_attr) {
find_p2p_ps = _TRUE;
noa_index = noa_attr[0];
if ((pwdinfo->p2p_ps_mode == P2P_PS_NONE) ||
(noa_index != pwdinfo->noa_index)) { /* if index change, driver should reconfigure related setting. */
pwdinfo->noa_index = noa_index;
pwdinfo->opp_ps = noa_attr[1] >> 7;
pwdinfo->ctwindow = noa_attr[1] & 0x7F;
noa_offset = 2;
noa_num = 0;
/* NoA length should be n*(13) + 2 */
if (attr_contentlen > 2 && (attr_contentlen - 2) % 13 == 0) {
while (noa_offset < attr_contentlen && noa_num < P2P_MAX_NOA_NUM) {
/* _rtw_memcpy(&wifidirect_info->noa_count[noa_num], &noa_attr[noa_offset], 1); */
pwdinfo->noa_count[noa_num] = noa_attr[noa_offset];
noa_offset += 1;
_rtw_memcpy(&pwdinfo->noa_duration[noa_num], &noa_attr[noa_offset], 4);
noa_offset += 4;
_rtw_memcpy(&pwdinfo->noa_interval[noa_num], &noa_attr[noa_offset], 4);
noa_offset += 4;
_rtw_memcpy(&pwdinfo->noa_start_time[noa_num], &noa_attr[noa_offset], 4);
noa_offset += 4;
noa_num++;
}
}
pwdinfo->noa_num = noa_num;
if (pwdinfo->opp_ps == 1) {
pwdinfo->p2p_ps_mode = P2P_PS_CTWINDOW;
/* driver should wait LPS for entering CTWindow */
if (adapter_to_pwrctl(padapter)->bFwCurrentInPSMode == _TRUE)
p2p_ps_wk_cmd(padapter, P2P_PS_ENABLE, 1);
} else if (pwdinfo->noa_num > 0) {
pwdinfo->p2p_ps_mode = P2P_PS_NOA;
p2p_ps_wk_cmd(padapter, P2P_PS_ENABLE, 1);
} else if (pwdinfo->p2p_ps_mode > P2P_PS_NONE)
p2p_ps_wk_cmd(padapter, P2P_PS_DISABLE, 1);
}
break; /* find target, just break. */
}
/* Get the next P2P IE */
p2p_ie = rtw_get_p2p_ie(p2p_ie + p2p_ielen, ies_len - (p2p_ie - ies + p2p_ielen), NULL, &p2p_ielen);
}
if (find_p2p == _TRUE) {
if ((pwdinfo->p2p_ps_mode > P2P_PS_NONE) && (find_p2p_ps == _FALSE))
p2p_ps_wk_cmd(padapter, P2P_PS_DISABLE, 1);
}
}
void p2p_ps_wk_hdl(_adapter *padapter, u8 p2p_ps_state)
{
struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
u32 ps_deny = 0;
/* Pre action for p2p state */
switch (p2p_ps_state) {
case P2P_PS_DISABLE:
pwdinfo->p2p_ps_state = p2p_ps_state;
rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_P2P_PS_OFFLOAD, (u8 *)(&p2p_ps_state));
pwdinfo->noa_index = 0;
pwdinfo->ctwindow = 0;
pwdinfo->opp_ps = 0;
pwdinfo->noa_num = 0;
pwdinfo->p2p_ps_mode = P2P_PS_NONE;
if (pwrpriv->bFwCurrentInPSMode == _TRUE) {
if (pwrpriv->smart_ps == 0) {
pwrpriv->smart_ps = 2;
rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&(pwrpriv->pwr_mode)));
}
}
break;
case P2P_PS_ENABLE:
_enter_pwrlock(&adapter_to_pwrctl(padapter)->lock);
ps_deny = rtw_ps_deny_get(padapter);
_exit_pwrlock(&adapter_to_pwrctl(padapter)->lock);
if ((ps_deny & (PS_DENY_SCAN | PS_DENY_JOIN))
|| rtw_mi_check_fwstate(padapter, (_FW_UNDER_SURVEY | _FW_UNDER_LINKING))) {
pwdinfo->p2p_ps_mode = P2P_PS_NONE;
RTW_DBG(FUNC_ADPT_FMT" Block P2P PS under site survey or LINKING\n", FUNC_ADPT_ARG(padapter));
return;
}
if (pwdinfo->p2p_ps_mode > P2P_PS_NONE) {
#ifdef CONFIG_MCC_MODE
if (MCC_EN(padapter)) {
if (rtw_hal_check_mcc_status(padapter, MCC_STATUS_DOING_MCC)) {
RTW_INFO("P2P PS enble under MCC\n");
rtw_warn_on(1);
}
}
#endif /* CONFIG_MCC_MODE */
pwdinfo->p2p_ps_state = p2p_ps_state;
if (pwdinfo->ctwindow > 0) {
if (pwrpriv->smart_ps != 0) {
pwrpriv->smart_ps = 0;
RTW_INFO("%s(): Enter CTW, change SmartPS\n", __FUNCTION__);
rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&(pwrpriv->pwr_mode)));
}
}
rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_P2P_PS_OFFLOAD, (u8 *)(&p2p_ps_state));
}
break;
case P2P_PS_SCAN:
case P2P_PS_SCAN_DONE:
case P2P_PS_ALLSTASLEEP:
if (pwdinfo->p2p_ps_mode > P2P_PS_NONE) {
pwdinfo->p2p_ps_state = p2p_ps_state;
rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_P2P_PS_OFFLOAD, (u8 *)(&p2p_ps_state));
}
break;
default:
break;
}
#ifdef CONFIG_MCC_MODE
rtw_hal_mcc_process_noa(padapter);
#endif /* CONFIG_MCC_MODE */
}
u8 p2p_ps_wk_cmd(_adapter *padapter, u8 p2p_ps_state, u8 enqueue)
{
struct cmd_obj *ph2c;
struct drvextra_cmd_parm *pdrvextra_cmd_parm;
struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
u8 res = _SUCCESS;
if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)
#ifdef CONFIG_CONCURRENT_MODE
#ifndef CONFIG_FW_MULTI_PORT_SUPPORT
|| (padapter->hw_port != HW_PORT0)
#endif
#endif
)
return res;
if (enqueue) {
ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
if (ph2c == NULL) {
res = _FAIL;
goto exit;
}
pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
if (pdrvextra_cmd_parm == NULL) {
rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj));
res = _FAIL;
goto exit;
}
pdrvextra_cmd_parm->ec_id = P2P_PS_WK_CID;
pdrvextra_cmd_parm->type = p2p_ps_state;
pdrvextra_cmd_parm->size = 0;
pdrvextra_cmd_parm->pbuf = NULL;
init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
res = rtw_enqueue_cmd(pcmdpriv, ph2c);
} else
p2p_ps_wk_hdl(padapter, p2p_ps_state);
exit:
return res;
}
#endif /* CONFIG_P2P_PS */
static void reset_ch_sitesurvey_timer_process(void *FunctionContext)
{
_adapter *adapter = (_adapter *)FunctionContext;
struct wifidirect_info *pwdinfo = &adapter->wdinfo;
if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
return;
RTW_INFO("[%s] In\n", __FUNCTION__);
/* Reset the operation channel information */
pwdinfo->rx_invitereq_info.operation_ch[0] = 0;
#ifdef CONFIG_P2P_OP_CHK_SOCIAL_CH
pwdinfo->rx_invitereq_info.operation_ch[1] = 0;
pwdinfo->rx_invitereq_info.operation_ch[2] = 0;
pwdinfo->rx_invitereq_info.operation_ch[3] = 0;
#endif /* CONFIG_P2P_OP_CHK_SOCIAL_CH */
pwdinfo->rx_invitereq_info.scan_op_ch_only = 0;
}
static void reset_ch_sitesurvey_timer_process2(void *FunctionContext)
{
_adapter *adapter = (_adapter *)FunctionContext;
struct wifidirect_info *pwdinfo = &adapter->wdinfo;
if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
return;
RTW_INFO("[%s] In\n", __FUNCTION__);
/* Reset the operation channel information */
pwdinfo->p2p_info.operation_ch[0] = 0;
#ifdef CONFIG_P2P_OP_CHK_SOCIAL_CH
pwdinfo->p2p_info.operation_ch[1] = 0;
pwdinfo->p2p_info.operation_ch[2] = 0;
pwdinfo->p2p_info.operation_ch[3] = 0;
#endif /* CONFIG_P2P_OP_CHK_SOCIAL_CH */
pwdinfo->p2p_info.scan_op_ch_only = 0;
}
static void restore_p2p_state_timer_process(void *FunctionContext)
{
_adapter *adapter = (_adapter *)FunctionContext;
struct wifidirect_info *pwdinfo = &adapter->wdinfo;
if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
return;
p2p_protocol_wk_cmd(adapter, P2P_RESTORE_STATE_WK);
}
static void pre_tx_scan_timer_process(void *FunctionContext)
{
_adapter *adapter = (_adapter *) FunctionContext;
struct wifidirect_info *pwdinfo = &adapter->wdinfo;
_irqL irqL;
struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
return;
_enter_critical_bh(&pmlmepriv->lock, &irqL);
if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_PROVISION_DIS_REQ)) {
if (_TRUE == pwdinfo->tx_prov_disc_info.benable) { /* the provision discovery request frame is trigger to send or not */
p2p_protocol_wk_cmd(adapter, P2P_PRE_TX_PROVDISC_PROCESS_WK);
/* issue_probereq_p2p(adapter, NULL); */
/* _set_timer( &pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT ); */
}
} else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING)) {
if (_TRUE == pwdinfo->nego_req_info.benable)
p2p_protocol_wk_cmd(adapter, P2P_PRE_TX_NEGOREQ_PROCESS_WK);
} else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_INVITE_REQ)) {
if (_TRUE == pwdinfo->invitereq_info.benable)
p2p_protocol_wk_cmd(adapter, P2P_PRE_TX_INVITEREQ_PROCESS_WK);
} else
RTW_INFO("[%s] p2p_state is %d, ignore!!\n", __FUNCTION__, rtw_p2p_state(pwdinfo));
_exit_critical_bh(&pmlmepriv->lock, &irqL);
}
static void find_phase_timer_process(void *FunctionContext)
{
_adapter *adapter = (_adapter *)FunctionContext;
struct wifidirect_info *pwdinfo = &adapter->wdinfo;
if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
return;
adapter->wdinfo.find_phase_state_exchange_cnt++;
p2p_protocol_wk_cmd(adapter, P2P_FIND_PHASE_WK);
}
#ifdef CONFIG_CONCURRENT_MODE
void ap_p2p_switch_timer_process(void *FunctionContext)
{
_adapter *adapter = (_adapter *)FunctionContext;
struct wifidirect_info *pwdinfo = &adapter->wdinfo;
#ifdef CONFIG_IOCTL_CFG80211
struct rtw_wdev_priv *pwdev_priv = adapter_wdev_data(adapter);
#endif
if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
return;
#ifdef CONFIG_IOCTL_CFG80211
ATOMIC_SET(&pwdev_priv->switch_ch_to, 1);
#endif
p2p_protocol_wk_cmd(adapter, P2P_AP_P2P_CH_SWITCH_PROCESS_WK);
}
#endif
void reset_global_wifidirect_info(_adapter *padapter)
{
struct wifidirect_info *pwdinfo;
pwdinfo = &padapter->wdinfo;
pwdinfo->persistent_supported = 0;
pwdinfo->session_available = _TRUE;
rtw_tdls_wfd_enable(padapter, 0);
pwdinfo->wfd_tdls_weaksec = _TRUE;
}
#ifdef CONFIG_WFD
int rtw_init_wifi_display_info(_adapter *padapter)
{
int res = _SUCCESS;
struct wifi_display_info *pwfd_info = &padapter->wfd_info;
/* Used in P2P and TDLS */
pwfd_info->init_rtsp_ctrlport = 554;
#ifdef CONFIG_IOCTL_CFG80211
pwfd_info->rtsp_ctrlport = 0;
#else
pwfd_info->rtsp_ctrlport = pwfd_info->init_rtsp_ctrlport; /* set non-zero value for legacy wfd */
#endif
pwfd_info->tdls_rtsp_ctrlport = 0;
pwfd_info->peer_rtsp_ctrlport = 0; /* Reset to 0 */
pwfd_info->wfd_enable = _FALSE;
pwfd_info->wfd_device_type = WFD_DEVINFO_PSINK;
pwfd_info->scan_result_type = SCAN_RESULT_P2P_ONLY;
/* Used in P2P */
pwfd_info->peer_session_avail = _TRUE;
pwfd_info->wfd_pc = _FALSE;
/* Used in TDLS */
_rtw_memset(pwfd_info->ip_address, 0x00, 4);
_rtw_memset(pwfd_info->peer_ip_address, 0x00, 4);
return res;
}
inline void rtw_wfd_enable(_adapter *adapter, bool on)
{
struct wifi_display_info *wfdinfo = &adapter->wfd_info;
if (on) {
wfdinfo->rtsp_ctrlport = wfdinfo->init_rtsp_ctrlport;
wfdinfo->wfd_enable = _TRUE;
} else {
wfdinfo->wfd_enable = _FALSE;
wfdinfo->rtsp_ctrlport = 0;
}
}
inline void rtw_wfd_set_ctrl_port(_adapter *adapter, u16 port)
{
struct wifi_display_info *wfdinfo = &adapter->wfd_info;
wfdinfo->init_rtsp_ctrlport = port;
if (wfdinfo->wfd_enable == _TRUE)
wfdinfo->rtsp_ctrlport = port;
if (adapter->wdinfo.wfd_tdls_enable == 1)
wfdinfo->tdls_rtsp_ctrlport = port;
}
inline void rtw_tdls_wfd_enable(_adapter *adapter, bool on)
{
struct wifi_display_info *wfdinfo = &adapter->wfd_info;
if (on) {
wfdinfo->tdls_rtsp_ctrlport = wfdinfo->init_rtsp_ctrlport;
adapter->wdinfo.wfd_tdls_enable = 1;
} else {
adapter->wdinfo.wfd_tdls_enable = 0;
wfdinfo->tdls_rtsp_ctrlport = 0;
}
}
u32 rtw_append_beacon_wfd_ie(_adapter *adapter, u8 *pbuf)
{
struct wifidirect_info *wdinfo = &adapter->wdinfo;
struct mlme_priv *mlme = &adapter->mlmepriv;
u8 build_ie_by_self = 0;
u32 len = 0;
if (!hal_chk_wl_func(adapter, WL_FUNC_MIRACAST))
goto exit;
#ifdef CONFIG_IOCTL_CFG80211
if (_TRUE == wdinfo->wfd_info->wfd_enable)
#endif
build_ie_by_self = 1;
if (build_ie_by_self)
len = build_beacon_wfd_ie(wdinfo, pbuf);
#ifdef CONFIG_IOCTL_CFG80211
else if (mlme->wfd_beacon_ie && mlme->wfd_beacon_ie_len > 0) {
len = mlme->wfd_beacon_ie_len;
_rtw_memcpy(pbuf, mlme->wfd_beacon_ie, len);
}
#endif
exit:
return len;
}
u32 rtw_append_probe_req_wfd_ie(_adapter *adapter, u8 *pbuf)
{
struct wifidirect_info *wdinfo = &adapter->wdinfo;
struct mlme_priv *mlme = &adapter->mlmepriv;
u8 build_ie_by_self = 0;
u32 len = 0;
if (!hal_chk_wl_func(adapter, WL_FUNC_MIRACAST))
goto exit;
#ifdef CONFIG_IOCTL_CFG80211
if (_TRUE == wdinfo->wfd_info->wfd_enable)
#endif
build_ie_by_self = 1;
if (build_ie_by_self)
len = build_probe_req_wfd_ie(wdinfo, pbuf);
#ifdef CONFIG_IOCTL_CFG80211
else if (mlme->wfd_probe_req_ie && mlme->wfd_probe_req_ie_len > 0) {
len = mlme->wfd_probe_req_ie_len;
_rtw_memcpy(pbuf, mlme->wfd_probe_req_ie, len);
}
#endif
exit:
return len;
}
u32 rtw_append_probe_resp_wfd_ie(_adapter *adapter, u8 *pbuf)
{
struct wifidirect_info *wdinfo = &adapter->wdinfo;
struct mlme_priv *mlme = &adapter->mlmepriv;
u8 build_ie_by_self = 0;
u32 len = 0;
if (!hal_chk_wl_func(adapter, WL_FUNC_MIRACAST))
goto exit;
#ifdef CONFIG_IOCTL_CFG80211
if (_TRUE == wdinfo->wfd_info->wfd_enable)
#endif
build_ie_by_self = 1;
if (build_ie_by_self)
len = build_probe_resp_wfd_ie(wdinfo, pbuf, 0);
#ifdef CONFIG_IOCTL_CFG80211
else if (mlme->wfd_probe_resp_ie && mlme->wfd_probe_resp_ie_len > 0) {
len = mlme->wfd_probe_resp_ie_len;
_rtw_memcpy(pbuf, mlme->wfd_probe_resp_ie, len);
}
#endif
exit:
return len;
}
u32 rtw_append_assoc_req_wfd_ie(_adapter *adapter, u8 *pbuf)
{
struct wifidirect_info *wdinfo = &adapter->wdinfo;
struct mlme_priv *mlme = &adapter->mlmepriv;
u8 build_ie_by_self = 0;
u32 len = 0;
if (!hal_chk_wl_func(adapter, WL_FUNC_MIRACAST))
goto exit;
#ifdef CONFIG_IOCTL_CFG80211
if (_TRUE == wdinfo->wfd_info->wfd_enable)
#endif
build_ie_by_self = 1;
if (build_ie_by_self)
len = build_assoc_req_wfd_ie(wdinfo, pbuf);
#ifdef CONFIG_IOCTL_CFG80211
else if (mlme->wfd_assoc_req_ie && mlme->wfd_assoc_req_ie_len > 0) {
len = mlme->wfd_assoc_req_ie_len;
_rtw_memcpy(pbuf, mlme->wfd_assoc_req_ie, len);
}
#endif
exit:
return len;
}
u32 rtw_append_assoc_resp_wfd_ie(_adapter *adapter, u8 *pbuf)
{
struct wifidirect_info *wdinfo = &adapter->wdinfo;
struct mlme_priv *mlme = &adapter->mlmepriv;
u8 build_ie_by_self = 0;
u32 len = 0;
if (!hal_chk_wl_func(adapter, WL_FUNC_MIRACAST))
goto exit;
#ifdef CONFIG_IOCTL_CFG80211
if (_TRUE == wdinfo->wfd_info->wfd_enable)
#endif
build_ie_by_self = 1;
if (build_ie_by_self)
len = build_assoc_resp_wfd_ie(wdinfo, pbuf);
#ifdef CONFIG_IOCTL_CFG80211
else if (mlme->wfd_assoc_resp_ie && mlme->wfd_assoc_resp_ie_len > 0) {
len = mlme->wfd_assoc_resp_ie_len;
_rtw_memcpy(pbuf, mlme->wfd_assoc_resp_ie, len);
}
#endif
exit:
return len;
}
#endif /* CONFIG_WFD */
void rtw_init_wifidirect_timers(_adapter *padapter)
{
struct wifidirect_info *pwdinfo = &padapter->wdinfo;
rtw_init_timer(&pwdinfo->find_phase_timer, padapter, find_phase_timer_process, padapter);
rtw_init_timer(&pwdinfo->restore_p2p_state_timer, padapter, restore_p2p_state_timer_process, padapter);
rtw_init_timer(&pwdinfo->pre_tx_scan_timer, padapter, pre_tx_scan_timer_process, padapter);
rtw_init_timer(&pwdinfo->reset_ch_sitesurvey, padapter, reset_ch_sitesurvey_timer_process, padapter);
rtw_init_timer(&pwdinfo->reset_ch_sitesurvey2, padapter, reset_ch_sitesurvey_timer_process2, padapter);
#ifdef CONFIG_CONCURRENT_MODE
rtw_init_timer(&pwdinfo->ap_p2p_switch_timer, padapter, ap_p2p_switch_timer_process, padapter);
#endif
}
void rtw_init_wifidirect_addrs(_adapter *padapter, u8 *dev_addr, u8 *iface_addr)
{
#ifdef CONFIG_P2P
struct wifidirect_info *pwdinfo = &padapter->wdinfo;
/*init device&interface address */
if (dev_addr)
_rtw_memcpy(pwdinfo->device_addr, dev_addr, ETH_ALEN);
if (iface_addr)
_rtw_memcpy(pwdinfo->interface_addr, iface_addr, ETH_ALEN);
#endif
}
void init_wifidirect_info(_adapter *padapter, enum P2P_ROLE role)
{
struct wifidirect_info *pwdinfo;
#ifdef CONFIG_WFD
struct wifi_display_info *pwfd_info = &padapter->wfd_info;
#endif
pwdinfo = &padapter->wdinfo;
pwdinfo->padapter = padapter;
/* 1, 6, 11 are the social channel defined in the WiFi Direct specification. */
pwdinfo->social_chan[0] = 1;
pwdinfo->social_chan[1] = 6;
pwdinfo->social_chan[2] = 11;
pwdinfo->social_chan[3] = 0; /* channel 0 for scanning ending in site survey function. */
if (role != P2P_ROLE_DISABLE
&& pwdinfo->driver_interface != DRIVER_CFG80211
) {
#ifdef CONFIG_CONCURRENT_MODE
u8 union_ch = 0;
if (rtw_mi_check_status(padapter, MI_LINKED))
union_ch = rtw_mi_get_union_chan(padapter);
if (union_ch != 0 &&
(union_ch == 1 || union_ch == 6 || union_ch == 11)
) {
/* Use the AP's channel as the listen channel */
/* This will avoid the channel switch between AP's channel and listen channel */
pwdinfo->listen_channel = union_ch;
} else
#endif /* CONFIG_CONCURRENT_MODE */
{
/* Use the channel 11 as the listen channel */
pwdinfo->listen_channel = 11;
}
}
if (role == P2P_ROLE_DEVICE) {
rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE);
#ifdef CONFIG_CONCURRENT_MODE
if (rtw_mi_check_status(padapter, MI_LINKED))
rtw_p2p_set_state(pwdinfo, P2P_STATE_IDLE);
else
#endif
rtw_p2p_set_state(pwdinfo, P2P_STATE_LISTEN);
pwdinfo->intent = 1;
rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_LISTEN);
} else if (role == P2P_ROLE_CLIENT) {
rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT);
rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK);
pwdinfo->intent = 1;
rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK);
} else if (role == P2P_ROLE_GO) {
rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO);
rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK);
pwdinfo->intent = 15;
rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK);
}
/* Use the OFDM rate in the P2P probe response frame. ( 6(B), 9(B), 12, 18, 24, 36, 48, 54 ) */
pwdinfo->support_rate[0] = 0x8c; /* 6(B) */
pwdinfo->support_rate[1] = 0x92; /* 9(B) */
pwdinfo->support_rate[2] = 0x18; /* 12 */
pwdinfo->support_rate[3] = 0x24; /* 18 */
pwdinfo->support_rate[4] = 0x30; /* 24 */
pwdinfo->support_rate[5] = 0x48; /* 36 */
pwdinfo->support_rate[6] = 0x60; /* 48 */
pwdinfo->support_rate[7] = 0x6c; /* 54 */
_rtw_memcpy((void *) pwdinfo->p2p_wildcard_ssid, "DIRECT-", 7);
_rtw_memset(pwdinfo->device_name, 0x00, WPS_MAX_DEVICE_NAME_LEN);
pwdinfo->device_name_len = 0;
_rtw_memset(&pwdinfo->invitereq_info, 0x00, sizeof(struct tx_invite_req_info));
pwdinfo->invitereq_info.token = 3; /* Token used for P2P invitation request frame. */
_rtw_memset(&pwdinfo->inviteresp_info, 0x00, sizeof(struct tx_invite_resp_info));
pwdinfo->inviteresp_info.token = 0;
pwdinfo->profileindex = 0;
_rtw_memset(&pwdinfo->profileinfo[0], 0x00, sizeof(struct profile_info) * P2P_MAX_PERSISTENT_GROUP_NUM);
rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_NONE);
pwdinfo->listen_dwell = (u8)((rtw_get_current_time() % 3) + 1);
/* RTW_INFO( "[%s] listen_dwell time is %d00ms\n", __FUNCTION__, pwdinfo->listen_dwell ); */
_rtw_memset(&pwdinfo->tx_prov_disc_info, 0x00, sizeof(struct tx_provdisc_req_info));
pwdinfo->tx_prov_disc_info.wps_config_method_request = WPS_CM_NONE;
_rtw_memset(&pwdinfo->nego_req_info, 0x00, sizeof(struct tx_nego_req_info));
pwdinfo->device_password_id_for_nego = WPS_DPID_PBC;
pwdinfo->negotiation_dialog_token = 1;
_rtw_memset(pwdinfo->nego_ssid, 0x00, WLAN_SSID_MAXLEN);
pwdinfo->nego_ssidlen = 0;
pwdinfo->ui_got_wps_info = P2P_NO_WPSINFO;
#ifdef CONFIG_WFD
pwdinfo->supported_wps_cm = WPS_CONFIG_METHOD_DISPLAY | WPS_CONFIG_METHOD_PBC;
pwdinfo->wfd_info = pwfd_info;
#else
pwdinfo->supported_wps_cm = WPS_CONFIG_METHOD_DISPLAY | WPS_CONFIG_METHOD_PBC | WPS_CONFIG_METHOD_KEYPAD;
#endif /* CONFIG_WFD */
pwdinfo->channel_list_attr_len = 0;
_rtw_memset(pwdinfo->channel_list_attr, 0x00, 100);
_rtw_memset(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, 0x00, 4);
_rtw_memset(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, '0', 3);
_rtw_memset(&pwdinfo->groupid_info, 0x00, sizeof(struct group_id_info));
#ifdef CONFIG_CONCURRENT_MODE
#ifdef CONFIG_IOCTL_CFG80211
pwdinfo->ext_listen_interval = 1000; /* The interval to be available with legacy AP during p2p0-find/scan */
pwdinfo->ext_listen_period = 3000; /* The time period to be available for P2P during nego */
#else /* !CONFIG_IOCTL_CFG80211 */
/* pwdinfo->ext_listen_interval = 3000; */
/* pwdinfo->ext_listen_period = 400; */
pwdinfo->ext_listen_interval = 1000;
pwdinfo->ext_listen_period = 1000;
#endif /* !CONFIG_IOCTL_CFG80211 */
#endif
/* Commented by Kurt 20130319
* For WiDi purpose: Use CFG80211 interface but controled WFD/RDS frame by driver itself. */
#ifdef CONFIG_IOCTL_CFG80211
pwdinfo->driver_interface = DRIVER_CFG80211;
#else
pwdinfo->driver_interface = DRIVER_WEXT;
#endif /* CONFIG_IOCTL_CFG80211 */
pwdinfo->wfd_tdls_enable = 0;
_rtw_memset(pwdinfo->p2p_peer_interface_addr, 0x00, ETH_ALEN);
_rtw_memset(pwdinfo->p2p_peer_device_addr, 0x00, ETH_ALEN);
pwdinfo->rx_invitereq_info.operation_ch[0] = 0;
pwdinfo->rx_invitereq_info.operation_ch[1] = 0; /* Used to indicate the scan end in site survey function */
#ifdef CONFIG_P2P_OP_CHK_SOCIAL_CH
pwdinfo->rx_invitereq_info.operation_ch[2] = 0;
pwdinfo->rx_invitereq_info.operation_ch[3] = 0;
pwdinfo->rx_invitereq_info.operation_ch[4] = 0;
#endif /* CONFIG_P2P_OP_CHK_SOCIAL_CH */
pwdinfo->rx_invitereq_info.scan_op_ch_only = 0;
pwdinfo->p2p_info.operation_ch[0] = 0;
pwdinfo->p2p_info.operation_ch[1] = 0; /* Used to indicate the scan end in site survey function */
#ifdef CONFIG_P2P_OP_CHK_SOCIAL_CH
pwdinfo->p2p_info.operation_ch[2] = 0;
pwdinfo->p2p_info.operation_ch[3] = 0;
pwdinfo->p2p_info.operation_ch[4] = 0;
#endif /* CONFIG_P2P_OP_CHK_SOCIAL_CH */
pwdinfo->p2p_info.scan_op_ch_only = 0;
}
void _rtw_p2p_set_role(struct wifidirect_info *wdinfo, enum P2P_ROLE role)
{
if (wdinfo->role != role) {
wdinfo->role = role;
rtw_mi_update_iface_status(&(wdinfo->padapter->mlmepriv), 0);
}
}
#ifdef CONFIG_DBG_P2P
/**
* rtw_p2p_role_txt - Get the p2p role name as a text string
* @role: P2P role
* Returns: The state name as a printable text string
*/
const char *rtw_p2p_role_txt(enum P2P_ROLE role)
{
switch (role) {
case P2P_ROLE_DISABLE:
return "P2P_ROLE_DISABLE";
case P2P_ROLE_DEVICE:
return "P2P_ROLE_DEVICE";
case P2P_ROLE_CLIENT:
return "P2P_ROLE_CLIENT";
case P2P_ROLE_GO:
return "P2P_ROLE_GO";
default:
return "UNKNOWN";
}
}
/**
* rtw_p2p_state_txt - Get the p2p state name as a text string
* @state: P2P state
* Returns: The state name as a printable text string
*/
const char *rtw_p2p_state_txt(enum P2P_STATE state)
{
switch (state) {
case P2P_STATE_NONE:
return "P2P_STATE_NONE";
case P2P_STATE_IDLE:
return "P2P_STATE_IDLE";
case P2P_STATE_LISTEN:
return "P2P_STATE_LISTEN";
case P2P_STATE_SCAN:
return "P2P_STATE_SCAN";
case P2P_STATE_FIND_PHASE_LISTEN:
return "P2P_STATE_FIND_PHASE_LISTEN";
case P2P_STATE_FIND_PHASE_SEARCH:
return "P2P_STATE_FIND_PHASE_SEARCH";
case P2P_STATE_TX_PROVISION_DIS_REQ:
return "P2P_STATE_TX_PROVISION_DIS_REQ";
case P2P_STATE_RX_PROVISION_DIS_RSP:
return "P2P_STATE_RX_PROVISION_DIS_RSP";
case P2P_STATE_RX_PROVISION_DIS_REQ:
return "P2P_STATE_RX_PROVISION_DIS_REQ";
case P2P_STATE_GONEGO_ING:
return "P2P_STATE_GONEGO_ING";
case P2P_STATE_GONEGO_OK:
return "P2P_STATE_GONEGO_OK";
case P2P_STATE_GONEGO_FAIL:
return "P2P_STATE_GONEGO_FAIL";
case P2P_STATE_RECV_INVITE_REQ_MATCH:
return "P2P_STATE_RECV_INVITE_REQ_MATCH";
case P2P_STATE_PROVISIONING_ING:
return "P2P_STATE_PROVISIONING_ING";
case P2P_STATE_PROVISIONING_DONE:
return "P2P_STATE_PROVISIONING_DONE";
case P2P_STATE_TX_INVITE_REQ:
return "P2P_STATE_TX_INVITE_REQ";
case P2P_STATE_RX_INVITE_RESP_OK:
return "P2P_STATE_RX_INVITE_RESP_OK";
case P2P_STATE_RECV_INVITE_REQ_DISMATCH:
return "P2P_STATE_RECV_INVITE_REQ_DISMATCH";
case P2P_STATE_RECV_INVITE_REQ_GO:
return "P2P_STATE_RECV_INVITE_REQ_GO";
case P2P_STATE_RECV_INVITE_REQ_JOIN:
return "P2P_STATE_RECV_INVITE_REQ_JOIN";
case P2P_STATE_RX_INVITE_RESP_FAIL:
return "P2P_STATE_RX_INVITE_RESP_FAIL";
case P2P_STATE_RX_INFOR_NOREADY:
return "P2P_STATE_RX_INFOR_NOREADY";
case P2P_STATE_TX_INFOR_NOREADY:
return "P2P_STATE_TX_INFOR_NOREADY";
default:
return "UNKNOWN";
}
}
void dbg_rtw_p2p_set_state(struct wifidirect_info *wdinfo, enum P2P_STATE state, const char *caller, int line)
{
if (!_rtw_p2p_chk_state(wdinfo, state)) {
enum P2P_STATE old_state = _rtw_p2p_state(wdinfo);
_rtw_p2p_set_state(wdinfo, state);
RTW_INFO("[CONFIG_DBG_P2P]%s:%d set_state from %s to %s\n", caller, line
, rtw_p2p_state_txt(old_state), rtw_p2p_state_txt(_rtw_p2p_state(wdinfo))
);
} else {
RTW_INFO("[CONFIG_DBG_P2P]%s:%d set_state to same state %s\n", caller, line
, rtw_p2p_state_txt(_rtw_p2p_state(wdinfo))
);
}
}
void dbg_rtw_p2p_set_pre_state(struct wifidirect_info *wdinfo, enum P2P_STATE state, const char *caller, int line)
{
if (_rtw_p2p_pre_state(wdinfo) != state) {
enum P2P_STATE old_state = _rtw_p2p_pre_state(wdinfo);
_rtw_p2p_set_pre_state(wdinfo, state);
RTW_INFO("[CONFIG_DBG_P2P]%s:%d set_pre_state from %s to %s\n", caller, line
, rtw_p2p_state_txt(old_state), rtw_p2p_state_txt(_rtw_p2p_pre_state(wdinfo))
);
} else {
RTW_INFO("[CONFIG_DBG_P2P]%s:%d set_pre_state to same state %s\n", caller, line
, rtw_p2p_state_txt(_rtw_p2p_pre_state(wdinfo))
);
}
}
#if 0
void dbg_rtw_p2p_restore_state(struct wifidirect_info *wdinfo, const char *caller, int line)
{
if (wdinfo->pre_p2p_state != -1) {
RTW_INFO("[CONFIG_DBG_P2P]%s:%d restore from %s to %s\n", caller, line
, p2p_state_str[wdinfo->p2p_state], p2p_state_str[wdinfo->pre_p2p_state]
);
_rtw_p2p_restore_state(wdinfo);
} else {
RTW_INFO("[CONFIG_DBG_P2P]%s:%d restore no pre state, cur state %s\n", caller, line
, p2p_state_str[wdinfo->p2p_state]
);
}
}
#endif
void dbg_rtw_p2p_set_role(struct wifidirect_info *wdinfo, enum P2P_ROLE role, const char *caller, int line)
{
if (wdinfo->role != role) {
enum P2P_ROLE old_role = wdinfo->role;
_rtw_p2p_set_role(wdinfo, role);
RTW_INFO("[CONFIG_DBG_P2P]%s:%d set_role from %s to %s\n", caller, line
, rtw_p2p_role_txt(old_role), rtw_p2p_role_txt(wdinfo->role)
);
} else {
RTW_INFO("[CONFIG_DBG_P2P]%s:%d set_role to same role %s\n", caller, line
, rtw_p2p_role_txt(wdinfo->role)
);
}
}
#endif /* CONFIG_DBG_P2P */
int rtw_p2p_enable(_adapter *padapter, enum P2P_ROLE role)
{
int ret = _SUCCESS;
struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
if (role == P2P_ROLE_DEVICE || role == P2P_ROLE_CLIENT || role == P2P_ROLE_GO) {
#if defined(CONFIG_CONCURRENT_MODE) && (!defined(RTW_P2P_GROUP_INTERFACE) || !RTW_P2P_GROUP_INTERFACE)
/* Commented by Albert 2011/12/30 */
/* The driver just supports 1 P2P group operation. */
/* So, this function will do nothing if the buddy adapter had enabled the P2P function. */
/*if(!rtw_p2p_chk_state(pbuddy_wdinfo, P2P_STATE_NONE))
return ret;*/
/*The buddy adapter had enabled the P2P function.*/
if (rtw_mi_buddy_stay_in_p2p_mode(padapter))
return ret;
#endif /* CONFIG_CONCURRENT_MODE */
/* leave IPS/Autosuspend */
if (_FAIL == rtw_pwr_wakeup(padapter)) {
ret = _FAIL;
goto exit;
}
/* Added by Albert 2011/03/22 */
/* In the P2P mode, the driver should not support the b mode. */
/* So, the Tx packet shouldn't use the CCK rate */
#ifdef CONFIG_IOCTL_CFG80211
if (rtw_cfg80211_iface_has_p2p_group_cap(padapter))
#endif
update_tx_basic_rate(padapter, WIRELESS_11AGN);
/* Enable P2P function */
init_wifidirect_info(padapter, role);
#ifdef CONFIG_IOCTL_CFG80211
if (padapter->wdinfo.driver_interface == DRIVER_CFG80211)
adapter_wdev_data(padapter)->p2p_enabled = _TRUE;
#endif
rtw_hal_set_odm_var(padapter, HAL_ODM_P2P_STATE, NULL, _TRUE);
#ifdef CONFIG_WFD
if (hal_chk_wl_func(padapter, WL_FUNC_MIRACAST))
rtw_hal_set_odm_var(padapter, HAL_ODM_WIFI_DISPLAY_STATE, NULL, _TRUE);
#endif
} else if (role == P2P_ROLE_DISABLE) {
#ifdef CONFIG_INTEL_WIDI
if (padapter->mlmepriv.p2p_reject_disable == _TRUE)
return ret;
#endif /* CONFIG_INTEL_WIDI */
#ifdef CONFIG_IOCTL_CFG80211
if (padapter->wdinfo.driver_interface == DRIVER_CFG80211)
adapter_wdev_data(padapter)->p2p_enabled = _FALSE;
#endif
pwdinfo->listen_channel = 0;
/* Disable P2P function */
if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) {
_cancel_timer_ex(&pwdinfo->find_phase_timer);
_cancel_timer_ex(&pwdinfo->restore_p2p_state_timer);
_cancel_timer_ex(&pwdinfo->pre_tx_scan_timer);
_cancel_timer_ex(&pwdinfo->reset_ch_sitesurvey);
_cancel_timer_ex(&pwdinfo->reset_ch_sitesurvey2);
reset_ch_sitesurvey_timer_process(padapter);
reset_ch_sitesurvey_timer_process2(padapter);
#ifdef CONFIG_CONCURRENT_MODE
_cancel_timer_ex(&pwdinfo->ap_p2p_switch_timer);
#endif
rtw_p2p_set_state(pwdinfo, P2P_STATE_NONE);
rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_NONE);
rtw_p2p_set_role(pwdinfo, P2P_ROLE_DISABLE);
_rtw_memset(&pwdinfo->rx_prov_disc_info, 0x00, sizeof(struct rx_provdisc_req_info));
/* Remove profiles in wifidirect_info structure. */
_rtw_memset(&pwdinfo->profileinfo[0], 0x00, sizeof(struct profile_info) * P2P_MAX_PERSISTENT_GROUP_NUM);
pwdinfo->profileindex = 0;
}
rtw_hal_set_odm_var(padapter, HAL_ODM_P2P_STATE, NULL, _FALSE);
#ifdef CONFIG_WFD
if (hal_chk_wl_func(padapter, WL_FUNC_MIRACAST))
rtw_hal_set_odm_var(padapter, HAL_ODM_WIFI_DISPLAY_STATE, NULL, _FALSE);
#endif
if (_FAIL == rtw_pwr_wakeup(padapter)) {
ret = _FAIL;
goto exit;
}
/* Restore to initial setting. */
update_tx_basic_rate(padapter, padapter->registrypriv.wireless_mode);
#ifdef CONFIG_INTEL_WIDI
rtw_reset_widi_info(padapter);
#endif /* CONFIG_INTEL_WIDI */
/* For WiDi purpose. */
#ifdef CONFIG_IOCTL_CFG80211
pwdinfo->driver_interface = DRIVER_CFG80211;
#else
pwdinfo->driver_interface = DRIVER_WEXT;
#endif /* CONFIG_IOCTL_CFG80211 */
}
exit:
return ret;
}
#endif /* CONFIG_P2P */