701 lines
30 KiB
C
701 lines
30 KiB
C
/*
|
|
* ***************************************************************************
|
|
* 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() */
|
|
|