| /* |
| * *************************************************************************** |
| * FILE: unifi_sme.c |
| * |
| * PURPOSE: SME related functions. |
| * |
| * Copyright (C) 2007-2009 by Cambridge Silicon Radio Ltd. |
| * |
| * Refer to LICENSE.txt included with this source code for details on |
| * the license terms. |
| * |
| * *************************************************************************** |
| */ |
| |
| #include "unifi_priv.h" |
| #include "csr_wifi_hip_unifi.h" |
| #include "csr_wifi_hip_conversions.h" |
| #include <linux/sched/rt.h> |
| |
| |
| |
| int |
| convert_sme_error(CsrResult error) |
| { |
| switch (error) { |
| case CSR_RESULT_SUCCESS: |
| return 0; |
| case CSR_RESULT_FAILURE: |
| case CSR_WIFI_RESULT_NOT_FOUND: |
| case CSR_WIFI_RESULT_TIMED_OUT: |
| case CSR_WIFI_RESULT_CANCELLED: |
| case CSR_WIFI_RESULT_UNAVAILABLE: |
| return -EIO; |
| case CSR_WIFI_RESULT_NO_ROOM: |
| return -EBUSY; |
| case CSR_WIFI_RESULT_INVALID_PARAMETER: |
| return -EINVAL; |
| case CSR_WIFI_RESULT_UNSUPPORTED: |
| return -EOPNOTSUPP; |
| default: |
| return -EIO; |
| } |
| } |
| |
| |
| /* |
| * --------------------------------------------------------------------------- |
| * sme_log_event |
| * |
| * Callback function to be registered as the SME event callback. |
| * Copies the signal content into a new udi_log_t struct and adds |
| * it to the read queue for the SME client. |
| * |
| * Arguments: |
| * arg This is the value given to unifi_add_udi_hook, in |
| * this case a pointer to the client instance. |
| * signal Pointer to the received signal. |
| * signal_len Size of the signal structure in bytes. |
| * bulkdata Pointers to any associated bulk data. |
| * dir Direction of the signal. Zero means from host, |
| * non-zero means to host. |
| * |
| * Returns: |
| * None. |
| * --------------------------------------------------------------------------- |
| */ |
| void |
| sme_log_event(ul_client_t *pcli, |
| const u8 *signal, int signal_len, |
| const bulk_data_param_t *bulkdata, |
| int dir) |
| { |
| unifi_priv_t *priv; |
| CSR_SIGNAL unpacked_signal; |
| CsrWifiSmeDataBlock mlmeCommand; |
| CsrWifiSmeDataBlock dataref1; |
| CsrWifiSmeDataBlock dataref2; |
| CsrResult result = CSR_RESULT_SUCCESS; |
| int r; |
| |
| /* Just a sanity check */ |
| if ((signal == NULL) || (signal_len <= 0)) { |
| return; |
| } |
| |
| priv = uf_find_instance(pcli->instance); |
| if (!priv) { |
| unifi_error(priv, "sme_log_event: invalid priv\n"); |
| return; |
| } |
| |
| if (priv->smepriv == NULL) { |
| unifi_error(priv, "sme_log_event: invalid smepriv\n"); |
| return; |
| } |
| |
| unifi_trace(priv, UDBG3, |
| "sme_log_event: Process signal 0x%.4X\n", |
| CSR_GET_UINT16_FROM_LITTLE_ENDIAN(signal)); |
| |
| |
| /* If the signal is known, then do any filtering required, otherwise it pass it to the SME. */ |
| r = read_unpack_signal(signal, &unpacked_signal); |
| if (r == CSR_RESULT_SUCCESS) { |
| if ((unpacked_signal.SignalPrimitiveHeader.SignalId == CSR_DEBUG_STRING_INDICATION_ID) || |
| (unpacked_signal.SignalPrimitiveHeader.SignalId == CSR_DEBUG_WORD16_INDICATION_ID)) |
| { |
| return; |
| } |
| if (unpacked_signal.SignalPrimitiveHeader.SignalId == CSR_MA_PACKET_INDICATION_ID) |
| { |
| u16 frmCtrl; |
| u8 unicastPdu = TRUE; |
| u8 *macHdrLocation; |
| u8 *raddr = NULL, *taddr = NULL; |
| CsrWifiMacAddress peerMacAddress; |
| /* Check if we need to send CsrWifiRouterCtrlMicFailureInd*/ |
| CSR_MA_PACKET_INDICATION *ind = &unpacked_signal.u.MaPacketIndication; |
| |
| macHdrLocation = (u8 *) bulkdata->d[0].os_data_ptr; |
| /* Fetch the frame control value from mac header */ |
| frmCtrl = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(macHdrLocation); |
| |
| /* Point to the addresses */ |
| raddr = macHdrLocation + MAC_HEADER_ADDR1_OFFSET; |
| taddr = macHdrLocation + MAC_HEADER_ADDR2_OFFSET; |
| |
| memcpy(peerMacAddress.a, taddr, ETH_ALEN); |
| |
| if(ind->ReceptionStatus == CSR_MICHAEL_MIC_ERROR) |
| { |
| if (*raddr & 0x1) |
| unicastPdu = FALSE; |
| |
| CsrWifiRouterCtrlMicFailureIndSend (priv->CSR_WIFI_SME_IFACEQUEUE, 0, |
| (ind->VirtualInterfaceIdentifier & 0xff),peerMacAddress, |
| unicastPdu); |
| return; |
| } |
| else |
| { |
| if(ind->ReceptionStatus == CSR_RX_SUCCESS) |
| { |
| u8 pmBit = (frmCtrl & 0x1000)?0x01:0x00; |
| u16 interfaceTag = (ind->VirtualInterfaceIdentifier & 0xff); |
| CsrWifiRouterCtrlStaInfo_t *srcStaInfo = CsrWifiRouterCtrlGetStationRecordFromPeerMacAddress(priv,taddr,interfaceTag); |
| if((srcStaInfo != NULL) && (uf_check_broadcast_bssid(priv, bulkdata)== FALSE)) |
| { |
| uf_process_pm_bit_for_peer(priv,srcStaInfo,pmBit,interfaceTag); |
| |
| /* Update station last activity flag */ |
| srcStaInfo->activity_flag = TRUE; |
| } |
| } |
| } |
| } |
| |
| if (unpacked_signal.SignalPrimitiveHeader.SignalId == CSR_MA_PACKET_CONFIRM_ID) |
| { |
| CSR_MA_PACKET_CONFIRM *cfm = &unpacked_signal.u.MaPacketConfirm; |
| u16 interfaceTag = (cfm->VirtualInterfaceIdentifier & 0xff); |
| netInterface_priv_t *interfacePriv; |
| CSR_MA_PACKET_REQUEST *req; |
| CsrWifiMacAddress peerMacAddress; |
| |
| if (interfaceTag >= CSR_WIFI_NUM_INTERFACES) |
| { |
| unifi_error(priv, "Bad MA_PACKET_CONFIRM interfaceTag %d\n", interfaceTag); |
| return; |
| } |
| |
| unifi_trace(priv,UDBG1,"MA-PACKET Confirm (%x, %x)\n", cfm->HostTag, cfm->TransmissionStatus); |
| |
| interfacePriv = priv->interfacePriv[interfaceTag]; |
| #ifdef CSR_SUPPORT_SME |
| if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP || |
| interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) { |
| |
| if(cfm->HostTag == interfacePriv->multicastPduHostTag){ |
| uf_process_ma_pkt_cfm_for_ap(priv ,interfaceTag, cfm); |
| } |
| } |
| #endif |
| |
| req = &interfacePriv->m4_signal.u.MaPacketRequest; |
| |
| if(cfm->HostTag & 0x80000000) |
| { |
| if (cfm->TransmissionStatus != CSR_TX_SUCCESSFUL) |
| { |
| result = CSR_RESULT_FAILURE; |
| } |
| #ifdef CSR_SUPPORT_SME |
| memcpy(peerMacAddress.a, req->Ra.x, ETH_ALEN); |
| /* Check if this is a confirm for EAPOL M4 frame and we need to send transmistted ind*/ |
| if (interfacePriv->m4_sent && (cfm->HostTag == interfacePriv->m4_hostTag)) |
| { |
| unifi_trace(priv, UDBG1, "%s: Sending M4 Transmit CFM\n", __FUNCTION__); |
| CsrWifiRouterCtrlM4TransmittedIndSend(priv->CSR_WIFI_SME_IFACEQUEUE, 0, |
| interfaceTag, |
| peerMacAddress, |
| result); |
| interfacePriv->m4_sent = FALSE; |
| interfacePriv->m4_hostTag = 0xffffffff; |
| } |
| #endif |
| /* If EAPOL was requested via router APIs then send cfm else ignore*/ |
| if((cfm->HostTag & 0x80000000) != CSR_WIFI_EAPOL_M4_HOST_TAG) { |
| CsrWifiRouterMaPacketCfmSend((u16)signal[2], |
| cfm->VirtualInterfaceIdentifier, |
| result, |
| (cfm->HostTag & 0x3fffffff), cfm->Rate); |
| } else { |
| unifi_trace(priv, UDBG1, "%s: M4 received from netdevice\n", __FUNCTION__); |
| } |
| return; |
| } |
| } |
| } |
| |
| mlmeCommand.length = signal_len; |
| mlmeCommand.data = (u8*)signal; |
| |
| dataref1.length = bulkdata->d[0].data_length; |
| if (dataref1.length > 0) { |
| dataref1.data = (u8 *) bulkdata->d[0].os_data_ptr; |
| } else |
| { |
| dataref1.data = NULL; |
| } |
| |
| dataref2.length = bulkdata->d[1].data_length; |
| if (dataref2.length > 0) { |
| dataref2.data = (u8 *) bulkdata->d[1].os_data_ptr; |
| } else |
| { |
| dataref2.data = NULL; |
| } |
| |
| CsrWifiRouterCtrlHipIndSend(priv->CSR_WIFI_SME_IFACEQUEUE, mlmeCommand.length, mlmeCommand.data, |
| dataref1.length, dataref1.data, |
| dataref2.length, dataref2.data); |
| |
| } /* sme_log_event() */ |
| |
| |
| /* |
| * --------------------------------------------------------------------------- |
| * uf_sme_port_state |
| * |
| * Return the state of the controlled port. |
| * |
| * Arguments: |
| * priv Pointer to device private context struct |
| * address Pointer to the destination for tx or sender for rx address |
| * queue Controlled or uncontrolled queue |
| * |
| * Returns: |
| * An unifi_ControlledPortAction value. |
| * --------------------------------------------------------------------------- |
| */ |
| CsrWifiRouterCtrlPortAction |
| uf_sme_port_state(unifi_priv_t *priv, unsigned char *address, int queue, u16 interfaceTag) |
| { |
| int i; |
| unifi_port_config_t *port; |
| netInterface_priv_t *interfacePriv; |
| |
| if (interfaceTag >= CSR_WIFI_NUM_INTERFACES) { |
| unifi_error(priv, "uf_sme_port_state: bad interfaceTag\n"); |
| return CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_DISCARD; |
| } |
| |
| interfacePriv = priv->interfacePriv[interfaceTag]; |
| |
| if (queue == UF_CONTROLLED_PORT_Q) { |
| port = &interfacePriv->controlled_data_port; |
| } else { |
| port = &interfacePriv->uncontrolled_data_port; |
| } |
| |
| if (!port->entries_in_use) { |
| unifi_trace(priv, UDBG5, "No port configurations, return Discard.\n"); |
| return CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_DISCARD; |
| } |
| |
| /* If the port configuration is common for all destinations, return it. */ |
| if (port->overide_action == UF_DATA_PORT_OVERIDE) { |
| unifi_trace(priv, UDBG5, "Single port configuration (%d).\n", |
| port->port_cfg[0].port_action); |
| return port->port_cfg[0].port_action; |
| } |
| |
| unifi_trace(priv, UDBG5, "Multiple (%d) port configurations.\n", port->entries_in_use); |
| |
| /* If multiple configurations exist.. */ |
| for (i = 0; i < UNIFI_MAX_CONNECTIONS; i++) { |
| /* .. go through the list and match the destination address. */ |
| if (port->port_cfg[i].in_use && |
| memcmp(address, port->port_cfg[i].mac_address.a, ETH_ALEN) == 0) { |
| /* Return the desired action. */ |
| return port->port_cfg[i].port_action; |
| } |
| } |
| |
| /* Could not find any information, return Open. */ |
| unifi_trace(priv, UDBG5, "port configuration not found, return Open.\n"); |
| return CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_OPEN; |
| } /* uf_sme_port_state() */ |
| |
| /* |
| * --------------------------------------------------------------------------- |
| * uf_sme_port_config_handle |
| * |
| * Return the port config handle of the controlled/uncontrolled port. |
| * |
| * Arguments: |
| * priv Pointer to device private context struct |
| * address Pointer to the destination for tx or sender for rx address |
| * queue Controlled or uncontrolled queue |
| * |
| * Returns: |
| * An unifi_port_cfg_t* . |
| * --------------------------------------------------------------------------- |
| */ |
| unifi_port_cfg_t* |
| uf_sme_port_config_handle(unifi_priv_t *priv, unsigned char *address, int queue, u16 interfaceTag) |
| { |
| int i; |
| unifi_port_config_t *port; |
| netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag]; |
| |
| if (interfaceTag >= CSR_WIFI_NUM_INTERFACES) { |
| unifi_error(priv, "uf_sme_port_config_handle: bad interfaceTag\n"); |
| return NULL; |
| } |
| |
| if (queue == UF_CONTROLLED_PORT_Q) { |
| port = &interfacePriv->controlled_data_port; |
| } else { |
| port = &interfacePriv->uncontrolled_data_port; |
| } |
| |
| if (!port->entries_in_use) { |
| unifi_trace(priv, UDBG5, "No port configurations, return Discard.\n"); |
| return NULL; |
| } |
| |
| /* If the port configuration is common for all destinations, return it. */ |
| if (port->overide_action == UF_DATA_PORT_OVERIDE) { |
| unifi_trace(priv, UDBG5, "Single port configuration (%d).\n", |
| port->port_cfg[0].port_action); |
| if (address) { |
| unifi_trace(priv, UDBG5, "addr[0] = %x, addr[1] = %x, addr[2] = %x, addr[3] = %x\n", address[0], address[1], address[2], address[3]); |
| } |
| return &port->port_cfg[0]; |
| } |
| |
| unifi_trace(priv, UDBG5, "Multiple port configurations.\n"); |
| |
| /* If multiple configurations exist.. */ |
| for (i = 0; i < UNIFI_MAX_CONNECTIONS; i++) { |
| /* .. go through the list and match the destination address. */ |
| if (port->port_cfg[i].in_use && |
| memcmp(address, port->port_cfg[i].mac_address.a, ETH_ALEN) == 0) { |
| /* Return the desired action. */ |
| return &port->port_cfg[i]; |
| } |
| } |
| |
| /* Could not find any information, return Open. */ |
| unifi_trace(priv, UDBG5, "port configuration not found, returning NULL (debug).\n"); |
| return NULL; |
| } /* uf_sme_port_config_handle */ |
| |
| void |
| uf_multicast_list_wq(struct work_struct *work) |
| { |
| unifi_priv_t *priv = container_of(work, unifi_priv_t, |
| multicast_list_task); |
| int i; |
| u16 interfaceTag = 0; |
| CsrWifiMacAddress* multicast_address_list = NULL; |
| int mc_count; |
| u8 *mc_list; |
| netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag]; |
| |
| if (interfaceTag >= CSR_WIFI_NUM_INTERFACES) { |
| unifi_error(priv, "uf_multicast_list_wq: bad interfaceTag\n"); |
| return; |
| } |
| |
| unifi_trace(priv, UDBG5, |
| "uf_multicast_list_wq: list count = %d\n", |
| interfacePriv->mc_list_count); |
| |
| /* Flush the current list */ |
| CsrWifiRouterCtrlMulticastAddressIndSend(priv->CSR_WIFI_SME_IFACEQUEUE,0, interfaceTag, CSR_WIFI_SME_LIST_ACTION_FLUSH, 0, NULL); |
| |
| mc_count = interfacePriv->mc_list_count; |
| mc_list = interfacePriv->mc_list; |
| /* |
| * Allocate a new list, need to free it later |
| * in unifi_mgt_multicast_address_cfm(). |
| */ |
| multicast_address_list = kmalloc(mc_count * sizeof(CsrWifiMacAddress), GFP_KERNEL); |
| |
| if (multicast_address_list == NULL) { |
| return; |
| } |
| |
| for (i = 0; i < mc_count; i++) { |
| memcpy(multicast_address_list[i].a, mc_list, ETH_ALEN); |
| mc_list += ETH_ALEN; |
| } |
| |
| if (priv->smepriv == NULL) { |
| kfree(multicast_address_list); |
| return; |
| } |
| |
| CsrWifiRouterCtrlMulticastAddressIndSend(priv->CSR_WIFI_SME_IFACEQUEUE,0, |
| interfaceTag, |
| CSR_WIFI_SME_LIST_ACTION_ADD, |
| mc_count, multicast_address_list); |
| |
| /* The SME will take a copy of the addreses*/ |
| kfree(multicast_address_list); |
| } |
| |
| |
| int unifi_cfg_power(unifi_priv_t *priv, unsigned char *arg) |
| { |
| unifi_cfg_power_t cfg_power; |
| int rc; |
| int wol; |
| |
| if (get_user(cfg_power, (unifi_cfg_power_t*)(((unifi_cfg_command_t*)arg) + 1))) { |
| unifi_error(priv, "UNIFI_CFG: Failed to get the argument\n"); |
| return -EFAULT; |
| } |
| |
| switch (cfg_power) { |
| case UNIFI_CFG_POWER_OFF: |
| priv->wol_suspend = (enable_wol == UNIFI_WOL_OFF) ? FALSE : TRUE; |
| rc = sme_sys_suspend(priv); |
| if (rc) { |
| return rc; |
| } |
| break; |
| case UNIFI_CFG_POWER_ON: |
| wol = priv->wol_suspend; |
| rc = sme_sys_resume(priv); |
| if (rc) { |
| return rc; |
| } |
| if (wol) { |
| /* Kick the BH to ensure pending transfers are handled when |
| * a suspend happened with card powered. |
| */ |
| unifi_send_signal(priv->card, NULL, 0, NULL); |
| } |
| break; |
| default: |
| unifi_error(priv, "WIFI POWER: Unknown value.\n"); |
| return -EINVAL; |
| } |
| |
| return 0; |
| } |
| |
| |
| int unifi_cfg_power_save(unifi_priv_t *priv, unsigned char *arg) |
| { |
| unifi_cfg_powersave_t cfg_power_save; |
| CsrWifiSmePowerConfig powerConfig; |
| int rc; |
| |
| if (get_user(cfg_power_save, (unifi_cfg_powersave_t*)(((unifi_cfg_command_t*)arg) + 1))) { |
| unifi_error(priv, "UNIFI_CFG: Failed to get the argument\n"); |
| return -EFAULT; |
| } |
| |
| /* Get the coex info from the SME */ |
| rc = sme_mgt_power_config_get(priv, &powerConfig); |
| if (rc) { |
| unifi_error(priv, "UNIFI_CFG: Get unifi_PowerConfigValue failed.\n"); |
| return rc; |
| } |
| |
| switch (cfg_power_save) { |
| case UNIFI_CFG_POWERSAVE_NONE: |
| powerConfig.powerSaveLevel = CSR_WIFI_SME_POWER_SAVE_LEVEL_LOW; |
| break; |
| case UNIFI_CFG_POWERSAVE_FAST: |
| powerConfig.powerSaveLevel = CSR_WIFI_SME_POWER_SAVE_LEVEL_MED; |
| break; |
| case UNIFI_CFG_POWERSAVE_FULL: |
| powerConfig.powerSaveLevel = CSR_WIFI_SME_POWER_SAVE_LEVEL_HIGH; |
| break; |
| case UNIFI_CFG_POWERSAVE_AUTO: |
| powerConfig.powerSaveLevel = CSR_WIFI_SME_POWER_SAVE_LEVEL_AUTO; |
| break; |
| default: |
| unifi_error(priv, "POWERSAVE: Unknown value.\n"); |
| return -EINVAL; |
| } |
| |
| rc = sme_mgt_power_config_set(priv, &powerConfig); |
| |
| if (rc) { |
| unifi_error(priv, "UNIFI_CFG: Set unifi_PowerConfigValue failed.\n"); |
| } |
| |
| return rc; |
| } |
| |
| |
| int unifi_cfg_power_supply(unifi_priv_t *priv, unsigned char *arg) |
| { |
| unifi_cfg_powersupply_t cfg_power_supply; |
| CsrWifiSmeHostConfig hostConfig; |
| int rc; |
| |
| if (get_user(cfg_power_supply, (unifi_cfg_powersupply_t*)(((unifi_cfg_command_t*)arg) + 1))) { |
| unifi_error(priv, "UNIFI_CFG: Failed to get the argument\n"); |
| return -EFAULT; |
| } |
| |
| /* Get the coex info from the SME */ |
| rc = sme_mgt_host_config_get(priv, &hostConfig); |
| if (rc) { |
| unifi_error(priv, "UNIFI_CFG: Get unifi_HostConfigValue failed.\n"); |
| return rc; |
| } |
| |
| switch (cfg_power_supply) { |
| case UNIFI_CFG_POWERSUPPLY_MAINS: |
| hostConfig.powerMode = CSR_WIFI_SME_HOST_POWER_MODE_ACTIVE; |
| break; |
| case UNIFI_CFG_POWERSUPPLY_BATTERIES: |
| hostConfig.powerMode = CSR_WIFI_SME_HOST_POWER_MODE_POWER_SAVE; |
| break; |
| default: |
| unifi_error(priv, "POWERSUPPLY: Unknown value.\n"); |
| return -EINVAL; |
| } |
| |
| rc = sme_mgt_host_config_set(priv, &hostConfig); |
| if (rc) { |
| unifi_error(priv, "UNIFI_CFG: Set unifi_HostConfigValue failed.\n"); |
| } |
| |
| return rc; |
| } |
| |
| |
| int unifi_cfg_packet_filters(unifi_priv_t *priv, unsigned char *arg) |
| { |
| unsigned char *tclas_buffer; |
| unsigned int tclas_buffer_length; |
| tclas_t *dhcp_tclas; |
| int rc; |
| |
| /* Free any TCLASs previously allocated */ |
| if (priv->packet_filters.tclas_ies_length) { |
| kfree(priv->filter_tclas_ies); |
| priv->filter_tclas_ies = NULL; |
| } |
| |
| tclas_buffer = ((unsigned char*)arg) + sizeof(unifi_cfg_command_t) + sizeof(unsigned int); |
| if (copy_from_user(&priv->packet_filters, (void*)tclas_buffer, |
| sizeof(uf_cfg_bcast_packet_filter_t))) { |
| unifi_error(priv, "UNIFI_CFG: Failed to get the filter struct\n"); |
| return -EFAULT; |
| } |
| |
| tclas_buffer_length = priv->packet_filters.tclas_ies_length; |
| |
| /* Allocate TCLASs if necessary */ |
| if (priv->packet_filters.dhcp_filter) { |
| priv->packet_filters.tclas_ies_length += sizeof(tclas_t); |
| } |
| if (priv->packet_filters.tclas_ies_length > 0) { |
| priv->filter_tclas_ies = kmalloc(priv->packet_filters.tclas_ies_length, GFP_KERNEL); |
| if (priv->filter_tclas_ies == NULL) { |
| return -ENOMEM; |
| } |
| if (tclas_buffer_length) { |
| tclas_buffer += sizeof(uf_cfg_bcast_packet_filter_t) - sizeof(unsigned char*); |
| if (copy_from_user(priv->filter_tclas_ies, |
| tclas_buffer, |
| tclas_buffer_length)) { |
| unifi_error(priv, "UNIFI_CFG: Failed to get the TCLAS buffer\n"); |
| return -EFAULT; |
| } |
| } |
| } |
| |
| if(priv->packet_filters.dhcp_filter) |
| { |
| /* Append the DHCP tclas IE */ |
| dhcp_tclas = (tclas_t*)(priv->filter_tclas_ies + tclas_buffer_length); |
| memset(dhcp_tclas, 0, sizeof(tclas_t)); |
| dhcp_tclas->element_id = 14; |
| dhcp_tclas->length = sizeof(tcpip_clsfr_t) + 1; |
| dhcp_tclas->user_priority = 0; |
| dhcp_tclas->tcp_ip_cls_fr.cls_fr_type = 1; |
| dhcp_tclas->tcp_ip_cls_fr.version = 4; |
| ((u8*)(&dhcp_tclas->tcp_ip_cls_fr.source_port))[0] = 0x00; |
| ((u8*)(&dhcp_tclas->tcp_ip_cls_fr.source_port))[1] = 0x44; |
| ((u8*)(&dhcp_tclas->tcp_ip_cls_fr.dest_port))[0] = 0x00; |
| ((u8*)(&dhcp_tclas->tcp_ip_cls_fr.dest_port))[1] = 0x43; |
| dhcp_tclas->tcp_ip_cls_fr.protocol = 0x11; |
| dhcp_tclas->tcp_ip_cls_fr.cls_fr_mask = 0x58; //bits: 3,4,6 |
| } |
| |
| rc = sme_mgt_packet_filter_set(priv); |
| |
| return rc; |
| } |
| |
| |
| int unifi_cfg_wmm_qos_info(unifi_priv_t *priv, unsigned char *arg) |
| { |
| u8 wmm_qos_info; |
| int rc = 0; |
| |
| if (get_user(wmm_qos_info, (u8*)(((unifi_cfg_command_t*)arg) + 1))) { |
| unifi_error(priv, "UNIFI_CFG: Failed to get the argument\n"); |
| return -EFAULT; |
| } |
| |
| /* Store the value in the connection info */ |
| priv->connection_config.wmmQosInfo = wmm_qos_info; |
| |
| return rc; |
| } |
| |
| |
| int unifi_cfg_wmm_addts(unifi_priv_t *priv, unsigned char *arg) |
| { |
| u32 addts_tid; |
| u8 addts_ie_length; |
| u8 *addts_ie; |
| u8 *addts_params; |
| CsrWifiSmeDataBlock tspec; |
| CsrWifiSmeDataBlock tclas; |
| int rc; |
| |
| addts_params = (u8*)(((unifi_cfg_command_t*)arg) + 1); |
| if (get_user(addts_tid, (u32*)addts_params)) { |
| unifi_error(priv, "unifi_cfg_wmm_addts: Failed to get the argument\n"); |
| return -EFAULT; |
| } |
| |
| addts_params += sizeof(u32); |
| if (get_user(addts_ie_length, (u8*)addts_params)) { |
| unifi_error(priv, "unifi_cfg_wmm_addts: Failed to get the argument\n"); |
| return -EFAULT; |
| } |
| |
| unifi_trace(priv, UDBG4, "addts: tid = 0x%x ie_length = %d\n", |
| addts_tid, addts_ie_length); |
| |
| addts_ie = kmalloc(addts_ie_length, GFP_KERNEL); |
| if (addts_ie == NULL) { |
| unifi_error(priv, |
| "unifi_cfg_wmm_addts: Failed to malloc %d bytes for addts_ie buffer\n", |
| addts_ie_length); |
| return -ENOMEM; |
| } |
| |
| addts_params += sizeof(u8); |
| rc = copy_from_user(addts_ie, addts_params, addts_ie_length); |
| if (rc) { |
| unifi_error(priv, "unifi_cfg_wmm_addts: Failed to get the addts buffer\n"); |
| kfree(addts_ie); |
| return -EFAULT; |
| } |
| |
| tspec.data = addts_ie; |
| tspec.length = addts_ie_length; |
| tclas.data = NULL; |
| tclas.length = 0; |
| |
| rc = sme_mgt_tspec(priv, CSR_WIFI_SME_LIST_ACTION_ADD, addts_tid, |
| &tspec, &tclas); |
| |
| kfree(addts_ie); |
| return rc; |
| } |
| |
| |
| int unifi_cfg_wmm_delts(unifi_priv_t *priv, unsigned char *arg) |
| { |
| u32 delts_tid; |
| u8 *delts_params; |
| CsrWifiSmeDataBlock tspec; |
| CsrWifiSmeDataBlock tclas; |
| int rc; |
| |
| delts_params = (u8*)(((unifi_cfg_command_t*)arg) + 1); |
| if (get_user(delts_tid, (u32*)delts_params)) { |
| unifi_error(priv, "unifi_cfg_wmm_delts: Failed to get the argument\n"); |
| return -EFAULT; |
| } |
| |
| unifi_trace(priv, UDBG4, "delts: tid = 0x%x\n", delts_tid); |
| |
| tspec.data = tclas.data = NULL; |
| tspec.length = tclas.length = 0; |
| |
| rc = sme_mgt_tspec(priv, CSR_WIFI_SME_LIST_ACTION_REMOVE, delts_tid, |
| &tspec, &tclas); |
| |
| return rc; |
| } |
| |
| int unifi_cfg_strict_draft_n(unifi_priv_t *priv, unsigned char *arg) |
| { |
| u8 strict_draft_n; |
| u8 *strict_draft_n_params; |
| int rc; |
| |
| CsrWifiSmeStaConfig staConfig; |
| CsrWifiSmeDeviceConfig deviceConfig; |
| |
| strict_draft_n_params = (u8*)(((unifi_cfg_command_t*)arg) + 1); |
| if (get_user(strict_draft_n, (u8*)strict_draft_n_params)) { |
| unifi_error(priv, "unifi_cfg_strict_draft_n: Failed to get the argument\n"); |
| return -EFAULT; |
| } |
| |
| unifi_trace(priv, UDBG4, "strict_draft_n: = %s\n", ((strict_draft_n) ? "yes":"no")); |
| |
| rc = sme_mgt_sme_config_get(priv, &staConfig, &deviceConfig); |
| |
| if (rc) { |
| unifi_warning(priv, "unifi_cfg_strict_draft_n: Get unifi_SMEConfigValue failed.\n"); |
| return -EFAULT; |
| } |
| |
| deviceConfig.enableStrictDraftN = strict_draft_n; |
| |
| rc = sme_mgt_sme_config_set(priv, &staConfig, &deviceConfig); |
| if (rc) { |
| unifi_warning(priv, "unifi_cfg_strict_draft_n: Set unifi_SMEConfigValue failed.\n"); |
| rc = -EFAULT; |
| } |
| |
| return rc; |
| } |
| |
| |
| int unifi_cfg_enable_okc(unifi_priv_t *priv, unsigned char *arg) |
| { |
| u8 enable_okc; |
| u8 *enable_okc_params; |
| int rc; |
| |
| CsrWifiSmeStaConfig staConfig; |
| CsrWifiSmeDeviceConfig deviceConfig; |
| |
| enable_okc_params = (u8*)(((unifi_cfg_command_t*)arg) + 1); |
| if (get_user(enable_okc, (u8*)enable_okc_params)) { |
| unifi_error(priv, "unifi_cfg_enable_okc: Failed to get the argument\n"); |
| return -EFAULT; |
| } |
| |
| unifi_trace(priv, UDBG4, "enable_okc: = %s\n", ((enable_okc) ? "yes":"no")); |
| |
| rc = sme_mgt_sme_config_get(priv, &staConfig, &deviceConfig); |
| if (rc) { |
| unifi_warning(priv, "unifi_cfg_enable_okc: Get unifi_SMEConfigValue failed.\n"); |
| return -EFAULT; |
| } |
| |
| staConfig.enableOpportunisticKeyCaching = enable_okc; |
| |
| rc = sme_mgt_sme_config_set(priv, &staConfig, &deviceConfig); |
| if (rc) { |
| unifi_warning(priv, "unifi_cfg_enable_okc: Set unifi_SMEConfigValue failed.\n"); |
| rc = -EFAULT; |
| } |
| |
| return rc; |
| } |
| |
| |
| int unifi_cfg_get_info(unifi_priv_t *priv, unsigned char *arg) |
| { |
| unifi_cfg_get_t get_cmd; |
| char inst_name[IFNAMSIZ]; |
| int rc; |
| |
| if (get_user(get_cmd, (unifi_cfg_get_t*)(((unifi_cfg_command_t*)arg) + 1))) { |
| unifi_error(priv, "UNIFI_CFG: Failed to get the argument\n"); |
| return -EFAULT; |
| } |
| |
| switch (get_cmd) { |
| case UNIFI_CFG_GET_COEX: |
| { |
| CsrWifiSmeCoexInfo coexInfo; |
| /* Get the coex info from the SME */ |
| rc = sme_mgt_coex_info_get(priv, &coexInfo); |
| if (rc) { |
| unifi_error(priv, "UNIFI_CFG: Get unifi_CoexInfoValue failed.\n"); |
| return rc; |
| } |
| |
| /* Copy the info to the out buffer */ |
| if (copy_to_user((void*)arg, |
| &coexInfo, |
| sizeof(CsrWifiSmeCoexInfo))) { |
| unifi_error(priv, "UNIFI_CFG: Failed to copy the coex info\n"); |
| return -EFAULT; |
| } |
| break; |
| } |
| case UNIFI_CFG_GET_POWER_MODE: |
| { |
| CsrWifiSmePowerConfig powerConfig; |
| rc = sme_mgt_power_config_get(priv, &powerConfig); |
| if (rc) { |
| unifi_error(priv, "UNIFI_CFG: Get unifi_PowerConfigValue failed.\n"); |
| return rc; |
| } |
| |
| /* Copy the info to the out buffer */ |
| if (copy_to_user((void*)arg, |
| &powerConfig.powerSaveLevel, |
| sizeof(CsrWifiSmePowerSaveLevel))) { |
| unifi_error(priv, "UNIFI_CFG: Failed to copy the power save info\n"); |
| return -EFAULT; |
| } |
| break; |
| } |
| case UNIFI_CFG_GET_POWER_SUPPLY: |
| { |
| CsrWifiSmeHostConfig hostConfig; |
| rc = sme_mgt_host_config_get(priv, &hostConfig); |
| if (rc) { |
| unifi_error(priv, "UNIFI_CFG: Get unifi_HostConfigValue failed.\n"); |
| return rc; |
| } |
| |
| /* Copy the info to the out buffer */ |
| if (copy_to_user((void*)arg, |
| &hostConfig.powerMode, |
| sizeof(CsrWifiSmeHostPowerMode))) { |
| unifi_error(priv, "UNIFI_CFG: Failed to copy the host power mode\n"); |
| return -EFAULT; |
| } |
| break; |
| } |
| case UNIFI_CFG_GET_VERSIONS: |
| break; |
| case UNIFI_CFG_GET_INSTANCE: |
| { |
| u16 InterfaceId=0; |
| uf_net_get_name(priv->netdev[InterfaceId], &inst_name[0], sizeof(inst_name)); |
| |
| /* Copy the info to the out buffer */ |
| if (copy_to_user((void*)arg, |
| &inst_name[0], |
| sizeof(inst_name))) { |
| unifi_error(priv, "UNIFI_CFG: Failed to copy the instance name\n"); |
| return -EFAULT; |
| } |
| } |
| break; |
| |
| case UNIFI_CFG_GET_AP_CONFIG: |
| { |
| #ifdef CSR_SUPPORT_WEXT_AP |
| uf_cfg_ap_config_t cfg_ap_config; |
| cfg_ap_config.channel = priv->ap_config.channel; |
| cfg_ap_config.beaconInterval = priv->ap_mac_config.beaconInterval; |
| cfg_ap_config.wmmEnabled = priv->ap_mac_config.wmmEnabled; |
| cfg_ap_config.dtimPeriod = priv->ap_mac_config.dtimPeriod; |
| cfg_ap_config.phySupportedBitmap = priv->ap_mac_config.phySupportedBitmap; |
| if (copy_to_user((void*)arg, |
| &cfg_ap_config, |
| sizeof(uf_cfg_ap_config_t))) { |
| unifi_error(priv, "UNIFI_CFG: Failed to copy the AP configuration\n"); |
| return -EFAULT; |
| } |
| #else |
| return -EPERM; |
| #endif |
| } |
| break; |
| |
| |
| default: |
| unifi_error(priv, "unifi_cfg_get_info: Unknown value.\n"); |
| return -EINVAL; |
| } |
| |
| return 0; |
| } |
| #ifdef CSR_SUPPORT_WEXT_AP |
| int |
| uf_configure_supported_rates(u8 * supportedRates, u8 phySupportedBitmap) |
| { |
| int i=0; |
| u8 b=FALSE, g = FALSE, n = FALSE; |
| b = phySupportedBitmap & CSR_WIFI_SME_AP_PHY_SUPPORT_B; |
| n = phySupportedBitmap & CSR_WIFI_SME_AP_PHY_SUPPORT_N; |
| g = phySupportedBitmap & CSR_WIFI_SME_AP_PHY_SUPPORT_G; |
| if(b || g) { |
| supportedRates[i++]=0x82; |
| supportedRates[i++]=0x84; |
| supportedRates[i++]=0x8b; |
| supportedRates[i++]=0x96; |
| } else if(n) { |
| /* For some strange reasons WiFi stack needs both b and g rates*/ |
| supportedRates[i++]=0x02; |
| supportedRates[i++]=0x04; |
| supportedRates[i++]=0x0b; |
| supportedRates[i++]=0x16; |
| supportedRates[i++]=0x0c; |
| supportedRates[i++]=0x12; |
| supportedRates[i++]=0x18; |
| supportedRates[i++]=0x24; |
| supportedRates[i++]=0x30; |
| supportedRates[i++]=0x48; |
| supportedRates[i++]=0x60; |
| supportedRates[i++]=0x6c; |
| } |
| if(g) { |
| if(!b) { |
| supportedRates[i++]=0x8c; |
| supportedRates[i++]=0x98; |
| supportedRates[i++]=0xb0; |
| } else { |
| supportedRates[i++]=0x0c; |
| supportedRates[i++]=0x18; |
| supportedRates[i++]=0x30; |
| } |
| supportedRates[i++]=0x48; |
| supportedRates[i++]=0x12; |
| supportedRates[i++]=0x24; |
| supportedRates[i++]=0x60; |
| supportedRates[i++]=0x6c; |
| } |
| return i; |
| } |
| int unifi_cfg_set_ap_config(unifi_priv_t * priv,unsigned char* arg) |
| { |
| uf_cfg_ap_config_t cfg_ap_config; |
| char *buffer; |
| |
| buffer = ((unsigned char*)arg) + sizeof(unifi_cfg_command_t) + sizeof(unsigned int); |
| if (copy_from_user(&cfg_ap_config, (void*)buffer, |
| sizeof(uf_cfg_ap_config_t))) { |
| unifi_error(priv, "UNIFI_CFG: Failed to get the ap config struct\n"); |
| return -EFAULT; |
| } |
| priv->ap_config.channel = cfg_ap_config.channel; |
| priv->ap_mac_config.dtimPeriod = cfg_ap_config.dtimPeriod; |
| priv->ap_mac_config.beaconInterval = cfg_ap_config.beaconInterval; |
| priv->group_sec_config.apGroupkeyTimeout = cfg_ap_config.groupkeyTimeout; |
| priv->group_sec_config.apStrictGtkRekey = cfg_ap_config.strictGtkRekeyEnabled; |
| priv->group_sec_config.apGmkTimeout = cfg_ap_config.gmkTimeout; |
| priv->group_sec_config.apResponseTimeout = cfg_ap_config.responseTimeout; |
| priv->group_sec_config.apRetransLimit = cfg_ap_config.retransLimit; |
| |
| priv->ap_mac_config.shortSlotTimeEnabled = cfg_ap_config.shortSlotTimeEnabled; |
| priv->ap_mac_config.ctsProtectionType=cfg_ap_config.ctsProtectionType; |
| |
| priv->ap_mac_config.wmmEnabled = cfg_ap_config.wmmEnabled; |
| |
| priv->ap_mac_config.apHtParams.rxStbc=cfg_ap_config.rxStbc; |
| priv->ap_mac_config.apHtParams.rifsModeAllowed=cfg_ap_config.rifsModeAllowed; |
| |
| priv->ap_mac_config.phySupportedBitmap = cfg_ap_config.phySupportedBitmap; |
| priv->ap_mac_config.maxListenInterval=cfg_ap_config.maxListenInterval; |
| |
| priv->ap_mac_config.supportedRatesCount= uf_configure_supported_rates(priv->ap_mac_config.supportedRates,priv->ap_mac_config.phySupportedBitmap); |
| |
| return 0; |
| } |
| |
| #endif |
| #ifdef CSR_SUPPORT_WEXT |
| |
| void |
| uf_sme_config_wq(struct work_struct *work) |
| { |
| CsrWifiSmeStaConfig staConfig; |
| CsrWifiSmeDeviceConfig deviceConfig; |
| unifi_priv_t *priv = container_of(work, unifi_priv_t, sme_config_task); |
| |
| /* Register to receive indications from the SME */ |
| CsrWifiSmeEventMaskSetReqSend(0, |
| CSR_WIFI_SME_INDICATIONS_WIFIOFF | CSR_WIFI_SME_INDICATIONS_CONNECTIONQUALITY | |
| CSR_WIFI_SME_INDICATIONS_MEDIASTATUS | CSR_WIFI_SME_INDICATIONS_MICFAILURE); |
| |
| if (sme_mgt_sme_config_get(priv, &staConfig, &deviceConfig)) { |
| unifi_warning(priv, "uf_sme_config_wq: Get unifi_SMEConfigValue failed.\n"); |
| return; |
| } |
| |
| if (priv->if_index == CSR_INDEX_5G) { |
| staConfig.ifIndex = CSR_WIFI_SME_RADIO_IF_GHZ_5_0; |
| } else { |
| staConfig.ifIndex = CSR_WIFI_SME_RADIO_IF_GHZ_2_4; |
| } |
| |
| deviceConfig.trustLevel = (CsrWifiSme80211dTrustLevel)tl_80211d; |
| if (sme_mgt_sme_config_set(priv, &staConfig, &deviceConfig)) { |
| unifi_warning(priv, |
| "SME config for 802.11d Trust Level and Radio Band failed.\n"); |
| return; |
| } |
| |
| } /* uf_sme_config_wq() */ |
| |
| #endif /* CSR_SUPPORT_WEXT */ |
| |
| |
| /* |
| * --------------------------------------------------------------------------- |
| * uf_ta_ind_wq |
| * |
| * Deferred work queue function to send Traffic Analysis protocols |
| * indications to the SME. |
| * These are done in a deferred work queue for two reasons: |
| * - the CsrWifiRouterCtrl...Send() functions are not safe for atomic context |
| * - we want to load the main driver data path as lightly as possible |
| * |
| * The TA classifications already come from a workqueue. |
| * |
| * Arguments: |
| * work Pointer to work queue item. |
| * |
| * Returns: |
| * None. |
| * --------------------------------------------------------------------------- |
| */ |
| void |
| uf_ta_ind_wq(struct work_struct *work) |
| { |
| struct ta_ind *ind = container_of(work, struct ta_ind, task); |
| unifi_priv_t *priv = container_of(ind, unifi_priv_t, ta_ind_work); |
| u16 interfaceTag = 0; |
| |
| |
| CsrWifiRouterCtrlTrafficProtocolIndSend(priv->CSR_WIFI_SME_IFACEQUEUE,0, |
| interfaceTag, |
| ind->packet_type, |
| ind->direction, |
| ind->src_addr); |
| ind->in_use = 0; |
| |
| } /* uf_ta_ind_wq() */ |
| |
| |
| /* |
| * --------------------------------------------------------------------------- |
| * uf_ta_sample_ind_wq |
| * |
| * Deferred work queue function to send Traffic Analysis sample |
| * indications to the SME. |
| * These are done in a deferred work queue for two reasons: |
| * - the CsrWifiRouterCtrl...Send() functions are not safe for atomic context |
| * - we want to load the main driver data path as lightly as possible |
| * |
| * The TA classifications already come from a workqueue. |
| * |
| * Arguments: |
| * work Pointer to work queue item. |
| * |
| * Returns: |
| * None. |
| * --------------------------------------------------------------------------- |
| */ |
| void |
| uf_ta_sample_ind_wq(struct work_struct *work) |
| { |
| struct ta_sample_ind *ind = container_of(work, struct ta_sample_ind, task); |
| unifi_priv_t *priv = container_of(ind, unifi_priv_t, ta_sample_ind_work); |
| u16 interfaceTag = 0; |
| |
| unifi_trace(priv, UDBG5, "rxtcp %d txtcp %d rxudp %d txudp %d prio %d\n", |
| priv->rxTcpThroughput, |
| priv->txTcpThroughput, |
| priv->rxUdpThroughput, |
| priv->txUdpThroughput, |
| priv->bh_thread.prio); |
| |
| if(priv->rxTcpThroughput > 1000) |
| { |
| if (bh_priority == -1 && priv->bh_thread.prio != 1) |
| { |
| struct sched_param param; |
| priv->bh_thread.prio = 1; |
| unifi_trace(priv, UDBG1, "%s new thread (RT) priority = %d\n", |
| priv->bh_thread.name, priv->bh_thread.prio); |
| param.sched_priority = priv->bh_thread.prio; |
| sched_setscheduler(priv->bh_thread.thread_task, SCHED_FIFO, ¶m); |
| } |
| } else |
| { |
| if (bh_priority == -1 && priv->bh_thread.prio != DEFAULT_PRIO) |
| { |
| struct sched_param param; |
| param.sched_priority = 0; |
| sched_setscheduler(priv->bh_thread.thread_task, SCHED_NORMAL, ¶m); |
| priv->bh_thread.prio = DEFAULT_PRIO; |
| unifi_trace(priv, UDBG1, "%s new thread priority = %d\n", |
| priv->bh_thread.name, priv->bh_thread.prio); |
| set_user_nice(priv->bh_thread.thread_task, PRIO_TO_NICE(priv->bh_thread.prio)); |
| } |
| } |
| |
| CsrWifiRouterCtrlTrafficSampleIndSend(priv->CSR_WIFI_SME_IFACEQUEUE,0, interfaceTag, ind->stats); |
| |
| ind->in_use = 0; |
| |
| } /* uf_ta_sample_ind_wq() */ |
| |
| |
| /* |
| * --------------------------------------------------------------------------- |
| * uf_send_m4_ready_wq |
| * |
| * Deferred work queue function to send M4 ReadyToSend inds to the SME. |
| * These are done in a deferred work queue for two reasons: |
| * - the CsrWifiRouterCtrl...Send() functions are not safe for atomic context |
| * - we want to load the main driver data path as lightly as possible |
| * |
| * Arguments: |
| * work Pointer to work queue item. |
| * |
| * Returns: |
| * None. |
| * --------------------------------------------------------------------------- |
| */ |
| void |
| uf_send_m4_ready_wq(struct work_struct *work) |
| { |
| netInterface_priv_t *InterfacePriv = container_of(work, netInterface_priv_t, send_m4_ready_task); |
| u16 iface = InterfacePriv->InterfaceTag; |
| unifi_priv_t *priv = InterfacePriv->privPtr; |
| CSR_MA_PACKET_REQUEST *req = &InterfacePriv->m4_signal.u.MaPacketRequest; |
| CsrWifiMacAddress peer; |
| unsigned long flags; |
| |
| /* The peer address was stored in the signal */ |
| spin_lock_irqsave(&priv->m4_lock, flags); |
| memcpy(peer.a, req->Ra.x, sizeof(peer.a)); |
| spin_unlock_irqrestore(&priv->m4_lock, flags); |
| |
| /* Send a signal to SME */ |
| CsrWifiRouterCtrlM4ReadyToSendIndSend(priv->CSR_WIFI_SME_IFACEQUEUE, 0, iface, peer); |
| |
| unifi_trace(priv, UDBG1, "M4ReadyToSendInd sent for peer %pMF\n", |
| peer.a); |
| |
| } /* uf_send_m4_ready_wq() */ |
| |
| #if (defined(CSR_WIFI_SECURITY_WAPI_ENABLE) && defined(CSR_WIFI_SECURITY_WAPI_SW_ENCRYPTION)) |
| /* |
| * --------------------------------------------------------------------------- |
| * uf_send_pkt_to_encrypt |
| * |
| * Deferred work queue function to send the WAPI data pkts to SME when unicast KeyId = 1 |
| * These are done in a deferred work queue for two reasons: |
| * - the CsrWifiRouterCtrl...Send() functions are not safe for atomic context |
| * - we want to load the main driver data path as lightly as possible |
| * |
| * Arguments: |
| * work Pointer to work queue item. |
| * |
| * Returns: |
| * None. |
| * --------------------------------------------------------------------------- |
| */ |
| void uf_send_pkt_to_encrypt(struct work_struct *work) |
| { |
| netInterface_priv_t *interfacePriv = container_of(work, netInterface_priv_t, send_pkt_to_encrypt); |
| u16 interfaceTag = interfacePriv->InterfaceTag; |
| unifi_priv_t *priv = interfacePriv->privPtr; |
| |
| u32 pktBulkDataLength; |
| u8 *pktBulkData; |
| unsigned long flags; |
| |
| if (interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_STA) { |
| |
| pktBulkDataLength = interfacePriv->wapi_unicast_bulk_data.data_length; |
| |
| if (pktBulkDataLength > 0) { |
| pktBulkData = kmalloc(pktBulkDataLength, GFP_KERNEL); |
| memset(pktBulkData, 0, pktBulkDataLength); |
| } else { |
| unifi_error(priv, "uf_send_pkt_to_encrypt() : invalid buffer\n"); |
| return; |
| } |
| |
| spin_lock_irqsave(&priv->wapi_lock, flags); |
| /* Copy over the MA PKT REQ bulk data */ |
| memcpy(pktBulkData, (u8*)interfacePriv->wapi_unicast_bulk_data.os_data_ptr, pktBulkDataLength); |
| /* Free any bulk data buffers allocated for the WAPI Data pkt */ |
| unifi_net_data_free(priv, &interfacePriv->wapi_unicast_bulk_data); |
| interfacePriv->wapi_unicast_bulk_data.net_buf_length = 0; |
| interfacePriv->wapi_unicast_bulk_data.data_length = 0; |
| interfacePriv->wapi_unicast_bulk_data.os_data_ptr = interfacePriv->wapi_unicast_bulk_data.os_net_buf_ptr = NULL; |
| spin_unlock_irqrestore(&priv->wapi_lock, flags); |
| |
| CsrWifiRouterCtrlWapiUnicastTxEncryptIndSend(priv->CSR_WIFI_SME_IFACEQUEUE, 0, interfaceTag, pktBulkDataLength, pktBulkData); |
| unifi_trace(priv, UDBG1, "WapiUnicastTxEncryptInd sent to SME\n"); |
| |
| kfree(pktBulkData); /* Would have been copied over by the SME Handler */ |
| |
| } else { |
| unifi_warning(priv, "uf_send_pkt_to_encrypt() is NOT applicable for interface mode - %d\n",interfacePriv->interfaceMode); |
| } |
| }/* uf_send_pkt_to_encrypt() */ |
| #endif |