Kernel  |  3.10

下载     查看原文件
C++程序  |  693行  |  29.64 KB
/*
 * ***************************************************************************
 *  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;

    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]);
                                }
                           }
                           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]);
                }
            }
    }

} /* 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;

    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;
    }
}

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;

    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
} /* unifi_receive_event() */