/* * This function initializes the private structure parameters. * * The following wait queues are initialized - * - IOCTL wait queue * - Command wait queue * - Statistics wait queue * * ...and the following default parameters are set - * - Current key index : Set to 0 * - Rate index : Set to auto * - Media connected : Set to disconnected * - Adhoc link sensed : Set to false * - Nick name : Set to null * - Number of Tx timeout : Set to 0 * - Device address : Set to current address * - Rx histogram statistc : Set to 0 * * In addition, the CFG80211 work queue is also created. */ void mwifiex_init_priv_params(struct mwifiex_private *priv, struct net_device *dev) { dev->netdev_ops = &mwifiex_netdev_ops; dev->destructor = free_netdev; /* Initialize private structure */ priv->current_key_index = 0; priv->media_connected = false; memset(priv->mgmt_ie, 0, sizeof(struct mwifiex_ie) * MAX_MGMT_IE_INDEX); priv->beacon_idx = MWIFIEX_AUTO_IDX_MASK; priv->proberesp_idx = MWIFIEX_AUTO_IDX_MASK; priv->assocresp_idx = MWIFIEX_AUTO_IDX_MASK; priv->gen_idx = MWIFIEX_AUTO_IDX_MASK; priv->num_tx_timeout = 0; ether_addr_copy(priv->curr_addr, priv->adapter->perm_addr); memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN); if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA || GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) { priv->hist_data = kmalloc(sizeof(*priv->hist_data), GFP_KERNEL); if (priv->hist_data) mwifiex_hist_data_reset(priv); } }
/* This function cleans up the USB driver. * * The following major steps are followed in .disconnect for cleanup: * - Resume the device if its suspended * - Disconnect the device if connected * - Shutdown the firmware * - Unregister the device from USB bus. */ static void mwifiex_usb_cleanup_module(void) { if (!down_interruptible(&add_remove_card_sem)) up(&add_remove_card_sem); if (usb_card) { struct mwifiex_adapter *adapter = usb_card->adapter; int i; /* In case driver is removed when asynchronous FW downloading is * in progress */ wait_for_completion(&adapter->fw_load); #ifdef CONFIG_PM if (adapter->is_suspended) mwifiex_usb_resume(usb_card->intf); #endif for (i = 0; i < adapter->priv_num; i++) if ((GET_BSS_ROLE(adapter->priv[i]) == MWIFIEX_BSS_ROLE_STA) && adapter->priv[i]->media_connected) mwifiex_deauthenticate(adapter->priv[i], NULL); mwifiex_init_shutdown_fw(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY), MWIFIEX_FUNC_SHUTDOWN); } usb_deregister(&mwifiex_usb_driver); }
/** * @brief This function will check if unicast packet need be dropped * * @param priv A pointer to mlan_private * @param mac mac address to find in station list table * * @return MLAN_STATUS_FAILURE -- drop packet, otherwise forward to network stack */ static mlan_status wlan_check_unicast_packet(mlan_private * priv, t_u8 * mac) { int j; sta_node *sta_ptr = MNULL; pmlan_adapter pmadapter = priv->adapter; pmlan_private pmpriv = MNULL; t_u8 pkt_type = 0; mlan_status ret = MLAN_STATUS_SUCCESS; ENTER(); for (j = 0; j < MLAN_MAX_BSS_NUM; ++j) { if ((pmpriv = pmadapter->priv[j])) { if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_STA) continue; sta_ptr = wlan_get_station_entry(pmpriv, mac); if (sta_ptr) { if (pmpriv == priv) pkt_type = PKT_INTRA_UCAST; else pkt_type = PKT_INTER_UCAST; break; } } } if ((pkt_type == PKT_INTRA_UCAST) && (priv->pkt_fwd & PKT_FWD_INTRA_UCAST)) { PRINTM(MDATA, "Drop INTRA_UCAST packet\n"); ret = MLAN_STATUS_FAILURE; } else if ((pkt_type == PKT_INTER_UCAST) && (priv->pkt_fwd & PKT_FWD_INTER_UCAST)) { PRINTM(MDATA, "Drop INTER_UCAST packet\n"); ret = MLAN_STATUS_FAILURE; } LEAVE(); return ret; }
/** * @brief This function gets if priv is a station (STA) * * @param pmpriv Pointer to mlan_private structure * * @return MTRUE or MFALSE */ t_bool wlan_is_station(mlan_private * pmpriv) { ENTER(); LEAVE(); return (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_STA) ? MTRUE : MFALSE; }
/* * This function associates to a specific BSS discovered in a scan. * * It clears any past association response stored for application * retrieval and calls the command preparation routine to send the * command to firmware. */ int mwifiex_associate(struct mwifiex_private *priv, struct mwifiex_bssdescriptor *bss_desc) { u8 current_bssid[ETH_ALEN]; /* Return error if the adapter is not STA role or table entry * is not marked as infra. */ if ((GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_STA) || (bss_desc->bss_mode != NL80211_IFTYPE_STATION)) return -1; if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info) && !bss_desc->disable_11n && !bss_desc->disable_11ac && priv->adapter->config_bands & BAND_AAC) mwifiex_set_11ac_ba_params(priv); else mwifiex_set_ba_params(priv); memcpy(¤t_bssid, &priv->curr_bss_params.bss_descriptor.mac_address, sizeof(current_bssid)); /* Clear any past association response stored for application retrieval */ priv->assoc_rsp_size = 0; return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_ASSOCIATE, HostCmd_ACT_GEN_SET, 0, bss_desc); }
/* * This function cleans up the SDIO driver. * * The following major steps are followed for cleanup - * - Resume the device if its suspended * - Disconnect the device if connected * - Shutdown the firmware * - Unregister the device from SDIO bus. */ static void mwifiex_sdio_cleanup_module(void) { struct mwifiex_adapter *adapter = g_adapter; int i; if (down_interruptible(&add_remove_card_sem)) goto exit_sem_err; if (!adapter || !adapter->priv_num) goto exit; if (adapter->is_suspended) mwifiex_sdio_resume(adapter->dev); for (i = 0; i < adapter->priv_num; i++) if ((GET_BSS_ROLE(adapter->priv[i]) == MWIFIEX_BSS_ROLE_STA) && adapter->priv[i]->media_connected) mwifiex_deauthenticate(adapter->priv[i], NULL); if (!adapter->surprise_removed) mwifiex_init_shutdown_fw(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY), MWIFIEX_FUNC_SHUTDOWN); exit: up(&add_remove_card_sem); exit_sem_err: sdio_unregister_driver(&mwifiex_sdio); }
int mwifiex_set_bss_role(struct mwifiex_private *priv, u8 bss_role) { if (GET_BSS_ROLE(priv) == bss_role) { dev_dbg(priv->adapter->dev, "info: already in the desired role.\n"); return 0; } mwifiex_free_priv(priv); mwifiex_init_priv(priv); priv->bss_role = bss_role; switch (bss_role) { case MWIFIEX_BSS_ROLE_UAP: priv->bss_mode = NL80211_IFTYPE_AP; break; case MWIFIEX_BSS_ROLE_STA: case MWIFIEX_BSS_ROLE_ANY: default: priv->bss_mode = NL80211_IFTYPE_STATION; break; } mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE, HostCmd_ACT_GEN_SET, 0, NULL, true); return mwifiex_sta_init_cmd(priv, false); }
/* * This function sends a packet to device. * * It processes the packet to add the TxPD, checks condition and * sends the processed packet to firmware for transmission. * * On successful completion, the function calls the completion callback * and logs the time. */ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb, struct mwifiex_tx_param *tx_param) { int ret = -1; struct mwifiex_adapter *adapter = priv->adapter; u8 *head_ptr; struct txpd *local_tx_pd = NULL; head_ptr = (u8 *) mwifiex_process_sta_txpd(priv, skb); if (head_ptr) { if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) local_tx_pd = (struct txpd *) (head_ptr + INTF_HEADER_LEN); ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, skb->data, skb->len, tx_param); } switch (ret) { case -EBUSY: if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) && (adapter->pps_uapsd_mode) && (adapter->tx_lock_flag)) { priv->adapter->tx_lock_flag = false; local_tx_pd->flags = 0; } dev_dbg(adapter->dev, "data: -EBUSY is returned\n"); break; case -1: adapter->data_sent = false; dev_err(adapter->dev, "mwifiex_write_data_async failed: 0x%X\n", ret); adapter->dbg.num_tx_host_to_card_failure++; mwifiex_write_data_complete(adapter, skb, ret); break; case -EINPROGRESS: adapter->data_sent = false; break; case 0: mwifiex_write_data_complete(adapter, skb, ret); break; default: break; } return ret; }
/* Enable or disable the 11h extensions in the firmware */ int mwifiex_11h_activate(struct mwifiex_private *priv, bool flag) { u32 enable = flag; /* enable master mode radar detection on AP interface */ if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) && enable) enable |= MWIFIEX_MASTER_RADAR_DET_MASK; return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB, HostCmd_ACT_GEN_SET, DOT11H_I, &enable, true); }
/* * Adds TxPD to AMSDU header. * * Each AMSDU packet will contain one TxPD at the beginning, * followed by multiple AMSDU subframes. */ static void mwifiex_11n_form_amsdu_txpd(struct mwifiex_private *priv, struct sk_buff *skb) { struct txpd *local_tx_pd; struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb); unsigned int pad; int headroom = (priv->adapter->iface_type == MWIFIEX_USB) ? 0 : INTF_HEADER_LEN; pad = ((void *)skb->data - sizeof(*local_tx_pd) - headroom - NULL) & (MWIFIEX_DMA_ALIGN_SZ - 1); skb_push(skb, pad); skb_push(skb, sizeof(*local_tx_pd)); local_tx_pd = (struct txpd *) skb->data; memset(local_tx_pd, 0, sizeof(struct txpd)); /* Original priority has been overwritten */ local_tx_pd->priority = (u8) skb->priority; local_tx_pd->pkt_delay_2ms = mwifiex_wmm_compute_drv_pkt_delay(priv, skb); local_tx_pd->bss_num = priv->bss_num; local_tx_pd->bss_type = priv->bss_type; /* Always zero as the data is followed by struct txpd */ local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd) + pad); local_tx_pd->tx_pkt_type = cpu_to_le16(PKT_TYPE_AMSDU); local_tx_pd->tx_pkt_length = cpu_to_le16(skb->len - sizeof(*local_tx_pd) - pad); if (tx_info->flags & MWIFIEX_BUF_FLAG_TDLS_PKT) local_tx_pd->flags |= MWIFIEX_TXPD_FLAGS_TDLS_PACKET; if (local_tx_pd->tx_control == 0) /* TxCtrl set by user or default */ local_tx_pd->tx_control = cpu_to_le32(priv->pkt_tx_ctrl); if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA && priv->adapter->pps_uapsd_mode) { if (true == mwifiex_check_last_packet_indication(priv)) { priv->adapter->tx_lock_flag = true; local_tx_pd->flags = MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET; } } }
/** * @brief This function will process the rx packet and * forward it to kernel/upper layer * * @param priv A pointer to mlan_private * @param payload A pointer to rx packet payload * * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE */ static mlan_status wlan_11n_dispatch_pkt(t_void * priv, t_void * payload) { mlan_status ret = MLAN_STATUS_SUCCESS; #ifdef STA_SUPPORT pmlan_adapter pmadapter = ((pmlan_private) priv)->adapter; #endif #ifdef UAP_SUPPORT if (GET_BSS_ROLE((mlan_private *) priv) == MLAN_BSS_ROLE_UAP) return wlan_process_uap_rx_packet(priv, (pmlan_buffer) payload); #endif /* UAP_SUPPORT */ #ifdef STA_SUPPORT ret = wlan_process_rx_packet(pmadapter, (pmlan_buffer) payload); #endif return ret; }
static void mwifiex_usb_disconnect(struct usb_interface *intf) { struct usb_card_rec *card = usb_get_intfdata(intf); struct mwifiex_adapter *adapter; int i; if (!card || !card->adapter) { pr_err("%s: card or card->adapter is NULL\n", __func__); return; } adapter = card->adapter; if (!adapter->priv_num) return; /* In case driver is removed when asynchronous FW downloading is * in progress */ wait_for_completion(&adapter->fw_load); if (user_rmmod) { #ifdef CONFIG_PM if (adapter->is_suspended) mwifiex_usb_resume(intf); #endif for (i = 0; i < adapter->priv_num; i++) if ((GET_BSS_ROLE(adapter->priv[i]) == MWIFIEX_BSS_ROLE_STA) && adapter->priv[i]->media_connected) mwifiex_deauthenticate(adapter->priv[i], NULL); mwifiex_init_shutdown_fw(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY), MWIFIEX_FUNC_SHUTDOWN); } mwifiex_usb_free(card); dev_dbg(adapter->dev, "%s: removing card\n", __func__); mwifiex_remove_card(adapter, &add_remove_card_sem); usb_set_intfdata(intf, NULL); usb_put_dev(interface_to_usbdev(intf)); kfree(card); return; }
/* * Packet send completion callback handler. * * It either frees the buffer directly or forwards it to another * completion callback which checks conditions, updates statistics, * wakes up stalled traffic queue if required, and then frees the buffer. */ int mwifiex_write_data_complete(struct mwifiex_adapter *adapter, struct sk_buff *skb, int status) { struct mwifiex_private *priv, *tpriv; struct mwifiex_txinfo *tx_info; int i; if (!skb) return 0; tx_info = MWIFIEX_SKB_TXCB(skb); priv = mwifiex_get_priv_by_id(adapter, tx_info->bss_num, tx_info->bss_type); if (!priv) goto done; mwifiex_set_trans_start(priv->netdev); if (!status) { priv->stats.tx_packets++; priv->stats.tx_bytes += skb->len; } else { priv->stats.tx_errors++; } if (atomic_dec_return(&adapter->tx_pending) >= LOW_TX_PENDING) goto done; for (i = 0; i < adapter->priv_num; i++) { tpriv = adapter->priv[i]; if ((GET_BSS_ROLE(tpriv) == MWIFIEX_BSS_ROLE_STA) && (tpriv->media_connected)) { if (netif_queue_stopped(tpriv->netdev)) mwifiex_wake_up_net_dev_queue(tpriv->netdev, adapter); } } done: dev_kfree_skb_any(skb); return 0; }
/** * @brief Update the TxPktLength field in TxPD after the complete AMSDU * packet is formed * * @param priv A pointer to mlan_private structure * @param mbuf TxPD buffer * * @return N/A */ static INLINE void wlan_11n_update_pktlen_amsdu_txpd(mlan_private * priv, pmlan_buffer mbuf) { TxPD *ptx_pd; ENTER(); ptx_pd = (TxPD *) mbuf->pbuf; ptx_pd->tx_pkt_length = (t_u16) wlan_cpu_to_le16(mbuf->data_len - sizeof(TxPD)); #ifdef STA_SUPPORT if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) && (priv->adapter->pps_uapsd_mode)) { if (MTRUE == wlan_check_last_packet_indication(priv)) { priv->adapter->tx_lock_flag = MTRUE; ptx_pd->flags |= MRVDRV_TxPD_POWER_MGMT_LAST_PACKET; } } #endif /* STA_SUPPORT */ LEAVE(); }
static bool mwifiex_bypass_tx_queue(struct mwifiex_private *priv, struct sk_buff *skb) { struct ethhdr *eth_hdr = (struct ethhdr *)skb->data; if (ntohs(eth_hdr->h_proto) == ETH_P_PAE || mwifiex_is_skb_mgmt_frame(skb) || (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA && ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) && (ntohs(eth_hdr->h_proto) == ETH_P_TDLS))) { mwifiex_dbg(priv->adapter, DATA, "bypass txqueue; eth type %#x, mgmt %d\n", ntohs(eth_hdr->h_proto), mwifiex_is_skb_mgmt_frame(skb)); return true; } return false; }
void mwifiex_process_tx_pause_event(struct mwifiex_private *priv, struct sk_buff *event_skb) { struct mwifiex_ie_types_header *tlv; u16 tlv_type, tlv_len; int tlv_buf_left; if (!priv->media_connected) { mwifiex_dbg(priv->adapter, ERROR, "tx_pause event while disconnected; bss_role=%d\n", priv->bss_role); return; } tlv_buf_left = event_skb->len - sizeof(u32); tlv = (void *)event_skb->data + sizeof(u32); while (tlv_buf_left >= (int)sizeof(struct mwifiex_ie_types_header)) { tlv_type = le16_to_cpu(tlv->type); tlv_len = le16_to_cpu(tlv->len); if ((sizeof(struct mwifiex_ie_types_header) + tlv_len) > tlv_buf_left) { mwifiex_dbg(priv->adapter, ERROR, "wrong tlv: tlvLen=%d, tlvBufLeft=%d\n", tlv_len, tlv_buf_left); break; } if (tlv_type == TLV_TYPE_TX_PAUSE) { if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) mwifiex_process_sta_tx_pause(priv, tlv); else mwifiex_process_uap_tx_pause(priv, tlv); } tlv_buf_left -= sizeof(struct mwifiex_ie_types_header) + tlv_len; tlv = (void *)((u8 *)tlv + tlv_len + sizeof(struct mwifiex_ie_types_header)); } }
/* * SDIO remove. * * This function removes the interface and frees up the card structure. */ static void mwifiex_sdio_remove(struct sdio_func *func) { struct sdio_mmc_card *card; struct mwifiex_adapter *adapter; struct mwifiex_private *priv; int i; pr_debug("info: SDIO func num=%d\n", func->num); card = sdio_get_drvdata(func); if (!card) return; adapter = card->adapter; if (!adapter || !adapter->priv_num) return; /* In case driver is removed when asynchronous FW load is in progress */ wait_for_completion(&adapter->fw_load); if (user_rmmod) { #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)) if (adapter->is_suspended) mwifiex_sdio_resume(adapter->dev); #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)) */ for (i = 0; i < adapter->priv_num; i++) if ((GET_BSS_ROLE(adapter->priv[i]) == MWIFIEX_BSS_ROLE_STA) && adapter->priv[i]->media_connected) mwifiex_deauthenticate(adapter->priv[i], NULL); priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); mwifiex_disable_auto_ds(priv); mwifiex_init_shutdown_fw(priv, MWIFIEX_FUNC_SHUTDOWN); } mwifiex_remove_card(card->adapter, &add_remove_card_sem); kfree(card); }
static void mwifiex_pcie_remove(struct pci_dev *pdev) { struct pcie_service_card *card; struct mwifiex_adapter *adapter; struct mwifiex_private *priv; int i; card = pci_get_drvdata(pdev); if (!card) return; adapter = card->adapter; if (!adapter || !adapter->priv_num) return; if (user_rmmod) { #ifdef CONFIG_PM if (adapter->is_suspended) mwifiex_pcie_resume(pdev); #endif for (i = 0; i < adapter->priv_num; i++) if ((GET_BSS_ROLE(adapter->priv[i]) == MWIFIEX_BSS_ROLE_STA) && adapter->priv[i]->media_connected) mwifiex_deauthenticate(adapter->priv[i], NULL); priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); mwifiex_disable_auto_ds(priv); mwifiex_init_shutdown_fw(priv, MWIFIEX_FUNC_SHUTDOWN); } mwifiex_remove_card(card->adapter, &add_remove_card_sem); kfree(card); }
static void mwifiex_sdio_remove(struct sdio_func *func) { struct sdio_mmc_card *card; struct mwifiex_adapter *adapter; struct mwifiex_private *priv; int i; pr_debug("info: SDIO func num=%d\n", func->num); card = sdio_get_drvdata(func); if (!card) return; adapter = card->adapter; if (!adapter || !adapter->priv_num) return; if (user_rmmod) { if (adapter->is_suspended) mwifiex_sdio_resume(adapter->dev); for (i = 0; i < adapter->priv_num; i++) if ((GET_BSS_ROLE(adapter->priv[i]) == MWIFIEX_BSS_ROLE_STA) && adapter->priv[i]->media_connected) mwifiex_deauthenticate(adapter->priv[i], NULL); priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); mwifiex_disable_auto_ds(priv); mwifiex_init_shutdown_fw(priv, MWIFIEX_FUNC_SHUTDOWN); } mwifiex_remove_card(card->adapter, &add_remove_card_sem); kfree(card); }
/* * Sends IOCTL request to set encoding parameters. * * This function allocates the IOCTL request buffer, fills it * with requisite parameters and calls the IOCTL handler. */ int mwifiex_set_encode(struct mwifiex_private *priv, struct key_params *kp, const u8 *key, int key_len, u8 key_index, const u8 *mac_addr, int disable) { struct mwifiex_ds_encrypt_key encrypt_key; memset(&encrypt_key, 0, sizeof(struct mwifiex_ds_encrypt_key)); encrypt_key.key_len = key_len; encrypt_key.key_index = key_index; if (kp && kp->cipher == WLAN_CIPHER_SUITE_AES_CMAC) encrypt_key.is_igtk_key = true; if (!disable) { if (key_len) memcpy(encrypt_key.key_material, key, key_len); else encrypt_key.is_current_wep_key = true; if (mac_addr) memcpy(encrypt_key.mac_addr, mac_addr, ETH_ALEN); if (kp && kp->seq && kp->seq_len) { memcpy(encrypt_key.pn, kp->seq, kp->seq_len); encrypt_key.pn_len = kp->seq_len; encrypt_key.is_rx_seq_valid = true; } } else { if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) return 0; encrypt_key.key_disable = true; if (mac_addr) memcpy(encrypt_key.mac_addr, mac_addr, ETH_ALEN); } return mwifiex_sec_ioctl_encrypt_key(priv, &encrypt_key); }
/* * Adds TxPD to AMSDU header. * * Each AMSDU packet will contain one TxPD at the beginning, * followed by multiple AMSDU subframes. */ static void mwifiex_11n_form_amsdu_txpd(struct mwifiex_private *priv, struct sk_buff *skb) { struct txpd *local_tx_pd; skb_push(skb, sizeof(*local_tx_pd)); local_tx_pd = (struct txpd *) skb->data; memset(local_tx_pd, 0, sizeof(struct txpd)); /* Original priority has been overwritten */ local_tx_pd->priority = (u8) skb->priority; local_tx_pd->pkt_delay_2ms = mwifiex_wmm_compute_drv_pkt_delay(priv, skb); local_tx_pd->bss_num = priv->bss_num; local_tx_pd->bss_type = priv->bss_type; /* Always zero as the data is followed by struct txpd */ local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd)); local_tx_pd->tx_pkt_type = cpu_to_le16(PKT_TYPE_AMSDU); local_tx_pd->tx_pkt_length = cpu_to_le16(skb->len - sizeof(*local_tx_pd)); if (local_tx_pd->tx_control == 0) /* TxCtrl set by user or default */ local_tx_pd->tx_control = cpu_to_le32(priv->pkt_tx_ctrl); if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) && (priv->adapter->pps_uapsd_mode)) { if (true == mwifiex_check_last_packet_indication(priv)) { priv->adapter->tx_lock_flag = true; local_tx_pd->flags = MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET; } } }
/* * This function resets the connection state. * * The function is invoked after receiving a disconnect event from firmware, * and performs the following actions - * - Set media status to disconnected * - Clean up Tx and Rx packets * - Resets SNR/NF/RSSI value in driver * - Resets security configurations in driver * - Enables auto data rate * - Saves the previous SSID and BSSID so that they can * be used for re-association, if required * - Erases current SSID and BSSID information * - Sends a disconnect event to upper layers/applications. */ void mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code, bool from_ap) { struct mwifiex_adapter *adapter = priv->adapter; if (!priv->media_connected) return; mwifiex_dbg(adapter, INFO, "info: handles disconnect event\n"); priv->media_connected = false; priv->scan_block = false; priv->port_open = false; if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) && ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info)) { mwifiex_disable_all_tdls_links(priv); if (priv->adapter->auto_tdls) mwifiex_clean_auto_tdls(priv); } /* Free Tx and Rx packets, report disconnect to upper layer */ mwifiex_clean_txrx(priv); /* Reset SNR/NF/RSSI values */ priv->data_rssi_last = 0; priv->data_nf_last = 0; priv->data_rssi_avg = 0; priv->data_nf_avg = 0; priv->bcn_rssi_last = 0; priv->bcn_nf_last = 0; priv->bcn_rssi_avg = 0; priv->bcn_nf_avg = 0; priv->rxpd_rate = 0; priv->rxpd_htinfo = 0; priv->sec_info.wpa_enabled = false; priv->sec_info.wpa2_enabled = false; priv->wpa_ie_len = 0; priv->sec_info.wapi_enabled = false; priv->wapi_ie_len = 0; priv->sec_info.wapi_key_on = false; priv->sec_info.encryption_mode = 0; /* Enable auto data rate */ priv->is_data_rate_auto = true; priv->data_rate = 0; priv->assoc_resp_ht_param = 0; priv->ht_param_present = false; if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA || GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) && priv->hist_data) mwifiex_hist_data_reset(priv); if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { priv->adhoc_state = ADHOC_IDLE; priv->adhoc_is_link_sensed = false; } /* * Memorize the previous SSID and BSSID so * it could be used for re-assoc */ mwifiex_dbg(adapter, INFO, "info: previous SSID=%s, SSID len=%u\n", priv->prev_ssid.ssid, priv->prev_ssid.ssid_len); mwifiex_dbg(adapter, INFO, "info: current SSID=%s, SSID len=%u\n", priv->curr_bss_params.bss_descriptor.ssid.ssid, priv->curr_bss_params.bss_descriptor.ssid.ssid_len); memcpy(&priv->prev_ssid, &priv->curr_bss_params.bss_descriptor.ssid, sizeof(struct cfg80211_ssid)); memcpy(priv->prev_bssid, priv->curr_bss_params.bss_descriptor.mac_address, ETH_ALEN); /* Need to erase the current SSID and BSSID info */ memset(&priv->curr_bss_params, 0x00, sizeof(priv->curr_bss_params)); adapter->tx_lock_flag = false; adapter->pps_uapsd_mode = false; if (test_bit(MWIFIEX_IS_CMD_TIMEDOUT, &adapter->work_flags) && adapter->curr_cmd) return; priv->media_connected = false; mwifiex_dbg(adapter, MSG, "info: successfully disconnected from %pM: reason code %d\n", priv->cfg_bssid, reason_code); if (priv->bss_mode == NL80211_IFTYPE_STATION || priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT) { cfg80211_disconnected(priv->netdev, reason_code, NULL, 0, !from_ap, GFP_KERNEL); } eth_zero_addr(priv->cfg_bssid); mwifiex_stop_net_dev_queue(priv->netdev, adapter); if (netif_carrier_ok(priv->netdev)) netif_carrier_off(priv->netdev); if (!ISSUPP_FIRMWARE_SUPPLICANT(priv->adapter->fw_cap_info)) return; mwifiex_send_cmd(priv, HostCmd_CMD_GTK_REKEY_OFFLOAD_CFG, HostCmd_ACT_GEN_REMOVE, 0, NULL, false); }
/** * @brief Create debug proc file * * @param priv A pointer to a moal_private structure * * @return N/A */ void woal_debug_entry(moal_private * priv) { struct proc_dir_entry *r; struct proc_dir_entry *r2; int i; int handle_items; ENTER(); if (priv->proc_entry == NULL) { LEAVE(); return; } #ifdef STA_SUPPORT if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) { priv->items_priv.items = (struct debug_data *) kmalloc(sizeof(items), GFP_KERNEL); if (!priv->items_priv.items) { PRINTM(MERROR, "Failed to allocate memory for debug data\n"); LEAVE(); return; } memcpy(priv->items_priv.items, items, sizeof(items)); priv->items_priv.num_of_items = sizeof(items) / sizeof(items[0]); priv->items_priv_hist.num_of_items = 0; } #endif #ifdef UAP_SUPPORT if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) { priv->items_priv.items = (struct debug_data *) kmalloc(sizeof(uap_items), GFP_KERNEL); if (!priv->items_priv.items) { PRINTM(MERROR, "Failed to allocate memory for debug data\n"); LEAVE(); return; } memcpy(priv->items_priv.items, uap_items, sizeof(uap_items)); priv->items_priv.num_of_items = sizeof(uap_items) / sizeof(uap_items[0]); } #endif priv->items_priv.priv = priv; priv->items_priv_hist.priv = priv; handle_items = 8; #ifdef SDIO_MMC_DEBUG handle_items += 2; #endif #if defined(SDIO_SUSPEND_RESUME) handle_items += 2; #endif for (i = 1; i <= handle_items; i++) priv->items_priv.items[priv->items_priv.num_of_items - i].addr += (t_ptr) (priv->phandle); /* Create proc entry */ r = create_proc_entry("debug", 0644, priv->proc_entry); if (r == NULL) { LEAVE(); return; } r->data = &priv->items_priv; r->read_proc = woal_debug_read; r->write_proc = woal_debug_write; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30) r->owner = THIS_MODULE; #endif /* Initialize hgm data structure */ hgm_seq_init_globals(); /* Create proc entry for driver histogram data */ r2 = create_proc_entry("histogram", 0664, priv->proc_entry); if (r2 == NULL) { LEAVE(); return; } r2->data = &priv->items_priv_hist; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30) r2->owner = THIS_MODULE; #endif r2->proc_fops = &hgm_file_ops; r2->uid = 0; r2->gid = 1008; // wifi group LEAVE(); }
/** * @brief This function checks the conditions and sends packet to device * * @param priv A pointer to mlan_private structure * @param pmbuf A pointer to the mlan_buffer for process * @param tx_param A pointer to mlan_tx_param structure * * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise failure */ mlan_status wlan_process_tx(pmlan_private priv, pmlan_buffer pmbuf, mlan_tx_param * tx_param) { mlan_status ret = MLAN_STATUS_SUCCESS; pmlan_adapter pmadapter = priv->adapter; t_u8 *head_ptr = MNULL; #ifdef DEBUG_LEVEL1 t_u32 sec = 0, usec = 0; #endif #ifdef STA_SUPPORT TxPD *plocal_tx_pd = MNULL; #endif ENTER(); head_ptr = (t_u8 *) priv->ops.process_txpd(priv, pmbuf); if (!head_ptr) { pmbuf->status_code = MLAN_ERROR_PKT_INVALID; ret = MLAN_STATUS_FAILURE; goto done; } #ifdef STA_SUPPORT if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) plocal_tx_pd = (TxPD *) (head_ptr + INTF_HEADER_LEN); #endif ret = wlan_sdio_host_to_card(pmadapter, MLAN_TYPE_DATA, pmbuf, tx_param); done: switch (ret) { case MLAN_STATUS_RESOURCE: #ifdef STA_SUPPORT if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) && pmadapter->pps_uapsd_mode && (pmadapter->tx_lock_flag == MTRUE)) { pmadapter->tx_lock_flag = MFALSE; plocal_tx_pd->flags = 0; } #endif PRINTM(MINFO, "MLAN_STATUS_RESOURCE is returned\n"); break; case MLAN_STATUS_FAILURE: pmadapter->data_sent = MFALSE; PRINTM(MERROR, "Error: host_to_card failed: 0x%X\n", ret); pmadapter->dbg.num_tx_host_to_card_failure++; pmbuf->status_code = MLAN_ERROR_DATA_TX_FAIL; wlan_write_data_complete(pmadapter, pmbuf, ret); break; case MLAN_STATUS_PENDING: DBG_HEXDUMP(MDAT_D, "Tx", head_ptr + INTF_HEADER_LEN, MIN(pmbuf->data_len + sizeof(TxPD), MAX_DATA_DUMP_LEN)); break; case MLAN_STATUS_SUCCESS: DBG_HEXDUMP(MDAT_D, "Tx", head_ptr + INTF_HEADER_LEN, MIN(pmbuf->data_len + sizeof(TxPD), MAX_DATA_DUMP_LEN)); wlan_write_data_complete(pmadapter, pmbuf, ret); break; default: break; } if ((ret == MLAN_STATUS_SUCCESS) || (ret == MLAN_STATUS_PENDING)) { PRINTM_GET_SYS_TIME(MDATA, &sec, &usec); PRINTM_NETINTF(MDATA, priv); PRINTM(MDATA, "%lu.%06lu : Data => FW\n", sec, usec); } LEAVE(); return ret; }
/** * @brief Aggregate multiple packets into one single AMSDU packet * * @param priv A pointer to mlan_private structure * @param pra_list Pointer to the RA List table containing the pointers * to packets. * @param headroom Any interface specific headroom that may be need. TxPD * will be formed leaving this headroom. * @param ptrindex Pointer index * * @return Final packet size or MLAN_STATUS_FAILURE */ int wlan_11n_aggregate_pkt(mlan_private * priv, raListTbl * pra_list, int headroom, int ptrindex) { int pkt_size = 0; pmlan_adapter pmadapter = priv->adapter; mlan_buffer *pmbuf_aggr, *pmbuf_src; t_u8 *data; int pad = 0; mlan_status ret = MLAN_STATUS_SUCCESS; #ifdef DEBUG_LEVEL1 t_u32 sec = 0, usec = 0; #endif mlan_tx_param tx_param; #ifdef STA_SUPPORT TxPD *ptx_pd = MNULL; #endif t_u32 max_amsdu_size = MIN(pra_list->max_amsdu, pmadapter->tx_buf_size); ENTER(); PRINTM(MDAT_D, "Handling Aggr packet\n"); pmbuf_src = (pmlan_buffer) util_peek_list(pmadapter->pmoal_handle, &pra_list->buf_head, MNULL, MNULL); if (pmbuf_src) { pmbuf_aggr = wlan_alloc_mlan_buffer(pmadapter, pmadapter->tx_buf_size, 0, MOAL_MALLOC_BUFFER); if (!pmbuf_aggr) { PRINTM(MERROR, "Error allocating mlan_buffer\n"); pmadapter->callbacks.moal_spin_unlock(pmadapter-> pmoal_handle, priv->wmm. ra_list_spinlock); LEAVE(); return MLAN_STATUS_FAILURE; } data = pmbuf_aggr->pbuf + headroom; pmbuf_aggr->bss_index = pmbuf_src->bss_index; pmbuf_aggr->buf_type = pmbuf_src->buf_type; pmbuf_aggr->priority = pmbuf_src->priority; pmbuf_aggr->pbuf = data; pmbuf_aggr->data_offset = 0; pmbuf_aggr->in_ts_sec = pmbuf_src->in_ts_sec; pmbuf_aggr->in_ts_usec = pmbuf_src->in_ts_usec; if (pmbuf_src->flags & MLAN_BUF_FLAG_TDLS) pmbuf_aggr->flags |= MLAN_BUF_FLAG_TDLS; /* Form AMSDU */ wlan_11n_form_amsdu_txpd(priv, pmbuf_aggr); pkt_size = sizeof(TxPD); #ifdef STA_SUPPORT if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) ptx_pd = (TxPD *) pmbuf_aggr->pbuf; #endif } else { pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle, priv->wmm. ra_list_spinlock); goto exit; } while (pmbuf_src && ((pkt_size + (pmbuf_src->data_len + LLC_SNAP_LEN) + headroom) <= max_amsdu_size)) { pmbuf_src = (pmlan_buffer) util_dequeue_list(pmadapter->pmoal_handle, &pra_list->buf_head, MNULL, MNULL); pra_list->total_pkts--; /* decrement for every PDU taken from the list */ priv->wmm.pkts_queued[ptrindex]--; util_scalar_decrement(pmadapter->pmoal_handle, &priv->wmm.tx_pkts_queued, MNULL, MNULL); pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle, priv->wmm. ra_list_spinlock); if (pmbuf_src->flags & MLAN_BUF_FLAG_TCP_ACK) pmadapter->callbacks.moal_tcp_ack_tx_ind(pmadapter-> pmoal_handle, pmbuf_src); pkt_size += wlan_11n_form_amsdu_pkt(pmadapter, (data + pkt_size), pmbuf_src->pbuf + pmbuf_src->data_offset, pmbuf_src->data_len, &pad); DBG_HEXDUMP(MDAT_D, "pmbuf_src", pmbuf_src, sizeof(mlan_buffer)); wlan_write_data_complete(pmadapter, pmbuf_src, MLAN_STATUS_SUCCESS); pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle, priv->wmm.ra_list_spinlock); if (!wlan_is_ralist_valid(priv, pra_list, ptrindex)) { pmadapter->callbacks.moal_spin_unlock(pmadapter-> pmoal_handle, priv->wmm. ra_list_spinlock); LEAVE(); return MLAN_STATUS_FAILURE; } pmbuf_src = (pmlan_buffer) util_peek_list(pmadapter->pmoal_handle, &pra_list->buf_head, MNULL, MNULL); } pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle, priv->wmm.ra_list_spinlock); /* Last AMSDU packet does not need padding */ pkt_size -= pad; pmbuf_aggr->data_len = pkt_size; wlan_11n_update_pktlen_amsdu_txpd(priv, pmbuf_aggr); pmbuf_aggr->data_len += headroom; pmbuf_aggr->pbuf = data - headroom; tx_param.next_pkt_len = ((pmbuf_src) ? pmbuf_src->data_len + sizeof(TxPD) : 0); ret = wlan_sdio_host_to_card(pmadapter, MLAN_TYPE_DATA, pmbuf_aggr, &tx_param); switch (ret) { case MLAN_STATUS_RESOURCE: pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle, priv->wmm.ra_list_spinlock); if (!wlan_is_ralist_valid(priv, pra_list, ptrindex)) { pmadapter->callbacks.moal_spin_unlock(pmadapter-> pmoal_handle, priv->wmm. ra_list_spinlock); pmbuf_aggr->status_code = MLAN_ERROR_PKT_INVALID; wlan_write_data_complete(pmadapter, pmbuf_aggr, MLAN_STATUS_FAILURE); LEAVE(); return MLAN_STATUS_FAILURE; } #ifdef STA_SUPPORT /* reset tx_lock_flag */ if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) && pmadapter->pps_uapsd_mode && (pmadapter->tx_lock_flag == MTRUE)) { pmadapter->tx_lock_flag = MFALSE; ptx_pd->flags = 0; } #endif util_enqueue_list_head(pmadapter->pmoal_handle, &pra_list->buf_head, (pmlan_linked_list) pmbuf_aggr, MNULL, MNULL); pra_list->total_pkts++; /* add back only one: aggregated packet is requeued as one */ priv->wmm.pkts_queued[ptrindex]++; util_scalar_increment(pmadapter->pmoal_handle, &priv->wmm.tx_pkts_queued, MNULL, MNULL); pmbuf_aggr->flags |= MLAN_BUF_FLAG_REQUEUED_PKT; pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle, priv->wmm. ra_list_spinlock); PRINTM(MINFO, "MLAN_STATUS_RESOURCE is returned\n"); pmbuf_aggr->status_code = MLAN_ERROR_PKT_INVALID; break; case MLAN_STATUS_FAILURE: pmadapter->data_sent = MFALSE; PRINTM(MERROR, "Error: host_to_card failed: 0x%X\n", ret); pmbuf_aggr->status_code = MLAN_ERROR_DATA_TX_FAIL; pmadapter->dbg.num_tx_host_to_card_failure++; wlan_write_data_complete(pmadapter, pmbuf_aggr, ret); goto exit; case MLAN_STATUS_PENDING: break; case MLAN_STATUS_SUCCESS: wlan_write_data_complete(pmadapter, pmbuf_aggr, ret); break; default: break; } if (ret != MLAN_STATUS_RESOURCE) { pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle, priv->wmm.ra_list_spinlock); if (wlan_is_ralist_valid(priv, pra_list, ptrindex)) { priv->wmm.packets_out[ptrindex]++; priv->wmm.tid_tbl_ptr[ptrindex].ra_list_curr = pra_list; } pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur = pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur-> pnext; pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle, priv->wmm. ra_list_spinlock); } PRINTM_GET_SYS_TIME(MDATA, &sec, &usec); PRINTM_NETINTF(MDATA, priv); PRINTM(MDATA, "%lu.%06lu : Data => FW\n", sec, usec); exit: LEAVE(); return pkt_size + headroom; }
/** * @brief Deaggregate the received AMSDU packet * * @param priv A pointer to mlan_private structure * @param pmbuf A pointer to aggregated data packet * * @return MLAN_STATUS_SUCCESS --success, otherwise fail */ mlan_status wlan_11n_deaggregate_pkt(mlan_private * priv, pmlan_buffer pmbuf) { t_u16 pkt_len; int total_pkt_len; t_u8 *data; t_u32 max_rx_data_size = MLAN_RX_DATA_BUF_SIZE; int pad; mlan_status ret = MLAN_STATUS_FAILURE; RxPacketHdr_t *prx_pkt; mlan_buffer *daggr_mbuf = MNULL; mlan_adapter *pmadapter = priv->adapter; t_u8 rfc1042_eth_hdr[MLAN_MAC_ADDR_LENGTH] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; t_u8 hdr_len = sizeof(Eth803Hdr_t); ENTER(); data = (t_u8 *) (pmbuf->pbuf + pmbuf->data_offset); total_pkt_len = pmbuf->data_len; /* Sanity test */ if (total_pkt_len > max_rx_data_size) { PRINTM(MERROR, "Total packet length greater than tx buffer" " size %d\n", total_pkt_len); goto done; } pmbuf->use_count = wlan_11n_get_num_aggrpkts(data, total_pkt_len); while (total_pkt_len >= hdr_len) { prx_pkt = (RxPacketHdr_t *) data; /* Length will be in network format, change it to host */ pkt_len = mlan_ntohs((*(t_u16 *) (data + (2 * MLAN_MAC_ADDR_LENGTH)))); if (pkt_len > total_pkt_len) { PRINTM(MERROR, "Error in packet length: total_pkt_len = %d, pkt_len = %d\n", total_pkt_len, pkt_len); break; } pad = (((pkt_len + sizeof(Eth803Hdr_t)) & 3)) ? (4 - ((pkt_len + sizeof(Eth803Hdr_t)) & 3)) : 0; total_pkt_len -= pkt_len + pad + sizeof(Eth803Hdr_t); if (memcmp(pmadapter, &prx_pkt->rfc1042_hdr, rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr)) == 0) { memmove(pmadapter, data + LLC_SNAP_LEN, data, (2 * MLAN_MAC_ADDR_LENGTH)); data += LLC_SNAP_LEN; pkt_len += sizeof(Eth803Hdr_t) - LLC_SNAP_LEN; } else { *(t_u16 *) (data + (2 * MLAN_MAC_ADDR_LENGTH)) = (t_u16) 0; pkt_len += sizeof(Eth803Hdr_t); } daggr_mbuf = wlan_alloc_mlan_buffer(pmadapter, pkt_len, 0, MOAL_ALLOC_MLAN_BUFFER); if (daggr_mbuf == MNULL) { PRINTM(MERROR, "Error allocating daggr mlan_buffer\n"); LEAVE(); return MLAN_STATUS_FAILURE; } daggr_mbuf->bss_index = pmbuf->bss_index; daggr_mbuf->buf_type = pmbuf->buf_type; daggr_mbuf->data_len = pkt_len; daggr_mbuf->in_ts_sec = pmbuf->in_ts_sec; daggr_mbuf->in_ts_usec = pmbuf->in_ts_usec; daggr_mbuf->pparent = pmbuf; daggr_mbuf->priority = pmbuf->priority; memcpy(pmadapter, daggr_mbuf->pbuf + daggr_mbuf->data_offset, data, pkt_len); #ifdef UAP_SUPPORT if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) { ret = wlan_uap_recv_packet(priv, daggr_mbuf); } else { #endif /* UAP_SUPPORT */ ret = pmadapter->callbacks.moal_recv_packet(pmadapter-> pmoal_handle, daggr_mbuf); #ifdef UAP_SUPPORT } #endif /* UAP_SUPPORT */ switch (ret) { case MLAN_STATUS_PENDING: break; case MLAN_STATUS_FAILURE: PRINTM(MERROR, "Deaggr, send to moal failed\n"); daggr_mbuf->status_code = MLAN_ERROR_PKT_INVALID; case MLAN_STATUS_SUCCESS: wlan_recv_packet_complete(pmadapter, daggr_mbuf, ret); break; default: break; } data += pkt_len + pad; } done: LEAVE(); return ret; }
/** * @brief Create debug proc file * * @param priv A pointer to a moal_private structure * * @return N/A */ void woal_debug_entry(moal_private * priv) { struct proc_dir_entry *r; ENTER(); if (priv->proc_entry == NULL) return; #ifdef STA_SUPPORT if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) { priv->items_priv.items = (struct debug_data *) kmalloc(sizeof(items), GFP_KERNEL); if (!priv->items_priv.items) { PRINTM(MERROR, "Failed to allocate memory for debug data\n"); LEAVE(); return; } memcpy(priv->items_priv.items, items, sizeof(items)); priv->items_priv.num_of_items = sizeof(items) / sizeof(items[0]); } #endif #ifdef UAP_SUPPORT if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) { priv->items_priv.items = (struct debug_data *) kmalloc(sizeof(uap_items), GFP_KERNEL); if (!priv->items_priv.items) { PRINTM(MERROR, "Failed to allocate memory for debug data\n"); LEAVE(); return; } memcpy(priv->items_priv.items, uap_items, sizeof(uap_items)); priv->items_priv.num_of_items = sizeof(uap_items) / sizeof(uap_items[0]); } #endif priv->items_priv.priv = priv; priv->items_priv.items[priv->items_priv.num_of_items - 1].addr += (t_u32) (priv->phandle); priv->items_priv.items[priv->items_priv.num_of_items - 2].addr += (t_u32) (priv->phandle); priv->items_priv.items[priv->items_priv.num_of_items - 3].addr += (t_u32) (priv->phandle); priv->items_priv.items[priv->items_priv.num_of_items - 4].addr += (t_u32) (priv->phandle); priv->items_priv.items[priv->items_priv.num_of_items - 5].addr += (t_u32) (priv->phandle); priv->items_priv.items[priv->items_priv.num_of_items - 6].addr += (t_u32) (priv->phandle); priv->items_priv.items[priv->items_priv.num_of_items - 7].addr += (t_u32) (priv->phandle); priv->items_priv.items[priv->items_priv.num_of_items - 8].addr += (t_u32) (priv->phandle); priv->items_priv.items[priv->items_priv.num_of_items - 9].addr += (t_u32) (priv->phandle); /* Create proc entry */ r = create_proc_entry("debug", 0644, priv->proc_entry); if (r == NULL) { LEAVE(); return; } r->data = &priv->items_priv; r->read_proc = woal_debug_read; r->write_proc = woal_debug_write; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30) r->owner = THIS_MODULE; #endif LEAVE(); }
/** * @brief This function will create a entry in rx reordering table for the * given ta/tid and will initialize it with seq_num, win_size * * @param priv A pointer to mlan_private * @param ta ta to find in reordering table * @param tid tid to find in reordering table * @param win_size win_size for the give ta/tid pair. * @param seq_num Starting sequence number for current entry. * * @return N/A */ t_void wlan_11n_create_rxreorder_tbl(mlan_private * priv, t_u8 * ta, int tid, int win_size, int seq_num) { int i; pmlan_adapter pmadapter = priv->adapter; RxReorderTbl *rx_reor_tbl_ptr, *new_node; #ifdef UAP_SUPPORT sta_node *sta_ptr = MNULL; #endif t_u16 last_seq = 0; ENTER(); /* * If we get a TID, ta pair which is already present dispatch all the * the packets and move the window size until the ssn */ if ((rx_reor_tbl_ptr = wlan_11n_get_rxreorder_tbl(priv, tid, ta))) { wlan_11n_dispatch_pkt_until_start_win(priv, rx_reor_tbl_ptr, seq_num); } else { PRINTM(MDAT_D, "%s: seq_num %d, tid %d, ta %02x:%02x:%02x:%02x:" "%02x:%02x, win_size %d\n", __FUNCTION__, seq_num, tid, ta[0], ta[1], ta[2], ta[3], ta[4], ta[5], win_size); if (pmadapter->callbacks. moal_malloc(pmadapter->pmoal_handle, sizeof(RxReorderTbl), MLAN_MEM_DEF, (t_u8 **) & new_node)) { PRINTM(MERROR, "Rx reorder memory allocation failed\n"); return; } util_init_list((pmlan_linked_list) new_node); new_node->tid = tid; memcpy(pmadapter, new_node->ta, ta, MLAN_MAC_ADDR_LENGTH); new_node->start_win = seq_num; if (queuing_ra_based(priv)) { // TODO for adhoc #ifdef UAP_SUPPORT if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) { if ((sta_ptr = wlan_get_station_entry(priv, ta))) last_seq = sta_ptr->rx_seq[tid]; } #endif PRINTM(MINFO, "UAP/ADHOC:last_seq=%d start_win=%d\n", last_seq, new_node->start_win); } else { last_seq = priv->rx_seq[tid]; } if (last_seq >= new_node->start_win) { PRINTM(MDAT_D, "Update start_win: last_seq=%d, start_win=%d\n", last_seq, new_node->start_win); new_node->start_win = last_seq + 1; } new_node->win_size = win_size; if (pmadapter->callbacks. moal_malloc(pmadapter->pmoal_handle, sizeof(t_void *) * win_size, MLAN_MEM_DEF, (t_u8 **) & new_node->rx_reorder_ptr)) { PRINTM(MERROR, "Rx reorder table memory allocation" "failed\n"); pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle, (t_u8 *) new_node); return; } PRINTM(MDAT_D, "Create ReorderPtr: %p\n", new_node); new_node->timer_context.ptr = new_node; new_node->timer_context.priv = priv; new_node->timer_context.timer_is_set = MFALSE; pmadapter->callbacks.moal_init_timer(pmadapter->pmoal_handle, &new_node->timer_context.timer, wlan_flush_data, &new_node->timer_context); for (i = 0; i < win_size; ++i) new_node->rx_reorder_ptr[i] = MNULL; util_enqueue_list_tail(pmadapter->pmoal_handle, &priv->rx_reorder_tbl_ptr, (pmlan_linked_list) new_node, pmadapter->callbacks.moal_spin_lock, pmadapter->callbacks.moal_spin_unlock); } LEAVE(); }
/* * This function resets the connection state. * * The function is invoked after receiving a disconnect event from firmware, * and performs the following actions - * - Set media status to disconnected * - Clean up Tx and Rx packets * - Resets SNR/NF/RSSI value in driver * - Resets security configurations in driver * - Enables auto data rate * - Saves the previous SSID and BSSID so that they can * be used for re-association, if required * - Erases current SSID and BSSID information * - Sends a disconnect event to upper layers/applications. */ void mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code) { struct mwifiex_adapter *adapter = priv->adapter; if (!priv->media_connected) return; dev_dbg(adapter->dev, "info: handles disconnect event\n"); priv->media_connected = false; priv->scan_block = false; if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) && ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info)) mwifiex_disable_all_tdls_links(priv); /* Free Tx and Rx packets, report disconnect to upper layer */ mwifiex_clean_txrx(priv); /* Reset SNR/NF/RSSI values */ priv->data_rssi_last = 0; priv->data_nf_last = 0; priv->data_rssi_avg = 0; priv->data_nf_avg = 0; priv->bcn_rssi_last = 0; priv->bcn_nf_last = 0; priv->bcn_rssi_avg = 0; priv->bcn_nf_avg = 0; priv->rxpd_rate = 0; priv->rxpd_htinfo = 0; priv->sec_info.wpa_enabled = false; priv->sec_info.wpa2_enabled = false; priv->wpa_ie_len = 0; priv->sec_info.wapi_enabled = false; priv->wapi_ie_len = 0; priv->sec_info.wapi_key_on = false; priv->sec_info.encryption_mode = 0; /* Enable auto data rate */ priv->is_data_rate_auto = true; priv->data_rate = 0; if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { priv->adhoc_state = ADHOC_IDLE; priv->adhoc_is_link_sensed = false; } /* * Memorize the previous SSID and BSSID so * it could be used for re-assoc */ dev_dbg(adapter->dev, "info: previous SSID=%s, SSID len=%u\n", priv->prev_ssid.ssid, priv->prev_ssid.ssid_len); dev_dbg(adapter->dev, "info: current SSID=%s, SSID len=%u\n", priv->curr_bss_params.bss_descriptor.ssid.ssid, priv->curr_bss_params.bss_descriptor.ssid.ssid_len); memcpy(&priv->prev_ssid, &priv->curr_bss_params.bss_descriptor.ssid, sizeof(struct cfg80211_ssid)); memcpy(priv->prev_bssid, priv->curr_bss_params.bss_descriptor.mac_address, ETH_ALEN); /* Need to erase the current SSID and BSSID info */ memset(&priv->curr_bss_params, 0x00, sizeof(priv->curr_bss_params)); adapter->tx_lock_flag = false; adapter->pps_uapsd_mode = false; if (adapter->is_cmd_timedout && adapter->curr_cmd) return; priv->media_connected = false; dev_dbg(adapter->dev, "info: successfully disconnected from %pM: reason code %d\n", priv->cfg_bssid, reason_code); if (priv->bss_mode == NL80211_IFTYPE_STATION || priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT) { cfg80211_disconnected(priv->netdev, reason_code, NULL, 0, GFP_KERNEL); } memset(priv->cfg_bssid, 0, ETH_ALEN); mwifiex_stop_net_dev_queue(priv->netdev, adapter); if (netif_carrier_ok(priv->netdev)) netif_carrier_off(priv->netdev); }
/* * Proc info file read handler. * * This function is called when the 'info' file is opened for reading. * It prints the following driver related information - * - Driver name * - Driver version * - Driver extended version * - Interface name * - BSS mode * - Media state (connected or disconnected) * - MAC address * - Total number of Tx bytes * - Total number of Rx bytes * - Total number of Tx packets * - Total number of Rx packets * - Total number of dropped Tx packets * - Total number of dropped Rx packets * - Total number of corrupted Tx packets * - Total number of corrupted Rx packets * - Carrier status (on or off) * - Tx queue status (started or stopped) * * For STA mode drivers, it also prints the following extra - * - ESSID * - BSSID * - Channel * - Region code * - Multicast count * - Multicast addresses */ static ssize_t mwifiex_info_read(struct file *file, char __user *ubuf, size_t count, loff_t *ppos) { struct mwifiex_private *priv = (struct mwifiex_private *) file->private_data; struct net_device *netdev = priv->netdev; struct netdev_hw_addr *ha; struct netdev_queue *txq; unsigned long page = get_zeroed_page(GFP_KERNEL); char *p = (char *) page, fmt[64]; struct mwifiex_bss_info info; ssize_t ret; int i = 0; if (!p) return -ENOMEM; memset(&info, 0, sizeof(info)); ret = mwifiex_get_bss_info(priv, &info); if (ret) goto free_and_exit; mwifiex_drv_get_driver_version(priv->adapter, fmt, sizeof(fmt) - 1); if (!priv->version_str[0]) mwifiex_get_ver_ext(priv); p += sprintf(p, "driver_name = " "\"mwifiex\"\n"); p += sprintf(p, "driver_version = %s", fmt); p += sprintf(p, "\nverext = %s", priv->version_str); p += sprintf(p, "\ninterface_name=\"%s\"\n", netdev->name); if (info.bss_mode >= ARRAY_SIZE(bss_modes)) p += sprintf(p, "bss_mode=\"%d\"\n", info.bss_mode); else p += sprintf(p, "bss_mode=\"%s\"\n", bss_modes[info.bss_mode]); p += sprintf(p, "media_state=\"%s\"\n", (!priv->media_connected ? "Disconnected" : "Connected")); p += sprintf(p, "mac_address=\"%pM\"\n", netdev->dev_addr); if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) { p += sprintf(p, "multicast_count=\"%d\"\n", netdev_mc_count(netdev)); p += sprintf(p, "essid=\"%s\"\n", info.ssid.ssid); p += sprintf(p, "bssid=\"%pM\"\n", info.bssid); p += sprintf(p, "channel=\"%d\"\n", (int) info.bss_chan); p += sprintf(p, "country_code = \"%s\"\n", info.country_code); netdev_for_each_mc_addr(ha, netdev) p += sprintf(p, "multicast_address[%d]=\"%pM\"\n", i++, ha->addr); } p += sprintf(p, "num_tx_bytes = %lu\n", priv->stats.tx_bytes); p += sprintf(p, "num_rx_bytes = %lu\n", priv->stats.rx_bytes); p += sprintf(p, "num_tx_pkts = %lu\n", priv->stats.tx_packets); p += sprintf(p, "num_rx_pkts = %lu\n", priv->stats.rx_packets); p += sprintf(p, "num_tx_pkts_dropped = %lu\n", priv->stats.tx_dropped); p += sprintf(p, "num_rx_pkts_dropped = %lu\n", priv->stats.rx_dropped); p += sprintf(p, "num_tx_pkts_err = %lu\n", priv->stats.tx_errors); p += sprintf(p, "num_rx_pkts_err = %lu\n", priv->stats.rx_errors); p += sprintf(p, "carrier %s\n", ((netif_carrier_ok(priv->netdev)) ? "on" : "off")); p += sprintf(p, "tx queue"); for (i = 0; i < netdev->num_tx_queues; i++) { txq = netdev_get_tx_queue(netdev, i); p += sprintf(p, " %d:%s", i, netif_tx_queue_stopped(txq) ? "stopped" : "started"); } p += sprintf(p, "\n"); ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page, (unsigned long) p - page); free_and_exit: free_page(page); return ret; }