/**************************************************************************** * Ralink Tech Inc. * Taiwan, R.O.C. * * (c) Copyright 2002, Ralink Technology, Inc. * * All rights reserved. Ralink's source code is an unpublished work and the * use of a copyright notice does not imply otherwise. This source code * contains confidential trade secret material of Ralink Tech. Any attemp * or participation in deciphering, decoding, reverse engineering or in any * way altering the source code is stricitly prohibited, unless the prior * written consent of Ralink Technology, Inc. is obtained. ***************************************************************************/ #include "rt_config.h" #include "wfd_cmm.h" #ifdef WFD_SUPPORT UCHAR WIFIDISPLAY_OUI[] = {0x50, 0x6f, 0x9a, 0x0a}; INT Set_WfdEnable_Proc(RTMP_ADAPTER *pAd, RTMP_STRING *arg) { BOOLEAN bEnable; bEnable = simple_strtol(arg, 0, 10); if (bEnable == TRUE) { pAd->StaCfg.WfdCfg.bWfdEnable= TRUE; DBGPRINT(RT_DEBUG_TRACE, ("%s:: Enable WFD Support!\n", __FUNCTION__)); } else { pAd->StaCfg.WfdCfg.bWfdEnable= FALSE; DBGPRINT(RT_DEBUG_ERROR, ("%s:: Disable WFD Support!\n", __FUNCTION__)); } return TRUE; } INT Set_WfdDeviceType_Proc(RTMP_ADAPTER *pAd, RTMP_STRING *arg) { UCHAR DeviceType; DeviceType = simple_strtol(arg, 0, 10); if (DeviceType <= WFD_SOURCE_PRIMARY_SINK) { pAd->StaCfg.WfdCfg.DeviceType = DeviceType; } else { DBGPRINT(RT_DEBUG_ERROR, ("%s:: Device Type Not Support!!\n", __FUNCTION__)); return FALSE; } DBGPRINT(RT_DEBUG_TRACE, ("%s:: Device Type = %d\n", __FUNCTION__, pAd->StaCfg.WfdCfg.DeviceType)); return TRUE; } INT Set_WfdCouple_Proc(RTMP_ADAPTER *pAd, RTMP_STRING *arg) { UCHAR coupled; if (simple_strtol(arg, 0, 10) == 0) coupled = WFD_COUPLED_NOT_SUPPORT; else if (simple_strtol(arg, 0, 10) == 1) coupled = WFD_COUPLED_SUPPORT; else { DBGPRINT(RT_DEBUG_ERROR, ("%s:: Coupled out of range!!\n", __FUNCTION__)); return FALSE; } switch (pAd->StaCfg.WfdCfg.DeviceType) { case WFD_SOURCE: pAd->StaCfg.WfdCfg.SourceCoupled = coupled; break; case WFD_PRIMARY_SINK: case WFD_SECONDARY_SINK: pAd->StaCfg.WfdCfg.SinkCoupled = coupled; break; case WFD_SOURCE_PRIMARY_SINK: pAd->StaCfg.WfdCfg.SourceCoupled = coupled; pAd->StaCfg.WfdCfg.SinkCoupled = coupled; break; } DBGPRINT(RT_DEBUG_TRACE, ("%s:: Device Type = %d, Source Coupled = %d, Sink Coupled = %d\n", __FUNCTION__, pAd->StaCfg.WfdCfg.DeviceType, pAd->StaCfg.WfdCfg.SourceCoupled, pAd->StaCfg.WfdCfg.SinkCoupled)); return TRUE; } INT Set_WfdSessionAvailable_Proc(RTMP_ADAPTER *pAd, RTMP_STRING *arg) { if (simple_strtol(arg, 0, 10) == 0) pAd->StaCfg.WfdCfg.SessionAvail= WFD_SESSION_NOT_AVAILABLE; else if (simple_strtol(arg, 0, 10) == 1) pAd->StaCfg.WfdCfg.SessionAvail = WFD_SESSION_AVAILABLE; else { pAd->StaCfg.WfdCfg.SessionAvail = WFD_SESSION_NOT_AVAILABLE; DBGPRINT(RT_DEBUG_ERROR, ("%s:: Session Available out of range, using default\n", __FUNCTION__, pAd->StaCfg.WfdCfg.SessionAvail)); } DBGPRINT(RT_DEBUG_TRACE, ("%s:: Session Available = %d\n", __FUNCTION__, pAd->StaCfg.WfdCfg.SessionAvail)); return TRUE; } INT Set_WfdCP_Proc(RTMP_ADAPTER *pAd, RTMP_STRING *arg) { if (simple_strtol(arg, 0, 10) == 0) pAd->StaCfg.WfdCfg.CP = WFD_CP_NOT_SUPPORT; else if (simple_strtol(arg, 0, 10) == 1) pAd->StaCfg.WfdCfg.CP = WFD_CP_HDCP20; else { pAd->StaCfg.WfdCfg.CP = WFD_CP_NOT_SUPPORT; DBGPRINT(RT_DEBUG_ERROR, ("%s:: Content Protection out of range, using default\n", __FUNCTION__, pAd->StaCfg.WfdCfg.CP)); } DBGPRINT(RT_DEBUG_TRACE, ("%s:: Content Protection = %d\n", __FUNCTION__, pAd->StaCfg.WfdCfg.CP)); return TRUE; } INT Set_WfdRtspPort_Proc(RTMP_ADAPTER *pAd, RTMP_STRING *arg) { INT32 RtspPort; RtspPort = simple_strtol(arg, 0, 10); if ((RtspPort < 0) || (65535 < RtspPort)) { pAd->StaCfg.WfdCfg.RtspPort = WFD_RTSP_DEFAULT_PORT; DBGPRINT(RT_DEBUG_ERROR, ("%s:: RTSP Port out of range, using default\n", __FUNCTION__, pAd->StaCfg.WfdCfg.RtspPort)); } else pAd->StaCfg.WfdCfg.RtspPort = RtspPort; DBGPRINT(RT_DEBUG_TRACE, ("%s:: RTSP Port = %d\n", __FUNCTION__, pAd->StaCfg.WfdCfg.RtspPort)); return TRUE; } INT Set_WfdMaxThroughput_Proc(RTMP_ADAPTER *pAd, RTMP_STRING *arg) { INT32 Throughput; Throughput = simple_strtol(arg, 0, 10); if ((Throughput <= 0)|| (65535 < Throughput)) { pAd->StaCfg.WfdCfg.MaxThroughput = WFD_MAX_THROUGHPUT_DEFAULT; DBGPRINT(RT_DEBUG_ERROR, ("%s:: Max Throughput out of range, using default\n", __FUNCTION__, pAd->StaCfg.WfdCfg.MaxThroughput)); } else pAd->StaCfg.WfdCfg.MaxThroughput = Throughput; DBGPRINT(RT_DEBUG_TRACE, ("%s:: Max Throughput = %d\n", __FUNCTION__, pAd->StaCfg.WfdCfg.MaxThroughput)); return TRUE; } INT Set_WfdLocalIp_Proc(RTMP_ADAPTER *pAd, RTMP_STRING *arg) { PRT_WFD_CONFIG pWFDCtrl = &pAd->StaCfg.WfdCfg; UINT32 ip_addr; rtinet_aton(arg, &ip_addr); printk("IP = %04x\n", ip_addr); pWFDCtrl->wfd_serv_disc_query_info.wfd_local_ip_ie[0] = WFD_LOCAL_IP_ADDR_VERSION_IPV4; RTMPMoveMemory(&pWFDCtrl->wfd_serv_disc_query_info.wfd_local_ip_ie[1], &ip_addr, sizeof(UINT32)); DBGPRINT(RT_DEBUG_TRACE, ("%s:: local IP Address = %d.%d.%d.%d\n", __FUNCTION__, pWFDCtrl->wfd_serv_disc_query_info.wfd_local_ip_ie[1], pWFDCtrl->wfd_serv_disc_query_info.wfd_local_ip_ie[2], pWFDCtrl->wfd_serv_disc_query_info.wfd_local_ip_ie[3], pWFDCtrl->wfd_serv_disc_query_info.wfd_local_ip_ie[4])); return TRUE; } INT Set_PeerRtspPort_Proc(RTMP_ADAPTER *pAd, RTMP_STRING *arg) { PRT_WFD_CONFIG pWFDCtrl = &pAd->StaCfg.WfdCfg; UINT32 ip_addr; MAC_TABLE_ENTRY *pEntry; USHORT RtspPort = WFD_RTSP_DEFAULT_PORT; UCHAR P2pIdx = P2P_NOT_FOUND; PRT_P2P_CONFIG pP2PCtrl = &pAd->P2pCfg; INT i; #ifdef DOT11Z_TDLS_SUPPORT i = -1; if (pAd->StaCfg.TdlsInfo.bTDLSCapable && pAd->StaCfg.WfdCfg.PC == WFD_PC_TDLS) { PRT_802_11_TDLS pTDLS = NULL; DBGPRINT(RT_DEBUG_TRACE, ("%s - TDLS peer rtsp port get...\n", __FUNCTION__)); for (i = MAX_NUM_OF_TDLS_ENTRY - 1; i >= 0; i--) { if ((pAd->StaCfg.TdlsInfo.TDLSEntry[i].Valid) && (pAd->StaCfg.TdlsInfo.TDLSEntry[i].Status == TDLS_MODE_CONNECTED)) { pTDLS = &pAd->StaCfg.TdlsInfo.TDLSEntry[i]; RtspPort = pTDLS->WfdEntryInfo.rtsp_port; DBGPRINT(RT_DEBUG_TRACE, ("TDLS Entry[%d][%02x:%02x:%02x:%02x:%02x:%02x]\n", i, PRINT_MAC(pTDLS->MacAddr))); DBGPRINT(RT_DEBUG_TRACE, ("RTSP_PORT = %d.\n", pTDLS->WfdEntryInfo.rtsp_port)); break; } } if ((RtspPort == 0) && (pTDLS != NULL)) { DBGPRINT(RT_DEBUG_ERROR, ("TDLS peer rtsp port is zero, search P2P Entry!\n", RtspPort)); P2pIdx = P2pGroupTabSearch(pAd, pTDLS->MacAddr); if (P2pIdx != P2P_NOT_FOUND) { RtspPort = pAd->P2pTable.Client[P2pIdx].WfdEntryInfo.rtsp_port; DBGPRINT(RT_DEBUG_TRACE, ("P2P Entry[%d][%02x:%02x:%02x:%02x:%02x:%02x]\n", P2pIdx, PRINT_MAC(pTDLS->MacAddr))); DBGPRINT(RT_DEBUG_TRACE, ("RTSP_PORT = %d.\n", pAd->P2pTable.Client[P2pIdx].WfdEntryInfo.rtsp_port)); if (RtspPort == 0) RtspPort = WFD_RTSP_DEFAULT_PORT; } else { RtspPort = WFD_RTSP_DEFAULT_PORT; DBGPRINT(RT_DEBUG_ERROR, ("OID_802_11_P2P_PEER_RTSP_PORT::P2P not found, use default RTSP port\n")); } } } if (i < 0) #endif /* DOT11Z_TDLS_SUPPORT */ { DBGPRINT(RT_DEBUG_TRACE, ("%s - P2P peer rtsp port get...\n", __FUNCTION__)); if (P2P_GO_ON(pAd) || P2P_CLI_ON(pAd)) { for (i=0; iMacTab.Content[i]; if (IS_P2P_GO_ENTRY(pEntry) || IS_P2P_CLI_ENTRY(pEntry)) { P2pIdx = P2pGroupTabSearch(pAd, pEntry->Addr); DBGPRINT(RT_DEBUG_TRACE, ("P2P Entry[%d][%02x:%02x:%02x:%02x:%02x:%02x]\n", pEntry->P2pInfo.p2pIndex, PRINT_MAC(pEntry->Addr))); DBGPRINT(RT_DEBUG_TRACE, ("RTSP_PORT = %d.\n", pAd->P2pTable.Client[pEntry->P2pInfo.p2pIndex].WfdEntryInfo.rtsp_port)); if (P2pIdx != P2P_NOT_FOUND) RtspPort = pAd->P2pTable.Client[P2pIdx].WfdEntryInfo.rtsp_port; else { RtspPort = WFD_RTSP_DEFAULT_PORT; DBGPRINT(RT_DEBUG_ERROR, ("OID_802_11_P2P_PEER_RTSP_PORT::P2P not found, use default RTSP port\n")); } if (pEntry->P2pInfo.p2pIndex < MAX_P2P_GROUP_SIZE) P2PPrintP2PEntry(pAd, pEntry->P2pInfo.p2pIndex); break; } } DBGPRINT(RT_DEBUG_TRACE, ("OID_802_11_P2P_PEER_RTSP_PORT bssid: %02x:%02x:%02x:%02x:%02x:%02x.\n", PRINT_MAC(pP2PCtrl->CurrentAddress))); } } DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_P2P_PEER_RTSP_PORT (=%d)\n", RtspPort)); return TRUE; } VOID WfdMakeWfdIE( IN PRTMP_ADAPTER pAd, IN UCHAR PacketType, OUT PUCHAR pOutBuf, OUT PULONG pIeLen) { PRT_WFD_CONFIG pWFDCtrl = &pAd->StaCfg.WfdCfg; UCHAR WfdIEFixed[6] = {0xdd, 0x0c, 0x50, 0x6f, 0x9a, 0x0a}; /* Length will be modified later */ PUCHAR pData, pBuf; ULONG TempLen; ULONG Len = 0; INT i = 0; pData = pOutBuf; *pIeLen = 0; if (!pWFDCtrl->bWfdEnable) return; RTMPMoveMemory(pData, &WfdIEFixed[0], 6); pData += 6; Len += 6; /* To append to WFD Device Information Subelement */ TempLen = InsertWfdSubelmtTlv(pAd, SUBID_WFD_DEVICE_INFO, NULL, pData, ACTION_WIFI_DIRECT); DBGPRINT(RT_DEBUG_INFO, ("%s(%d) ---->\n", __FUNCTION__, TempLen)); for (i=0; i\n", __FUNCTION__, TempLen)); for (i=0; i\n", __FUNCTION__, TempLen)); for (i=0; i\n", __FUNCTION__, TempLen)); for (i=0; iStaCfg.WfdCfg; PUCHAR pDest; ULONG Length, tmpValue = 0; USHORT EidLen = 0; pDest = pOutBuffer; RTMPZeroMemory(pDest, 255); *pDest = SubId; pDest += 1; Length = 0; switch (SubId) { case SUBID_WFD_DEVICE_INFO: { WFD_DEVICE_INFO DevInfo; PUSHORT pDevInfo = &DevInfo; RTMPZeroMemory(&DevInfo, sizeof(WFD_DEVICE_INFO)); EidLen = SUBID_WFD_DEVICE_INFO_LEN; tmpValue = cpu2be16(EidLen); RTMPMoveMemory(pDest, &tmpValue, 2); DevInfo.DeviceType = pWFDCtrl->DeviceType; DevInfo.SourceCoupled = pWFDCtrl->SourceCoupled; DevInfo.SinkCoupled = pWFDCtrl->SinkCoupled; DevInfo.SessionAvail = pWFDCtrl->SessionAvail; DevInfo.WSD = pWFDCtrl->WSD; if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) && (INFRA_ON(pAd))) DevInfo.PC = pWFDCtrl->PC; else DevInfo.PC = WFD_PC_P2P; DevInfo.CP = pWFDCtrl->CP; DevInfo.TimeSync = pWFDCtrl->TimeSync; /* RTMPMoveMemory(pDest + 1, &DevInfo, sizeof(WFD_DEVICE_INFO)); */ tmpValue = cpu2be16(*pDevInfo); RTMPMoveMemory((pDest + 2), &tmpValue, 2); tmpValue = cpu2be16(pWFDCtrl->RtspPort); RTMPMoveMemory((pDest + 4), &tmpValue, 2); tmpValue = cpu2be16(pWFDCtrl->MaxThroughput); RTMPMoveMemory((pDest + 6), &tmpValue, 2); Length = 9; break; } case SUBID_WFD_ASSOCIATED_BSSID: { UCHAR AllZero[MAC_ADDR_LEN] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; if ((Action == ACTION_GAS_INITIAL_REQ) || (Action == ACTION_GAS_INITIAL_RSP)) { EidLen = SUBID_WFD_ASSOCIATED_BSSID_LEN; tmpValue = cpu2be16(EidLen); RTMPMoveMemory(pDest, &tmpValue, 2); Length = EidLen + 3; if (!NdisEqualMemory(AllZero, pAd->CommonCfg.Bssid, MAC_ADDR_LEN) && (Action == ACTION_GAS_INITIAL_RSP)) { RTMPMoveMemory(pDest + 2, pAd->CommonCfg.Bssid, MAC_ADDR_LEN); } } else { if (!NdisEqualMemory(AllZero, pAd->CommonCfg.Bssid, MAC_ADDR_LEN)) { EidLen = SUBID_WFD_ASSOCIATED_BSSID_LEN; tmpValue = cpu2be16(EidLen); RTMPMoveMemory(pDest, &tmpValue, 2); RTMPMoveMemory(pDest + 2, pAd->CommonCfg.Bssid, MAC_ADDR_LEN); Length = EidLen + 3; } } break; } case SUBID_WFD_AUDIO_FORMATS: { if ((Action == ACTION_GAS_INITIAL_REQ) || (Action == ACTION_GAS_INITIAL_RSP)) { EidLen = SUBID_WFD_AUDIO_FORMATS_LEN; tmpValue = cpu2be16(EidLen); RTMPMoveMemory(pDest, &tmpValue, 2); Length = EidLen + 3; } break; } case SUBID_WFD_VIDEO_FORMATS: { if ((Action == ACTION_GAS_INITIAL_REQ) || (Action == ACTION_GAS_INITIAL_RSP)) { EidLen = SUBID_WFD_VIDEO_FORMATS_LEN; tmpValue = cpu2be16(EidLen); RTMPMoveMemory(pDest, &tmpValue, 2); Length = EidLen + 3; } break; } case SUBID_WFD_3D_VIDEO_FORMATS: { if ((Action == ACTION_GAS_INITIAL_REQ) || (Action == ACTION_GAS_INITIAL_RSP)) { EidLen = SUBID_WFD_3D_VIDEO_FORMATS_LEN; tmpValue = cpu2be16(EidLen); RTMPMoveMemory(pDest, &tmpValue, 2); Length = EidLen + 3; } break; } case SUBID_WFD_CONTENT_PROTECTION: { if ((Action == ACTION_GAS_INITIAL_REQ) || (Action == ACTION_GAS_INITIAL_RSP)) { EidLen = SUBID_WFD_CONTENT_PROTECTION_LEN; tmpValue = cpu2be16(EidLen); RTMPMoveMemory(pDest, &tmpValue, 2); Length = EidLen + 3; } break; } case SUBID_WFD_COUPLED_SINK_INFO: { // if ((pWFDCtrl->DeviceType != WFD_SOURCE ) && (pWFDCtrl->SinkCoupled == WFD_COUPLED_SUPPORT)) { WFD_COUPLED_SINK_INFO SinkInfo; RTMPZeroMemory(&SinkInfo, sizeof(WFD_COUPLED_SINK_INFO)); EidLen = SUBID_WFD_COUPLED_SINK_INFO_LEN; tmpValue = cpu2be16(EidLen); RTMPMoveMemory(pDest, &tmpValue, 2); SinkInfo.CoupledStat = pWFDCtrl->CoupledSinkStatus.CoupledStat; RTMPMoveMemory(pDest + 2, &SinkInfo, sizeof(WFD_COUPLED_SINK_INFO)); Length = EidLen + 3; } break; } case SUBID_WFD_EXTENDED_CAP: { if ((Action == ACTION_GAS_INITIAL_REQ) || (Action == ACTION_GAS_INITIAL_RSP)) { EidLen = SUBID_WFD_EXTENDED_CAP_LEN; tmpValue = cpu2be16(EidLen); RTMPMoveMemory(pDest, &tmpValue, 2); Length = EidLen + 3; } break; } case SUBID_WFD_LOCAL_IP_ADDR: { if ((Action == ACTION_GAS_INITIAL_REQ) || (Action == ACTION_GAS_INITIAL_RSP)) { EidLen = SUBID_WFD_LOCAL_IP_ADDR_LEN; tmpValue = cpu2be16(EidLen); RTMPMoveMemory(pDest, &tmpValue, 2); Length = EidLen + 3; } else { EidLen = SUBID_WFD_LOCAL_IP_ADDR_LEN; tmpValue = cpu2be16(EidLen); RTMPMoveMemory(pDest, &tmpValue, 2); RTMPMoveMemory(pDest + 2, &pWFDCtrl->wfd_serv_disc_query_info.wfd_local_ip_ie, SUBID_WFD_LOCAL_IP_ADDR_LEN); Length = EidLen + 3; } break; } case SUBID_WFD_SESSION_INFO: { INT i = 0, NumOfDev = 0; UCHAR P2pIdx = P2P_NOT_FOUND; PRT_P2P_TABLE Tab = &pAd->P2pTable; if (Action == ACTION_WIFI_DIRECT) { for (i = 1; i < MAX_LEN_OF_MAC_TABLE; i++) { MAC_TABLE_ENTRY *pEntry = &pAd->MacTab.Content[i]; P2pIdx = P2pGroupTabSearch(pAd, pEntry->Addr); if ((P2pIdx < MAX_P2P_GROUP_SIZE) && (Tab->Client[P2pIdx].WfdEntryInfo.bWfdClient == TRUE)) NumOfDev++; } EidLen = 24*NumOfDev; tmpValue = cpu2be16(EidLen); RTMPMoveMemory(pDest, &tmpValue, 2); DBGPRINT(RT_DEBUG_INFO, ("%s:: NumOfDev = %d, Len = %d\n", __FUNCTION__, NumOfDev, *pDest)); pDest+=2; for (i = 1; i < MAX_LEN_OF_MAC_TABLE; i++) { MAC_TABLE_ENTRY *pEntry = &pAd->MacTab.Content[i]; P2pIdx = P2pGroupTabSearch(pAd, pEntry->Addr); if ((P2pIdx < MAX_P2P_GROUP_SIZE) && (Tab->Client[P2pIdx].WfdEntryInfo.bWfdClient == TRUE)) { INT j = 0; WFD_SESSION_INFO SessionInfo; RTMPZeroMemory(&SessionInfo, sizeof(WFD_SESSION_INFO)); SessionInfo.Length = 23; RTMPMoveMemory(&SessionInfo.DeviceAddr[0], &pAd->P2pTable.Client[P2pIdx].addr[0], MAC_ADDR_LEN); RTMPMoveMemory(&SessionInfo.Bssid[0], &pAd->P2pTable.Client[P2pIdx].WfdEntryInfo.assoc_addr[0], MAC_ADDR_LEN); /* Below is the WFD Device Information */ SessionInfo.WfdDevInfo.DeviceType = pAd->P2pTable.Client[P2pIdx].WfdEntryInfo.wfd_devive_type; SessionInfo.WfdDevInfo.SourceCoupled = pAd->P2pTable.Client[P2pIdx].WfdEntryInfo.source_coupled; SessionInfo.WfdDevInfo.SinkCoupled = pAd->P2pTable.Client[P2pIdx].WfdEntryInfo.sink_coupled; SessionInfo.WfdDevInfo.SessionAvail = pAd->P2pTable.Client[P2pIdx].WfdEntryInfo.session_avail; SessionInfo.WfdDevInfo.WSD = pAd->P2pTable.Client[P2pIdx].WfdEntryInfo.wfd_service_discovery; SessionInfo.WfdDevInfo.PC = pAd->P2pTable.Client[P2pIdx].WfdEntryInfo.wfd_PC; SessionInfo.WfdDevInfo.TimeSync = pAd->P2pTable.Client[P2pIdx].WfdEntryInfo.wfd_time_sync; SessionInfo.MaxThroughput = pAd->P2pTable.Client[P2pIdx].WfdEntryInfo.max_throughput; SessionInfo.CoupledSinkInfo = pAd->P2pTable.Client[P2pIdx].WfdEntryInfo.coupled_sink_status; /* So far we cannot know the address of coupled devices, the coupled address will be filled "0" until WiFi Display spec. is ready for this part. */ RTMPMoveMemory(&SessionInfo.CoupledPeerAddr[0], &pAd->P2pTable.Client[P2pIdx].WfdEntryInfo.coupled_peer_addr[0], MAC_ADDR_LEN); RTMPMoveMemory(pDest, &SessionInfo, sizeof(WFD_SESSION_INFO)); for (j = 0; j < 24; j++) DBGPRINT(RT_DEBUG_INFO, ("%02x ", *(pDest+j))); DBGPRINT(RT_DEBUG_INFO, ("\n")); pDest += 24; } } Length = 24*NumOfDev + 3; } break; } case SUBID_WFD_ALTERNATE_MAC_ADDR: { UCHAR AllZero[MAC_ADDR_LEN] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; if ((Action == ACTION_GAS_INITIAL_REQ) || (Action == ACTION_GAS_INITIAL_RSP) || (Action == ACTION_WIFI_DIRECT)) { EidLen = SUBID_WFD_ALTERNATE_MAC_ADDR_LEN; *((PUSHORT) (pDest)) = cpu2be16(EidLen); Length = EidLen + 3; if (!NdisEqualMemory(AllZero, pAd->CurrentAddress, MAC_ADDR_LEN) && (Action == ACTION_GAS_INITIAL_RSP)) { RTMPMoveMemory(pDest + 2, pAd->CurrentAddress, MAC_ADDR_LEN); } } else { if (!NdisEqualMemory(AllZero, pAd->CurrentAddress, MAC_ADDR_LEN)) { EidLen = SUBID_WFD_ALTERNATE_MAC_ADDR_LEN; *((PUSHORT) (pDest)) = cpu2be16(EidLen); RTMPMoveMemory(pDest + 2, pAd->CurrentAddress, MAC_ADDR_LEN); Length = EidLen + 3; } } break; } default: *pDest = 0; Length = 0; break; } return Length; } VOID WfdParseSubElmt( IN PRTMP_ADAPTER pAd, IN PWFD_ENTRY_INFO pWfdEntryInfo, IN VOID *Msg, IN ULONG MsgLen) { PWFD_COUPLED_SINK_INFO pSinkInfo; PWFD_DEVICE_INFO pWfd_info; WFD_DEVICE_INFO DevInfo; PP2PEID_STRUCT pWfdEid; PEID_STRUCT pEid; PUCHAR pWfdIe = NULL; ULONG AccuWfdIELen; ULONG AccuIeLen = 0; ULONG Length = 0; ULONG AttriLen; UCHAR offset; BOOLEAN bTdlsEntry = FALSE; DBGPRINT(RT_DEBUG_INFO, ("%s ----->\n", __FUNCTION__)); //QQ TBD, p2p widi need to parse rtsp port! #ifdef WFA_WFD_SUPPORT if (pAd->P2pCfg.bWIDI == FALSE) #endif { if ((!pAd->StaCfg.WfdCfg.bWfdEnable) || (MsgLen == 0)) return; } // hex_dump("WfdParseSubElmt::", Msg, MsgLen); pEid = (PEID_STRUCT)Msg; AccuIeLen = pEid->Len + 2; // printk("MsgLen = %d. AccuIeLen = %d.\n", MsgLen, AccuIeLen); while ((ULONG)(AccuIeLen) <= MsgLen) { if (RTMPEqualMemory(&pEid->Octet[0], WIFIDISPLAY_OUI, 4)) { /* Get Request content capability */ pWfdIe = pWfdEid = (PP2PEID_STRUCT) &pEid->Octet[4]; AccuWfdIELen = pEid->Len; // printk("AccuWfdIeLen = %d. EidLen = %04x\n", AccuWfdIELen, pEid->Len); /* The value of AccuP2PIELen shall reduce the length of OUI (4) */ AccuWfdIELen -= 4; AttriLen = pWfdEid->Len[1] + (pWfdEid->Len[0] << 8); Length = 0; // printk("AttriLen = %d. WfdEid = %d. WfdEidLen = %x %x\n", AttriLen, pWfdEid->Eid, pWfdEid->Len[1], pWfdEid->Len[0]); pWfdEntryInfo->bWfdClient = TRUE; /* Set the P2P client as the WFD device */ // while (Length <=(Length + 3 + AttriLen) <= AccuWfdIELen) while (Length <= AccuWfdIELen) { // printk(">> Eid = %d.\n", pWfdEid->Eid); switch (pWfdEid->Eid) { case SUBID_WFD_DEVICE_INFO: { pWfd_info = &(pWfdEid->Octet[0]); RTMPMoveMemory(&DevInfo, pWfdIe, sizeof(WFD_DEVICE_INFO)); RTMPMoveMemory(&pWfdEntryInfo->wfd_serv_disc_query_info.wfd_device_info_ie, pWfdEid->Octet, SUBID_WFD_DEVICE_INFO_LEN); cpu2le16(&DevInfo); pWfdEntryInfo->wfd_devive_type = ((be2cpu16(get_unaligned((PUSHORT)(&pWfdEid->Octet[0]))) >> 0) & 0x3); pWfdEntryInfo->source_coupled = ((be2cpu16(get_unaligned((PUSHORT)(&pWfdEid->Octet[0]))) >> 2) & 0x1); pWfdEntryInfo->sink_coupled = ((be2cpu16(get_unaligned((PUSHORT)(&pWfdEid->Octet[0]))) >> 3) & 0x1); pWfdEntryInfo->session_avail = ((be2cpu16(get_unaligned((PUSHORT)(&pWfdEid->Octet[0]))) >> 4) & 0x3); pWfdEntryInfo->wfd_service_discovery = ((be2cpu16(get_unaligned((PUSHORT)(&pWfdEid->Octet[0]))) >> 6) & 0x1); pWfdEntryInfo->wfd_PC = ((be2cpu16(get_unaligned((PUSHORT)(&pWfdEid->Octet[0]))) >> 7) & 0x1); pWfdEntryInfo->wfd_CP = ((be2cpu16(get_unaligned((PUSHORT)(&pWfdEid->Octet[0]))) >> 8) & 0x1); pWfdEntryInfo->wfd_time_sync = ((be2cpu16(get_unaligned((PUSHORT)(&pWfdEid->Octet[0]))) >> 9) & 0x1); pWfdEntryInfo->sink_audio_unsupport = ((be2cpu16(get_unaligned((PUSHORT)(&pWfdEid->Octet[0]))) >> 10) & 0x1); pWfdEntryInfo->source_audio_only= ((be2cpu16(get_unaligned((PUSHORT)(&pWfdEid->Octet[0]))) >> 11) & 0x1); pWfdEntryInfo->tdls_persistent_group = ((be2cpu16(get_unaligned((PUSHORT)(&pWfdEid->Octet[0]))) >> 12) & 0x1); pWfdEntryInfo->rtsp_port = be2cpu16(get_unaligned((PUSHORT)(&pWfdEid->Octet[2]))); pWfdEntryInfo->max_throughput = be2cpu16(get_unaligned((PUSHORT)(&pWfdEid->Octet[4]))); DBGPRINT(RT_DEBUG_INFO, ("%s::SUBID_WFD_DEVICE_INFO\n", __FUNCTION__)); break; } case SUBID_WFD_ASSOCIATED_BSSID: { RTMPMoveMemory(&pWfdEntryInfo->wfd_serv_disc_query_info.wfd_associate_bssid_ie, pWfdEid->Octet, SUBID_WFD_ASSOCIATED_BSSID_LEN); RTMPMoveMemory(&pWfdEntryInfo->assoc_addr, pWfdEid->Octet, MAC_ADDR_LEN); DBGPRINT(RT_DEBUG_INFO, ("%s::SUBID_WFD_ASSOCIATED_BSSID\n", __FUNCTION__)); break; } case SUBID_WFD_AUDIO_FORMATS: { RTMPMoveMemory(&pWfdEntryInfo->wfd_serv_disc_query_info.wfd_audio_format_ie, pWfdEid->Octet, SUBID_WFD_AUDIO_FORMATS_LEN); DBGPRINT(RT_DEBUG_INFO, ("%s::SUBID_WFD_AUDIO_FORMATS\n", __FUNCTION__)); break; } case SUBID_WFD_VIDEO_FORMATS: { RTMPMoveMemory(&pWfdEntryInfo->wfd_serv_disc_query_info.wfd_video_format_ie, pWfdEid->Octet, SUBID_WFD_VIDEO_FORMATS_LEN); DBGPRINT(RT_DEBUG_INFO, ("%s::SUBID_WFD_VIDEO_FORMATS\n", __FUNCTION__)); break; } case SUBID_WFD_3D_VIDEO_FORMATS: { RTMPMoveMemory(&pWfdEntryInfo->wfd_serv_disc_query_info.wfd_3d_video_format_ie, pWfdEid->Octet, SUBID_WFD_3D_VIDEO_FORMATS_LEN); DBGPRINT(RT_DEBUG_INFO, ("%s::SUBID_WFD_3D_VIDEO_FORMATS\n", __FUNCTION__)); break; } case SUBID_WFD_CONTENT_PROTECTION: { RTMPMoveMemory(&pWfdEntryInfo->wfd_serv_disc_query_info.wfd_content_proctection, pWfdEid->Octet, SUBID_WFD_CONTENT_PROTECTION_LEN); DBGPRINT(RT_DEBUG_INFO, ("%s::SUBID_WFD_CONTENT_PROTECTION\n", __FUNCTION__)); break; } case SUBID_WFD_COUPLED_SINK_INFO: { RTMPMoveMemory(&pWfdEntryInfo->wfd_serv_disc_query_info.wfd_couple_sink_info_ie, pWfdEid->Octet, SUBID_WFD_COUPLED_SINK_INFO_LEN); RTMPMoveMemory(&pWfdEntryInfo->coupled_sink_status, pWfdEid->Octet, SUBID_WFD_COUPLED_SINK_INFO_LEN); DBGPRINT(RT_DEBUG_INFO, ("%s::SUBID_WFD_COUPLED_SINK_INFO\n", __FUNCTION__)); break; } case SUBID_WFD_EXTENDED_CAP: { RTMPMoveMemory(&pWfdEntryInfo->wfd_serv_disc_query_info.wfd_extent_capability_ie, &pWfdEid->Octet, SUBID_WFD_EXTENDED_CAP_LEN); DBGPRINT(RT_DEBUG_INFO, ("%s::SUBID_WFD_EXTENDED_CAP\n", __FUNCTION__)); break; } case SUBID_WFD_LOCAL_IP_ADDR: { RTMPMoveMemory(&pWfdEntryInfo->wfd_serv_disc_query_info.wfd_local_ip_ie, &pWfdEid->Octet, SUBID_WFD_LOCAL_IP_ADDR_LEN); DBGPRINT(RT_DEBUG_INFO, ("%s::SUBID_WFD_LOCAL_IP_ADDR\n", __FUNCTION__)); break; } case SUBID_WFD_SESSION_INFO: { /* TODO : allocate memory to store the parsed WFD device tables */ RTMPMoveMemory(&pWfdEntryInfo->wfd_serv_disc_query_info.wfd_session_info_ie, &pWfdEid->Octet, SUBID_WFD_DEVICE_INFO_LEN); DBGPRINT(RT_DEBUG_INFO, ("%s::SUBID_WFD_SESSION_INFO\n", __FUNCTION__)); break; } case SUBID_WFD_ALTERNATE_MAC_ADDR: { RTMPMoveMemory(&pWfdEntryInfo->wfd_serv_disc_query_info.wfd_alternate_mac_addr_ie, &pWfdEid->Octet, SUBID_WFD_ALTERNATE_MAC_ADDR_LEN); DBGPRINT(RT_DEBUG_INFO, ("%s::SUBID_WFD_ALTERNATE_MAC_ADDR\n", __FUNCTION__)); break; } default: DBGPRINT(RT_DEBUG_ERROR, (" SUBID_WFD_ unknown Eid = %x \n", pWfdEid->Eid)); hex_dump("WfdParseSubElement::", Msg, MsgLen); break; } // printk("<< Length = %d. AttriLen = %d. AccuWfdIELen = %d.\n", Length, AttriLen, AccuWfdIELen); Length = Length + 3 + AttriLen; /* Eid[1] + Len[2] + content[Len] */ // printk(">> Length = %d. AttriLen = %d. AccuWfdIELen = %d.\n", Length, AttriLen, AccuWfdIELen); if (Length >= AccuWfdIELen) break; pWfdEid = (PP2PEID_STRUCT)((UCHAR*)pWfdEid + 3 + AttriLen); AttriLen = pWfdEid->Len[1] + (pWfdEid->Len[0] << 8); } } /* Already reach the final IE and stop finding next Eid. */ if (AccuIeLen >= MsgLen) break; /* Forward buffer to next pEid */ if (RTMPEqualMemory(&pEid->Octet[0], WIFIDISPLAY_OUI, 4)) { pEid = (PEID_STRUCT)((UCHAR*)pEid + pEid->Len + 2); } /* Since we get the next pEid, Predict the accumulated IeLen after adding the next pEid's length. The accumulated IeLen is for checking length. */ if (RTMPEqualMemory(&pEid->Octet[0], WIFIDISPLAY_OUI, 4)) { AccuIeLen += (pEid->Len + 2); } } return; } VOID WfdCfgInit( IN PRTMP_ADAPTER pAd) { PRT_WFD_CONFIG pWfdcfg = &pAd->StaCfg.WfdCfg; RTMPZeroMemory(&pAd->StaCfg.WfdCfg, sizeof(RT_WFD_CONFIG)); pWfdcfg->bWfdEnable = FALSE; pWfdcfg->DeviceType = WFD_PRIMARY_SINK; pWfdcfg->SessionAvail = WFD_SESSION_AVAILABLE; pWfdcfg->PeerSessionAvail = WFD_SESSION_AVAILABLE; pWfdcfg->PeerPC = WFD_PC_TDLS; pWfdcfg->TdlsSecurity = WFD_TDLS_STRONG_SECURITY; pWfdcfg->RtspPort = WFD_RTSP_DEFAULT_PORT; } #endif /* WFD_SUPPORT */