| /* |
| * *************************************************************************** |
| * FILE: unifi_event.c |
| * |
| * PURPOSE: |
| * Process the signals received by UniFi. |
| * It is part of the porting exercise. |
| * |
| * Copyright (C) 2009 by Cambridge Silicon Radio Ltd. |
| * |
| * Refer to LICENSE.txt included with this source code for details on |
| * the license terms. |
| * |
| * *************************************************************************** |
| */ |
| |
| |
| /* |
| * Porting notes: |
| * The implementation of unifi_receive_event() in Linux is fairly complicated. |
| * The linux driver support multiple userspace applications and several |
| * build configurations, so the received signals are processed by different |
| * processes and multiple times. |
| * In a simple implementation, this function needs to deliver: |
| * - The MLME-UNITDATA.ind signals to the Rx data plane and to the Traffic |
| * Analysis using unifi_ta_sample(). |
| * - The MLME-UNITDATA-STATUS.ind signals to the Tx data plane. |
| * - All the other signals to the SME using unifi_sys_hip_ind(). |
| */ |
| |
| #include "csr_wifi_hip_unifi.h" |
| #include "csr_wifi_hip_conversions.h" |
| #include "unifi_priv.h" |
| |
| |
| /* |
| * --------------------------------------------------------------------------- |
| * send_to_client |
| * |
| * Helper for unifi_receive_event. |
| * |
| * This function forwards a signal to one client. |
| * |
| * Arguments: |
| * priv Pointer to driver's private data. |
| * client Pointer to the client structure. |
| * receiver_id The reciever id of the signal. |
| * sigdata Pointer to the packed signal buffer. |
| * siglen Length of the packed signal. |
| * bulkdata Pointer to the signal's bulk data. |
| * |
| * Returns: |
| * None. |
| * |
| * --------------------------------------------------------------------------- |
| */ |
| static void send_to_client(unifi_priv_t *priv, ul_client_t *client, |
| int receiver_id, |
| unsigned char *sigdata, int siglen, |
| const bulk_data_param_t *bulkdata) |
| { |
| if (client && client->event_hook) { |
| /*unifi_trace(priv, UDBG3, |
| "Receive: client %d, (s:0x%X, r:0x%X) - Signal 0x%.4X \n", |
| client->client_id, client->sender_id, receiver_id, |
| CSR_GET_UINT16_FROM_LITTLE_ENDIAN(sigdata));*/ |
| |
| client->event_hook(client, sigdata, siglen, bulkdata, UDI_TO_HOST); |
| } |
| } |
| |
| /* |
| * --------------------------------------------------------------------------- |
| * process_pkt_data_ind |
| * |
| * Dispatcher for received signals. |
| * |
| * This function receives the 'to host' signals and forwards |
| * them to the unifi linux clients. |
| * |
| * Arguments: |
| * priv Context |
| * sigdata Pointer to the packed signal buffer(Its in form of MA-PACKET.ind). |
| * bulkdata Pointer to signal's bulkdata |
| * freeBulkData Pointer to a flag which gets set if the bulkdata needs to |
| * be freed after calling the logging handlers. If it is not |
| * set the bulkdata must be freed by the MLME handler or |
| * passed to the network stack. |
| * Returns: |
| * TRUE if the packet should be routed to the SME etc. |
| * FALSE if the packet is for the driver or network stack |
| * --------------------------------------------------------------------------- |
| */ |
| static u8 check_routing_pkt_data_ind(unifi_priv_t *priv, |
| u8 *sigdata, |
| const bulk_data_param_t* bulkdata, |
| u8 *freeBulkData, |
| netInterface_priv_t *interfacePriv) |
| { |
| u16 frmCtrl, receptionStatus, frmCtrlSubType; |
| u8 *macHdrLocation; |
| u8 interfaceTag; |
| u8 isDataFrame; |
| u8 isProtocolVerInvalid = FALSE; |
| u8 isDataFrameSubTypeNoData = FALSE; |
| |
| #ifdef CSR_WIFI_SECURITY_WAPI_ENABLE |
| static const u8 wapiProtocolIdSNAPHeader[] = {0x88,0xb4}; |
| static const u8 wapiProtocolIdSNAPHeaderOffset = 6; |
| u8 *destAddr; |
| u8 *srcAddr; |
| u8 isWapiUnicastPkt = FALSE; |
| |
| #ifdef CSR_WIFI_SECURITY_WAPI_QOSCTRL_MIC_WORKAROUND |
| u16 qosControl; |
| #endif |
| |
| u8 llcSnapHeaderOffset = 0; |
| |
| destAddr = (u8 *) bulkdata->d[0].os_data_ptr + MAC_HEADER_ADDR1_OFFSET; |
| srcAddr = (u8 *) bulkdata->d[0].os_data_ptr + MAC_HEADER_ADDR2_OFFSET; |
| |
| /*Individual/Group bit - Bit 0 of first byte*/ |
| isWapiUnicastPkt = (!(destAddr[0] & 0x01)) ? TRUE : FALSE; |
| #endif |
| |
| #define CSR_WIFI_MA_PKT_IND_RECEPTION_STATUS_OFFSET sizeof(CSR_SIGNAL_PRIMITIVE_HEADER) + 22 |
| |
| *freeBulkData = FALSE; |
| |
| /* Fetch the MAC header location from MA_PKT_IND packet */ |
| macHdrLocation = (u8 *) bulkdata->d[0].os_data_ptr; |
| /* Fetch the Frame Control value from MAC header */ |
| frmCtrl = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(macHdrLocation); |
| |
| /* Pull out interface tag from virtual interface identifier */ |
| interfaceTag = (CSR_GET_UINT16_FROM_LITTLE_ENDIAN(sigdata + 14)) & 0xff; |
| |
| /* check for MIC failure before processing the signal */ |
| receptionStatus = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(sigdata + CSR_WIFI_MA_PKT_IND_RECEPTION_STATUS_OFFSET); |
| |
| /* To discard any spurious MIC failures that could be reported by the firmware */ |
| isDataFrame = ((frmCtrl & IEEE80211_FC_TYPE_MASK) == (IEEE802_11_FC_TYPE_DATA & IEEE80211_FC_TYPE_MASK)) ? TRUE : FALSE; |
| /* 0x00 is the only valid protocol version*/ |
| isProtocolVerInvalid = (frmCtrl & IEEE80211_FC_PROTO_VERSION_MASK) ? TRUE : FALSE; |
| frmCtrlSubType = (frmCtrl & IEEE80211_FC_SUBTYPE_MASK) >> FRAME_CONTROL_SUBTYPE_FIELD_OFFSET; |
| /*Exclude the no data & reserved sub-types from MIC failure processing*/ |
| isDataFrameSubTypeNoData = (((frmCtrlSubType>0x03)&&(frmCtrlSubType<0x08)) || (frmCtrlSubType>0x0B)) ? TRUE : FALSE; |
| if ((receptionStatus == CSR_MICHAEL_MIC_ERROR) && |
| ((!isDataFrame) || isProtocolVerInvalid || (isDataFrame && isDataFrameSubTypeNoData))) { |
| /* Currently MIC errors are discarded for frames other than data frames. This might need changing when we start |
| * supporting 802.11w (Protected Management frames) |
| */ |
| *freeBulkData = TRUE; |
| unifi_trace(priv, UDBG4, "Discarding this frame and ignoring the MIC failure as this is a garbage/non-data/no data frame\n"); |
| return FALSE; |
| } |
| |
| #ifdef CSR_WIFI_SECURITY_WAPI_ENABLE |
| |
| if (receptionStatus == CSR_MICHAEL_MIC_ERROR) { |
| |
| if (interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_STA) { |
| |
| #ifdef CSR_WIFI_SECURITY_WAPI_QOSCTRL_MIC_WORKAROUND |
| if ((isDataFrame) && |
| ((IEEE802_11_FC_TYPE_QOS_DATA & IEEE80211_FC_SUBTYPE_MASK) == (frmCtrl & IEEE80211_FC_SUBTYPE_MASK)) && |
| (priv->isWapiConnection)) |
| { |
| qosControl = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(macHdrLocation + (((frmCtrl & IEEE802_11_FC_TO_DS_MASK) && (frmCtrl & IEEE802_11_FC_FROM_DS_MASK)) ? 30 : 24) ); |
| |
| unifi_trace(priv, UDBG4, "check_routing_pkt_data_ind() :: Value of the QoS control field - 0x%04x \n", qosControl); |
| |
| if (qosControl & IEEE802_11_QC_NON_TID_BITS_MASK) |
| { |
| unifi_trace(priv, UDBG4, "Ignore the MIC failure and pass the MPDU to the stack when any of bits [4-15] is set in the QoS control field\n"); |
| |
| /*Exclude the MIC [16] and the PN [16] that are appended by the firmware*/ |
| ((bulk_data_param_t*)bulkdata)->d[0].data_length = bulkdata->d[0].data_length - 32; |
| |
| /*Clear the reception status of the signal (CSR_RX_SUCCESS)*/ |
| *(sigdata + CSR_WIFI_MA_PKT_IND_RECEPTION_STATUS_OFFSET) = 0x00; |
| *(sigdata + CSR_WIFI_MA_PKT_IND_RECEPTION_STATUS_OFFSET+1) = 0x00; |
| |
| *freeBulkData = FALSE; |
| |
| return FALSE; |
| } |
| } |
| #endif |
| /* If this MIC ERROR reported by the firmware is either for |
| * [1] a WAPI Multicast MPDU and the Multicast filter has NOT been set (It is set only when group key index (MSKID) = 1 in Group Rekeying) OR |
| * [2] a WAPI Unicast MPDU and either the CONTROL PORT is open or the WAPI Unicast filter or filter(s) is NOT set |
| * then report a MIC FAILURE indication to the SME. |
| */ |
| #ifndef CSR_WIFI_SECURITY_WAPI_SW_ENCRYPTION |
| if ((priv->wapi_multicast_filter == 0) || isWapiUnicastPkt) { |
| #else |
| /*When SW encryption is enabled and USKID=1 (wapi_unicast_filter = 1), we are expected |
| *to receive MIC failure INDs for unicast MPDUs*/ |
| if ( ((priv->wapi_multicast_filter == 0) && !isWapiUnicastPkt) || |
| ((priv->wapi_unicast_filter == 0) && isWapiUnicastPkt) ) { |
| #endif |
| /*Discard the frame*/ |
| *freeBulkData = TRUE; |
| unifi_trace(priv, UDBG4, "Discarding the contents of the frame with MIC failure \n"); |
| |
| if (isWapiUnicastPkt && |
| ((uf_sme_port_state(priv,srcAddr,UF_CONTROLLED_PORT_Q,interfaceTag) != CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_OPEN)|| |
| #ifndef CSR_WIFI_SECURITY_WAPI_SW_ENCRYPTION |
| (priv->wapi_unicast_filter) || |
| #endif |
| (priv->wapi_unicast_queued_pkt_filter))) { |
| |
| /* Workaround to handle MIC failures reported by the firmware for encrypted packets from the AP |
| * while we are in the process of re-association induced by unsupported WAPI Unicast key index |
| * - Discard the packets with MIC failures "until" we have |
| * a. negotiated a key, |
| * b. opened the CONTROL PORT and |
| * c. the AP has started using the new key |
| */ |
| unifi_trace(priv, UDBG4, "Ignoring the MIC failure as either a. CONTROL PORT isn't OPEN or b. Unicast filter is set or c. WAPI AP using old key for buffered pkts\n"); |
| |
| /*Ignore this MIC failure*/ |
| return FALSE; |
| |
| }/*WAPI re-key specific workaround*/ |
| |
| unifi_trace(priv, UDBG6, "check_routing_pkt_data_ind - MIC FAILURE : interfaceTag %x Src Addr %x:%x:%x:%x:%x:%x\n", |
| interfaceTag, srcAddr[0], srcAddr[1], srcAddr[2], srcAddr[3], srcAddr[4], srcAddr[5]); |
| unifi_trace(priv, UDBG6, "check_routing_pkt_data_ind - MIC FAILURE : Dest Addr %x:%x:%x:%x:%x:%x\n", |
| destAddr[0], destAddr[1], destAddr[2], destAddr[3], destAddr[4], destAddr[5]); |
| unifi_trace(priv, UDBG6, "check_routing_pkt_data_ind - MIC FAILURE : Control Port State - 0x%.4X \n", |
| uf_sme_port_state(priv,srcAddr,UF_CONTROLLED_PORT_Q,interfaceTag)); |
| |
| unifi_error(priv, "MIC failure in %s\n", __FUNCTION__); |
| |
| /*Report the MIC failure to the SME*/ |
| return TRUE; |
| } |
| }/* STA mode */ |
| else { |
| /* Its AP Mode . Just Return */ |
| *freeBulkData = TRUE; |
| unifi_error(priv, "MIC failure in %s\n", __FUNCTION__); |
| return TRUE; |
| } /* AP mode */ |
| }/* MIC error */ |
| #else |
| if (receptionStatus == CSR_MICHAEL_MIC_ERROR) { |
| *freeBulkData = TRUE; |
| unifi_error(priv, "MIC failure in %s\n", __FUNCTION__); |
| return TRUE; |
| } |
| #endif /*CSR_WIFI_SECURITY_WAPI_ENABLE*/ |
| |
| unifi_trace(priv, UDBG4, "frmCtrl = 0x%04x %s\n", |
| frmCtrl, |
| (((frmCtrl & 0x000c)>>FRAME_CONTROL_TYPE_FIELD_OFFSET) == IEEE802_11_FRAMETYPE_MANAGEMENT) ? |
| "Mgt" : "Ctrl/Data"); |
| |
| #ifdef CSR_WIFI_SECURITY_WAPI_ENABLE |
| /* To ignore MIC failures reported due to the WAPI AP using the old key for queued packets before |
| * starting to use the new key negotiated as part of unicast re-keying |
| */ |
| if ((interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_STA)&& |
| isWapiUnicastPkt && |
| (receptionStatus == CSR_RX_SUCCESS) && |
| (priv->wapi_unicast_queued_pkt_filter==1)) { |
| |
| unifi_trace(priv, UDBG6, "check_routing_pkt_data_ind(): WAPI unicast pkt received when the (wapi_unicast_queued_pkt_filter) is set\n"); |
| |
| if (isDataFrame) { |
| switch(frmCtrl & IEEE80211_FC_SUBTYPE_MASK) { |
| case IEEE802_11_FC_TYPE_QOS_DATA & IEEE80211_FC_SUBTYPE_MASK: |
| llcSnapHeaderOffset = MAC_HEADER_SIZE + 2; |
| break; |
| case IEEE802_11_FC_TYPE_QOS_NULL & IEEE80211_FC_SUBTYPE_MASK: |
| case IEEE802_11_FC_TYPE_NULL & IEEE80211_FC_SUBTYPE_MASK: |
| break; |
| default: |
| llcSnapHeaderOffset = MAC_HEADER_SIZE; |
| } |
| } |
| |
| if (llcSnapHeaderOffset > 0) { |
| /* QoS data or Data */ |
| unifi_trace(priv, UDBG6, "check_routing_pkt_data_ind(): SNAP header found & its offset %d\n",llcSnapHeaderOffset); |
| if (memcmp((u8 *)(bulkdata->d[0].os_data_ptr+llcSnapHeaderOffset+wapiProtocolIdSNAPHeaderOffset), |
| wapiProtocolIdSNAPHeader,sizeof(wapiProtocolIdSNAPHeader))) { |
| |
| unifi_trace(priv, UDBG6, "check_routing_pkt_data_ind(): This is a data & NOT a WAI protocol packet\n"); |
| /* On the first unicast data pkt that is decrypted successfully after re-keying, reset the filter */ |
| priv->wapi_unicast_queued_pkt_filter = 0; |
| unifi_trace(priv, UDBG4, "check_routing_pkt_data_ind(): WAPI AP has started using the new unicast key, no more MIC failures expected (reset filter)\n"); |
| } |
| else { |
| unifi_trace(priv, UDBG6, "check_routing_pkt_data_ind(): WAPI - This is a WAI protocol packet\n"); |
| } |
| } |
| } |
| #endif |
| |
| |
| switch ((frmCtrl & 0x000c)>>FRAME_CONTROL_TYPE_FIELD_OFFSET) { |
| case IEEE802_11_FRAMETYPE_MANAGEMENT: |
| *freeBulkData = TRUE; /* Free (after SME handler copies it) */ |
| |
| /* In P2P device mode, filter the legacy AP beacons here */ |
| if((interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2P)&&\ |
| ((CSR_WIFI_80211_GET_FRAME_SUBTYPE(macHdrLocation)) == CSR_WIFI_80211_FRAME_SUBTYPE_BEACON)){ |
| |
| u8 *pSsid, *pSsidLen; |
| static u8 P2PWildCardSsid[CSR_WIFI_P2P_WILDCARD_SSID_LENGTH] = {'D', 'I', 'R', 'E', 'C', 'T', '-'}; |
| |
| pSsidLen = macHdrLocation + MAC_HEADER_SIZE + CSR_WIFI_BEACON_FIXED_LENGTH; |
| pSsid = pSsidLen + 2; |
| |
| if(*(pSsidLen + 1) >= CSR_WIFI_P2P_WILDCARD_SSID_LENGTH){ |
| if(memcmp(pSsid, P2PWildCardSsid, CSR_WIFI_P2P_WILDCARD_SSID_LENGTH) == 0){ |
| unifi_trace(priv, UDBG6, "Received a P2P Beacon, pass it to SME\n"); |
| return TRUE; |
| } |
| } |
| unifi_trace(priv, UDBG6, "Received a Legacy AP beacon in P2P mode, drop it\n"); |
| return FALSE; |
| } |
| return TRUE; /* Route to SME */ |
| case IEEE802_11_FRAMETYPE_DATA: |
| case IEEE802_11_FRAMETYPE_CONTROL: |
| *freeBulkData = FALSE; /* Network stack or MLME handler frees */ |
| return FALSE; |
| default: |
| unifi_error(priv, "Unhandled frame type %04x\n", frmCtrl); |
| *freeBulkData = TRUE; /* Not interested, but must free it */ |
| return FALSE; |
| } |
| } |
| |
| /* |
| * --------------------------------------------------------------------------- |
| * unifi_process_receive_event |
| * |
| * Dispatcher for received signals. |
| * |
| * This function receives the 'to host' signals and forwards |
| * them to the unifi linux clients. |
| * |
| * Arguments: |
| * ospriv Pointer to driver's private data. |
| * sigdata Pointer to the packed signal buffer. |
| * siglen Length of the packed signal. |
| * bulkdata Pointer to the signal's bulk data. |
| * |
| * Returns: |
| * None. |
| * |
| * Notes: |
| * The signals are received in the format described in the host interface |
| * specification, i.e wire formatted. Certain clients use the same format |
| * to interpret them and other clients use the host formatted structures. |
| * Each client has to call read_unpack_signal() to transform the wire |
| * formatted signal into the host formatted signal, if necessary. |
| * The code is in the core, since the signals are defined therefore |
| * binded to the host interface specification. |
| * --------------------------------------------------------------------------- |
| */ |
| static void |
| unifi_process_receive_event(void *ospriv, |
| u8 *sigdata, u32 siglen, |
| const bulk_data_param_t *bulkdata) |
| { |
| unifi_priv_t *priv = (unifi_priv_t*)ospriv; |
| int i, receiver_id; |
| int client_id; |
| s16 signal_id; |
| u8 pktIndToSme = FALSE, freeBulkData = FALSE; |
| |
| func_enter(); |
| |
| unifi_trace(priv, UDBG5, "unifi_process_receive_event: " |
| "%04x %04x %04x %04x %04x %04x %04x %04x (%d)\n", |
| CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(s16)*0) & 0xFFFF, |
| CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(s16)*1) & 0xFFFF, |
| CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(s16)*2) & 0xFFFF, |
| CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(s16)*3) & 0xFFFF, |
| CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(s16)*4) & 0xFFFF, |
| CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(s16)*5) & 0xFFFF, |
| CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(s16)*6) & 0xFFFF, |
| CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(s16)*7) & 0xFFFF, |
| siglen); |
| |
| receiver_id = CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(s16)) & 0xFF00; |
| client_id = (receiver_id & 0x0F00) >> UDI_SENDER_ID_SHIFT; |
| signal_id = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(sigdata); |
| |
| |
| |
| /* check for the type of frame received (checks for 802.11 management frames) */ |
| if (signal_id == CSR_MA_PACKET_INDICATION_ID) |
| { |
| #define CSR_MA_PACKET_INDICATION_INTERFACETAG_OFFSET 14 |
| u8 interfaceTag; |
| netInterface_priv_t *interfacePriv; |
| |
| /* Pull out interface tag from virtual interface identifier */ |
| interfaceTag = (CSR_GET_UINT16_FROM_LITTLE_ENDIAN(sigdata + CSR_MA_PACKET_INDICATION_INTERFACETAG_OFFSET)) & 0xff; |
| interfacePriv = priv->interfacePriv[interfaceTag]; |
| |
| /* Update activity for this station in case of IBSS */ |
| #ifdef CSR_SUPPORT_SME |
| if (interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_IBSS) |
| { |
| u8 *saddr; |
| /* Fetch the source address from mac header */ |
| saddr = (u8 *) bulkdata->d[0].os_data_ptr + MAC_HEADER_ADDR2_OFFSET; |
| unifi_trace(priv, UDBG5, |
| "Updating sta activity in IBSS interfaceTag %x Src Addr %x:%x:%x:%x:%x:%x\n", |
| interfaceTag, saddr[0], saddr[1], saddr[2], saddr[3], saddr[4], saddr[5]); |
| |
| uf_update_sta_activity(priv, interfaceTag, saddr); |
| } |
| #endif |
| |
| pktIndToSme = check_routing_pkt_data_ind(priv, sigdata, bulkdata, &freeBulkData, interfacePriv); |
| |
| unifi_trace(priv, UDBG6, "RX: packet entry point to driver from HIP,pkt to SME ?(%s) \n", (pktIndToSme)? "YES":"NO"); |
| |
| } |
| |
| if (pktIndToSme) |
| { |
| /* Management MA_PACKET_IND for SME */ |
| if(sigdata != NULL && bulkdata != NULL){ |
| send_to_client(priv, priv->sme_cli, receiver_id, sigdata, siglen, bulkdata); |
| } |
| else{ |
| unifi_error(priv, "unifi_receive_event2: sigdata or Bulkdata is NULL \n"); |
| } |
| #ifdef CSR_NATIVE_LINUX |
| send_to_client(priv, priv->wext_client, |
| receiver_id, |
| sigdata, siglen, bulkdata); |
| #endif |
| } |
| else |
| { |
| /* Signals with ReceiverId==0 are also reported to SME / WEXT, |
| * unless they are data/control MA_PACKET_INDs or VIF_AVAILABILITY_INDs |
| */ |
| if (!receiver_id) { |
| if(signal_id == CSR_MA_VIF_AVAILABILITY_INDICATION_ID) { |
| uf_process_ma_vif_availibility_ind(priv, sigdata, siglen); |
| } |
| else if (signal_id != CSR_MA_PACKET_INDICATION_ID) { |
| send_to_client(priv, priv->sme_cli, receiver_id, sigdata, siglen, bulkdata); |
| #ifdef CSR_NATIVE_LINUX |
| send_to_client(priv, priv->wext_client, |
| receiver_id, |
| sigdata, siglen, bulkdata); |
| #endif |
| } |
| else |
| { |
| |
| #if (defined(CSR_SUPPORT_SME) && defined(CSR_WIFI_SECURITY_WAPI_ENABLE)) |
| #define CSR_MA_PACKET_INDICATION_RECEPTION_STATUS_OFFSET sizeof(CSR_SIGNAL_PRIMITIVE_HEADER) + 22 |
| netInterface_priv_t *interfacePriv; |
| u8 interfaceTag; |
| u16 receptionStatus = CSR_RX_SUCCESS; |
| |
| /* Pull out interface tag from virtual interface identifier */ |
| interfaceTag = (CSR_GET_UINT16_FROM_LITTLE_ENDIAN(sigdata + CSR_MA_PACKET_INDICATION_INTERFACETAG_OFFSET)) & 0xff; |
| interfacePriv = priv->interfacePriv[interfaceTag]; |
| |
| /* check for MIC failure */ |
| receptionStatus = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(sigdata + CSR_MA_PACKET_INDICATION_RECEPTION_STATUS_OFFSET); |
| |
| /* Send a WAPI MPDU to SME for re-check MIC if the respective filter has been set*/ |
| if ((!freeBulkData) && |
| (interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_STA) && |
| (receptionStatus == CSR_MICHAEL_MIC_ERROR) && |
| ((priv->wapi_multicast_filter == 1) |
| #ifdef CSR_WIFI_SECURITY_WAPI_SW_ENCRYPTION |
| || (priv->wapi_unicast_filter == 1) |
| #endif |
| )) |
| { |
| CSR_SIGNAL signal; |
| u8 *destAddr; |
| CsrResult res; |
| u16 interfaceTag = 0; |
| u8 isMcastPkt = TRUE; |
| |
| unifi_trace(priv, UDBG6, "Received a WAPI data packet when the Unicast/Multicast filter is set\n"); |
| res = read_unpack_signal(sigdata, &signal); |
| if (res) { |
| unifi_error(priv, "Received unknown or corrupted signal (0x%x).\n", |
| CSR_GET_UINT16_FROM_LITTLE_ENDIAN(sigdata)); |
| return; |
| } |
| |
| /* Check if the type of MPDU and the respective filter status*/ |
| destAddr = (u8 *) bulkdata->d[0].os_data_ptr + MAC_HEADER_ADDR1_OFFSET; |
| isMcastPkt = (destAddr[0] & 0x01) ? TRUE : FALSE; |
| unifi_trace(priv, UDBG6, |
| "1.MPDU type: (%s), 2.Multicast filter: (%s), 3. Unicast filter: (%s)\n", |
| ((isMcastPkt) ? "Multiast":"Unicast"), |
| ((priv->wapi_multicast_filter) ? "Enabled":"Disabled"), |
| ((priv->wapi_unicast_filter) ? "Enabled":"Disabled")); |
| |
| if (((isMcastPkt) && (priv->wapi_multicast_filter == 1)) |
| #ifdef CSR_WIFI_SECURITY_WAPI_SW_ENCRYPTION |
| || ((!isMcastPkt) && (priv->wapi_unicast_filter == 1)) |
| #endif |
| ) |
| { |
| unifi_trace(priv, UDBG4, "Sending the WAPI MPDU for MIC check\n"); |
| CsrWifiRouterCtrlWapiRxMicCheckIndSend(priv->CSR_WIFI_SME_IFACEQUEUE, 0, interfaceTag, siglen, sigdata, bulkdata->d[0].data_length, (u8*)bulkdata->d[0].os_data_ptr); |
| |
| for (i = 0; i < UNIFI_MAX_DATA_REFERENCES; i++) { |
| if (bulkdata->d[i].data_length != 0) { |
| unifi_net_data_free(priv, (void *)&bulkdata->d[i]); |
| } |
| } |
| func_exit(); |
| return; |
| } |
| } /* CSR_MA_PACKET_INDICATION_ID */ |
| #endif /*CSR_SUPPORT_SME && CSR_WIFI_SECURITY_WAPI_ENABLE*/ |
| } |
| } |
| |
| /* calls the registered clients handler callback func. |
| * netdev_mlme_event_handler is one of the registered handler used to route |
| * data packet to network stack or AMP/EAPOL related data to SME |
| * |
| * The freeBulkData check ensures that, it has received a management frame and |
| * the frame needs to be freed here. So not to be passed to netdev handler |
| */ |
| if(!freeBulkData){ |
| if ((client_id < MAX_UDI_CLIENTS) && |
| (&priv->ul_clients[client_id] != priv->logging_client)) { |
| unifi_trace(priv, UDBG6, "Call the registered clients handler callback func\n"); |
| send_to_client(priv, &priv->ul_clients[client_id], |
| receiver_id, |
| sigdata, siglen, bulkdata); |
| } |
| } |
| } |
| |
| /* |
| * Free bulk data buffers here unless it is a CSR_MA_PACKET_INDICATION |
| */ |
| switch (signal_id) |
| { |
| #ifdef UNIFI_SNIFF_ARPHRD |
| case CSR_MA_SNIFFDATA_INDICATION_ID: |
| #endif |
| break; |
| |
| case CSR_MA_PACKET_INDICATION_ID: |
| if (!freeBulkData) |
| { |
| break; |
| } |
| /* FALLS THROUGH... */ |
| default: |
| for (i = 0; i < UNIFI_MAX_DATA_REFERENCES; i++) { |
| if (bulkdata->d[i].data_length != 0) { |
| unifi_net_data_free(priv, (void *)&bulkdata->d[i]); |
| } |
| } |
| } |
| |
| func_exit(); |
| } /* unifi_process_receive_event() */ |
| |
| |
| #ifdef CSR_WIFI_RX_PATH_SPLIT |
| static u8 signal_buffer_is_full(unifi_priv_t* priv) |
| { |
| return (((priv->rxSignalBuffer.writePointer + 1)% priv->rxSignalBuffer.size) == (priv->rxSignalBuffer.readPointer)); |
| } |
| |
| void unifi_rx_queue_flush(void *ospriv) |
| { |
| unifi_priv_t *priv = (unifi_priv_t*)ospriv; |
| |
| func_enter(); |
| unifi_trace(priv, UDBG4, "rx_wq_handler: RdPtr = %d WritePtr = %d\n", |
| priv->rxSignalBuffer.readPointer,priv->rxSignalBuffer.writePointer); |
| if(priv != NULL) { |
| u8 readPointer = priv->rxSignalBuffer.readPointer; |
| while (readPointer != priv->rxSignalBuffer.writePointer) |
| { |
| rx_buff_struct_t *buf = &priv->rxSignalBuffer.rx_buff[readPointer]; |
| unifi_trace(priv, UDBG6, "rx_wq_handler: RdPtr = %d WritePtr = %d\n", |
| readPointer,priv->rxSignalBuffer.writePointer); |
| unifi_process_receive_event(priv, buf->bufptr, buf->sig_len, &buf->data_ptrs); |
| readPointer ++; |
| if(readPointer >= priv->rxSignalBuffer.size) { |
| readPointer = 0; |
| } |
| } |
| priv->rxSignalBuffer.readPointer = readPointer; |
| } |
| func_exit(); |
| } |
| |
| void rx_wq_handler(struct work_struct *work) |
| { |
| unifi_priv_t *priv = container_of(work, unifi_priv_t, rx_work_struct); |
| unifi_rx_queue_flush(priv); |
| } |
| #endif |
| |
| |
| |
| /* |
| * --------------------------------------------------------------------------- |
| * unifi_receive_event |
| * |
| * Dispatcher for received signals. |
| * |
| * This function receives the 'to host' signals and forwards |
| * them to the unifi linux clients. |
| * |
| * Arguments: |
| * ospriv Pointer to driver's private data. |
| * sigdata Pointer to the packed signal buffer. |
| * siglen Length of the packed signal. |
| * bulkdata Pointer to the signal's bulk data. |
| * |
| * Returns: |
| * None. |
| * |
| * Notes: |
| * The signals are received in the format described in the host interface |
| * specification, i.e wire formatted. Certain clients use the same format |
| * to interpret them and other clients use the host formatted structures. |
| * Each client has to call read_unpack_signal() to transform the wire |
| * formatted signal into the host formatted signal, if necessary. |
| * The code is in the core, since the signals are defined therefore |
| * binded to the host interface specification. |
| * --------------------------------------------------------------------------- |
| */ |
| void |
| unifi_receive_event(void *ospriv, |
| u8 *sigdata, u32 siglen, |
| const bulk_data_param_t *bulkdata) |
| { |
| #ifdef CSR_WIFI_RX_PATH_SPLIT |
| unifi_priv_t *priv = (unifi_priv_t*)ospriv; |
| u8 writePointer; |
| int i; |
| rx_buff_struct_t * rx_buff; |
| func_enter(); |
| |
| unifi_trace(priv, UDBG5, "unifi_receive_event: " |
| "%04x %04x %04x %04x %04x %04x %04x %04x (%d)\n", |
| CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(s16)*0) & 0xFFFF, |
| CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(s16)*1) & 0xFFFF, |
| CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(s16)*2) & 0xFFFF, |
| CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(s16)*3) & 0xFFFF, |
| CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(s16)*4) & 0xFFFF, |
| CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(s16)*5) & 0xFFFF, |
| CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(s16)*6) & 0xFFFF, |
| CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sigdata) + sizeof(s16)*7) & 0xFFFF, siglen); |
| if(signal_buffer_is_full(priv)) { |
| unifi_error(priv,"TO HOST signal queue FULL dropping the PDU\n"); |
| for (i = 0; i < UNIFI_MAX_DATA_REFERENCES; i++) { |
| if (bulkdata->d[i].data_length != 0) { |
| unifi_net_data_free(priv, (void *)&bulkdata->d[i]); |
| } |
| } |
| return; |
| } |
| writePointer = priv->rxSignalBuffer.writePointer; |
| rx_buff = &priv->rxSignalBuffer.rx_buff[writePointer]; |
| memcpy(rx_buff->bufptr,sigdata,siglen); |
| rx_buff->sig_len = siglen; |
| rx_buff->data_ptrs = *bulkdata; |
| writePointer++; |
| if(writePointer >= priv->rxSignalBuffer.size) { |
| writePointer =0; |
| } |
| unifi_trace(priv, UDBG4, "unifi_receive_event:writePtr = %d\n",priv->rxSignalBuffer.writePointer); |
| priv->rxSignalBuffer.writePointer = writePointer; |
| |
| #ifndef CSR_WIFI_RX_PATH_SPLIT_DONT_USE_WQ |
| queue_work(priv->rx_workqueue, &priv->rx_work_struct); |
| #endif |
| |
| #else |
| unifi_process_receive_event(ospriv, sigdata, siglen, bulkdata); |
| #endif |
| func_exit(); |
| } /* unifi_receive_event() */ |
| |