diff options
Diffstat (limited to 'drivers/net/wireless/mwifiex')
33 files changed, 1415 insertions, 2472 deletions
diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c index 916183d..6543f4f 100644 --- a/drivers/net/wireless/mwifiex/11n.c +++ b/drivers/net/wireless/mwifiex/11n.c @@ -185,13 +185,12 @@ int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv, * * Handling includes changing the header fields into CPU format. */ -int mwifiex_ret_11n_cfg(struct host_cmd_ds_command *resp, void *data_buf) +int mwifiex_ret_11n_cfg(struct host_cmd_ds_command *resp, + struct mwifiex_ds_11n_tx_cfg *tx_cfg) { - struct mwifiex_ds_11n_tx_cfg *tx_cfg; struct host_cmd_ds_11n_cfg *htcfg = &resp->params.htcfg; - if (data_buf) { - tx_cfg = (struct mwifiex_ds_11n_tx_cfg *) data_buf; + if (tx_cfg) { tx_cfg->tx_htcap = le16_to_cpu(htcfg->ht_tx_cap); tx_cfg->tx_htinfo = le16_to_cpu(htcfg->ht_tx_info); } @@ -208,11 +207,10 @@ int mwifiex_ret_11n_cfg(struct host_cmd_ds_command *resp, void *data_buf) */ int mwifiex_cmd_recfg_tx_buf(struct mwifiex_private *priv, struct host_cmd_ds_command *cmd, int cmd_action, - void *data_buf) + u16 *buf_size) { struct host_cmd_ds_txbuf_cfg *tx_buf = &cmd->params.tx_buf; u16 action = (u16) cmd_action; - u16 buf_size = *((u16 *) data_buf); cmd->command = cpu_to_le16(HostCmd_CMD_RECONFIGURE_TX_BUFF); cmd->size = @@ -220,8 +218,8 @@ int mwifiex_cmd_recfg_tx_buf(struct mwifiex_private *priv, tx_buf->action = cpu_to_le16(action); switch (action) { case HostCmd_ACT_GEN_SET: - dev_dbg(priv->adapter->dev, "cmd: set tx_buf=%d\n", buf_size); - tx_buf->buff_size = cpu_to_le16(buf_size); + dev_dbg(priv->adapter->dev, "cmd: set tx_buf=%d\n", *buf_size); + tx_buf->buff_size = cpu_to_le16(*buf_size); break; case HostCmd_ACT_GEN_GET: default: @@ -240,13 +238,12 @@ int mwifiex_cmd_recfg_tx_buf(struct mwifiex_private *priv, * - Ensuring correct endian-ness */ int mwifiex_cmd_amsdu_aggr_ctrl(struct host_cmd_ds_command *cmd, - int cmd_action, void *data_buf) + int cmd_action, + struct mwifiex_ds_11n_amsdu_aggr_ctrl *aa_ctrl) { struct host_cmd_ds_amsdu_aggr_ctrl *amsdu_ctrl = &cmd->params.amsdu_aggr_ctrl; u16 action = (u16) cmd_action; - struct mwifiex_ds_11n_amsdu_aggr_ctrl *aa_ctrl = - (struct mwifiex_ds_11n_amsdu_aggr_ctrl *) data_buf; cmd->command = cpu_to_le16(HostCmd_CMD_AMSDU_AGGR_CTRL); cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_amsdu_aggr_ctrl) @@ -272,15 +269,13 @@ int mwifiex_cmd_amsdu_aggr_ctrl(struct host_cmd_ds_command *cmd, * Handling includes changing the header fields into CPU format. */ int mwifiex_ret_amsdu_aggr_ctrl(struct host_cmd_ds_command *resp, - void *data_buf) + struct mwifiex_ds_11n_amsdu_aggr_ctrl + *amsdu_aggr_ctrl) { - struct mwifiex_ds_11n_amsdu_aggr_ctrl *amsdu_aggr_ctrl; struct host_cmd_ds_amsdu_aggr_ctrl *amsdu_ctrl = &resp->params.amsdu_aggr_ctrl; - if (data_buf) { - amsdu_aggr_ctrl = - (struct mwifiex_ds_11n_amsdu_aggr_ctrl *) data_buf; + if (amsdu_aggr_ctrl) { amsdu_aggr_ctrl->enable = le16_to_cpu(amsdu_ctrl->enable); amsdu_aggr_ctrl->curr_buf_size = le16_to_cpu(amsdu_ctrl->curr_buf_size); @@ -296,12 +291,10 @@ int mwifiex_ret_amsdu_aggr_ctrl(struct host_cmd_ds_command *resp, * - Setting HT Tx capability and HT Tx information fields * - Ensuring correct endian-ness */ -int mwifiex_cmd_11n_cfg(struct host_cmd_ds_command *cmd, - u16 cmd_action, void *data_buf) +int mwifiex_cmd_11n_cfg(struct host_cmd_ds_command *cmd, u16 cmd_action, + struct mwifiex_ds_11n_tx_cfg *txcfg) { struct host_cmd_ds_11n_cfg *htcfg = &cmd->params.htcfg; - struct mwifiex_ds_11n_tx_cfg *txcfg = - (struct mwifiex_ds_11n_tx_cfg *) data_buf; cmd->command = cpu_to_le16(HostCmd_CMD_11N_CFG); cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_11n_cfg) + S_DS_GEN); @@ -350,8 +343,7 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, ht_cap->header.len = cpu_to_le16(sizeof(struct ieee80211_ht_cap)); memcpy((u8 *) ht_cap + sizeof(struct mwifiex_ie_types_header), - (u8 *) bss_desc->bcn_ht_cap + - sizeof(struct ieee_types_header), + (u8 *)bss_desc->bcn_ht_cap, le16_to_cpu(ht_cap->header.len)); mwifiex_fill_cap_info(priv, radio_type, ht_cap); diff --git a/drivers/net/wireless/mwifiex/11n.h b/drivers/net/wireless/mwifiex/11n.h index a4390a1..90b421e 100644 --- a/drivers/net/wireless/mwifiex/11n.h +++ b/drivers/net/wireless/mwifiex/11n.h @@ -29,9 +29,9 @@ int mwifiex_ret_11n_delba(struct mwifiex_private *priv, int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv, struct host_cmd_ds_command *resp); int mwifiex_ret_11n_cfg(struct host_cmd_ds_command *resp, - void *data_buf); -int mwifiex_cmd_11n_cfg(struct host_cmd_ds_command *cmd, - u16 cmd_action, void *data_buf); + struct mwifiex_ds_11n_tx_cfg *tx_cfg); +int mwifiex_cmd_11n_cfg(struct host_cmd_ds_command *cmd, u16 cmd_action, + struct mwifiex_ds_11n_tx_cfg *txcfg); int mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, struct mwifiex_bssdescriptor *bss_desc, @@ -62,12 +62,14 @@ int mwifiex_get_rx_reorder_tbl(struct mwifiex_private *priv, int mwifiex_get_tx_ba_stream_tbl(struct mwifiex_private *priv, struct mwifiex_ds_tx_ba_stream_tbl *buf); int mwifiex_ret_amsdu_aggr_ctrl(struct host_cmd_ds_command *resp, - void *data_buf); + struct mwifiex_ds_11n_amsdu_aggr_ctrl + *amsdu_aggr_ctrl); int mwifiex_cmd_recfg_tx_buf(struct mwifiex_private *priv, struct host_cmd_ds_command *cmd, - int cmd_action, void *data_buf); + int cmd_action, u16 *buf_size); int mwifiex_cmd_amsdu_aggr_ctrl(struct host_cmd_ds_command *cmd, - int cmd_action, void *data_buf); + int cmd_action, + struct mwifiex_ds_11n_amsdu_aggr_ctrl *aa_ctrl); /* * This function checks whether AMPDU is allowed or not for a particular TID. diff --git a/drivers/net/wireless/mwifiex/11n_aggr.c b/drivers/net/wireless/mwifiex/11n_aggr.c index f807447..079e553 100644 --- a/drivers/net/wireless/mwifiex/11n_aggr.c +++ b/drivers/net/wireless/mwifiex/11n_aggr.c @@ -164,12 +164,13 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, struct mwifiex_tx_param tx_param; struct txpd *ptx_pd = NULL; - if (skb_queue_empty(&pra_list->skb_head)) { + skb_src = skb_peek(&pra_list->skb_head); + if (!skb_src) { spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags); return 0; } - skb_src = skb_peek(&pra_list->skb_head); + tx_info_src = MWIFIEX_SKB_TXCB(skb_src); skb_aggr = dev_alloc_skb(adapter->tx_buf_size); if (!skb_aggr) { @@ -184,17 +185,14 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, tx_info_aggr->bss_index = tx_info_src->bss_index; skb_aggr->priority = skb_src->priority; - while (skb_src && ((skb_headroom(skb_aggr) + skb_src->len - + LLC_SNAP_LEN) - <= adapter->tx_buf_size)) { + do { + /* Check if AMSDU can accommodate this MSDU */ + if (skb_tailroom(skb_aggr) < (skb_src->len + LLC_SNAP_LEN)) + break; - if (!skb_queue_empty(&pra_list->skb_head)) - skb_src = skb_dequeue(&pra_list->skb_head); - else - skb_src = NULL; + skb_src = skb_dequeue(&pra_list->skb_head); - if (skb_src) - pra_list->total_pkts_size -= skb_src->len; + pra_list->total_pkts_size -= skb_src->len; atomic_dec(&priv->wmm.tx_pkts_queued); @@ -212,11 +210,15 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, return -1; } - if (!skb_queue_empty(&pra_list->skb_head)) - skb_src = skb_peek(&pra_list->skb_head); - else - skb_src = NULL; - } + if (skb_tailroom(skb_aggr) < pad) { + pad = 0; + break; + } + skb_put(skb_aggr, pad); + + skb_src = skb_peek(&pra_list->skb_head); + + } while (skb_src); spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags); @@ -230,14 +232,21 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, skb_push(skb_aggr, headroom); - tx_param.next_pkt_len = ((pra_list->total_pkts_size) ? - (((pra_list->total_pkts_size) > - adapter->tx_buf_size) ? adapter-> - tx_buf_size : pra_list->total_pkts_size + - LLC_SNAP_LEN + sizeof(struct txpd)) : 0); + /* + * Padding per MSDU will affect the length of next + * packet and hence the exact length of next packet + * is uncertain here. + * + * Also, aggregation of transmission buffer, while + * downloading the data to the card, wont gain much + * on the AMSDU packets as the AMSDU packets utilizes + * the transmission buffer space to the maximum + * (adapter->tx_buf_size). + */ + tx_param.next_pkt_len = 0; + ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, - skb_aggr->data, - skb_aggr->len, &tx_param); + skb_aggr, &tx_param); switch (ret) { case -EBUSY: spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags); diff --git a/drivers/net/wireless/mwifiex/11n_aggr.h b/drivers/net/wireless/mwifiex/11n_aggr.h index 9c6dca7..900e1c6 100644 --- a/drivers/net/wireless/mwifiex/11n_aggr.h +++ b/drivers/net/wireless/mwifiex/11n_aggr.h @@ -21,6 +21,7 @@ #define _MWIFIEX_11N_AGGR_H_ #define PKT_TYPE_AMSDU 0xE6 +#define MIN_NUM_AMSDU 2 int mwifiex_11n_deaggregate_pkt(struct mwifiex_private *priv, struct sk_buff *skb); diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c index d2358cf..39fd4d5 100644 --- a/drivers/net/wireless/mwifiex/11n_rxreorder.c +++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c @@ -329,13 +329,12 @@ int mwifiex_cmd_11n_addba_req(struct host_cmd_ds_command *cmd, void *data_buf) */ int mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *priv, struct host_cmd_ds_command *cmd, - void *data_buf) + struct host_cmd_ds_11n_addba_req + *cmd_addba_req) { struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = (struct host_cmd_ds_11n_addba_rsp *) &cmd->params.add_ba_rsp; - struct host_cmd_ds_11n_addba_req *cmd_addba_req = - (struct host_cmd_ds_11n_addba_req *) data_buf; u8 tid; int win_size; uint16_t block_ack_param_set; diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.h b/drivers/net/wireless/mwifiex/11n_rxreorder.h index 7576c2a..7128baa 100644 --- a/drivers/net/wireless/mwifiex/11n_rxreorder.h +++ b/drivers/net/wireless/mwifiex/11n_rxreorder.h @@ -59,8 +59,9 @@ int mwifiex_ret_11n_addba_resp(struct mwifiex_private *priv, int mwifiex_cmd_11n_delba(struct host_cmd_ds_command *cmd, void *data_buf); int mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *priv, - struct host_cmd_ds_command - *cmd, void *data_buf); + struct host_cmd_ds_command *cmd, + struct host_cmd_ds_11n_addba_req + *cmd_addba_req); int mwifiex_cmd_11n_addba_req(struct host_cmd_ds_command *cmd, void *data_buf); void mwifiex_11n_cleanup_reorder_tbl(struct mwifiex_private *priv); diff --git a/drivers/net/wireless/mwifiex/Kconfig b/drivers/net/wireless/mwifiex/Kconfig index 8696292..8f2797a 100644 --- a/drivers/net/wireless/mwifiex/Kconfig +++ b/drivers/net/wireless/mwifiex/Kconfig @@ -19,3 +19,14 @@ config MWIFIEX_SDIO If you choose to build it as a module, it will be called mwifiex_sdio. + +config MWIFIEX_PCIE + tristate "Marvell WiFi-Ex Driver for PCIE 8766" + depends on MWIFIEX && PCI + select FW_LOADER + ---help--- + This adds support for wireless adapters based on Marvell + 8766 chipset with PCIe interface. + + If you choose to build it as a module, it will be called + mwifiex_pcie. diff --git a/drivers/net/wireless/mwifiex/Makefile b/drivers/net/wireless/mwifiex/Makefile index 42cb733..b0257ad 100644 --- a/drivers/net/wireless/mwifiex/Makefile +++ b/drivers/net/wireless/mwifiex/Makefile @@ -39,3 +39,6 @@ obj-$(CONFIG_MWIFIEX) += mwifiex.o mwifiex_sdio-y += sdio.o obj-$(CONFIG_MWIFIEX_SDIO) += mwifiex_sdio.o + +mwifiex_pcie-y += pcie.o +obj-$(CONFIG_MWIFIEX_PCIE) += mwifiex_pcie.o diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 687c1f2..45ac407 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -543,12 +543,28 @@ mwifiex_dump_station_info(struct mwifiex_private *priv, ret = -EFAULT; } + /* + * Bit 0 in tx_htinfo indicates that current Tx rate is 11n rate. Valid + * MCS index values for us are 0 to 15. + */ + if ((priv->tx_htinfo & BIT(0)) && (priv->tx_rate < 16)) { + sinfo->txrate.mcs = priv->tx_rate; + sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS; + /* 40MHz rate */ + if (priv->tx_htinfo & BIT(1)) + sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; + /* SGI enabled */ + if (priv->tx_htinfo & BIT(2)) + sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; + } + sinfo->rx_bytes = priv->stats.rx_bytes; sinfo->tx_bytes = priv->stats.tx_bytes; sinfo->rx_packets = priv->stats.rx_packets; sinfo->tx_packets = priv->stats.tx_packets; - sinfo->signal = priv->w_stats.qual.level; - sinfo->txrate.legacy = rate.rate; + sinfo->signal = priv->qual_level; + /* bit rate is in 500 kb/s units. Convert it to 100kb/s units */ + sinfo->txrate.legacy = rate.rate * 5; return ret; } @@ -565,8 +581,6 @@ mwifiex_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); - mwifiex_dump_station_info(priv, sinfo); - if (!priv->media_connected) return -ENOENT; if (memcmp(mac, priv->cfg_bssid, ETH_ALEN)) @@ -672,6 +686,59 @@ static const u32 mwifiex_cipher_suites[] = { }; /* + * CFG802.11 operation handler for setting bit rates. + * + * Function selects legacy bang B/G/BG from corresponding bitrates selection. + * Currently only 2.4GHz band is supported. + */ +static int mwifiex_cfg80211_set_bitrate_mask(struct wiphy *wiphy, + struct net_device *dev, + const u8 *peer, + const struct cfg80211_bitrate_mask *mask) +{ + struct mwifiex_ds_band_cfg band_cfg; + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + int index = 0, mode = 0, i; + + /* Currently only 2.4GHz is supported */ + for (i = 0; i < mwifiex_band_2ghz.n_bitrates; i++) { + /* + * Rates below 6 Mbps in the table are CCK rates; 802.11b + * and from 6 they are OFDM; 802.11G + */ + if (mwifiex_rates[i].bitrate == 60) { + index = 1 << i; + break; + } + } + + if (mask->control[IEEE80211_BAND_2GHZ].legacy < index) { + mode = BAND_B; + } else { + mode = BAND_G; + if (mask->control[IEEE80211_BAND_2GHZ].legacy % index) + mode |= BAND_B; + } + + memset(&band_cfg, 0, sizeof(band_cfg)); + band_cfg.config_bands = mode; + + if (priv->bss_mode == NL80211_IFTYPE_ADHOC) + band_cfg.adhoc_start_band = mode; + + band_cfg.sec_chan_offset = NO_SEC_CHANNEL; + + if (mwifiex_set_radio_band_cfg(priv, &band_cfg)) + return -EFAULT; + + wiphy_debug(wiphy, "info: device configured in 802.11%s%s mode\n", + (mode & BAND_B) ? "b" : "", + (mode & BAND_G) ? "g" : ""); + + return 0; +} + +/* * CFG802.11 operation handler for disconnection request. * * This function does not work when there is already a disconnection @@ -715,6 +782,7 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv) struct mwifiex_bss_info bss_info; int ie_len; u8 ie_buf[IEEE80211_MAX_SSID_LEN + sizeof(struct ieee_types_header)]; + enum ieee80211_band band; if (mwifiex_get_bss_info(priv, &bss_info)) return -1; @@ -727,9 +795,10 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv) bss_info.ssid.ssid_len); ie_len = ie_buf[1] + sizeof(struct ieee_types_header); + band = mwifiex_band_to_radio_type(priv->curr_bss_params.band); chan = __ieee80211_get_channel(priv->wdev->wiphy, ieee80211_channel_to_frequency(bss_info.bss_chan, - priv->curr_bss_params.band)); + band)); cfg80211_inform_bss(priv->wdev->wiphy, chan, bss_info.bssid, 0, WLAN_CAPABILITY_IBSS, @@ -740,139 +809,6 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv) } /* - * This function informs the CFG802.11 subsystem of a new BSS connection. - * - * The following information are sent to the CFG802.11 subsystem - * to register the new BSS connection. If we do not register the new BSS, - * a kernel panic will result. - * - MAC address - * - Capabilities - * - Beacon period - * - RSSI value - * - Channel - * - Supported rates IE - * - Extended capabilities IE - * - DS parameter set IE - * - HT Capability IE - * - Vendor Specific IE (221) - * - WPA IE - * - RSN IE - */ -static int mwifiex_inform_bss_from_scan_result(struct mwifiex_private *priv, - struct mwifiex_802_11_ssid *ssid) -{ - struct mwifiex_bssdescriptor *scan_table; - int i, j; - struct ieee80211_channel *chan; - u8 *ie, *ie_buf; - u32 ie_len; - u8 *beacon; - int beacon_size; - u8 element_id, element_len; - -#define MAX_IE_BUF 2048 - ie_buf = kzalloc(MAX_IE_BUF, GFP_KERNEL); - if (!ie_buf) { - dev_err(priv->adapter->dev, "%s: failed to alloc ie_buf\n", - __func__); - return -ENOMEM; - } - - scan_table = priv->adapter->scan_table; - for (i = 0; i < priv->adapter->num_in_scan_table; i++) { - if (ssid) { - /* Inform specific BSS only */ - if (memcmp(ssid->ssid, scan_table[i].ssid.ssid, - ssid->ssid_len)) - continue; - } - memset(ie_buf, 0, MAX_IE_BUF); - ie_buf[0] = WLAN_EID_SSID; - ie_buf[1] = scan_table[i].ssid.ssid_len; - memcpy(&ie_buf[sizeof(struct ieee_types_header)], - scan_table[i].ssid.ssid, ie_buf[1]); - - ie = ie_buf + ie_buf[1] + sizeof(struct ieee_types_header); - ie_len = ie_buf[1] + sizeof(struct ieee_types_header); - - ie[0] = WLAN_EID_SUPP_RATES; - - for (j = 0; j < sizeof(scan_table[i].supported_rates); j++) { - if (!scan_table[i].supported_rates[j]) - break; - else - ie[j + sizeof(struct ieee_types_header)] = - scan_table[i].supported_rates[j]; - } - - ie[1] = j; - ie_len += ie[1] + sizeof(struct ieee_types_header); - - beacon = scan_table[i].beacon_buf; - beacon_size = scan_table[i].beacon_buf_size; - - /* Skip time stamp, beacon interval and capability */ - - if (beacon) { - beacon += sizeof(scan_table[i].beacon_period) - + sizeof(scan_table[i].time_stamp) + - +sizeof(scan_table[i].cap_info_bitmap); - - beacon_size -= sizeof(scan_table[i].beacon_period) - + sizeof(scan_table[i].time_stamp) - + sizeof(scan_table[i].cap_info_bitmap); - } - - while (beacon_size >= sizeof(struct ieee_types_header)) { - ie = ie_buf + ie_len; - element_id = *beacon; - element_len = *(beacon + 1); - if (beacon_size < (int) element_len + - sizeof(struct ieee_types_header)) { - dev_err(priv->adapter->dev, "%s: in processing" - " IE, bytes left < IE length\n", - __func__); - break; - } - switch (element_id) { - case WLAN_EID_EXT_CAPABILITY: - case WLAN_EID_DS_PARAMS: - case WLAN_EID_HT_CAPABILITY: - case WLAN_EID_VENDOR_SPECIFIC: - case WLAN_EID_RSN: - case WLAN_EID_BSS_AC_ACCESS_DELAY: - ie[0] = element_id; - ie[1] = element_len; - memcpy(&ie[sizeof(struct ieee_types_header)], - (u8 *) beacon - + sizeof(struct ieee_types_header), - element_len); - ie_len += ie[1] + - sizeof(struct ieee_types_header); - break; - default: - break; - } - beacon += element_len + - sizeof(struct ieee_types_header); - beacon_size -= element_len + - sizeof(struct ieee_types_header); - } - chan = ieee80211_get_channel(priv->wdev->wiphy, - scan_table[i].freq); - cfg80211_inform_bss(priv->wdev->wiphy, chan, - scan_table[i].mac_address, - 0, scan_table[i].cap_info_bitmap, - scan_table[i].beacon_period, - ie_buf, ie_len, - scan_table[i].rssi, GFP_KERNEL); - } - - kfree(ie_buf); - return 0; -} - -/* * This function connects with a BSS. * * This function handles both Infra and Ad-Hoc modes. It also performs @@ -884,8 +820,7 @@ static int mwifiex_inform_bss_from_scan_result(struct mwifiex_private *priv, * For Infra mode, the function returns failure if the specified SSID * is not found in scan table. However, for Ad-Hoc mode, it can create * the IBSS if it does not exist. On successful completion in either case, - * the function notifies the CFG802.11 subsystem of the new BSS connection, - * otherwise the kernel will panic. + * the function notifies the CFG802.11 subsystem of the new BSS connection. */ static int mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid, @@ -893,11 +828,11 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid, struct cfg80211_connect_params *sme, bool privacy) { struct mwifiex_802_11_ssid req_ssid; - struct mwifiex_ssid_bssid ssid_bssid; int ret, auth_type = 0; + struct cfg80211_bss *bss = NULL; + u8 is_scanning_required = 0; memset(&req_ssid, 0, sizeof(struct mwifiex_802_11_ssid)); - memset(&ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid)); req_ssid.ssid_len = ssid_len; if (ssid_len > IEEE80211_MAX_SSID_LEN) { @@ -960,7 +895,7 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid, ret = mwifiex_set_gen_ie(priv, sme->ie, sme->ie_len); if (sme->key) { - if (mwifiex_is_alg_wep(0) | mwifiex_is_alg_wep(0)) { + if (mwifiex_is_alg_wep(priv->sec_info.encryption_mode)) { dev_dbg(priv->adapter->dev, "info: setting wep encryption" " with key len %d\n", sme->key_len); @@ -975,30 +910,48 @@ done: return -EFAULT; } + /* + * Scan entries are valid for some time (15 sec). So we can save one + * active scan time if we just try cfg80211_get_bss first. If it fails + * then request scan and cfg80211_get_bss() again for final output. + */ + while (1) { + if (is_scanning_required) { + /* Do specific SSID scanning */ + if (mwifiex_request_scan(priv, &req_ssid)) { + dev_err(priv->adapter->dev, "scan error\n"); + return -EFAULT; + } + } - memcpy(&ssid_bssid.ssid, &req_ssid, sizeof(struct mwifiex_802_11_ssid)); - - if (mode != NL80211_IFTYPE_ADHOC) { - if (mwifiex_find_best_bss(priv, &ssid_bssid)) - return -EFAULT; - /* Inform the BSS information to kernel, otherwise - * kernel will give a panic after successful assoc */ - if (mwifiex_inform_bss_from_scan_result(priv, &req_ssid)) - return -EFAULT; + /* Find the BSS we want using available scan results */ + if (mode == NL80211_IFTYPE_ADHOC) + bss = cfg80211_get_bss(priv->wdev->wiphy, channel, + bssid, ssid, ssid_len, + WLAN_CAPABILITY_IBSS, + WLAN_CAPABILITY_IBSS); + else + bss = cfg80211_get_bss(priv->wdev->wiphy, channel, + bssid, ssid, ssid_len, + WLAN_CAPABILITY_ESS, + WLAN_CAPABILITY_ESS); + + if (!bss) { + if (is_scanning_required) { + dev_warn(priv->adapter->dev, "assoc: requested " + "bss not found in scan results\n"); + break; + } + is_scanning_required = 1; + } else { + dev_dbg(priv->adapter->dev, "info: trying to associate to %s and bssid %pM\n", + (char *) req_ssid.ssid, bss->bssid); + memcpy(&priv->cfg_bssid, bss->bssid, ETH_ALEN); + break; + } } - dev_dbg(priv->adapter->dev, "info: trying to associate to %s and bssid %pM\n", - (char *) req_ssid.ssid, ssid_bssid.bssid); - - memcpy(&priv->cfg_bssid, ssid_bssid.bssid, 6); - - /* Connect to BSS by ESSID */ - memset(&ssid_bssid.bssid, 0, ETH_ALEN); - - if (!netif_queue_stopped(priv->netdev)) - netif_stop_queue(priv->netdev); - - if (mwifiex_bss_start(priv, &ssid_bssid)) + if (mwifiex_bss_start(priv, bss, &req_ssid)) return -EFAULT; if (mode == NL80211_IFTYPE_ADHOC) { @@ -1209,8 +1162,144 @@ mwifiex_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info, ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; } +/* + * create a new virtual interface with the given name + */ +struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy, + char *name, + enum nl80211_iftype type, + u32 *flags, + struct vif_params *params) +{ + struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); + struct mwifiex_adapter *adapter; + struct net_device *dev; + void *mdev_priv; + + if (!priv) + return ERR_PTR(-EFAULT); + + adapter = priv->adapter; + if (!adapter) + return ERR_PTR(-EFAULT); + + switch (type) { + case NL80211_IFTYPE_UNSPECIFIED: + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + if (priv->bss_mode) { + wiphy_err(wiphy, "cannot create multiple" + " station/adhoc interfaces\n"); + return ERR_PTR(-EINVAL); + } + + if (type == NL80211_IFTYPE_UNSPECIFIED) + priv->bss_mode = NL80211_IFTYPE_STATION; + else + priv->bss_mode = type; + + priv->bss_type = MWIFIEX_BSS_TYPE_STA; + priv->frame_type = MWIFIEX_DATA_FRAME_TYPE_ETH_II; + priv->bss_priority = 0; + priv->bss_role = MWIFIEX_BSS_ROLE_STA; + priv->bss_index = 0; + priv->bss_num = 0; + + break; + default: + wiphy_err(wiphy, "type not supported\n"); + return ERR_PTR(-EINVAL); + } + + dev = alloc_netdev_mq(sizeof(struct mwifiex_private *), name, + ether_setup, 1); + if (!dev) { + wiphy_err(wiphy, "no memory available for netdevice\n"); + priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; + return ERR_PTR(-ENOMEM); + } + + dev_net_set(dev, wiphy_net(wiphy)); + dev->ieee80211_ptr = priv->wdev; + dev->ieee80211_ptr->iftype = priv->bss_mode; + memcpy(dev->dev_addr, wiphy->perm_addr, ETH_ALEN); + memcpy(dev->perm_addr, wiphy->perm_addr, ETH_ALEN); + SET_NETDEV_DEV(dev, wiphy_dev(wiphy)); + + dev->flags |= IFF_BROADCAST | IFF_MULTICAST; + dev->watchdog_timeo = MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT; + dev->hard_header_len += MWIFIEX_MIN_DATA_HEADER_LEN; + + mdev_priv = netdev_priv(dev); + *((unsigned long *) mdev_priv) = (unsigned long) priv; + + priv->netdev = dev; + mwifiex_init_priv_params(priv, dev); + + SET_NETDEV_DEV(dev, adapter->dev); + + /* Register network device */ + if (register_netdevice(dev)) { + wiphy_err(wiphy, "cannot register virtual network device\n"); + free_netdev(dev); + priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; + return ERR_PTR(-EFAULT); + } + + sema_init(&priv->async_sem, 1); + priv->scan_pending_on_block = false; + + dev_dbg(adapter->dev, "info: %s: Marvell 802.11 Adapter\n", dev->name); + +#ifdef CONFIG_DEBUG_FS + mwifiex_dev_debugfs_init(priv); +#endif + return dev; +} +EXPORT_SYMBOL_GPL(mwifiex_add_virtual_intf); + +/* + * del_virtual_intf: remove the virtual interface determined by dev + */ +int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev) +{ + struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); + + if (!priv || !dev) + return 0; + +#ifdef CONFIG_DEBUG_FS + mwifiex_dev_debugfs_remove(priv); +#endif + + if (!netif_queue_stopped(priv->netdev)) + netif_stop_queue(priv->netdev); + + if (netif_carrier_ok(priv->netdev)) + netif_carrier_off(priv->netdev); + + if (dev->reg_state == NETREG_REGISTERED) + unregister_netdevice(dev); + + /* Clear the priv in adapter */ + priv->netdev = NULL; + + priv->media_connected = false; + + cancel_work_sync(&priv->cfg_workqueue); + flush_workqueue(priv->workqueue); + destroy_workqueue(priv->workqueue); + + priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; + + return 0; +} +EXPORT_SYMBOL_GPL(mwifiex_del_virtual_intf); + /* station cfg80211 operations */ static struct cfg80211_ops mwifiex_cfg80211_ops = { + .add_virtual_intf = mwifiex_add_virtual_intf, + .del_virtual_intf = mwifiex_del_virtual_intf, .change_virtual_intf = mwifiex_cfg80211_change_virtual_intf, .scan = mwifiex_cfg80211_scan, .connect = mwifiex_cfg80211_connect, @@ -1225,6 +1314,7 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = { .set_default_key = mwifiex_cfg80211_set_default_key, .set_power_mgmt = mwifiex_cfg80211_set_power_mgmt, .set_tx_power = mwifiex_cfg80211_set_tx_power, + .set_bitrate_mask = mwifiex_cfg80211_set_bitrate_mask, }; /* @@ -1234,8 +1324,7 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = { * default parameters and handler function pointers, and finally * registers the device. */ -int mwifiex_register_cfg80211(struct net_device *dev, u8 *mac, - struct mwifiex_private *priv) +int mwifiex_register_cfg80211(struct mwifiex_private *priv) { int ret; void *wdev_priv; @@ -1275,12 +1364,15 @@ int mwifiex_register_cfg80211(struct net_device *dev, u8 *mac, wdev->wiphy->cipher_suites = mwifiex_cipher_suites; wdev->wiphy->n_cipher_suites = ARRAY_SIZE(mwifiex_cipher_suites); - memcpy(wdev->wiphy->perm_addr, mac, 6); + memcpy(wdev->wiphy->perm_addr, priv->curr_addr, ETH_ALEN); wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; /* We are using custom domains */ wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; + /* Reserve space for bss band information */ + wdev->wiphy->bss_priv_size = sizeof(u8); + wdev->wiphy->reg_notifier = mwifiex_reg_notifier; /* Set struct mwifiex_private pointer in wiphy_priv */ @@ -1302,17 +1394,8 @@ int mwifiex_register_cfg80211(struct net_device *dev, u8 *mac, "info: successfully registered wiphy device\n"); } - dev_net_set(dev, wiphy_net(wdev->wiphy)); - dev->ieee80211_ptr = wdev; - memcpy(dev->dev_addr, wdev->wiphy->perm_addr, 6); - memcpy(dev->perm_addr, wdev->wiphy->perm_addr, 6); - SET_NETDEV_DEV(dev, wiphy_dev(wdev->wiphy)); priv->wdev = wdev; - dev->flags |= IFF_BROADCAST | IFF_MULTICAST; - dev->watchdog_timeo = MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT; - dev->hard_header_len += MWIFIEX_MIN_DATA_HEADER_LEN; - return ret; } @@ -1362,13 +1445,8 @@ mwifiex_cfg80211_results(struct work_struct *work) MWIFIEX_SCAN_TYPE_ACTIVE; scan_req->chan_list[i].scan_time = 0; } - if (mwifiex_set_user_scan_ioctl(priv, scan_req)) { - ret = -EFAULT; - goto done; - } - if (mwifiex_inform_bss_from_scan_result(priv, NULL)) + if (mwifiex_set_user_scan_ioctl(priv, scan_req)) ret = -EFAULT; -done: priv->scan_result_status = ret; dev_dbg(priv->adapter->dev, "info: %s: sending scan results\n", __func__); diff --git a/drivers/net/wireless/mwifiex/cfg80211.h b/drivers/net/wireless/mwifiex/cfg80211.h index c4db8f3..8d010f2 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.h +++ b/drivers/net/wireless/mwifiex/cfg80211.h @@ -24,8 +24,7 @@ #include "main.h" -int mwifiex_register_cfg80211(struct net_device *, u8 *, - struct mwifiex_private *); +int mwifiex_register_cfg80211(struct mwifiex_private *); void mwifiex_cfg80211_results(struct work_struct *work); #endif diff --git a/drivers/net/wireless/mwifiex/cfp.c b/drivers/net/wireless/mwifiex/cfp.c index d0cada5..f2e6de0 100644 --- a/drivers/net/wireless/mwifiex/cfp.c +++ b/drivers/net/wireless/mwifiex/cfp.c @@ -48,7 +48,7 @@ static u8 adhoc_rates_bg[BG_SUPPORTED_RATES] = { 0x82, 0x84, 0x8b, 0x96, static u8 adhoc_rates_a[A_SUPPORTED_RATES] = { 0x8c, 0x12, 0x98, 0x24, 0xb0, 0x48, 0x60, 0x6c, 0 }; -u8 supported_rates_a[A_SUPPORTED_RATES] = { 0x0c, 0x12, 0x18, 0x24, +static u8 supported_rates_a[A_SUPPORTED_RATES] = { 0x0c, 0x12, 0x18, 0x24, 0xb0, 0x48, 0x60, 0x6c, 0 }; static u16 mwifiex_data_rates[MWIFIEX_SUPPORTED_RATES_EXT] = { 0x02, 0x04, 0x0B, 0x16, 0x00, 0x0C, 0x12, 0x18, @@ -57,19 +57,19 @@ static u16 mwifiex_data_rates[MWIFIEX_SUPPORTED_RATES_EXT] = { 0x02, 0x04, 0x75, 0x82, 0x0C, 0x1B, 0x36, 0x51, 0x6C, 0xA2, 0xD8, 0xF3, 0x10E, 0x00 }; -u8 supported_rates_b[B_SUPPORTED_RATES] = { 0x02, 0x04, 0x0b, 0x16, 0 }; +static u8 supported_rates_b[B_SUPPORTED_RATES] = { 0x02, 0x04, 0x0b, 0x16, 0 }; -u8 supported_rates_g[G_SUPPORTED_RATES] = { 0x0c, 0x12, 0x18, 0x24, +static u8 supported_rates_g[G_SUPPORTED_RATES] = { 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c, 0 }; -u8 supported_rates_bg[BG_SUPPORTED_RATES] = { 0x02, 0x04, 0x0b, 0x0c, +static u8 supported_rates_bg[BG_SUPPORTED_RATES] = { 0x02, 0x04, 0x0b, 0x0c, 0x12, 0x16, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c, 0 }; u16 region_code_index[MWIFIEX_MAX_REGION_CODE] = { 0x10, 0x20, 0x30, 0x32, 0x40, 0x41, 0xff }; -u8 supported_rates_n[N_SUPPORTED_RATES] = { 0x02, 0x04, 0 }; +static u8 supported_rates_n[N_SUPPORTED_RATES] = { 0x02, 0x04, 0 }; /* * This function maps an index in supported rates table into diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 677e60b..90ffc76 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -40,8 +40,12 @@ mwifiex_init_cmd_node(struct mwifiex_private *priv, { cmd_node->priv = priv; cmd_node->cmd_oid = cmd_oid; - cmd_node->wait_q_enabled = priv->adapter->cmd_wait_q_required; - priv->adapter->cmd_wait_q_required = false; + if (priv->adapter->cmd_wait_q_required) { + cmd_node->wait_q_enabled = priv->adapter->cmd_wait_q_required; + priv->adapter->cmd_wait_q_required = false; + cmd_node->cmd_wait_q_woken = false; + cmd_node->condition = &cmd_node->cmd_wait_q_woken; + } cmd_node->data_buf = data_buf; cmd_node->cmd_skb = cmd_node->skb; } @@ -90,8 +94,11 @@ mwifiex_clean_cmd_node(struct mwifiex_adapter *adapter, cmd_node->data_buf = NULL; cmd_node->wait_q_enabled = false; + if (cmd_node->cmd_skb) + skb_trim(cmd_node->cmd_skb, 0); + if (cmd_node->resp_skb) { - dev_kfree_skb_any(cmd_node->resp_skb); + adapter->if_ops.cmdrsp_complete(adapter, cmd_node->resp_skb); cmd_node->resp_skb = NULL; } } @@ -104,13 +111,11 @@ mwifiex_clean_cmd_node(struct mwifiex_adapter *adapter, * main thread. */ static int mwifiex_cmd_host_cmd(struct mwifiex_private *priv, - struct host_cmd_ds_command *cmd, void *data_buf) + struct host_cmd_ds_command *cmd, + struct mwifiex_ds_misc_cmd *pcmd_ptr) { - struct mwifiex_ds_misc_cmd *pcmd_ptr = - (struct mwifiex_ds_misc_cmd *) data_buf; - /* Copy the HOST command to command buffer */ - memcpy((void *) cmd, pcmd_ptr->cmd, pcmd_ptr->len); + memcpy(cmd, pcmd_ptr->cmd, pcmd_ptr->len); dev_dbg(priv->adapter->dev, "cmd: host cmd size = %d\n", pcmd_ptr->len); return 0; } @@ -175,8 +180,7 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv, skb_push(cmd_node->cmd_skb, INTF_HEADER_LEN); ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_CMD, - cmd_node->cmd_skb->data, - cmd_node->cmd_skb->len, NULL); + cmd_node->cmd_skb, NULL); skb_pull(cmd_node->cmd_skb, INTF_HEADER_LEN); @@ -237,8 +241,7 @@ static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter) skb_push(adapter->sleep_cfm, INTF_HEADER_LEN); ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_CMD, - adapter->sleep_cfm->data, - adapter->sleep_cfm->len, NULL); + adapter->sleep_cfm, NULL); skb_pull(adapter->sleep_cfm, INTF_HEADER_LEN); if (ret == -1) { @@ -401,8 +404,7 @@ int mwifiex_process_event(struct mwifiex_adapter *adapter) adapter->event_cause = 0; adapter->event_skb = NULL; - - dev_kfree_skb_any(skb); + adapter->if_ops.event_complete(adapter, skb); return ret; } @@ -420,7 +422,6 @@ int mwifiex_send_cmd_sync(struct mwifiex_private *priv, uint16_t cmd_no, struct mwifiex_adapter *adapter = priv->adapter; adapter->cmd_wait_q_required = true; - adapter->cmd_wait_q.condition = false; ret = mwifiex_send_cmd_async(priv, cmd_no, cmd_action, cmd_oid, data_buf); @@ -513,10 +514,12 @@ int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no, } /* Send command */ - if (cmd_no == HostCmd_CMD_802_11_SCAN) + if (cmd_no == HostCmd_CMD_802_11_SCAN) { mwifiex_queue_scan_cmd(priv, cmd_node); - else + } else { + adapter->cmd_queued = cmd_node; mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true); + } return ret; } @@ -537,7 +540,7 @@ mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter, return; if (cmd_node->wait_q_enabled) - mwifiex_complete_cmd(adapter); + mwifiex_complete_cmd(adapter, cmd_node); /* Clean the node */ mwifiex_clean_cmd_node(adapter, cmd_node); @@ -707,15 +710,14 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter) if (adapter->curr_cmd->cmd_flag & CMD_F_HOSTCMD) { /* Copy original response back to response buffer */ - struct mwifiex_ds_misc_cmd *hostcmd = NULL; + struct mwifiex_ds_misc_cmd *hostcmd; uint16_t size = le16_to_cpu(resp->size); dev_dbg(adapter->dev, "info: host cmd resp size = %d\n", size); size = min_t(u16, size, MWIFIEX_SIZE_OF_CMD_BUFFER); if (adapter->curr_cmd->data_buf) { - hostcmd = (struct mwifiex_ds_misc_cmd *) - adapter->curr_cmd->data_buf; + hostcmd = adapter->curr_cmd->data_buf; hostcmd->len = size; - memcpy(hostcmd->cmd, (void *) resp, size); + memcpy(hostcmd->cmd, resp, size); } } orig_cmdresp_no = le16_to_cpu(resp->command); @@ -814,9 +816,6 @@ mwifiex_cmd_timeout_func(unsigned long function_context) return; } cmd_node = adapter->curr_cmd; - if (cmd_node->wait_q_enabled) - adapter->cmd_wait_q.status = -ETIMEDOUT; - if (cmd_node) { adapter->dbg.timeout_cmd_id = adapter->dbg.last_cmd_id[adapter->dbg.last_cmd_index]; @@ -861,6 +860,14 @@ mwifiex_cmd_timeout_func(unsigned long function_context) dev_err(adapter->dev, "ps_mode=%d ps_state=%d\n", adapter->ps_mode, adapter->ps_state); + + if (cmd_node->wait_q_enabled) { + adapter->cmd_wait_q.status = -ETIMEDOUT; + wake_up_interruptible(&adapter->cmd_wait_q.wait); + mwifiex_cancel_pending_ioctl(adapter); + /* reset cmd_sent flag to unblock new commands */ + adapter->cmd_sent = false; + } } if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING) mwifiex_init_fw_complete(adapter); @@ -885,7 +892,7 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter) adapter->curr_cmd->wait_q_enabled = false; spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); adapter->cmd_wait_q.status = -1; - mwifiex_complete_cmd(adapter); + mwifiex_complete_cmd(adapter, adapter->curr_cmd); } /* Cancel all pending command */ spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags); @@ -896,7 +903,7 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter) if (cmd_node->wait_q_enabled) { adapter->cmd_wait_q.status = -1; - mwifiex_complete_cmd(adapter); + mwifiex_complete_cmd(adapter, cmd_node); cmd_node->wait_q_enabled = false; } mwifiex_insert_cmd_to_free_q(adapter, cmd_node); @@ -937,7 +944,6 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter) { struct cmd_ctrl_node *cmd_node = NULL, *tmp_node = NULL; unsigned long cmd_flags; - unsigned long cmd_pending_q_flags; unsigned long scan_pending_q_flags; uint16_t cancel_scan_cmd = false; @@ -947,12 +953,9 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter) cmd_node = adapter->curr_cmd; cmd_node->wait_q_enabled = false; cmd_node->cmd_flag |= CMD_F_CANCELED; - spin_lock_irqsave(&adapter->cmd_pending_q_lock, - cmd_pending_q_flags); - list_del(&cmd_node->list); - spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, - cmd_pending_q_flags); mwifiex_insert_cmd_to_free_q(adapter, cmd_node); + mwifiex_complete_cmd(adapter, adapter->curr_cmd); + adapter->curr_cmd = NULL; spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); } @@ -979,7 +982,6 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter) spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); } adapter->cmd_wait_q.status = -1; - mwifiex_complete_cmd(adapter); } /* @@ -1156,7 +1158,7 @@ EXPORT_SYMBOL_GPL(mwifiex_process_sleep_confirm_resp); int mwifiex_cmd_enh_power_mode(struct mwifiex_private *priv, struct host_cmd_ds_command *cmd, u16 cmd_action, uint16_t ps_bitmap, - void *data_buf) + struct mwifiex_ds_auto_ds *auto_ds) { struct host_cmd_ds_802_11_ps_mode_enh *psmode_enh = &cmd->params.psmode_enh; @@ -1219,9 +1221,8 @@ int mwifiex_cmd_enh_power_mode(struct mwifiex_private *priv, sizeof(struct mwifiex_ie_types_header)); cmd_size += sizeof(*auto_ds_tlv); tlv += sizeof(*auto_ds_tlv); - if (data_buf) - idletime = ((struct mwifiex_ds_auto_ds *) - data_buf)->idle_time; + if (auto_ds) + idletime = auto_ds->idle_time; dev_dbg(priv->adapter->dev, "cmd: PS Command: Enter Auto Deep Sleep\n"); auto_ds_tlv->deep_sleep_timeout = cpu_to_le16(idletime); @@ -1240,7 +1241,7 @@ int mwifiex_cmd_enh_power_mode(struct mwifiex_private *priv, */ int mwifiex_ret_enh_power_mode(struct mwifiex_private *priv, struct host_cmd_ds_command *resp, - void *data_buf) + struct mwifiex_ds_pm_cfg *pm_cfg) { struct mwifiex_adapter *adapter = priv->adapter; struct host_cmd_ds_802_11_ps_mode_enh *ps_mode = @@ -1283,10 +1284,8 @@ int mwifiex_ret_enh_power_mode(struct mwifiex_private *priv, dev_dbg(adapter->dev, "cmd: ps_bitmap=%#x\n", ps_bitmap); - if (data_buf) { + if (pm_cfg) { /* This section is for get power save mode */ - struct mwifiex_ds_pm_cfg *pm_cfg = - (struct mwifiex_ds_pm_cfg *)data_buf; if (ps_bitmap & BITMAP_STA_PS) pm_cfg->param.ps_mode = 1; else diff --git a/drivers/net/wireless/mwifiex/debugfs.c b/drivers/net/wireless/mwifiex/debugfs.c index 46d65e0..d26a78b 100644 --- a/drivers/net/wireless/mwifiex/debugfs.c +++ b/drivers/net/wireless/mwifiex/debugfs.c @@ -27,8 +27,8 @@ static struct dentry *mwifiex_dfs_dir; static char *bss_modes[] = { "Unknown", - "Managed", "Ad-hoc", + "Managed", "Auto" }; @@ -216,28 +216,19 @@ mwifiex_info_read(struct file *file, char __user *ubuf, 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=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n", - netdev->dev_addr[0], netdev->dev_addr[1], - netdev->dev_addr[2], netdev->dev_addr[3], - netdev->dev_addr[4], netdev->dev_addr[5]); + 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=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n", - info.bssid[0], info.bssid[1], - info.bssid[2], info.bssid[3], - info.bssid[4], info.bssid[5]); + p += sprintf(p, "bssid=\"%pM\"\n", info.bssid); p += sprintf(p, "channel=\"%d\"\n", (int) info.bss_chan); p += sprintf(p, "region_code = \"%02x\"\n", info.region_code); netdev_for_each_mc_addr(ha, netdev) - p += sprintf(p, "multicast_address[%d]=" - "\"%02x:%02x:%02x:%02x:%02x:%02x\"\n", i++, - ha->addr[0], ha->addr[1], - ha->addr[2], ha->addr[3], - ha->addr[4], ha->addr[5]); + p += sprintf(p, "multicast_address[%d]=\"%pM\"\n", + i++, ha->addr); } p += sprintf(p, "num_tx_bytes = %lu\n", priv->stats.tx_bytes); @@ -451,26 +442,18 @@ mwifiex_debug_read(struct file *file, char __user *ubuf, if (info.tx_tbl_num) { p += sprintf(p, "Tx BA stream table:\n"); for (i = 0; i < info.tx_tbl_num; i++) - p += sprintf(p, "tid = %d, " - "ra = %02x:%02x:%02x:%02x:%02x:%02x\n", - info.tx_tbl[i].tid, info.tx_tbl[i].ra[0], - info.tx_tbl[i].ra[1], info.tx_tbl[i].ra[2], - info.tx_tbl[i].ra[3], info.tx_tbl[i].ra[4], - info.tx_tbl[i].ra[5]); + p += sprintf(p, "tid = %d, ra = %pM\n", + info.tx_tbl[i].tid, info.tx_tbl[i].ra); } if (info.rx_tbl_num) { p += sprintf(p, "Rx reorder table:\n"); for (i = 0; i < info.rx_tbl_num; i++) { - - p += sprintf(p, "tid = %d, " - "ta = %02x:%02x:%02x:%02x:%02x:%02x, " + p += sprintf(p, "tid = %d, ta = %pM, " "start_win = %d, " "win_size = %d, buffer: ", info.rx_tbl[i].tid, - info.rx_tbl[i].ta[0], info.rx_tbl[i].ta[1], - info.rx_tbl[i].ta[2], info.rx_tbl[i].ta[3], - info.rx_tbl[i].ta[4], info.rx_tbl[i].ta[5], + info.rx_tbl[i].ta, info.rx_tbl[i].start_win, info.rx_tbl[i].win_size); diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h index 0e90b09..ae17ce0 100644 --- a/drivers/net/wireless/mwifiex/decl.h +++ b/drivers/net/wireless/mwifiex/decl.h @@ -30,7 +30,9 @@ #define MWIFIEX_MAX_BSS_NUM (1) -#define MWIFIEX_MIN_DATA_HEADER_LEN 32 /* (sizeof(mwifiex_txpd)) */ +#define MWIFIEX_MIN_DATA_HEADER_LEN 36 /* sizeof(mwifiex_txpd) + * + 4 byte alignment + */ #define MWIFIEX_MAX_TX_BASTREAM_SUPPORTED 2 #define MWIFIEX_MAX_RX_BASTREAM_SUPPORTED 16 @@ -96,7 +98,6 @@ struct mwifiex_802_11_ssid { struct mwifiex_wait_queue { wait_queue_head_t wait; - u16 condition; int status; }; @@ -112,14 +113,6 @@ struct mwifiex_txinfo { u8 bss_index; }; -struct mwifiex_bss_attr { - u8 bss_type; - u8 frame_type; - u8 active; - u8 bss_priority; - u8 bss_num; -}; - enum mwifiex_wmm_ac_e { WMM_AC_BK, WMM_AC_BE, diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index afdd145..0cc5d73 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -57,12 +57,6 @@ struct tx_packet_hdr { #define GET_FW_DEFAULT_BANDS(adapter) \ ((adapter->fw_cap_info >> 8) & ALL_802_11_BANDS) -extern u8 supported_rates_b[B_SUPPORTED_RATES]; -extern u8 supported_rates_g[G_SUPPORTED_RATES]; -extern u8 supported_rates_bg[BG_SUPPORTED_RATES]; -extern u8 supported_rates_a[A_SUPPORTED_RATES]; -extern u8 supported_rates_n[N_SUPPORTED_RATES]; - #define HostCmd_WEP_KEY_INDEX_MASK 0x3fff #define KEY_INFO_ENABLED 0x01 @@ -84,7 +78,8 @@ enum KEY_TYPE_ID { #define MAX_FIRMWARE_POLL_TRIES 100 -#define FIRMWARE_READY 0xfedc +#define FIRMWARE_READY_SDIO 0xfedc +#define FIRMWARE_READY_PCIE 0xfedcba00 enum MWIFIEX_802_11_PRIVACY_FILTER { MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL, @@ -157,6 +152,17 @@ enum MWIFIEX_802_11_WEP_STATUS { #define ISSUPP_RXSTBC(Dot11nDevCap) (Dot11nDevCap & BIT(26)) #define ISSUPP_GREENFIELD(Dot11nDevCap) (Dot11nDevCap & BIT(29)) +/* httxcfg bitmap + * 0 reserved + * 1 20/40 Mhz enable(1)/disable(0) + * 2-3 reserved + * 4 green field enable(1)/disable(0) + * 5 short GI in 20 Mhz enable(1)/disable(0) + * 6 short GI in 40 Mhz enable(1)/disable(0) + * 7-15 reserved + */ +#define MWIFIEX_FW_DEF_HTTXCFG (BIT(1) | BIT(4) | BIT(5) | BIT(6)) + #define GET_RXMCSSUPP(DevMCSSupported) (DevMCSSupported & 0x0f) #define SETHT_MCS32(x) (x[4] |= 1) @@ -210,7 +216,7 @@ enum MWIFIEX_802_11_WEP_STATUS { #define HostCmd_CMD_802_11_HS_CFG_ENH 0x00e5 #define HostCmd_CMD_CAU_REG_ACCESS 0x00ed #define HostCmd_CMD_SET_BSS_MODE 0x00f7 - +#define HostCmd_CMD_PCIE_DESC_DETAILS 0x00fa enum ENH_PS_MODES { EN_PS = 1, @@ -810,6 +816,14 @@ struct host_cmd_ds_txpwr_cfg { __le32 mode; } __packed; +struct mwifiex_bcn_param { + u8 bssid[ETH_ALEN]; + u8 rssi; + __le32 timestamp[2]; + __le16 beacon_period; + __le16 cap_info_bitmap; +} __packed; + #define MWIFIEX_USER_SCAN_CHAN_MAX 50 #define MWIFIEX_MAX_SSID_LIST_LENGTH 10 @@ -851,13 +865,6 @@ struct mwifiex_user_scan_ssid { struct mwifiex_user_scan_cfg { /* - * Flag set to keep the previous scan table intact - * - * If set, the scan results will accumulate, replacing any previous - * matched entries for a BSS with the new scan data - */ - u8 keep_previous_scan; - /* * BSS mode to be sent in the firmware command */ u8 bss_mode; @@ -1125,6 +1132,30 @@ struct host_cmd_ds_set_bss_mode { u8 con_type; } __packed; +struct host_cmd_ds_pcie_details { + /* TX buffer descriptor ring address */ + u32 txbd_addr_lo; + u32 txbd_addr_hi; + /* TX buffer descriptor ring count */ + u32 txbd_count; + + /* RX buffer descriptor ring address */ + u32 rxbd_addr_lo; + u32 rxbd_addr_hi; + /* RX buffer descriptor ring count */ + u32 rxbd_count; + + /* Event buffer descriptor ring address */ + u32 evtbd_addr_lo; + u32 evtbd_addr_hi; + /* Event buffer descriptor ring count */ + u32 evtbd_count; + + /* Sleep cookie buffer physical address */ + u32 sleep_cookie_addr_lo; + u32 sleep_cookie_addr_hi; +} __packed; + struct host_cmd_ds_command { __le16 command; __le16 size; @@ -1172,6 +1203,7 @@ struct host_cmd_ds_command { struct host_cmd_ds_rf_reg_access rf_reg; struct host_cmd_ds_pmic_reg_access pmic_reg; struct host_cmd_ds_set_bss_mode bss_mode; + struct host_cmd_ds_pcie_details pcie_host_spec; struct host_cmd_ds_802_11_eeprom_access eeprom; } params; } __packed; diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index 3f1559e..d792b3f 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -76,7 +76,7 @@ static int mwifiex_init_priv(struct mwifiex_private *priv) memset(priv->curr_addr, 0xff, ETH_ALEN); priv->pkt_tx_ctrl = 0; - priv->bss_mode = NL80211_IFTYPE_STATION; + priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; priv->data_rate = 0; /* Initially indicate the rate as auto */ priv->is_data_rate_auto = true; priv->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR; @@ -152,19 +152,6 @@ static int mwifiex_init_priv(struct mwifiex_private *priv) static int mwifiex_allocate_adapter(struct mwifiex_adapter *adapter) { int ret; - u32 buf_size; - struct mwifiex_bssdescriptor *temp_scan_table; - - /* Allocate buffer to store the BSSID list */ - buf_size = sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP; - temp_scan_table = kzalloc(buf_size, GFP_KERNEL); - if (!temp_scan_table) { - dev_err(adapter->dev, "%s: failed to alloc temp_scan_table\n", - __func__); - return -ENOMEM; - } - - adapter->scan_table = temp_scan_table; /* Allocate command buffer */ ret = mwifiex_alloc_cmd_buffer(adapter); @@ -204,7 +191,12 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) (adapter->sleep_cfm->data); adapter->cmd_sent = false; - adapter->data_sent = true; + + if (adapter->iface_type == MWIFIEX_PCIE) + adapter->data_sent = false; + else + adapter->data_sent = true; + adapter->cmd_resp_received = false; adapter->event_received = false; adapter->data_received = false; @@ -222,14 +214,8 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) adapter->active_scan_time = MWIFIEX_ACTIVE_SCAN_CHAN_TIME; adapter->passive_scan_time = MWIFIEX_PASSIVE_SCAN_CHAN_TIME; - adapter->num_in_scan_table = 0; - memset(adapter->scan_table, 0, - (sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP)); adapter->scan_probes = 1; - memset(adapter->bcn_buf, 0, sizeof(adapter->bcn_buf)); - adapter->bcn_buf_end = adapter->bcn_buf; - adapter->multiple_dtim = 1; adapter->local_listen_interval = 0; /* default value in firmware @@ -297,6 +283,34 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) } /* + * This function releases the lock variables and frees the locks and + * associated locks. + */ +static void mwifiex_free_lock_list(struct mwifiex_adapter *adapter) +{ + struct mwifiex_private *priv; + s32 i, j; + + /* Free lists */ + list_del(&adapter->cmd_free_q); + list_del(&adapter->cmd_pending_q); + list_del(&adapter->scan_pending_q); + + for (i = 0; i < adapter->priv_num; i++) + list_del(&adapter->bss_prio_tbl[i].bss_prio_head); + + for (i = 0; i < adapter->priv_num; i++) { + if (adapter->priv[i]) { + priv = adapter->priv[i]; + for (j = 0; j < MAX_NUM_TID; ++j) + list_del(&priv->wmm.tid_tbl_ptr[j].ra_list); + list_del(&priv->tx_ba_stream_tbl_ptr); + list_del(&priv->rx_reorder_tbl_ptr); + } + } +} + +/* * This function frees the adapter structure. * * The freeing operation is done recursively, by canceling all @@ -326,8 +340,6 @@ mwifiex_free_adapter(struct mwifiex_adapter *adapter) del_timer(&adapter->cmd_timer); dev_dbg(adapter->dev, "info: free scan table\n"); - kfree(adapter->scan_table); - adapter->scan_table = NULL; adapter->if_ops.cleanup_if(adapter); @@ -392,34 +404,6 @@ int mwifiex_init_lock_list(struct mwifiex_adapter *adapter) } /* - * This function releases the lock variables and frees the locks and - * associated locks. - */ -void mwifiex_free_lock_list(struct mwifiex_adapter *adapter) -{ - struct mwifiex_private *priv; - s32 i, j; - - /* Free lists */ - list_del(&adapter->cmd_free_q); - list_del(&adapter->cmd_pending_q); - list_del(&adapter->scan_pending_q); - - for (i = 0; i < adapter->priv_num; i++) - list_del(&adapter->bss_prio_tbl[i].bss_prio_head); - - for (i = 0; i < adapter->priv_num; i++) { - if (adapter->priv[i]) { - priv = adapter->priv[i]; - for (j = 0; j < MAX_NUM_TID; ++j) - list_del(&priv->wmm.tid_tbl_ptr[j].ra_list); - list_del(&priv->tx_ba_stream_tbl_ptr); - list_del(&priv->rx_reorder_tbl_ptr); - } - } -} - -/* * This function initializes the firmware. * * The following operations are performed sequentially - @@ -602,11 +586,13 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter) int mwifiex_dnld_fw(struct mwifiex_adapter *adapter, struct mwifiex_fw_image *pmfw) { - int ret, winner; + int ret; u32 poll_num = 1; + adapter->winner = 0; + /* Check if firmware is already running */ - ret = adapter->if_ops.check_fw_status(adapter, poll_num, &winner); + ret = adapter->if_ops.check_fw_status(adapter, poll_num); if (!ret) { dev_notice(adapter->dev, "WLAN FW already running! Skip FW download\n"); @@ -615,7 +601,7 @@ int mwifiex_dnld_fw(struct mwifiex_adapter *adapter, poll_num = MAX_FIRMWARE_POLL_TRIES; /* Check if we are the winner for downloading FW */ - if (!winner) { + if (!adapter->winner) { dev_notice(adapter->dev, "Other interface already running!" " Skip FW download\n"); @@ -633,7 +619,7 @@ int mwifiex_dnld_fw(struct mwifiex_adapter *adapter, poll_fw: /* Check if the firmware is downloaded successfully or not */ - ret = adapter->if_ops.check_fw_status(adapter, poll_num, NULL); + ret = adapter->if_ops.check_fw_status(adapter, poll_num); if (ret) { dev_err(adapter->dev, "FW failed to be active in time\n"); return -1; diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h index 7c1c5ee..e0b68e7 100644 --- a/drivers/net/wireless/mwifiex/ioctl.h +++ b/drivers/net/wireless/mwifiex/ioctl.h @@ -134,7 +134,6 @@ struct mwifiex_ver_ext { struct mwifiex_bss_info { u32 bss_mode; struct mwifiex_802_11_ssid ssid; - u32 scan_table_idx; u32 bss_chan; u32 region_code; u32 media_connected; @@ -249,6 +248,7 @@ struct mwifiex_ds_hs_cfg { }; #define DEEP_SLEEP_ON 1 +#define DEEP_SLEEP_OFF 0 #define DEEP_SLEEP_IDLE_TIME 100 #define PS_MODE_AUTO 1 @@ -306,10 +306,12 @@ struct mwifiex_ds_read_eeprom { u8 value[MAX_EEPROM_DATA]; }; +#define IEEE_MAX_IE_SIZE 256 + struct mwifiex_ds_misc_gen_ie { u32 type; u32 len; - u8 ie_data[IW_CUSTOM_MAX]; + u8 ie_data[IEEE_MAX_IE_SIZE]; }; struct mwifiex_ds_misc_cmd { diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c index 890841a..d48dfb7 100644 --- a/drivers/net/wireless/mwifiex/join.c +++ b/drivers/net/wireless/mwifiex/join.c @@ -147,13 +147,12 @@ static int mwifiex_get_common_rates(struct mwifiex_private *priv, u8 *rate1, u8 *ptr = rate1, *tmp; u32 i, j; - tmp = kmalloc(rate1_size, GFP_KERNEL); + tmp = kmemdup(rate1, rate1_size, GFP_KERNEL); if (!tmp) { dev_err(priv->adapter->dev, "failed to alloc tmp buf\n"); return -ENOMEM; } - memcpy(tmp, rate1, rate1_size); memset(rate1, 0, rate1_size); for (i = 0; rate2[i] && i < rate2_size; i++) { @@ -224,32 +223,6 @@ mwifiex_setup_rates_from_bssdesc(struct mwifiex_private *priv, } /* - * This function updates the scan entry TSF timestamps to reflect - * a new association. - */ -static void -mwifiex_update_tsf_timestamps(struct mwifiex_private *priv, - struct mwifiex_bssdescriptor *new_bss_desc) -{ - struct mwifiex_adapter *adapter = priv->adapter; - u32 table_idx; - long long new_tsf_base; - signed long long tsf_delta; - - memcpy(&new_tsf_base, new_bss_desc->time_stamp, sizeof(new_tsf_base)); - - tsf_delta = new_tsf_base - new_bss_desc->network_tsf; - - dev_dbg(adapter->dev, "info: TSF: update TSF timestamps, " - "0x%016llx -> 0x%016llx\n", - new_bss_desc->network_tsf, new_tsf_base); - - for (table_idx = 0; table_idx < adapter->num_in_scan_table; - table_idx++) - adapter->scan_table[table_idx].network_tsf += tsf_delta; -} - -/* * This function appends a WAPI IE. * * This function is called from the network join command preparation routine. @@ -364,10 +337,9 @@ static int mwifiex_append_rsn_ie_wpa_wpa2(struct mwifiex_private *priv, */ int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv, struct host_cmd_ds_command *cmd, - void *data_buf) + struct mwifiex_bssdescriptor *bss_desc) { struct host_cmd_ds_802_11_associate *assoc = &cmd->params.associate; - struct mwifiex_bssdescriptor *bss_desc; struct mwifiex_ie_types_ssid_param_set *ssid_tlv; struct mwifiex_ie_types_phy_param_set *phy_tlv; struct mwifiex_ie_types_ss_param_set *ss_tlv; @@ -380,7 +352,6 @@ int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv, u8 *pos; int rsn_ie_len = 0; - bss_desc = (struct mwifiex_bssdescriptor *) data_buf; pos = (u8 *) assoc; mwifiex_cfg_tx_buf(priv, bss_desc); @@ -641,12 +612,6 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv, priv->curr_bss_params.band = (u8) bss_desc->bss_band; - /* - * Adjust the timestamps in the scan table to be relative to the newly - * associated AP's TSF - */ - mwifiex_update_tsf_timestamps(priv, bss_desc); - if (bss_desc->wmm_ie.vend_hdr.element_id == WLAN_EID_VENDOR_SPECIFIC) priv->curr_bss_params.wmm_enabled = true; else @@ -748,7 +713,8 @@ done: */ int mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv, - struct host_cmd_ds_command *cmd, void *data_buf) + struct host_cmd_ds_command *cmd, + struct mwifiex_802_11_ssid *req_ssid) { int rsn_ie_len = 0; struct mwifiex_adapter *adapter = priv->adapter; @@ -786,20 +752,15 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv, memset(adhoc_start->ssid, 0, IEEE80211_MAX_SSID_LEN); - memcpy(adhoc_start->ssid, - ((struct mwifiex_802_11_ssid *) data_buf)->ssid, - ((struct mwifiex_802_11_ssid *) data_buf)->ssid_len); + memcpy(adhoc_start->ssid, req_ssid->ssid, req_ssid->ssid_len); dev_dbg(adapter->dev, "info: ADHOC_S_CMD: SSID = %s\n", adhoc_start->ssid); memset(bss_desc->ssid.ssid, 0, IEEE80211_MAX_SSID_LEN); - memcpy(bss_desc->ssid.ssid, - ((struct mwifiex_802_11_ssid *) data_buf)->ssid, - ((struct mwifiex_802_11_ssid *) data_buf)->ssid_len); + memcpy(bss_desc->ssid.ssid, req_ssid->ssid, req_ssid->ssid_len); - bss_desc->ssid.ssid_len = - ((struct mwifiex_802_11_ssid *) data_buf)->ssid_len; + bss_desc->ssid.ssid_len = req_ssid->ssid_len; /* Set the BSS mode */ adhoc_start->bss_mode = HostCmd_BSS_MODE_IBSS; @@ -1036,13 +997,12 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv, */ int mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv, - struct host_cmd_ds_command *cmd, void *data_buf) + struct host_cmd_ds_command *cmd, + struct mwifiex_bssdescriptor *bss_desc) { int rsn_ie_len = 0; struct host_cmd_ds_802_11_ad_hoc_join *adhoc_join = &cmd->params.adhoc_join; - struct mwifiex_bssdescriptor *bss_desc = - (struct mwifiex_bssdescriptor *) data_buf; struct mwifiex_ie_types_chan_list_param_set *chan_tlv; u32 cmd_append_size = 0; u16 tmp_cap; diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index f058225..018276f 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -26,26 +26,6 @@ const char driver_version[] = "mwifiex " VERSION " (%s) "; -struct mwifiex_adapter *g_adapter; -EXPORT_SYMBOL_GPL(g_adapter); - -static struct mwifiex_bss_attr mwifiex_bss_sta[] = { - {MWIFIEX_BSS_TYPE_STA, MWIFIEX_DATA_FRAME_TYPE_ETH_II, true, 0, 0}, -}; - -static int drv_mode = DRV_MODE_STA; - -static char fw_name[32] = DEFAULT_FW_NAME; - -/* Supported drv_mode table */ -static struct mwifiex_drv_mode mwifiex_drv_mode_tbl[] = { - { - .drv_mode = DRV_MODE_STA, - .intf_num = ARRAY_SIZE(mwifiex_bss_sta), - .bss_attr = mwifiex_bss_sta, - }, -}; - /* * This function registers the device and performs all the necessary * initializations. @@ -62,7 +42,7 @@ static struct mwifiex_drv_mode mwifiex_drv_mode_tbl[] = { * proper cleanup before exiting. */ static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops, - struct mwifiex_drv_mode *drv_mode_ptr) + void **padapter) { struct mwifiex_adapter *adapter; int i; @@ -71,7 +51,7 @@ static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops, if (!adapter) return -ENOMEM; - g_adapter = adapter; + *padapter = adapter; adapter->card = card; /* Save interface specific operations in adapter */ @@ -82,44 +62,20 @@ static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops, goto error; adapter->priv_num = 0; - for (i = 0; i < drv_mode_ptr->intf_num; i++) { - adapter->priv[i] = NULL; - if (!drv_mode_ptr->bss_attr[i].active) - continue; - - /* Allocate memory for private structure */ - adapter->priv[i] = kzalloc(sizeof(struct mwifiex_private), - GFP_KERNEL); - if (!adapter->priv[i]) { - dev_err(adapter->dev, "%s: failed to alloc priv[%d]\n", - __func__, i); - goto error; - } - - adapter->priv_num++; - adapter->priv[i]->adapter = adapter; - /* Save bss_type, frame_type & bss_priority */ - adapter->priv[i]->bss_type = drv_mode_ptr->bss_attr[i].bss_type; - adapter->priv[i]->frame_type = - drv_mode_ptr->bss_attr[i].frame_type; - adapter->priv[i]->bss_priority = - drv_mode_ptr->bss_attr[i].bss_priority; - - if (drv_mode_ptr->bss_attr[i].bss_type == MWIFIEX_BSS_TYPE_STA) - adapter->priv[i]->bss_role = MWIFIEX_BSS_ROLE_STA; - else if (drv_mode_ptr->bss_attr[i].bss_type == - MWIFIEX_BSS_TYPE_UAP) - adapter->priv[i]->bss_role = MWIFIEX_BSS_ROLE_UAP; - - /* Save bss_index & bss_num */ - adapter->priv[i]->bss_index = i; - adapter->priv[i]->bss_num = drv_mode_ptr->bss_attr[i].bss_num; + /* Allocate memory for private structure */ + adapter->priv[0] = kzalloc(sizeof(struct mwifiex_private), + GFP_KERNEL); + if (!adapter->priv[0]) { + dev_err(adapter->dev, "%s: failed to alloc priv[0]\n", + __func__); + goto error; } - adapter->drv_mode = drv_mode_ptr; - if (mwifiex_init_lock_list(adapter)) - goto error; + adapter->priv_num++; + + adapter->priv[0]->adapter = adapter; + mwifiex_init_lock_list(adapter); init_timer(&adapter->cmd_timer); adapter->cmd_timer.function = mwifiex_cmd_timeout_func; @@ -130,9 +86,9 @@ static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops, error: dev_dbg(adapter->dev, "info: leave mwifiex_register with error\n"); - mwifiex_free_lock_list(adapter); - for (i = 0; i < drv_mode_ptr->intf_num; i++) + for (i = 0; i < adapter->priv_num; i++) kfree(adapter->priv[i]); + kfree(adapter); return -1; @@ -320,38 +276,6 @@ exit_main_proc: } /* - * This function initializes the software. - * - * The main work includes allocating and initializing the adapter structure - * and initializing the private structures. - */ -static int -mwifiex_init_sw(void *card, struct mwifiex_if_ops *if_ops) -{ - int i; - struct mwifiex_drv_mode *drv_mode_ptr; - - /* find mwifiex_drv_mode entry from mwifiex_drv_mode_tbl */ - drv_mode_ptr = NULL; - for (i = 0; i < ARRAY_SIZE(mwifiex_drv_mode_tbl); i++) { - if (mwifiex_drv_mode_tbl[i].drv_mode == drv_mode) { - drv_mode_ptr = &mwifiex_drv_mode_tbl[i]; - break; - } - } - - if (!drv_mode_ptr) { - pr_err("invalid drv_mode=%d\n", drv_mode); - return -1; - } - - if (mwifiex_register(card, if_ops, drv_mode_ptr)) - return -1; - - return 0; -} - -/* * This function frees the adapter structure. * * Additionally, this closes the netlink socket, frees the timers @@ -384,20 +308,8 @@ static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter) memset(&fw, 0, sizeof(struct mwifiex_fw_image)); - switch (adapter->revision_id) { - case SD8787_W0: - case SD8787_W1: - strcpy(fw_name, SD8787_W1_FW_NAME); - break; - case SD8787_A0: - case SD8787_A1: - strcpy(fw_name, SD8787_AX_FW_NAME); - break; - default: - break; - } - - err = request_firmware(&adapter->firmware, fw_name, adapter->dev); + err = request_firmware(&adapter->firmware, adapter->fw_name, + adapter->dev); if (err < 0) { dev_err(adapter->dev, "request_firmware() returned" " error code %#x\n", err); @@ -546,6 +458,7 @@ mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) } tx_info = MWIFIEX_SKB_TXCB(skb); + memset(tx_info, 0, sizeof(*tx_info)); tx_info->bss_index = priv->bss_index; mwifiex_fill_buffer(skb); @@ -569,7 +482,7 @@ static int mwifiex_set_mac_address(struct net_device *dev, void *addr) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); - struct sockaddr *hw_addr = (struct sockaddr *) addr; + struct sockaddr *hw_addr = addr; int ret; memcpy(priv->curr_addr, hw_addr->sa_data, ETH_ALEN); @@ -643,7 +556,7 @@ static const struct net_device_ops mwifiex_netdev_ops = { .ndo_set_mac_address = mwifiex_set_mac_address, .ndo_tx_timeout = mwifiex_tx_timeout, .ndo_get_stats = mwifiex_get_stats, - .ndo_set_multicast_list = mwifiex_set_multicast_list, + .ndo_set_rx_mode = mwifiex_set_multicast_list, }; /* @@ -665,10 +578,11 @@ static const struct net_device_ops mwifiex_netdev_ops = { * * In addition, the CFG80211 work queue is also created. */ -static void -mwifiex_init_priv_params(struct mwifiex_private *priv, struct net_device *dev) +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; @@ -680,118 +594,6 @@ mwifiex_init_priv_params(struct mwifiex_private *priv, struct net_device *dev) } /* - * This function adds a new logical interface. - * - * It allocates, initializes and registers the interface by performing - * the following opearations - - * - Allocate a new net device structure - * - Assign device name - * - Register the new device with CFG80211 subsystem - * - Initialize semaphore and private structure - * - Register the new device with kernel - * - Create the complete debug FS structure if configured - */ -static struct mwifiex_private *mwifiex_add_interface( - struct mwifiex_adapter *adapter, - u8 bss_index, u8 bss_type) -{ - struct net_device *dev; - struct mwifiex_private *priv; - void *mdev_priv; - - dev = alloc_netdev_mq(sizeof(struct mwifiex_private *), "mlan%d", - ether_setup, 1); - if (!dev) { - dev_err(adapter->dev, "no memory available for netdevice\n"); - goto error; - } - - if (mwifiex_register_cfg80211(dev, adapter->priv[bss_index]->curr_addr, - adapter->priv[bss_index]) != 0) { - dev_err(adapter->dev, "cannot register netdevice with cfg80211\n"); - goto error; - } - /* Save the priv pointer in netdev */ - priv = adapter->priv[bss_index]; - mdev_priv = netdev_priv(dev); - *((unsigned long *) mdev_priv) = (unsigned long) priv; - - priv->netdev = dev; - - sema_init(&priv->async_sem, 1); - priv->scan_pending_on_block = false; - - mwifiex_init_priv_params(priv, dev); - - SET_NETDEV_DEV(dev, adapter->dev); - - /* Register network device */ - if (register_netdev(dev)) { - dev_err(adapter->dev, "cannot register virtual network device\n"); - goto error; - } - - dev_dbg(adapter->dev, "info: %s: Marvell 802.11 Adapter\n", dev->name); -#ifdef CONFIG_DEBUG_FS - mwifiex_dev_debugfs_init(priv); -#endif - return priv; -error: - if (dev) - free_netdev(dev); - return NULL; -} - -/* - * This function removes a logical interface. - * - * It deregisters, resets and frees the interface by performing - * the following operations - - * - Disconnect the device if connected, send wireless event to - * notify applications. - * - Remove the debug FS structure if configured - * - Unregister the device from kernel - * - Free the net device structure - * - Cancel all works and destroy work queue - * - Unregister and free the wireless device from CFG80211 subsystem - */ -static void -mwifiex_remove_interface(struct mwifiex_adapter *adapter, u8 bss_index) -{ - struct net_device *dev; - struct mwifiex_private *priv = adapter->priv[bss_index]; - - if (!priv) - return; - dev = priv->netdev; - - if (priv->media_connected) - priv->media_connected = false; - -#ifdef CONFIG_DEBUG_FS - mwifiex_dev_debugfs_remove(priv); -#endif - /* Last reference is our one */ - dev_dbg(adapter->dev, "info: %s: refcnt = %d\n", - dev->name, netdev_refcnt_read(dev)); - - if (dev->reg_state == NETREG_REGISTERED) - unregister_netdev(dev); - - /* Clear the priv in adapter */ - priv->netdev = NULL; - if (dev) - free_netdev(dev); - - cancel_work_sync(&priv->cfg_workqueue); - flush_workqueue(priv->workqueue); - destroy_workqueue(priv->workqueue); - wiphy_unregister(priv->wdev->wiphy); - wiphy_free(priv->wdev->wiphy); - kfree(priv->wdev); -} - -/* * This function check if command is pending. */ int is_command_pending(struct mwifiex_adapter *adapter) @@ -861,20 +663,21 @@ mwifiex_terminate_workqueue(struct mwifiex_adapter *adapter) */ int mwifiex_add_card(void *card, struct semaphore *sem, - struct mwifiex_if_ops *if_ops) + struct mwifiex_if_ops *if_ops, u8 iface_type) { - int i; struct mwifiex_adapter *adapter; + char fmt[64]; + struct mwifiex_private *priv; if (down_interruptible(sem)) goto exit_sem_err; - if (mwifiex_init_sw(card, if_ops)) { + if (mwifiex_register(card, if_ops, (void **)&adapter)) { pr_err("%s: software init failed\n", __func__); goto err_init_sw; } - adapter = g_adapter; + adapter->iface_type = iface_type; adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING; adapter->surprise_removed = false; @@ -884,8 +687,8 @@ mwifiex_add_card(void *card, struct semaphore *sem, init_waitqueue_head(&adapter->hs_activate_wait_q); adapter->cmd_wait_q_required = false; init_waitqueue_head(&adapter->cmd_wait_q.wait); - adapter->cmd_wait_q.condition = false; adapter->cmd_wait_q.status = 0; + adapter->scan_wait_q_woken = false; adapter->workqueue = create_workqueue("MWIFIEX_WORK_QUEUE"); if (!adapter->workqueue) @@ -905,21 +708,37 @@ mwifiex_add_card(void *card, struct semaphore *sem, goto err_init_fw; } - /* Add interfaces */ - for (i = 0; i < adapter->drv_mode->intf_num; i++) { - if (!mwifiex_add_interface(adapter, i, - adapter->drv_mode->bss_attr[i].bss_type)) { - goto err_add_intf; - } + priv = adapter->priv[0]; + + if (mwifiex_register_cfg80211(priv) != 0) { + dev_err(adapter->dev, "cannot register netdevice" + " with cfg80211\n"); + goto err_init_fw; } + rtnl_lock(); + /* Create station interface by default */ + if (!mwifiex_add_virtual_intf(priv->wdev->wiphy, "mlan%d", + NL80211_IFTYPE_STATION, NULL, NULL)) { + rtnl_unlock(); + dev_err(adapter->dev, "cannot create default station" + " interface\n"); + goto err_add_intf; + } + + rtnl_unlock(); + up(sem); + mwifiex_drv_get_driver_version(adapter, fmt, sizeof(fmt) - 1); + dev_notice(adapter->dev, "driver_version = %s\n", fmt); + return 0; err_add_intf: - for (i = 0; i < adapter->priv_num; i++) - mwifiex_remove_interface(adapter, i); + rtnl_lock(); + mwifiex_del_virtual_intf(priv->wdev->wiphy, priv->netdev); + rtnl_unlock(); err_init_fw: pr_debug("info: %s: unregister device\n", __func__); adapter->if_ops.unregister_dev(adapter); @@ -974,7 +793,7 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem) /* Stop data */ for (i = 0; i < adapter->priv_num; i++) { priv = adapter->priv[i]; - if (priv) { + if (priv && priv->netdev) { if (!netif_queue_stopped(priv->netdev)) netif_stop_queue(priv->netdev); if (netif_carrier_ok(priv->netdev)) @@ -999,9 +818,24 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem) atomic_read(&adapter->cmd_pending)); } - /* Remove interface */ - for (i = 0; i < adapter->priv_num; i++) - mwifiex_remove_interface(adapter, i); + for (i = 0; i < adapter->priv_num; i++) { + priv = adapter->priv[i]; + + if (!priv) + continue; + + rtnl_lock(); + mwifiex_del_virtual_intf(priv->wdev->wiphy, priv->netdev); + rtnl_unlock(); + } + + priv = adapter->priv[0]; + if (!priv) + goto exit_remove; + + wiphy_unregister(priv->wdev->wiphy); + wiphy_free(priv->wdev->wiphy); + kfree(priv->wdev); mwifiex_terminate_workqueue(adapter); diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 8316b3c..30f138b 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -37,32 +37,16 @@ #include "ioctl.h" #include "util.h" #include "fw.h" +#include "pcie.h" extern const char driver_version[]; -extern struct mwifiex_adapter *g_adapter; enum { MWIFIEX_ASYNC_CMD, MWIFIEX_SYNC_CMD }; -#define DRV_MODE_STA 0x1 - -#define SD8787_W0 0x30 -#define SD8787_W1 0x31 -#define SD8787_A0 0x40 -#define SD8787_A1 0x41 - -#define DEFAULT_FW_NAME "mrvl/sd8787_uapsta.bin" -#define SD8787_W1_FW_NAME "mrvl/sd8787_uapsta_w1.bin" -#define SD8787_AX_FW_NAME "mrvl/sd8787_uapsta.bin" - -struct mwifiex_drv_mode { - u16 drv_mode; - u16 intf_num; - struct mwifiex_bss_attr *bss_attr; -}; - +#define MWIFIEX_MAX_AP 64 #define MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT (5 * HZ) @@ -124,6 +108,8 @@ struct mwifiex_drv_mode { #define MAX_FREQUENCY_BAND_BG 2484 +#define MWIFIEX_EVENT_HEADER_LEN 4 + struct mwifiex_dbg { u32 num_cmd_host_to_card_failure; u32 num_cmd_sleep_cfm_host_to_card_failure; @@ -173,6 +159,11 @@ enum MWIFIEX_PS_STATE { PS_STATE_SLEEP }; +enum mwifiex_iface_type { + MWIFIEX_SDIO, + MWIFIEX_PCIE, +}; + struct mwifiex_add_ba_param { u32 tx_win_size; u32 rx_win_size; @@ -236,27 +227,10 @@ struct ieee_types_header { u8 len; } __packed; -struct ieee_obss_scan_param { - u16 obss_scan_passive_dwell; - u16 obss_scan_active_dwell; - u16 bss_chan_width_trigger_scan_int; - u16 obss_scan_passive_total; - u16 obss_scan_active_total; - u16 bss_width_chan_trans_delay; - u16 obss_scan_active_threshold; -} __packed; - -struct ieee_types_obss_scan_param { - struct ieee_types_header ieee_hdr; - struct ieee_obss_scan_param obss_scan; -} __packed; - #define MWIFIEX_SUPPORTED_RATES 14 #define MWIFIEX_SUPPORTED_RATES_EXT 32 -#define IEEE_MAX_IE_SIZE 256 - struct ieee_types_vendor_specific { struct ieee_types_vendor_header vend_hdr; u8 data[IEEE_MAX_IE_SIZE - sizeof(struct ieee_types_vendor_header)]; @@ -300,8 +274,6 @@ struct mwifiex_bssdescriptor { u16 bss_co_2040_offset; u8 *bcn_ext_cap; u16 ext_cap_offset; - struct ieee_types_obss_scan_param *bcn_obss_scan; - u16 overlap_bss_offset; struct ieee_types_vendor_specific *bcn_wpa_ie; u16 wpa_offset; struct ieee_types_generic *bcn_rsn_ie; @@ -310,8 +282,6 @@ struct mwifiex_bssdescriptor { u16 wapi_offset; u8 *beacon_buf; u32 beacon_buf_size; - u32 beacon_buf_size_max; - }; struct mwifiex_current_bss_params { @@ -477,7 +447,7 @@ struct mwifiex_private { struct dentry *dfs_dev_dir; #endif u8 nick_name[16]; - struct iw_statistics w_stats; + u8 qual_level, qual_noise; u16 current_key_index; struct semaphore async_sem; u8 scan_pending_on_block; @@ -550,36 +520,41 @@ struct cmd_ctrl_node { void *data_buf; u32 wait_q_enabled; struct sk_buff *skb; + u8 *condition; + u8 cmd_wait_q_woken; }; struct mwifiex_if_ops { int (*init_if) (struct mwifiex_adapter *); void (*cleanup_if) (struct mwifiex_adapter *); - int (*check_fw_status) (struct mwifiex_adapter *, u32, int *); + int (*check_fw_status) (struct mwifiex_adapter *, u32); int (*prog_fw) (struct mwifiex_adapter *, struct mwifiex_fw_image *); int (*register_dev) (struct mwifiex_adapter *); void (*unregister_dev) (struct mwifiex_adapter *); int (*enable_int) (struct mwifiex_adapter *); int (*process_int_status) (struct mwifiex_adapter *); - int (*host_to_card) (struct mwifiex_adapter *, u8, - u8 *payload, u32 pkt_len, + int (*host_to_card) (struct mwifiex_adapter *, u8, struct sk_buff *, struct mwifiex_tx_param *); int (*wakeup) (struct mwifiex_adapter *); int (*wakeup_complete) (struct mwifiex_adapter *); + /* Interface specific functions */ void (*update_mp_end_port) (struct mwifiex_adapter *, u16); void (*cleanup_mpa_buf) (struct mwifiex_adapter *); + int (*cmdrsp_complete) (struct mwifiex_adapter *, struct sk_buff *); + int (*event_complete) (struct mwifiex_adapter *, struct sk_buff *); }; struct mwifiex_adapter { + u8 iface_type; struct mwifiex_private *priv[MWIFIEX_MAX_BSS_NUM]; u8 priv_num; - struct mwifiex_drv_mode *drv_mode; const struct firmware *firmware; + char fw_name[32]; + int winner; struct device *dev; bool surprise_removed; u32 fw_release_number; - u32 revision_id; u16 init_wait_q_woken; wait_queue_head_t init_wait_q; void *card; @@ -633,15 +608,11 @@ struct mwifiex_adapter { u32 scan_processing; u16 region_code; struct mwifiex_802_11d_domain_reg domain_reg; - struct mwifiex_bssdescriptor *scan_table; - u32 num_in_scan_table; u16 scan_probes; u32 scan_mode; u16 specific_scan_time; u16 active_scan_time; u16 passive_scan_time; - u8 bcn_buf[MAX_SCAN_BEACON_BUFFER]; - u8 *bcn_buf_end; u8 fw_bands; u8 adhoc_start_band; u8 config_bands; @@ -682,10 +653,11 @@ struct mwifiex_adapter { u32 arp_filter_size; u16 cmd_wait_q_required; struct mwifiex_wait_queue cmd_wait_q; + u8 scan_wait_q_woken; + struct cmd_ctrl_node *cmd_queued; }; int mwifiex_init_lock_list(struct mwifiex_adapter *adapter); -void mwifiex_free_lock_list(struct mwifiex_adapter *adapter); int mwifiex_init_fw(struct mwifiex_adapter *adapter); @@ -701,7 +673,8 @@ int mwifiex_recv_packet(struct mwifiex_adapter *, struct sk_buff *skb); int mwifiex_process_event(struct mwifiex_adapter *adapter); -int mwifiex_complete_cmd(struct mwifiex_adapter *adapter); +int mwifiex_complete_cmd(struct mwifiex_adapter *adapter, + struct cmd_ctrl_node *cmd_node); int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no, u16 cmd_action, u32 cmd_oid, void *data_buf); @@ -735,8 +708,6 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb, int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags); int mwifiex_write_data_complete(struct mwifiex_adapter *adapter, struct sk_buff *skb, int status); -int mwifiex_recv_packet_complete(struct mwifiex_adapter *, - struct sk_buff *skb, int status); void mwifiex_clean_txrx(struct mwifiex_private *priv); u8 mwifiex_check_last_packet_indication(struct mwifiex_private *priv); void mwifiex_check_ps_cond(struct mwifiex_adapter *adapter); @@ -745,10 +716,10 @@ void mwifiex_process_sleep_confirm_resp(struct mwifiex_adapter *, u8 *, int mwifiex_cmd_enh_power_mode(struct mwifiex_private *priv, struct host_cmd_ds_command *cmd, u16 cmd_action, uint16_t ps_bitmap, - void *data_buf); + struct mwifiex_ds_auto_ds *auto_ds); int mwifiex_ret_enh_power_mode(struct mwifiex_private *priv, struct host_cmd_ds_command *resp, - void *data_buf); + struct mwifiex_ds_pm_cfg *pm_cfg); void mwifiex_process_hs_config(struct mwifiex_adapter *adapter); void mwifiex_hs_activated_event(struct mwifiex_private *priv, u8 activated); @@ -760,38 +731,28 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *, uint16_t cmd_no, u16 cmd_action, u32 cmd_oid, void *data_buf, void *cmd_buf); int mwifiex_process_sta_cmdresp(struct mwifiex_private *, u16 cmdresp_no, - void *cmd_buf); + struct host_cmd_ds_command *resp); int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *, struct sk_buff *skb); int mwifiex_process_sta_event(struct mwifiex_private *); void *mwifiex_process_sta_txpd(struct mwifiex_private *, struct sk_buff *skb); int mwifiex_sta_init_cmd(struct mwifiex_private *, u8 first_sta); -int mwifiex_scan_networks(struct mwifiex_private *priv, - const struct mwifiex_user_scan_cfg *user_scan_in); int mwifiex_cmd_802_11_scan(struct host_cmd_ds_command *cmd, - void *data_buf); + struct mwifiex_scan_cmd_config *scan_cfg); void mwifiex_queue_scan_cmd(struct mwifiex_private *priv, struct cmd_ctrl_node *cmd_node); int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, struct host_cmd_ds_command *resp); -s32 mwifiex_find_ssid_in_list(struct mwifiex_private *priv, - struct mwifiex_802_11_ssid *ssid, u8 *bssid, - u32 mode); -s32 mwifiex_find_bssid_in_list(struct mwifiex_private *priv, u8 *bssid, - u32 mode); -int mwifiex_find_best_network(struct mwifiex_private *priv, - struct mwifiex_ssid_bssid *req_ssid_bssid); s32 mwifiex_ssid_cmp(struct mwifiex_802_11_ssid *ssid1, struct mwifiex_802_11_ssid *ssid2); int mwifiex_associate(struct mwifiex_private *priv, struct mwifiex_bssdescriptor *bss_desc); int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv, - struct host_cmd_ds_command - *cmd, void *data_buf); + struct host_cmd_ds_command *cmd, + struct mwifiex_bssdescriptor *bss_desc); int mwifiex_ret_802_11_associate(struct mwifiex_private *priv, struct host_cmd_ds_command *resp); void mwifiex_reset_connect_state(struct mwifiex_private *priv); -void mwifiex_2040_coex_event(struct mwifiex_private *priv); u8 mwifiex_band_to_radio_type(u8 band); int mwifiex_deauthenticate(struct mwifiex_private *priv, u8 *mac); int mwifiex_adhoc_start(struct mwifiex_private *priv, @@ -800,10 +761,10 @@ int mwifiex_adhoc_join(struct mwifiex_private *priv, struct mwifiex_bssdescriptor *bss_desc); int mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv, struct host_cmd_ds_command *cmd, - void *data_buf); + struct mwifiex_802_11_ssid *req_ssid); int mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv, struct host_cmd_ds_command *cmd, - void *data_buf); + struct mwifiex_bssdescriptor *bss_desc); int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv, struct host_cmd_ds_command *resp); int mwifiex_cmd_802_11_bg_scan_query(struct host_cmd_ds_command *cmd); @@ -832,6 +793,8 @@ int mwifiex_cmd_get_hw_spec(struct mwifiex_private *priv, int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv, struct host_cmd_ds_command *resp); int is_command_pending(struct mwifiex_adapter *adapter); +void mwifiex_init_priv_params(struct mwifiex_private *priv, + struct net_device *dev); /* * This function checks if the queuing is RA based or not. @@ -921,7 +884,7 @@ struct mwifiex_private *mwifiex_bss_index_to_priv(struct mwifiex_adapter *adapter, u8 bss_index); int mwifiex_init_shutdown_fw(struct mwifiex_private *priv, u32 func_init_shutdown); -int mwifiex_add_card(void *, struct semaphore *, struct mwifiex_if_ops *); +int mwifiex_add_card(void *, struct semaphore *, struct mwifiex_if_ops *, u8); int mwifiex_remove_card(struct mwifiex_adapter *, struct semaphore *); void mwifiex_get_version(struct mwifiex_adapter *adapter, char *version, @@ -931,19 +894,15 @@ int mwifiex_request_set_multicast_list(struct mwifiex_private *priv, int mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist, struct net_device *dev); int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter); -int mwifiex_bss_start(struct mwifiex_private *priv, - struct mwifiex_ssid_bssid *ssid_bssid); -int mwifiex_set_hs_params(struct mwifiex_private *priv, - u16 action, int cmd_type, - struct mwifiex_ds_hs_cfg *hscfg); +int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, + struct mwifiex_802_11_ssid *req_ssid); int mwifiex_cancel_hs(struct mwifiex_private *priv, int cmd_type); int mwifiex_enable_hs(struct mwifiex_adapter *adapter); +int mwifiex_disable_auto_ds(struct mwifiex_private *priv); int mwifiex_get_signal_info(struct mwifiex_private *priv, struct mwifiex_ds_get_signal *signal); int mwifiex_drv_get_data_rate(struct mwifiex_private *priv, struct mwifiex_rate_cfg *rate); -int mwifiex_find_best_bss(struct mwifiex_private *priv, - struct mwifiex_ssid_bssid *ssid_bssid); int mwifiex_request_scan(struct mwifiex_private *priv, struct mwifiex_802_11_ssid *req_ssid); int mwifiex_set_user_scan_ioctl(struct mwifiex_private *priv, @@ -992,12 +951,26 @@ int mwifiex_main_process(struct mwifiex_adapter *); int mwifiex_bss_set_channel(struct mwifiex_private *, struct mwifiex_chan_freq_power *cfp); -int mwifiex_bss_ioctl_find_bss(struct mwifiex_private *, - struct mwifiex_ssid_bssid *); int mwifiex_set_radio_band_cfg(struct mwifiex_private *, struct mwifiex_ds_band_cfg *); int mwifiex_get_bss_info(struct mwifiex_private *, struct mwifiex_bss_info *); +int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv, + u8 *bssid, s32 rssi, u8 *ie_buf, + size_t ie_len, u16 beacon_period, + u16 cap_info_bitmap, u8 band, + struct mwifiex_bssdescriptor *bss_desc); +int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, + struct mwifiex_bssdescriptor *bss_entry, + u8 *ie_buf, u32 ie_len); +int mwifiex_check_network_compatibility(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc); + +struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy, + char *name, enum nl80211_iftype type, + u32 *flags, struct vif_params *params); +int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev); + #ifdef CONFIG_DEBUG_FS void mwifiex_debugfs_init(void); diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index 5c22860..6618dd6 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -172,59 +172,6 @@ mwifiex_ssid_cmp(struct mwifiex_802_11_ssid *ssid1, } /* - * Sends IOCTL request to get the best BSS. - * - * This function allocates the IOCTL request buffer, fills it - * with requisite parameters and calls the IOCTL handler. - */ -int mwifiex_find_best_bss(struct mwifiex_private *priv, - struct mwifiex_ssid_bssid *ssid_bssid) -{ - struct mwifiex_ssid_bssid tmp_ssid_bssid; - u8 *mac; - - if (!ssid_bssid) - return -1; - - memcpy(&tmp_ssid_bssid, ssid_bssid, - sizeof(struct mwifiex_ssid_bssid)); - - if (!mwifiex_bss_ioctl_find_bss(priv, &tmp_ssid_bssid)) { - memcpy(ssid_bssid, &tmp_ssid_bssid, - sizeof(struct mwifiex_ssid_bssid)); - mac = (u8 *) &ssid_bssid->bssid; - dev_dbg(priv->adapter->dev, "cmd: found network: ssid=%s," - " %pM\n", ssid_bssid->ssid.ssid, mac); - return 0; - } - - return -1; -} - -/* - * Sends IOCTL request to start a scan with user configurations. - * - * This function allocates the IOCTL request buffer, fills it - * with requisite parameters and calls the IOCTL handler. - * - * Upon completion, it also generates a wireless event to notify - * applications. - */ -int mwifiex_set_user_scan_ioctl(struct mwifiex_private *priv, - struct mwifiex_user_scan_cfg *scan_req) -{ - int status; - - priv->adapter->cmd_wait_q.condition = false; - - status = mwifiex_scan_networks(priv, scan_req); - if (!status) - status = mwifiex_wait_queue_complete(priv->adapter); - - return status; -} - -/* * This function checks if wapi is enabled in driver and scanned network is * compatible with it. */ @@ -286,8 +233,7 @@ mwifiex_is_network_compatible_for_static_wep(struct mwifiex_private *priv, */ static bool mwifiex_is_network_compatible_for_wpa(struct mwifiex_private *priv, - struct mwifiex_bssdescriptor *bss_desc, - int index) + struct mwifiex_bssdescriptor *bss_desc) { if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED && priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled @@ -298,9 +244,9 @@ mwifiex_is_network_compatible_for_wpa(struct mwifiex_private *priv, * LinkSys WRT54G && bss_desc->privacy */ ) { - dev_dbg(priv->adapter->dev, "info: %s: WPA: index=%d" + dev_dbg(priv->adapter->dev, "info: %s: WPA:" " wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s " - "EncMode=%#x privacy=%#x\n", __func__, index, + "EncMode=%#x privacy=%#x\n", __func__, (bss_desc->bcn_wpa_ie) ? (*(bss_desc->bcn_wpa_ie)). vend_hdr.element_id : 0, @@ -324,8 +270,7 @@ mwifiex_is_network_compatible_for_wpa(struct mwifiex_private *priv, */ static bool mwifiex_is_network_compatible_for_wpa2(struct mwifiex_private *priv, - struct mwifiex_bssdescriptor *bss_desc, - int index) + struct mwifiex_bssdescriptor *bss_desc) { if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED && !priv->sec_info.wpa_enabled && priv->sec_info.wpa2_enabled @@ -336,9 +281,9 @@ mwifiex_is_network_compatible_for_wpa2(struct mwifiex_private *priv, * LinkSys WRT54G && bss_desc->privacy */ ) { - dev_dbg(priv->adapter->dev, "info: %s: WPA2: index=%d" + dev_dbg(priv->adapter->dev, "info: %s: WPA2: " " wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s " - "EncMode=%#x privacy=%#x\n", __func__, index, + "EncMode=%#x privacy=%#x\n", __func__, (bss_desc->bcn_wpa_ie) ? (*(bss_desc->bcn_wpa_ie)). vend_hdr.element_id : 0, @@ -383,8 +328,7 @@ mwifiex_is_network_compatible_for_adhoc_aes(struct mwifiex_private *priv, */ static bool mwifiex_is_network_compatible_for_dynamic_wep(struct mwifiex_private *priv, - struct mwifiex_bssdescriptor *bss_desc, - int index) + struct mwifiex_bssdescriptor *bss_desc) { if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled @@ -395,9 +339,9 @@ mwifiex_is_network_compatible_for_dynamic_wep(struct mwifiex_private *priv, && priv->sec_info.encryption_mode && bss_desc->privacy) { dev_dbg(priv->adapter->dev, "info: %s: dynamic " - "WEP: index=%d wpa_ie=%#x wpa2_ie=%#x " + "WEP: wpa_ie=%#x wpa2_ie=%#x " "EncMode=%#x privacy=%#x\n", - __func__, index, + __func__, (bss_desc->bcn_wpa_ie) ? (*(bss_desc->bcn_wpa_ie)). vend_hdr.element_id : 0, @@ -430,42 +374,41 @@ mwifiex_is_network_compatible_for_dynamic_wep(struct mwifiex_private *priv, * Compatibility is not matched while roaming, except for mode. */ static s32 -mwifiex_is_network_compatible(struct mwifiex_private *priv, u32 index, u32 mode) +mwifiex_is_network_compatible(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc, u32 mode) { struct mwifiex_adapter *adapter = priv->adapter; - struct mwifiex_bssdescriptor *bss_desc; - bss_desc = &adapter->scan_table[index]; bss_desc->disable_11n = false; /* Don't check for compatibility if roaming */ if (priv->media_connected && (priv->bss_mode == NL80211_IFTYPE_STATION) && (bss_desc->bss_mode == NL80211_IFTYPE_STATION)) - return index; + return 0; if (priv->wps.session_enable) { dev_dbg(adapter->dev, "info: return success directly in WPS period\n"); - return index; + return 0; } if (mwifiex_is_network_compatible_for_wapi(priv, bss_desc)) { dev_dbg(adapter->dev, "info: return success for WAPI AP\n"); - return index; + return 0; } if (bss_desc->bss_mode == mode) { if (mwifiex_is_network_compatible_for_no_sec(priv, bss_desc)) { /* No security */ - return index; + return 0; } else if (mwifiex_is_network_compatible_for_static_wep(priv, bss_desc)) { /* Static WEP enabled */ dev_dbg(adapter->dev, "info: Disable 11n in WEP mode.\n"); bss_desc->disable_11n = true; - return index; - } else if (mwifiex_is_network_compatible_for_wpa(priv, bss_desc, - index)) { + return 0; + } else if (mwifiex_is_network_compatible_for_wpa(priv, + bss_desc)) { /* WPA enabled */ if (((priv->adapter->config_bands & BAND_GN || priv->adapter->config_bands & BAND_AN) @@ -483,9 +426,9 @@ mwifiex_is_network_compatible(struct mwifiex_private *priv, u32 index, u32 mode) return -1; } } - return index; + return 0; } else if (mwifiex_is_network_compatible_for_wpa2(priv, - bss_desc, index)) { + bss_desc)) { /* WPA2 enabled */ if (((priv->adapter->config_bands & BAND_GN || priv->adapter->config_bands & BAND_AN) @@ -503,22 +446,22 @@ mwifiex_is_network_compatible(struct mwifiex_private *priv, u32 index, u32 mode) return -1; } } - return index; + return 0; } else if (mwifiex_is_network_compatible_for_adhoc_aes(priv, bss_desc)) { /* Ad-hoc AES enabled */ - return index; + return 0; } else if (mwifiex_is_network_compatible_for_dynamic_wep(priv, - bss_desc, index)) { + bss_desc)) { /* Dynamic WEP enabled */ - return index; + return 0; } /* Security doesn't match */ - dev_dbg(adapter->dev, "info: %s: failed: index=%d " + dev_dbg(adapter->dev, "info: %s: failed: " "wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s EncMode" "=%#x privacy=%#x\n", - __func__, index, + __func__, (bss_desc->bcn_wpa_ie) ? (*(bss_desc->bcn_wpa_ie)).vend_hdr. element_id : 0, @@ -538,52 +481,6 @@ mwifiex_is_network_compatible(struct mwifiex_private *priv, u32 index, u32 mode) } /* - * This function finds the best SSID in the scan list. - * - * It searches the scan table for the best SSID that also matches the current - * adapter network preference (mode, security etc.). - */ -static s32 -mwifiex_find_best_network_in_list(struct mwifiex_private *priv) -{ - struct mwifiex_adapter *adapter = priv->adapter; - u32 mode = priv->bss_mode; - s32 best_net = -1; - s32 best_rssi = 0; - u32 i; - - dev_dbg(adapter->dev, "info: num of BSSIDs = %d\n", - adapter->num_in_scan_table); - - for (i = 0; i < adapter->num_in_scan_table; i++) { - switch (mode) { - case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_ADHOC: - if (mwifiex_is_network_compatible(priv, i, mode) >= 0) { - if (SCAN_RSSI(adapter->scan_table[i].rssi) > - best_rssi) { - best_rssi = SCAN_RSSI(adapter-> - scan_table[i].rssi); - best_net = i; - } - } - break; - case NL80211_IFTYPE_UNSPECIFIED: - default: - if (SCAN_RSSI(adapter->scan_table[i].rssi) > - best_rssi) { - best_rssi = SCAN_RSSI(adapter->scan_table[i]. - rssi); - best_net = i; - } - break; - } - } - - return best_net; -} - -/* * This function creates a channel list for the driver to scan, based * on region/band information. * @@ -612,7 +509,7 @@ mwifiex_scan_create_channel_list(struct mwifiex_private *priv, sband = priv->wdev->wiphy->bands[band]; - for (i = 0; (i < sband->n_channels) ; i++, chan_idx++) { + for (i = 0; (i < sband->n_channels) ; i++) { ch = &sband->channels[i]; if (ch->flags & IEEE80211_CHAN_DISABLED) continue; @@ -643,6 +540,7 @@ mwifiex_scan_create_channel_list(struct mwifiex_private *priv, scan_chan_list[chan_idx].chan_scan_mode_bitmap |= MWIFIEX_DISABLE_CHAN_FILT; } + chan_idx++; } } @@ -921,8 +819,10 @@ mwifiex_scan_setup_scan_config(struct mwifiex_private *priv, wildcard_ssid_tlv->header.len = cpu_to_le16( (u16) (ssid_len + sizeof(wildcard_ssid_tlv-> max_ssid_length))); - wildcard_ssid_tlv->max_ssid_length = - user_scan_in->ssid_list[ssid_idx].max_len; + + /* max_ssid_length = 0 tells firmware to perform + specific scan for the SSID filled */ + wildcard_ssid_tlv->max_ssid_length = 0; memcpy(wildcard_ssid_tlv->ssid, user_scan_in->ssid_list[ssid_idx].ssid, @@ -1161,34 +1061,13 @@ mwifiex_ret_802_11_scan_get_tlv_ptrs(struct mwifiex_adapter *adapter, } /* - * This function interprets a BSS scan response returned from the firmware. - * - * The various fixed fields and IEs are parsed and passed back for a BSS - * probe response or beacon from scan command. Information is recorded as - * needed in the scan table for that entry. - * - * The following IE types are recognized and parsed - - * - SSID - * - Supported rates - * - FH parameters set - * - DS parameters set - * - CF parameters set - * - IBSS parameters set - * - ERP information - * - Extended supported rates - * - Vendor specific (221) - * - RSN IE - * - WAPI IE - * - HT capability - * - HT operation - * - BSS Coexistence 20/40 - * - Extended capability - * - Overlapping BSS scan parameters + * This function parses provided beacon buffer and updates + * respective fields in bss descriptor structure. */ -static int -mwifiex_interpret_bss_desc_with_ie(struct mwifiex_adapter *adapter, - struct mwifiex_bssdescriptor *bss_entry, - u8 **beacon_info, u32 *bytes_left) +int +mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, + struct mwifiex_bssdescriptor *bss_entry, + u8 *ie_buf, u32 ie_len) { int ret = 0; u8 element_id; @@ -1196,135 +1075,43 @@ mwifiex_interpret_bss_desc_with_ie(struct mwifiex_adapter *adapter, struct ieee_types_ds_param_set *ds_param_set; struct ieee_types_cf_param_set *cf_param_set; struct ieee_types_ibss_param_set *ibss_param_set; - __le16 beacon_interval; - __le16 capabilities; u8 *current_ptr; u8 *rate; u8 element_len; u16 total_ie_len; u8 bytes_to_copy; u8 rate_size; - u16 beacon_size; u8 found_data_rate_ie; - u32 bytes_left_for_current_beacon; + u32 bytes_left; struct ieee_types_vendor_specific *vendor_ie; const u8 wpa_oui[4] = { 0x00, 0x50, 0xf2, 0x01 }; const u8 wmm_oui[4] = { 0x00, 0x50, 0xf2, 0x02 }; found_data_rate_ie = false; rate_size = 0; - beacon_size = 0; - - if (*bytes_left >= sizeof(beacon_size)) { - /* Extract & convert beacon size from the command buffer */ - memcpy(&beacon_size, *beacon_info, sizeof(beacon_size)); - *bytes_left -= sizeof(beacon_size); - *beacon_info += sizeof(beacon_size); - } - - if (!beacon_size || beacon_size > *bytes_left) { - *beacon_info += *bytes_left; - *bytes_left = 0; - return -1; - } - - /* Initialize the current working beacon pointer for this BSS - iteration */ - current_ptr = *beacon_info; - - /* Advance the return beacon pointer past the current beacon */ - *beacon_info += beacon_size; - *bytes_left -= beacon_size; - - bytes_left_for_current_beacon = beacon_size; - - memcpy(bss_entry->mac_address, current_ptr, ETH_ALEN); - dev_dbg(adapter->dev, "info: InterpretIE: AP MAC Addr: %pM\n", - bss_entry->mac_address); - - current_ptr += ETH_ALEN; - bytes_left_for_current_beacon -= ETH_ALEN; - - if (bytes_left_for_current_beacon < 12) { - dev_err(adapter->dev, "InterpretIE: not enough bytes left\n"); - return -1; - } - - /* - * Next 4 fields are RSSI, time stamp, beacon interval, - * and capability information - */ - - /* RSSI is 1 byte long */ - bss_entry->rssi = (s32) (*current_ptr); - dev_dbg(adapter->dev, "info: InterpretIE: RSSI=%02X\n", *current_ptr); - current_ptr += 1; - bytes_left_for_current_beacon -= 1; - - /* - * The RSSI is not part of the beacon/probe response. After we have - * advanced current_ptr past the RSSI field, save the remaining - * data for use at the application layer - */ - bss_entry->beacon_buf = current_ptr; - bss_entry->beacon_buf_size = bytes_left_for_current_beacon; - - /* Time stamp is 8 bytes long */ - memcpy(bss_entry->time_stamp, current_ptr, 8); - current_ptr += 8; - bytes_left_for_current_beacon -= 8; - - /* Beacon interval is 2 bytes long */ - memcpy(&beacon_interval, current_ptr, 2); - bss_entry->beacon_period = le16_to_cpu(beacon_interval); - current_ptr += 2; - bytes_left_for_current_beacon -= 2; - - /* Capability information is 2 bytes long */ - memcpy(&capabilities, current_ptr, 2); - dev_dbg(adapter->dev, "info: InterpretIE: capabilities=0x%X\n", - capabilities); - bss_entry->cap_info_bitmap = le16_to_cpu(capabilities); - current_ptr += 2; - bytes_left_for_current_beacon -= 2; - - /* Rest of the current buffer are IE's */ - dev_dbg(adapter->dev, "info: InterpretIE: IELength for this AP = %d\n", - bytes_left_for_current_beacon); - - if (bss_entry->cap_info_bitmap & WLAN_CAPABILITY_PRIVACY) { - dev_dbg(adapter->dev, "info: InterpretIE: AP WEP enabled\n"); - bss_entry->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP; - } else { - bss_entry->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL; - } - - if (bss_entry->cap_info_bitmap & WLAN_CAPABILITY_IBSS) - bss_entry->bss_mode = NL80211_IFTYPE_ADHOC; - else - bss_entry->bss_mode = NL80211_IFTYPE_STATION; - + current_ptr = ie_buf; + bytes_left = ie_len; + bss_entry->beacon_buf = ie_buf; + bss_entry->beacon_buf_size = ie_len; /* Process variable IE */ - while (bytes_left_for_current_beacon >= 2) { + while (bytes_left >= 2) { element_id = *current_ptr; element_len = *(current_ptr + 1); total_ie_len = element_len + sizeof(struct ieee_types_header); - if (bytes_left_for_current_beacon < total_ie_len) { + if (bytes_left < total_ie_len) { dev_err(adapter->dev, "err: InterpretIE: in processing" " IE, bytes left < IE length\n"); - bytes_left_for_current_beacon = 0; - ret = -1; - continue; + return -1; } switch (element_id) { case WLAN_EID_SSID: bss_entry->ssid.ssid_len = element_len; memcpy(bss_entry->ssid.ssid, (current_ptr + 2), element_len); - dev_dbg(adapter->dev, "info: InterpretIE: ssid: %-32s\n", - bss_entry->ssid.ssid); + dev_dbg(adapter->dev, "info: InterpretIE: ssid: " + "%-32s\n", bss_entry->ssid.ssid); break; case WLAN_EID_SUPP_RATES: @@ -1471,13 +1258,6 @@ mwifiex_interpret_bss_desc_with_ie(struct mwifiex_adapter *adapter, sizeof(struct ieee_types_header) - bss_entry->beacon_buf); break; - case WLAN_EID_OVERLAP_BSS_SCAN_PARAM: - bss_entry->bcn_obss_scan = - (struct ieee_types_obss_scan_param *) - current_ptr; - bss_entry->overlap_bss_offset = (u16) (current_ptr - - bss_entry->beacon_buf); - break; default: break; } @@ -1485,577 +1265,13 @@ mwifiex_interpret_bss_desc_with_ie(struct mwifiex_adapter *adapter, current_ptr += element_len + 2; /* Need to account for IE ID and IE Len */ - bytes_left_for_current_beacon -= (element_len + 2); + bytes_left -= (element_len + 2); - } /* while (bytes_left_for_current_beacon > 2) */ + } /* while (bytes_left > 2) */ return ret; } /* - * This function adjusts the pointers used in beacon buffers to reflect - * shifts. - * - * The memory allocated for beacon buffers is of fixed sizes where all the - * saved beacons must be stored. New beacons are added in the free portion - * of this memory, space permitting; while duplicate beacon buffers are - * placed at the same start location. However, since duplicate beacon - * buffers may not match the size of the old one, all the following buffers - * in the memory must be shifted to either make space, or to fill up freed - * up space. - * - * This function is used to update the beacon buffer pointers that are past - * an existing beacon buffer that is updated with a new one of different - * size. The pointers are shifted by a fixed amount, either forward or - * backward. - * - * the following pointers in every affected beacon buffers are changed, if - * present - - * - WPA IE pointer - * - RSN IE pointer - * - WAPI IE pointer - * - HT capability IE pointer - * - HT information IE pointer - * - BSS coexistence 20/40 IE pointer - * - Extended capability IE pointer - * - Overlapping BSS scan parameter IE pointer - */ -static void -mwifiex_adjust_beacon_buffer_ptrs(struct mwifiex_private *priv, u8 advance, - u8 *bcn_store, u32 rem_bcn_size, - u32 num_of_ent) -{ - struct mwifiex_adapter *adapter = priv->adapter; - u32 adj_idx; - for (adj_idx = 0; adj_idx < num_of_ent; adj_idx++) { - if (adapter->scan_table[adj_idx].beacon_buf > bcn_store) { - - if (advance) - adapter->scan_table[adj_idx].beacon_buf += - rem_bcn_size; - else - adapter->scan_table[adj_idx].beacon_buf -= - rem_bcn_size; - - if (adapter->scan_table[adj_idx].bcn_wpa_ie) - adapter->scan_table[adj_idx].bcn_wpa_ie = - (struct ieee_types_vendor_specific *) - (adapter->scan_table[adj_idx].beacon_buf + - adapter->scan_table[adj_idx].wpa_offset); - if (adapter->scan_table[adj_idx].bcn_rsn_ie) - adapter->scan_table[adj_idx].bcn_rsn_ie = - (struct ieee_types_generic *) - (adapter->scan_table[adj_idx].beacon_buf + - adapter->scan_table[adj_idx].rsn_offset); - if (adapter->scan_table[adj_idx].bcn_wapi_ie) - adapter->scan_table[adj_idx].bcn_wapi_ie = - (struct ieee_types_generic *) - (adapter->scan_table[adj_idx].beacon_buf + - adapter->scan_table[adj_idx].wapi_offset); - if (adapter->scan_table[adj_idx].bcn_ht_cap) - adapter->scan_table[adj_idx].bcn_ht_cap = - (struct ieee80211_ht_cap *) - (adapter->scan_table[adj_idx].beacon_buf + - adapter->scan_table[adj_idx].ht_cap_offset); - - if (adapter->scan_table[adj_idx].bcn_ht_info) - adapter->scan_table[adj_idx].bcn_ht_info = - (struct ieee80211_ht_info *) - (adapter->scan_table[adj_idx].beacon_buf + - adapter->scan_table[adj_idx].ht_info_offset); - if (adapter->scan_table[adj_idx].bcn_bss_co_2040) - adapter->scan_table[adj_idx].bcn_bss_co_2040 = - (u8 *) - (adapter->scan_table[adj_idx].beacon_buf + - adapter->scan_table[adj_idx].bss_co_2040_offset); - if (adapter->scan_table[adj_idx].bcn_ext_cap) - adapter->scan_table[adj_idx].bcn_ext_cap = - (u8 *) - (adapter->scan_table[adj_idx].beacon_buf + - adapter->scan_table[adj_idx].ext_cap_offset); - if (adapter->scan_table[adj_idx].bcn_obss_scan) - adapter->scan_table[adj_idx].bcn_obss_scan = - (struct ieee_types_obss_scan_param *) - (adapter->scan_table[adj_idx].beacon_buf + - adapter->scan_table[adj_idx].overlap_bss_offset); - } - } -} - -/* - * This function updates the pointers used in beacon buffer for given bss - * descriptor to reflect shifts - * - * Following pointers are updated - * - WPA IE pointer - * - RSN IE pointer - * - WAPI IE pointer - * - HT capability IE pointer - * - HT information IE pointer - * - BSS coexistence 20/40 IE pointer - * - Extended capability IE pointer - * - Overlapping BSS scan parameter IE pointer - */ -static void -mwifiex_update_beacon_buffer_ptrs(struct mwifiex_bssdescriptor *beacon) -{ - if (beacon->bcn_wpa_ie) - beacon->bcn_wpa_ie = (struct ieee_types_vendor_specific *) - (beacon->beacon_buf + beacon->wpa_offset); - if (beacon->bcn_rsn_ie) - beacon->bcn_rsn_ie = (struct ieee_types_generic *) - (beacon->beacon_buf + beacon->rsn_offset); - if (beacon->bcn_wapi_ie) - beacon->bcn_wapi_ie = (struct ieee_types_generic *) - (beacon->beacon_buf + beacon->wapi_offset); - if (beacon->bcn_ht_cap) - beacon->bcn_ht_cap = (struct ieee80211_ht_cap *) - (beacon->beacon_buf + beacon->ht_cap_offset); - if (beacon->bcn_ht_info) - beacon->bcn_ht_info = (struct ieee80211_ht_info *) - (beacon->beacon_buf + beacon->ht_info_offset); - if (beacon->bcn_bss_co_2040) - beacon->bcn_bss_co_2040 = (u8 *) (beacon->beacon_buf + - beacon->bss_co_2040_offset); - if (beacon->bcn_ext_cap) - beacon->bcn_ext_cap = (u8 *) (beacon->beacon_buf + - beacon->ext_cap_offset); - if (beacon->bcn_obss_scan) - beacon->bcn_obss_scan = (struct ieee_types_obss_scan_param *) - (beacon->beacon_buf + beacon->overlap_bss_offset); -} - -/* - * This function stores a beacon or probe response for a BSS returned - * in the scan. - * - * This stores a new scan response or an update for a previous scan response. - * New entries need to verify that they do not exceed the total amount of - * memory allocated for the table. - * - * Replacement entries need to take into consideration the amount of space - * currently allocated for the beacon/probe response and adjust the entry - * as needed. - * - * A small amount of extra pad (SCAN_BEACON_ENTRY_PAD) is generally reserved - * for an entry in case it is a beacon since a probe response for the - * network will by larger per the standard. This helps to reduce the - * amount of memory copying to fit a new probe response into an entry - * already occupied by a network's previously stored beacon. - */ -static void -mwifiex_ret_802_11_scan_store_beacon(struct mwifiex_private *priv, - u32 beacon_idx, u32 num_of_ent, - struct mwifiex_bssdescriptor *new_beacon) -{ - struct mwifiex_adapter *adapter = priv->adapter; - u8 *bcn_store; - u32 new_bcn_size; - u32 old_bcn_size; - u32 bcn_space; - - if (adapter->scan_table[beacon_idx].beacon_buf) { - - new_bcn_size = new_beacon->beacon_buf_size; - old_bcn_size = adapter->scan_table[beacon_idx].beacon_buf_size; - bcn_space = adapter->scan_table[beacon_idx].beacon_buf_size_max; - bcn_store = adapter->scan_table[beacon_idx].beacon_buf; - - /* Set the max to be the same as current entry unless changed - below */ - new_beacon->beacon_buf_size_max = bcn_space; - if (new_bcn_size == old_bcn_size) { - /* - * Beacon is the same size as the previous entry. - * Replace the previous contents with the scan result - */ - memcpy(bcn_store, new_beacon->beacon_buf, - new_beacon->beacon_buf_size); - - } else if (new_bcn_size <= bcn_space) { - /* - * New beacon size will fit in the amount of space - * we have previously allocated for it - */ - - /* Copy the new beacon buffer entry over the old one */ - memcpy(bcn_store, new_beacon->beacon_buf, new_bcn_size); - - /* - * If the old beacon size was less than the maximum - * we had alloted for the entry, and the new entry - * is even smaller, reset the max size to the old - * beacon entry and compress the storage space - * (leaving a new pad space of (old_bcn_size - - * new_bcn_size). - */ - if (old_bcn_size < bcn_space - && new_bcn_size <= old_bcn_size) { - /* - * Old Beacon size is smaller than the alloted - * storage size. Shrink the alloted storage - * space. - */ - dev_dbg(adapter->dev, "info: AppControl:" - " smaller duplicate beacon " - "(%d), old = %d, new = %d, space = %d," - "left = %d\n", - beacon_idx, old_bcn_size, new_bcn_size, - bcn_space, - (int)(sizeof(adapter->bcn_buf) - - (adapter->bcn_buf_end - - adapter->bcn_buf))); - - /* - * memmove (since the memory overlaps) the - * data after the beacon we just stored to the - * end of the current beacon. This cleans up - * any unused space the old larger beacon was - * using in the buffer - */ - memmove(bcn_store + old_bcn_size, - bcn_store + bcn_space, - adapter->bcn_buf_end - (bcn_store + - bcn_space)); - - /* - * Decrement the end pointer by the difference - * between the old larger size and the new - * smaller size since we are using less space - * due to the new beacon being smaller - */ - adapter->bcn_buf_end -= - (bcn_space - old_bcn_size); - - /* Set the maximum storage size to the old - beacon size */ - new_beacon->beacon_buf_size_max = old_bcn_size; - - /* Adjust beacon buffer pointers that are past - the current */ - mwifiex_adjust_beacon_buffer_ptrs(priv, 0, - bcn_store, (bcn_space - old_bcn_size), - num_of_ent); - } - } else if (adapter->bcn_buf_end + (new_bcn_size - bcn_space) - < (adapter->bcn_buf + sizeof(adapter->bcn_buf))) { - /* - * Beacon is larger than space previously allocated - * (bcn_space) and there is enough space left in the - * beaconBuffer to store the additional data - */ - dev_dbg(adapter->dev, "info: AppControl:" - " larger duplicate beacon (%d), " - "old = %d, new = %d, space = %d, left = %d\n", - beacon_idx, old_bcn_size, new_bcn_size, - bcn_space, - (int)(sizeof(adapter->bcn_buf) - - (adapter->bcn_buf_end - - adapter->bcn_buf))); - - /* - * memmove (since the memory overlaps) the data - * after the beacon we just stored to the end of - * the current beacon. This moves the data for - * the beacons after this further in memory to - * make space for the new larger beacon we are - * about to copy in. - */ - memmove(bcn_store + new_bcn_size, - bcn_store + bcn_space, - adapter->bcn_buf_end - (bcn_store + bcn_space)); - - /* Copy the new beacon buffer entry over the old one */ - memcpy(bcn_store, new_beacon->beacon_buf, new_bcn_size); - - /* Move the beacon end pointer by the amount of new - beacon data we are adding */ - adapter->bcn_buf_end += (new_bcn_size - bcn_space); - - /* - * This entry is bigger than the alloted max space - * previously reserved. Increase the max space to - * be equal to the new beacon size - */ - new_beacon->beacon_buf_size_max = new_bcn_size; - - /* Adjust beacon buffer pointers that are past the - current */ - mwifiex_adjust_beacon_buffer_ptrs(priv, 1, bcn_store, - (new_bcn_size - bcn_space), - num_of_ent); - } else { - /* - * Beacon is larger than the previously allocated space, - * but there is not enough free space to store the - * additional data. - */ - dev_err(adapter->dev, "AppControl: larger duplicate " - " beacon (%d), old = %d new = %d, space = %d," - " left = %d\n", beacon_idx, old_bcn_size, - new_bcn_size, bcn_space, - (int)(sizeof(adapter->bcn_buf) - - (adapter->bcn_buf_end - adapter->bcn_buf))); - - /* Storage failure, keep old beacon intact */ - new_beacon->beacon_buf_size = old_bcn_size; - if (new_beacon->bcn_wpa_ie) - new_beacon->wpa_offset = - adapter->scan_table[beacon_idx]. - wpa_offset; - if (new_beacon->bcn_rsn_ie) - new_beacon->rsn_offset = - adapter->scan_table[beacon_idx]. - rsn_offset; - if (new_beacon->bcn_wapi_ie) - new_beacon->wapi_offset = - adapter->scan_table[beacon_idx]. - wapi_offset; - if (new_beacon->bcn_ht_cap) - new_beacon->ht_cap_offset = - adapter->scan_table[beacon_idx]. - ht_cap_offset; - if (new_beacon->bcn_ht_info) - new_beacon->ht_info_offset = - adapter->scan_table[beacon_idx]. - ht_info_offset; - if (new_beacon->bcn_bss_co_2040) - new_beacon->bss_co_2040_offset = - adapter->scan_table[beacon_idx]. - bss_co_2040_offset; - if (new_beacon->bcn_ext_cap) - new_beacon->ext_cap_offset = - adapter->scan_table[beacon_idx]. - ext_cap_offset; - if (new_beacon->bcn_obss_scan) - new_beacon->overlap_bss_offset = - adapter->scan_table[beacon_idx]. - overlap_bss_offset; - } - /* Point the new entry to its permanent storage space */ - new_beacon->beacon_buf = bcn_store; - mwifiex_update_beacon_buffer_ptrs(new_beacon); - } else { - /* - * No existing beacon data exists for this entry, check to see - * if we can fit it in the remaining space - */ - if (adapter->bcn_buf_end + new_beacon->beacon_buf_size + - SCAN_BEACON_ENTRY_PAD < (adapter->bcn_buf + - sizeof(adapter->bcn_buf))) { - - /* - * Copy the beacon buffer data from the local entry to - * the adapter dev struct buffer space used to store - * the raw beacon data for each entry in the scan table - */ - memcpy(adapter->bcn_buf_end, new_beacon->beacon_buf, - new_beacon->beacon_buf_size); - - /* Update the beacon ptr to point to the table save - area */ - new_beacon->beacon_buf = adapter->bcn_buf_end; - new_beacon->beacon_buf_size_max = - (new_beacon->beacon_buf_size + - SCAN_BEACON_ENTRY_PAD); - - mwifiex_update_beacon_buffer_ptrs(new_beacon); - - /* Increment the end pointer by the size reserved */ - adapter->bcn_buf_end += new_beacon->beacon_buf_size_max; - - dev_dbg(adapter->dev, "info: AppControl: beacon[%02d]" - " sz=%03d, used = %04d, left = %04d\n", - beacon_idx, - new_beacon->beacon_buf_size, - (int)(adapter->bcn_buf_end - adapter->bcn_buf), - (int)(sizeof(adapter->bcn_buf) - - (adapter->bcn_buf_end - - adapter->bcn_buf))); - } else { - /* No space for new beacon */ - dev_dbg(adapter->dev, "info: AppControl: no space for" - " beacon (%d): %pM sz=%03d, left=%03d\n", - beacon_idx, new_beacon->mac_address, - new_beacon->beacon_buf_size, - (int)(sizeof(adapter->bcn_buf) - - (adapter->bcn_buf_end - - adapter->bcn_buf))); - - /* Storage failure; clear storage records for this - bcn */ - new_beacon->beacon_buf = NULL; - new_beacon->beacon_buf_size = 0; - new_beacon->beacon_buf_size_max = 0; - new_beacon->bcn_wpa_ie = NULL; - new_beacon->wpa_offset = 0; - new_beacon->bcn_rsn_ie = NULL; - new_beacon->rsn_offset = 0; - new_beacon->bcn_wapi_ie = NULL; - new_beacon->wapi_offset = 0; - new_beacon->bcn_ht_cap = NULL; - new_beacon->ht_cap_offset = 0; - new_beacon->bcn_ht_info = NULL; - new_beacon->ht_info_offset = 0; - new_beacon->bcn_bss_co_2040 = NULL; - new_beacon->bss_co_2040_offset = 0; - new_beacon->bcn_ext_cap = NULL; - new_beacon->ext_cap_offset = 0; - new_beacon->bcn_obss_scan = NULL; - new_beacon->overlap_bss_offset = 0; - } - } -} - -/* - * This function restores a beacon buffer of the current BSS descriptor. - */ -static void mwifiex_restore_curr_bcn(struct mwifiex_private *priv) -{ - struct mwifiex_adapter *adapter = priv->adapter; - struct mwifiex_bssdescriptor *curr_bss = - &priv->curr_bss_params.bss_descriptor; - unsigned long flags; - - if (priv->curr_bcn_buf && - ((adapter->bcn_buf_end + priv->curr_bcn_size) < - (adapter->bcn_buf + sizeof(adapter->bcn_buf)))) { - spin_lock_irqsave(&priv->curr_bcn_buf_lock, flags); - - /* restore the current beacon buffer */ - memcpy(adapter->bcn_buf_end, priv->curr_bcn_buf, - priv->curr_bcn_size); - curr_bss->beacon_buf = adapter->bcn_buf_end; - curr_bss->beacon_buf_size = priv->curr_bcn_size; - adapter->bcn_buf_end += priv->curr_bcn_size; - - /* adjust the pointers in the current BSS descriptor */ - if (curr_bss->bcn_wpa_ie) - curr_bss->bcn_wpa_ie = - (struct ieee_types_vendor_specific *) - (curr_bss->beacon_buf + - curr_bss->wpa_offset); - - if (curr_bss->bcn_rsn_ie) - curr_bss->bcn_rsn_ie = (struct ieee_types_generic *) - (curr_bss->beacon_buf + - curr_bss->rsn_offset); - - if (curr_bss->bcn_ht_cap) - curr_bss->bcn_ht_cap = (struct ieee80211_ht_cap *) - (curr_bss->beacon_buf + - curr_bss->ht_cap_offset); - - if (curr_bss->bcn_ht_info) - curr_bss->bcn_ht_info = (struct ieee80211_ht_info *) - (curr_bss->beacon_buf + - curr_bss->ht_info_offset); - - if (curr_bss->bcn_bss_co_2040) - curr_bss->bcn_bss_co_2040 = - (u8 *) (curr_bss->beacon_buf + - curr_bss->bss_co_2040_offset); - - if (curr_bss->bcn_ext_cap) - curr_bss->bcn_ext_cap = (u8 *) (curr_bss->beacon_buf + - curr_bss->ext_cap_offset); - - if (curr_bss->bcn_obss_scan) - curr_bss->bcn_obss_scan = - (struct ieee_types_obss_scan_param *) - (curr_bss->beacon_buf + - curr_bss->overlap_bss_offset); - - spin_unlock_irqrestore(&priv->curr_bcn_buf_lock, flags); - - dev_dbg(adapter->dev, "info: current beacon restored %d\n", - priv->curr_bcn_size); - } else { - dev_warn(adapter->dev, - "curr_bcn_buf not saved or bcn_buf has no space\n"); - } -} - -/* - * This function post processes the scan table after a new scan command has - * completed. - * - * It inspects each entry of the scan table and tries to find an entry that - * matches with our current associated/joined network from the scan. If - * one is found, the stored copy of the BSS descriptor of our current network - * is updated. - * - * It also debug dumps the current scan table contents after processing is over. - */ -static void -mwifiex_process_scan_results(struct mwifiex_private *priv) -{ - struct mwifiex_adapter *adapter = priv->adapter; - s32 j; - u32 i; - unsigned long flags; - - if (priv->media_connected) { - - j = mwifiex_find_ssid_in_list(priv, &priv->curr_bss_params. - bss_descriptor.ssid, - priv->curr_bss_params. - bss_descriptor.mac_address, - priv->bss_mode); - - if (j >= 0) { - spin_lock_irqsave(&priv->curr_bcn_buf_lock, flags); - priv->curr_bss_params.bss_descriptor.bcn_wpa_ie = NULL; - priv->curr_bss_params.bss_descriptor.wpa_offset = 0; - priv->curr_bss_params.bss_descriptor.bcn_rsn_ie = NULL; - priv->curr_bss_params.bss_descriptor.rsn_offset = 0; - priv->curr_bss_params.bss_descriptor.bcn_wapi_ie = NULL; - priv->curr_bss_params.bss_descriptor.wapi_offset = 0; - priv->curr_bss_params.bss_descriptor.bcn_ht_cap = NULL; - priv->curr_bss_params.bss_descriptor.ht_cap_offset = - 0; - priv->curr_bss_params.bss_descriptor.bcn_ht_info = NULL; - priv->curr_bss_params.bss_descriptor.ht_info_offset = - 0; - priv->curr_bss_params.bss_descriptor.bcn_bss_co_2040 = - NULL; - priv->curr_bss_params.bss_descriptor. - bss_co_2040_offset = 0; - priv->curr_bss_params.bss_descriptor.bcn_ext_cap = NULL; - priv->curr_bss_params.bss_descriptor.ext_cap_offset = 0; - priv->curr_bss_params.bss_descriptor. - bcn_obss_scan = NULL; - priv->curr_bss_params.bss_descriptor. - overlap_bss_offset = 0; - priv->curr_bss_params.bss_descriptor.beacon_buf = NULL; - priv->curr_bss_params.bss_descriptor.beacon_buf_size = - 0; - priv->curr_bss_params.bss_descriptor. - beacon_buf_size_max = 0; - - dev_dbg(adapter->dev, "info: Found current ssid/bssid" - " in list @ index #%d\n", j); - /* Make a copy of current BSSID descriptor */ - memcpy(&priv->curr_bss_params.bss_descriptor, - &adapter->scan_table[j], - sizeof(priv->curr_bss_params.bss_descriptor)); - - mwifiex_save_curr_bcn(priv); - spin_unlock_irqrestore(&priv->curr_bcn_buf_lock, flags); - - } else { - mwifiex_restore_curr_bcn(priv); - } - } - - for (i = 0; i < adapter->num_in_scan_table; i++) - dev_dbg(adapter->dev, "info: scan:(%02d) %pM " - "RSSI[%03d], SSID[%s]\n", - i, adapter->scan_table[i].mac_address, - (s32) adapter->scan_table[i].rssi, - adapter->scan_table[i].ssid.ssid); -} - -/* * This function converts radio type scan parameter to a band configuration * to be used in join command. */ @@ -2072,175 +1288,6 @@ mwifiex_radio_type_to_band(u8 radio_type) } /* - * This function deletes a specific indexed entry from the scan table. - * - * This also compacts the remaining entries and adjusts any buffering - * of beacon/probe response data if needed. - */ -static void -mwifiex_scan_delete_table_entry(struct mwifiex_private *priv, s32 table_idx) -{ - struct mwifiex_adapter *adapter = priv->adapter; - u32 del_idx; - u32 beacon_buf_adj; - u8 *beacon_buf; - - /* - * Shift the saved beacon buffer data for the scan table back over the - * entry being removed. Update the end of buffer pointer. Save the - * deleted buffer allocation size for pointer adjustments for entries - * compacted after the deleted index. - */ - beacon_buf_adj = adapter->scan_table[table_idx].beacon_buf_size_max; - - dev_dbg(adapter->dev, "info: Scan: Delete Entry %d, beacon buffer " - "removal = %d bytes\n", table_idx, beacon_buf_adj); - - /* Check if the table entry had storage allocated for its beacon */ - if (beacon_buf_adj) { - beacon_buf = adapter->scan_table[table_idx].beacon_buf; - - /* - * Remove the entry's buffer space, decrement the table end - * pointer by the amount we are removing - */ - adapter->bcn_buf_end -= beacon_buf_adj; - - dev_dbg(adapter->dev, "info: scan: delete entry %d," - " compact data: %p <- %p (sz = %d)\n", - table_idx, beacon_buf, - beacon_buf + beacon_buf_adj, - (int)(adapter->bcn_buf_end - beacon_buf)); - - /* - * Compact data storage. Copy all data after the deleted - * entry's end address (beacon_buf + beacon_buf_adj) back - * to the original start address (beacon_buf). - * - * Scan table entries affected by the move will have their - * entry pointer adjusted below. - * - * Use memmove since the dest/src memory regions overlap. - */ - memmove(beacon_buf, beacon_buf + beacon_buf_adj, - adapter->bcn_buf_end - beacon_buf); - } - - dev_dbg(adapter->dev, - "info: Scan: Delete Entry %d, num_in_scan_table = %d\n", - table_idx, adapter->num_in_scan_table); - - /* Shift all of the entries after the table_idx back by one, compacting - the table and removing the requested entry */ - for (del_idx = table_idx; (del_idx + 1) < adapter->num_in_scan_table; - del_idx++) { - /* Copy the next entry over this one */ - memcpy(adapter->scan_table + del_idx, - adapter->scan_table + del_idx + 1, - sizeof(struct mwifiex_bssdescriptor)); - - /* - * Adjust this entry's pointer to its beacon buffer based on - * the removed/compacted entry from the deleted index. Don't - * decrement if the buffer pointer is NULL (no data stored for - * this entry). - */ - if (adapter->scan_table[del_idx].beacon_buf) { - adapter->scan_table[del_idx].beacon_buf -= - beacon_buf_adj; - if (adapter->scan_table[del_idx].bcn_wpa_ie) - adapter->scan_table[del_idx].bcn_wpa_ie = - (struct ieee_types_vendor_specific *) - (adapter->scan_table[del_idx]. - beacon_buf + - adapter->scan_table[del_idx]. - wpa_offset); - if (adapter->scan_table[del_idx].bcn_rsn_ie) - adapter->scan_table[del_idx].bcn_rsn_ie = - (struct ieee_types_generic *) - (adapter->scan_table[del_idx]. - beacon_buf + - adapter->scan_table[del_idx]. - rsn_offset); - if (adapter->scan_table[del_idx].bcn_wapi_ie) - adapter->scan_table[del_idx].bcn_wapi_ie = - (struct ieee_types_generic *) - (adapter->scan_table[del_idx].beacon_buf - + adapter->scan_table[del_idx]. - wapi_offset); - if (adapter->scan_table[del_idx].bcn_ht_cap) - adapter->scan_table[del_idx].bcn_ht_cap = - (struct ieee80211_ht_cap *) - (adapter->scan_table[del_idx].beacon_buf - + adapter->scan_table[del_idx]. - ht_cap_offset); - - if (adapter->scan_table[del_idx].bcn_ht_info) - adapter->scan_table[del_idx].bcn_ht_info = - (struct ieee80211_ht_info *) - (adapter->scan_table[del_idx].beacon_buf - + adapter->scan_table[del_idx]. - ht_info_offset); - if (adapter->scan_table[del_idx].bcn_bss_co_2040) - adapter->scan_table[del_idx].bcn_bss_co_2040 = - (u8 *) - (adapter->scan_table[del_idx].beacon_buf - + adapter->scan_table[del_idx]. - bss_co_2040_offset); - if (adapter->scan_table[del_idx].bcn_ext_cap) - adapter->scan_table[del_idx].bcn_ext_cap = - (u8 *) - (adapter->scan_table[del_idx].beacon_buf - + adapter->scan_table[del_idx]. - ext_cap_offset); - if (adapter->scan_table[del_idx].bcn_obss_scan) - adapter->scan_table[del_idx]. - bcn_obss_scan = - (struct ieee_types_obss_scan_param *) - (adapter->scan_table[del_idx].beacon_buf - + adapter->scan_table[del_idx]. - overlap_bss_offset); - } - } - - /* The last entry is invalid now that it has been deleted or moved - back */ - memset(adapter->scan_table + adapter->num_in_scan_table - 1, - 0x00, sizeof(struct mwifiex_bssdescriptor)); - - adapter->num_in_scan_table--; -} - -/* - * This function deletes all occurrences of a given SSID from the scan table. - * - * This iterates through the scan table and deletes all entries that match - * the given SSID. It also compacts the remaining scan table entries. - */ -static int -mwifiex_scan_delete_ssid_table_entry(struct mwifiex_private *priv, - struct mwifiex_802_11_ssid *del_ssid) -{ - s32 table_idx = -1; - - dev_dbg(priv->adapter->dev, "info: scan: delete ssid entry: %-32s\n", - del_ssid->ssid); - - /* If the requested SSID is found in the table, delete it. Then keep - searching the table for multiple entires for the SSID until no - more are found */ - while ((table_idx = mwifiex_find_ssid_in_list(priv, del_ssid, NULL, - NL80211_IFTYPE_UNSPECIFIED)) >= 0) { - dev_dbg(priv->adapter->dev, - "info: Scan: Delete SSID Entry: Found Idx = %d\n", - table_idx); - mwifiex_scan_delete_table_entry(priv, table_idx); - } - - return table_idx == -1 ? -1 : 0; -} - -/* * This is an internal function used to start a scan based on an input * configuration. * @@ -2248,8 +1295,8 @@ mwifiex_scan_delete_ssid_table_entry(struct mwifiex_private *priv, * order to send the appropriate scan commands to firmware to populate or * update the internal driver scan table. */ -int mwifiex_scan_networks(struct mwifiex_private *priv, - const struct mwifiex_user_scan_cfg *user_scan_in) +static int mwifiex_scan_networks(struct mwifiex_private *priv, + const struct mwifiex_user_scan_cfg *user_scan_in) { int ret = 0; struct mwifiex_adapter *adapter = priv->adapter; @@ -2258,7 +1305,6 @@ int mwifiex_scan_networks(struct mwifiex_private *priv, struct mwifiex_ie_types_chan_list_param_set *chan_list_out; u32 buf_size; struct mwifiex_chan_scan_param_set *scan_chan_list; - u8 keep_previous_scan; u8 filtered_scan; u8 scan_current_chan_only; u8 max_chan_per_scan; @@ -2295,24 +1341,11 @@ int mwifiex_scan_networks(struct mwifiex_private *priv, return -ENOMEM; } - keep_previous_scan = false; - mwifiex_scan_setup_scan_config(priv, user_scan_in, &scan_cfg_out->config, &chan_list_out, scan_chan_list, &max_chan_per_scan, &filtered_scan, &scan_current_chan_only); - if (user_scan_in) - keep_previous_scan = user_scan_in->keep_previous_scan; - - - if (!keep_previous_scan) { - memset(adapter->scan_table, 0x00, - sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP); - adapter->num_in_scan_table = 0; - adapter->bcn_buf_end = adapter->bcn_buf; - } - ret = mwifiex_scan_channel_list(priv, max_chan_per_scan, filtered_scan, &scan_cfg_out->config, chan_list_out, scan_chan_list); @@ -2326,6 +1359,7 @@ int mwifiex_scan_networks(struct mwifiex_private *priv, list_del(&cmd_node->list); spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); + adapter->cmd_queued = cmd_node; mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true); } else { @@ -2344,6 +1378,29 @@ int mwifiex_scan_networks(struct mwifiex_private *priv, } /* + * Sends IOCTL request to start a scan with user configurations. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + * + * Upon completion, it also generates a wireless event to notify + * applications. + */ +int mwifiex_set_user_scan_ioctl(struct mwifiex_private *priv, + struct mwifiex_user_scan_cfg *scan_req) +{ + int status; + + priv->adapter->scan_wait_q_woken = false; + + status = mwifiex_scan_networks(priv, scan_req); + if (!status) + status = mwifiex_wait_queue_complete(priv->adapter); + + return status; +} + +/* * This function prepares a scan command to be sent to the firmware. * * This uses the scan command configuration sent to the command processing @@ -2357,12 +1414,10 @@ int mwifiex_scan_networks(struct mwifiex_private *priv, * - Setting command ID, and proper size * - Ensuring correct endian-ness */ -int mwifiex_cmd_802_11_scan(struct host_cmd_ds_command *cmd, void *data_buf) +int mwifiex_cmd_802_11_scan(struct host_cmd_ds_command *cmd, + struct mwifiex_scan_cmd_config *scan_cfg) { struct host_cmd_ds_802_11_scan *scan_cmd = &cmd->params.scan; - struct mwifiex_scan_cmd_config *scan_cfg; - - scan_cfg = (struct mwifiex_scan_cmd_config *) data_buf; /* Set fixed field variables in scan command */ scan_cmd->bss_mode = scan_cfg->bss_mode; @@ -2381,6 +1436,113 @@ int mwifiex_cmd_802_11_scan(struct host_cmd_ds_command *cmd, void *data_buf) } /* + * This function checks compatibility of requested network with current + * driver settings. + */ +int mwifiex_check_network_compatibility(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc) +{ + int ret = -1; + + if (!bss_desc) + return -1; + + if ((mwifiex_get_cfp_by_band_and_channel_from_cfg80211(priv, + (u8) bss_desc->bss_band, (u16) bss_desc->channel))) { + switch (priv->bss_mode) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + ret = mwifiex_is_network_compatible(priv, bss_desc, + priv->bss_mode); + if (ret) + dev_err(priv->adapter->dev, "cannot find ssid " + "%s\n", bss_desc->ssid.ssid); + break; + default: + ret = 0; + } + } + + return ret; +} + +static int +mwifiex_update_curr_bss_params(struct mwifiex_private *priv, u8 *bssid, + s32 rssi, const u8 *ie_buf, size_t ie_len, + u16 beacon_period, u16 cap_info_bitmap, u8 band) +{ + struct mwifiex_bssdescriptor *bss_desc; + int ret; + unsigned long flags; + u8 *beacon_ie; + + /* Allocate and fill new bss descriptor */ + bss_desc = kzalloc(sizeof(struct mwifiex_bssdescriptor), + GFP_KERNEL); + if (!bss_desc) { + dev_err(priv->adapter->dev, " failed to alloc bss_desc\n"); + return -ENOMEM; + } + + beacon_ie = kmemdup(ie_buf, ie_len, GFP_KERNEL); + if (!beacon_ie) { + kfree(bss_desc); + dev_err(priv->adapter->dev, " failed to alloc beacon_ie\n"); + return -ENOMEM; + } + + ret = mwifiex_fill_new_bss_desc(priv, bssid, rssi, beacon_ie, + ie_len, beacon_period, + cap_info_bitmap, band, bss_desc); + if (ret) + goto done; + + ret = mwifiex_check_network_compatibility(priv, bss_desc); + if (ret) + goto done; + + /* Update current bss descriptor parameters */ + spin_lock_irqsave(&priv->curr_bcn_buf_lock, flags); + priv->curr_bss_params.bss_descriptor.bcn_wpa_ie = NULL; + priv->curr_bss_params.bss_descriptor.wpa_offset = 0; + priv->curr_bss_params.bss_descriptor.bcn_rsn_ie = NULL; + priv->curr_bss_params.bss_descriptor.rsn_offset = 0; + priv->curr_bss_params.bss_descriptor.bcn_wapi_ie = NULL; + priv->curr_bss_params.bss_descriptor.wapi_offset = 0; + priv->curr_bss_params.bss_descriptor.bcn_ht_cap = NULL; + priv->curr_bss_params.bss_descriptor.ht_cap_offset = + 0; + priv->curr_bss_params.bss_descriptor.bcn_ht_info = NULL; + priv->curr_bss_params.bss_descriptor.ht_info_offset = + 0; + priv->curr_bss_params.bss_descriptor.bcn_bss_co_2040 = + NULL; + priv->curr_bss_params.bss_descriptor. + bss_co_2040_offset = 0; + priv->curr_bss_params.bss_descriptor.bcn_ext_cap = NULL; + priv->curr_bss_params.bss_descriptor.ext_cap_offset = 0; + priv->curr_bss_params.bss_descriptor.beacon_buf = NULL; + priv->curr_bss_params.bss_descriptor.beacon_buf_size = + 0; + + /* Make a copy of current BSSID descriptor */ + memcpy(&priv->curr_bss_params.bss_descriptor, bss_desc, + sizeof(priv->curr_bss_params.bss_descriptor)); + mwifiex_save_curr_bcn(priv); + spin_unlock_irqrestore(&priv->curr_bcn_buf_lock, flags); + +done: + kfree(bss_desc); + kfree(beacon_ie); + return 0; +} + +static void mwifiex_free_bss_priv(struct cfg80211_bss *bss) +{ + kfree(bss->priv); +} + +/* * This function handles the command response of scan. * * The response buffer for the scan command has the following @@ -2406,23 +1568,19 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, struct mwifiex_adapter *adapter = priv->adapter; struct cmd_ctrl_node *cmd_node; struct host_cmd_ds_802_11_scan_rsp *scan_rsp; - struct mwifiex_bssdescriptor *bss_new_entry = NULL; struct mwifiex_ie_types_data *tlv_data; struct mwifiex_ie_types_tsf_timestamp *tsf_tlv; u8 *bss_info; u32 scan_resp_size; u32 bytes_left; - u32 num_in_table; - u32 bss_idx; u32 idx; u32 tlv_buf_size; - long long tsf_val; struct mwifiex_chan_freq_power *cfp; struct mwifiex_ie_types_chan_band_list_param_set *chan_band_tlv; struct chan_band_param_set *chan_band; - u8 band; u8 is_bgscan_resp; unsigned long flags; + struct cfg80211_bss *bss; is_bgscan_resp = (le16_to_cpu(resp->command) == HostCmd_CMD_802_11_BG_SCAN_QUERY); @@ -2432,11 +1590,11 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, scan_rsp = &resp->params.scan_resp; - if (scan_rsp->number_of_sets > IW_MAX_AP) { + if (scan_rsp->number_of_sets > MWIFIEX_MAX_AP) { dev_err(adapter->dev, "SCAN_RESP: too many AP returned (%d)\n", scan_rsp->number_of_sets); ret = -1; - goto done; + goto check_next_scan; } bytes_left = le16_to_cpu(scan_rsp->bss_descript_size); @@ -2449,7 +1607,6 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, "info: SCAN_RESP: returned %d APs before parsing\n", scan_rsp->number_of_sets); - num_in_table = adapter->num_in_scan_table; bss_info = scan_rsp->bss_desc_and_tlv_buffer; /* @@ -2481,143 +1638,163 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, (struct mwifiex_ie_types_data **) &chan_band_tlv); - /* - * Process each scan response returned (scan_rsp->number_of_sets). - * Save the information in the bss_new_entry and then insert into the - * driver scan table either as an update to an existing entry - * or as an addition at the end of the table - */ - bss_new_entry = kzalloc(sizeof(struct mwifiex_bssdescriptor), - GFP_KERNEL); - if (!bss_new_entry) { - dev_err(adapter->dev, " failed to alloc bss_new_entry\n"); - return -ENOMEM; - } - for (idx = 0; idx < scan_rsp->number_of_sets && bytes_left; idx++) { - /* Zero out the bss_new_entry we are about to store info in */ - memset(bss_new_entry, 0x00, - sizeof(struct mwifiex_bssdescriptor)); - - if (mwifiex_interpret_bss_desc_with_ie(adapter, bss_new_entry, - &bss_info, - &bytes_left)) { - /* Error parsing/interpreting scan response, skipped */ - dev_err(adapter->dev, "SCAN_RESP: " - "mwifiex_interpret_bss_desc_with_ie " - "returned ERROR\n"); - continue; + u8 bssid[ETH_ALEN]; + s32 rssi; + const u8 *ie_buf; + size_t ie_len; + int channel = -1; + u64 network_tsf = 0; + u16 beacon_size = 0; + u32 curr_bcn_bytes; + u32 freq; + u16 beacon_period; + u16 cap_info_bitmap; + u8 *current_ptr; + struct mwifiex_bcn_param *bcn_param; + + if (bytes_left >= sizeof(beacon_size)) { + /* Extract & convert beacon size from command buffer */ + memcpy(&beacon_size, bss_info, sizeof(beacon_size)); + bytes_left -= sizeof(beacon_size); + bss_info += sizeof(beacon_size); + } + + if (!beacon_size || beacon_size > bytes_left) { + bss_info += bytes_left; + bytes_left = 0; + ret = -1; + goto check_next_scan; } - /* Process the data fields and IEs returned for this BSS */ - dev_dbg(adapter->dev, "info: SCAN_RESP: BSSID = %pM\n", - bss_new_entry->mac_address); + /* Initialize the current working beacon pointer for this BSS + * iteration */ + current_ptr = bss_info; - /* Search the scan table for the same bssid */ - for (bss_idx = 0; bss_idx < num_in_table; bss_idx++) { - if (memcmp(bss_new_entry->mac_address, - adapter->scan_table[bss_idx].mac_address, - sizeof(bss_new_entry->mac_address))) { - continue; + /* Advance the return beacon pointer past the current beacon */ + bss_info += beacon_size; + bytes_left -= beacon_size; + + curr_bcn_bytes = beacon_size; + + /* + * First 5 fields are bssid, RSSI, time stamp, beacon interval, + * and capability information + */ + if (curr_bcn_bytes < sizeof(struct mwifiex_bcn_param)) { + dev_err(adapter->dev, "InterpretIE: not enough bytes left\n"); + continue; + } + bcn_param = (struct mwifiex_bcn_param *)current_ptr; + current_ptr += sizeof(*bcn_param); + curr_bcn_bytes -= sizeof(*bcn_param); + + memcpy(bssid, bcn_param->bssid, ETH_ALEN); + + rssi = (s32) (bcn_param->rssi); + dev_dbg(adapter->dev, "info: InterpretIE: RSSI=%02X\n", + rssi); + + beacon_period = le16_to_cpu(bcn_param->beacon_period); + + cap_info_bitmap = le16_to_cpu(bcn_param->cap_info_bitmap); + dev_dbg(adapter->dev, "info: InterpretIE: capabilities=0x%X\n", + cap_info_bitmap); + + /* Rest of the current buffer are IE's */ + ie_buf = current_ptr; + ie_len = curr_bcn_bytes; + dev_dbg(adapter->dev, "info: InterpretIE: IELength for this AP" + " = %d\n", curr_bcn_bytes); + + while (curr_bcn_bytes >= sizeof(struct ieee_types_header)) { + u8 element_id, element_len; + + element_id = *current_ptr; + element_len = *(current_ptr + 1); + if (curr_bcn_bytes < element_len + + sizeof(struct ieee_types_header)) { + dev_err(priv->adapter->dev, "%s: in processing" + " IE, bytes left < IE length\n", + __func__); + goto check_next_scan; } - /* - * If the SSID matches as well, it is a - * duplicate of this entry. Keep the bss_idx - * set to this entry so we replace the old - * contents in the table - */ - if ((bss_new_entry->ssid.ssid_len - == adapter->scan_table[bss_idx]. ssid.ssid_len) - && (!memcmp(bss_new_entry->ssid.ssid, - adapter->scan_table[bss_idx].ssid.ssid, - bss_new_entry->ssid.ssid_len))) { - dev_dbg(adapter->dev, "info: SCAN_RESP:" - " duplicate of index: %d\n", bss_idx); + if (element_id == WLAN_EID_DS_PARAMS) { + channel = *(u8 *) (current_ptr + + sizeof(struct ieee_types_header)); break; } - } - /* - * If the bss_idx is equal to the number of entries in - * the table, the new entry was not a duplicate; append - * it to the scan table - */ - if (bss_idx == num_in_table) { - /* Range check the bss_idx, keep it limited to - the last entry */ - if (bss_idx == IW_MAX_AP) - bss_idx--; - else - num_in_table++; + + current_ptr += element_len + + sizeof(struct ieee_types_header); + curr_bcn_bytes -= element_len + + sizeof(struct ieee_types_header); } /* - * Save the beacon/probe response returned for later application - * retrieval. Duplicate beacon/probe responses are updated if - * possible - */ - mwifiex_ret_802_11_scan_store_beacon(priv, bss_idx, - num_in_table, bss_new_entry); - /* * If the TSF TLV was appended to the scan results, save this * entry's TSF value in the networkTSF field.The networkTSF is * the firmware's TSF value at the time the beacon or probe * response was received. */ - if (tsf_tlv) { - memcpy(&tsf_val, &tsf_tlv->tsf_data[idx * TSF_DATA_SIZE] - , sizeof(tsf_val)); - memcpy(&bss_new_entry->network_tsf, &tsf_val, - sizeof(bss_new_entry->network_tsf)); - } - band = BAND_G; - if (chan_band_tlv) { - chan_band = &chan_band_tlv->chan_band_param[idx]; - band = mwifiex_radio_type_to_band(chan_band->radio_type - & (BIT(0) | BIT(1))); - } + if (tsf_tlv) + memcpy(&network_tsf, + &tsf_tlv->tsf_data[idx * TSF_DATA_SIZE], + sizeof(network_tsf)); + + if (channel != -1) { + struct ieee80211_channel *chan; + u8 band; + + band = BAND_G; + if (chan_band_tlv) { + chan_band = + &chan_band_tlv->chan_band_param[idx]; + band = mwifiex_radio_type_to_band( + chan_band->radio_type + & (BIT(0) | BIT(1))); + } - /* Save the band designation for this entry for use in join */ - bss_new_entry->bss_band = band; - cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211(priv, - (u8) bss_new_entry->bss_band, - (u16)bss_new_entry->channel); + cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211( + priv, (u8)band, (u16)channel); - if (cfp) - bss_new_entry->freq = cfp->freq; - else - bss_new_entry->freq = 0; + freq = cfp ? cfp->freq : 0; - /* Copy the locally created bss_new_entry to the scan table */ - memcpy(&adapter->scan_table[bss_idx], bss_new_entry, - sizeof(adapter->scan_table[bss_idx])); + chan = ieee80211_get_channel(priv->wdev->wiphy, freq); - } + if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) { + bss = cfg80211_inform_bss(priv->wdev->wiphy, + chan, bssid, network_tsf, + cap_info_bitmap, beacon_period, + ie_buf, ie_len, rssi, GFP_KERNEL); + *(u8 *)bss->priv = band; + bss->free_priv = mwifiex_free_bss_priv; - dev_dbg(adapter->dev, - "info: SCAN_RESP: Scanned %2d APs, %d valid, %d total\n", - scan_rsp->number_of_sets, - num_in_table - adapter->num_in_scan_table, num_in_table); - - /* Update the total number of BSSIDs in the scan table */ - adapter->num_in_scan_table = num_in_table; + if (priv->media_connected && !memcmp(bssid, + priv->curr_bss_params.bss_descriptor + .mac_address, ETH_ALEN)) + mwifiex_update_curr_bss_params(priv, + bssid, rssi, ie_buf, + ie_len, beacon_period, + cap_info_bitmap, band); + } + } else { + dev_dbg(adapter->dev, "missing BSS channel IE\n"); + } + } +check_next_scan: spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); if (list_empty(&adapter->scan_pending_q)) { spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); adapter->scan_processing = false; spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); - /* - * Process the resulting scan table: - * - Remove any bad ssids - * - Update our current BSS information from scan data - */ - mwifiex_process_scan_results(priv); /* Need to indicate IOCTL complete */ if (adapter->curr_cmd->wait_q_enabled) { adapter->cmd_wait_q.status = 0; - mwifiex_complete_cmd(adapter); + mwifiex_complete_cmd(adapter, adapter->curr_cmd); } if (priv->report_scan_result) priv->report_scan_result = false; @@ -2637,8 +1814,6 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true); } -done: - kfree((u8 *) bss_new_entry); return ret; } @@ -2665,141 +1840,6 @@ int mwifiex_cmd_802_11_bg_scan_query(struct host_cmd_ds_command *cmd) } /* - * This function finds a SSID in the scan table. - * - * A BSSID may optionally be provided to qualify the SSID. - * For non-Auto mode, further check is made to make sure the - * BSS found in the scan table is compatible with the current - * settings of the driver. - */ -s32 -mwifiex_find_ssid_in_list(struct mwifiex_private *priv, - struct mwifiex_802_11_ssid *ssid, u8 *bssid, - u32 mode) -{ - struct mwifiex_adapter *adapter = priv->adapter; - s32 net = -1, j; - u8 best_rssi = 0; - u32 i; - - dev_dbg(adapter->dev, "info: num of entries in table = %d\n", - adapter->num_in_scan_table); - - /* - * Loop through the table until the maximum is reached or until a match - * is found based on the bssid field comparison - */ - for (i = 0; - i < adapter->num_in_scan_table && (!bssid || (bssid && net < 0)); - i++) { - if (!mwifiex_ssid_cmp(&adapter->scan_table[i].ssid, ssid) && - (!bssid - || !memcmp(adapter->scan_table[i].mac_address, bssid, - ETH_ALEN)) - && - (mwifiex_get_cfp_by_band_and_channel_from_cfg80211 - (priv, (u8) adapter->scan_table[i].bss_band, - (u16) adapter->scan_table[i].channel))) { - switch (mode) { - case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_ADHOC: - j = mwifiex_is_network_compatible(priv, i, - mode); - - if (j >= 0) { - if (SCAN_RSSI - (adapter->scan_table[i].rssi) > - best_rssi) { - best_rssi = SCAN_RSSI(adapter-> - scan_table - [i].rssi); - net = i; - } - } else { - if (net == -1) - net = j; - } - break; - case NL80211_IFTYPE_UNSPECIFIED: - default: - /* - * Do not check compatibility if the mode - * requested is Auto/Unknown. Allows generic - * find to work without verifying against the - * Adapter security settings - */ - if (SCAN_RSSI(adapter->scan_table[i].rssi) > - best_rssi) { - best_rssi = SCAN_RSSI(adapter-> - scan_table[i].rssi); - net = i; - } - break; - } - } - } - - return net; -} - -/* - * This function finds a specific compatible BSSID in the scan list. - * - * This function loops through the scan table looking for a compatible - * match. If a BSSID matches, but the BSS is found to be not compatible - * the function ignores it and continues to search through the rest of - * the entries in case there is an AP with multiple SSIDs assigned to - * the same BSSID. - */ -s32 -mwifiex_find_bssid_in_list(struct mwifiex_private *priv, u8 *bssid, - u32 mode) -{ - struct mwifiex_adapter *adapter = priv->adapter; - s32 net = -1; - u32 i; - - if (!bssid) - return -1; - - dev_dbg(adapter->dev, "info: FindBSSID: Num of BSSIDs = %d\n", - adapter->num_in_scan_table); - - /* - * Look through the scan table for a compatible match. The ret return - * variable will be equal to the index in the scan table (greater - * than zero) if the network is compatible. The loop will continue - * past a matched bssid that is not compatible in case there is an - * AP with multiple SSIDs assigned to the same BSSID - */ - for (i = 0; net < 0 && i < adapter->num_in_scan_table; i++) { - if (!memcmp - (adapter->scan_table[i].mac_address, bssid, ETH_ALEN) - && mwifiex_get_cfp_by_band_and_channel_from_cfg80211 - (priv, - (u8) adapter-> - scan_table[i]. - bss_band, - (u16) adapter-> - scan_table[i]. - channel)) { - switch (mode) { - case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_ADHOC: - net = mwifiex_is_network_compatible(priv, i, - mode); - break; - default: - net = i; - break; - } - } - } - - return net; -} - -/* * This function inserts scan command node to the scan pending queue. */ void @@ -2810,48 +1850,13 @@ mwifiex_queue_scan_cmd(struct mwifiex_private *priv, unsigned long flags; cmd_node->wait_q_enabled = true; + cmd_node->condition = &adapter->scan_wait_q_woken; spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); list_add_tail(&cmd_node->list, &adapter->scan_pending_q); spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); } /* - * This function finds an AP with specific ssid in the scan list. - */ -int mwifiex_find_best_network(struct mwifiex_private *priv, - struct mwifiex_ssid_bssid *req_ssid_bssid) -{ - struct mwifiex_adapter *adapter = priv->adapter; - struct mwifiex_bssdescriptor *req_bss; - s32 i; - - memset(req_ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid)); - - i = mwifiex_find_best_network_in_list(priv); - - if (i >= 0) { - req_bss = &adapter->scan_table[i]; - memcpy(&req_ssid_bssid->ssid, &req_bss->ssid, - sizeof(struct mwifiex_802_11_ssid)); - memcpy((u8 *) &req_ssid_bssid->bssid, - (u8 *) &req_bss->mac_address, ETH_ALEN); - - /* Make sure we are in the right mode */ - if (priv->bss_mode == NL80211_IFTYPE_UNSPECIFIED) - priv->bss_mode = req_bss->bss_mode; - } - - if (!req_ssid_bssid->ssid.ssid_len) - return -1; - - dev_dbg(adapter->dev, "info: Best network found = [%s], " - "[%pM]\n", req_ssid_bssid->ssid.ssid, - req_ssid_bssid->bssid); - - return 0; -} - -/* * This function sends a scan command for all available channels to the * firmware, filtered on a specific SSID. */ @@ -2876,8 +1881,6 @@ static int mwifiex_scan_specific_ssid(struct mwifiex_private *priv, return ret; } - mwifiex_scan_delete_ssid_table_entry(priv, req_ssid); - scan_cfg = kzalloc(sizeof(struct mwifiex_user_scan_cfg), GFP_KERNEL); if (!scan_cfg) { dev_err(adapter->dev, "failed to alloc scan_cfg\n"); @@ -2886,7 +1889,6 @@ static int mwifiex_scan_specific_ssid(struct mwifiex_private *priv, memcpy(scan_cfg->ssid_list[0].ssid, req_ssid->ssid, req_ssid->ssid_len); - scan_cfg->keep_previous_scan = true; ret = mwifiex_scan_networks(priv, scan_cfg); @@ -2915,7 +1917,7 @@ int mwifiex_request_scan(struct mwifiex_private *priv, } priv->scan_pending_on_block = true; - priv->adapter->cmd_wait_q.condition = false; + priv->adapter->scan_wait_q_woken = false; if (req_ssid && req_ssid->ssid_len != 0) /* Specific SSID scan */ @@ -2999,7 +2001,7 @@ mwifiex_save_curr_bcn(struct mwifiex_private *priv) priv->curr_bcn_size = curr_bss->beacon_buf_size; kfree(priv->curr_bcn_buf); - priv->curr_bcn_buf = kzalloc(curr_bss->beacon_buf_size, + priv->curr_bcn_buf = kmalloc(curr_bss->beacon_buf_size, GFP_KERNEL); if (!priv->curr_bcn_buf) { dev_err(priv->adapter->dev, @@ -3012,6 +2014,39 @@ mwifiex_save_curr_bcn(struct mwifiex_private *priv) curr_bss->beacon_buf_size); dev_dbg(priv->adapter->dev, "info: current beacon saved %d\n", priv->curr_bcn_size); + + curr_bss->beacon_buf = priv->curr_bcn_buf; + + /* adjust the pointers in the current BSS descriptor */ + if (curr_bss->bcn_wpa_ie) + curr_bss->bcn_wpa_ie = + (struct ieee_types_vendor_specific *) + (curr_bss->beacon_buf + + curr_bss->wpa_offset); + + if (curr_bss->bcn_rsn_ie) + curr_bss->bcn_rsn_ie = (struct ieee_types_generic *) + (curr_bss->beacon_buf + + curr_bss->rsn_offset); + + if (curr_bss->bcn_ht_cap) + curr_bss->bcn_ht_cap = (struct ieee80211_ht_cap *) + (curr_bss->beacon_buf + + curr_bss->ht_cap_offset); + + if (curr_bss->bcn_ht_info) + curr_bss->bcn_ht_info = (struct ieee80211_ht_info *) + (curr_bss->beacon_buf + + curr_bss->ht_info_offset); + + if (curr_bss->bcn_bss_co_2040) + curr_bss->bcn_bss_co_2040 = + (u8 *) (curr_bss->beacon_buf + + curr_bss->bss_co_2040_offset); + + if (curr_bss->bcn_ext_cap) + curr_bss->bcn_ext_cap = (u8 *) (curr_bss->beacon_buf + + curr_bss->ext_cap_offset); } /* diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index 61e152d..72b253d2 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -31,10 +31,27 @@ #define SDIO_VERSION "1.0" +/* The mwifiex_sdio_remove() callback function is called when + * user removes this module from kernel space or ejects + * the card from the slot. The driver handles these 2 cases + * differently. + * If the user is removing the module, the few commands (FUNC_SHUTDOWN, + * HS_CANCEL etc.) are sent to the firmware. + * If the card is removed, there is no need to send these command. + * + * The variable 'user_rmmod' is used to distinguish these two + * scenarios. This flag is initialized as FALSE in case the card + * is removed, and will be set to TRUE for module removal when + * module_exit function is called. + */ +static u8 user_rmmod; + static struct mwifiex_if_ops sdio_ops; static struct semaphore add_remove_card_sem; +static int mwifiex_sdio_resume(struct device *dev); + /* * SDIO probe. * @@ -72,7 +89,8 @@ mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) return -EIO; } - if (mwifiex_add_card(card, &add_remove_card_sem, &sdio_ops)) { + if (mwifiex_add_card(card, &add_remove_card_sem, &sdio_ops, + MWIFIEX_SDIO)) { pr_err("%s: add card failed\n", __func__); kfree(card); sdio_claim_host(func); @@ -93,17 +111,39 @@ static void mwifiex_sdio_remove(struct sdio_func *func) { struct sdio_mmc_card *card; + struct mwifiex_adapter *adapter; + int i; pr_debug("info: SDIO func num=%d\n", func->num); - if (func) { - card = sdio_get_drvdata(func); - if (card) { - mwifiex_remove_card(card->adapter, - &add_remove_card_sem); - kfree(card); - } + 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); + + mwifiex_disable_auto_ds(mwifiex_get_priv(adapter, + MWIFIEX_BSS_ROLE_ANY)); + + mwifiex_init_shutdown_fw(mwifiex_get_priv(adapter, + MWIFIEX_BSS_ROLE_ANY), + MWIFIEX_FUNC_SHUTDOWN); } + + mwifiex_remove_card(card->adapter, &add_remove_card_sem); + kfree(card); } /* @@ -792,7 +832,7 @@ done: * The winner interface is also determined by this function. */ static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter, - u32 poll_num, int *winner) + u32 poll_num) { int ret = 0; u16 firmware_stat; @@ -804,7 +844,7 @@ static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter, ret = mwifiex_sdio_read_fw_status(adapter, &firmware_stat); if (ret) continue; - if (firmware_stat == FIRMWARE_READY) { + if (firmware_stat == FIRMWARE_READY_SDIO) { ret = 0; break; } else { @@ -813,15 +853,15 @@ static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter, } } - if (winner && ret) { + if (ret) { if (mwifiex_read_reg (adapter, CARD_FW_STATUS0_REG, &winner_status)) winner_status = 0; if (winner_status) - *winner = 0; + adapter->winner = 0; else - *winner = 1; + adapter->winner = 1; } return ret; } @@ -896,7 +936,10 @@ static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter, struct sk_buff *skb, u32 upld_typ) { u8 *cmd_buf; + __le16 *curr_ptr = (__le16 *)skb->data; + u16 pkt_len = le16_to_cpu(*curr_ptr); + skb_trim(skb, pkt_len); skb_pull(skb, INTF_HEADER_LEN); switch (upld_typ) { @@ -1284,7 +1327,7 @@ static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter, if (!(card->mp_wr_bitmap & (1 << card->curr_wr_port)) || !MP_TX_AGGR_BUF_HAS_ROOM( - card, next_pkt_len)) + card, pkt_len + next_pkt_len)) f_send_aggr_buf = 1; } else { /* No room in Aggr buf, send it */ @@ -1375,7 +1418,7 @@ tx_curr_single: * the type. The firmware handles the packets based upon this set type. */ static int mwifiex_sdio_host_to_card(struct mwifiex_adapter *adapter, - u8 type, u8 *payload, u32 pkt_len, + u8 type, struct sk_buff *skb, struct mwifiex_tx_param *tx_param) { struct sdio_mmc_card *card = adapter->card; @@ -1383,6 +1426,8 @@ static int mwifiex_sdio_host_to_card(struct mwifiex_adapter *adapter, u32 buf_block_len; u32 blk_size; u8 port = CTRL_PORT; + u8 *payload = (u8 *)skb->data; + u32 pkt_len = skb->len; /* Allocate buffer and copy payload */ blk_size = MWIFIEX_SDIO_BLOCK_SIZE; @@ -1532,6 +1577,7 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter) sdio_set_drvdata(func, card); adapter->dev = &func->dev; + strcpy(adapter->fw_name, SD8787_DEFAULT_FW_NAME); return 0; @@ -1553,7 +1599,6 @@ disable_func: * the first interrupt got from bootloader * - Disable host interrupt mask register * - Get SDIO port - * - Get revision ID * - Initialize SDIO variables in card * - Allocate MP registers * - Allocate MPA Tx and Rx buffers @@ -1577,10 +1622,6 @@ static int mwifiex_init_sdio(struct mwifiex_adapter *adapter) /* Get SDIO ioport */ mwifiex_init_sdio_ioport(adapter); - /* Get revision ID */ -#define REV_ID_REG 0x5c - mwifiex_read_reg(adapter, REV_ID_REG, &adapter->revision_id); - /* Initialize SDIO variables in card */ card->mp_rd_bitmap = 0; card->mp_wr_bitmap = 0; @@ -1688,6 +1729,8 @@ static struct mwifiex_if_ops sdio_ops = { /* SDIO specific */ .update_mp_end_port = mwifiex_update_mp_end_port, .cleanup_mpa_buf = mwifiex_cleanup_mpa_buf, + .cmdrsp_complete = mwifiex_sdio_cmdrsp_complete, + .event_complete = mwifiex_sdio_event_complete, }; /* @@ -1701,6 +1744,9 @@ mwifiex_sdio_init_module(void) { sema_init(&add_remove_card_sem, 1); + /* Clear the flag in case user removes the card. */ + user_rmmod = 0; + return sdio_register_driver(&mwifiex_sdio); } @@ -1716,32 +1762,12 @@ mwifiex_sdio_init_module(void) 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); + if (!down_interruptible(&add_remove_card_sem)) + up(&add_remove_card_sem); -exit: - up(&add_remove_card_sem); + /* Set the flag as user is removing this module. */ + user_rmmod = 1; -exit_sem_err: sdio_unregister_driver(&mwifiex_sdio); } @@ -1752,4 +1778,4 @@ MODULE_AUTHOR("Marvell International Ltd."); MODULE_DESCRIPTION("Marvell WiFi-Ex SDIO Driver version " SDIO_VERSION); MODULE_VERSION(SDIO_VERSION); MODULE_LICENSE("GPL v2"); -MODULE_FIRMWARE("sd8787.bin"); +MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin"); diff --git a/drivers/net/wireless/mwifiex/sdio.h b/drivers/net/wireless/mwifiex/sdio.h index 4e97e90..3f71180 100644 --- a/drivers/net/wireless/mwifiex/sdio.h +++ b/drivers/net/wireless/mwifiex/sdio.h @@ -28,6 +28,8 @@ #include "main.h" +#define SD8787_DEFAULT_FW_NAME "mrvl/sd8787_uapsta.bin" + #define BLOCK_MODE 1 #define BYTE_MODE 0 @@ -52,10 +54,10 @@ #define SDIO_MP_AGGR_DEF_PKT_LIMIT 8 -#define SDIO_MP_TX_AGGR_DEF_BUF_SIZE (4096) /* 4K */ +#define SDIO_MP_TX_AGGR_DEF_BUF_SIZE (8192) /* 8K */ /* Multi port RX aggregation buffer size */ -#define SDIO_MP_RX_AGGR_DEF_BUF_SIZE (4096) /* 4K */ +#define SDIO_MP_RX_AGGR_DEF_BUF_SIZE (16384) /* 16K */ /* Misc. Config Register : Auto Re-enable interrupts */ #define AUTO_RE_ENABLE_INT BIT(4) @@ -167,9 +169,6 @@ /* Rx unit register */ #define CARD_RX_UNIT_REG 0x63 -/* Event header len w/o 4 bytes of interface header */ -#define MWIFIEX_EVENT_HEADER_LEN 4 - /* Max retry number of CMD53 write */ #define MAX_WRITE_IOMEM_RETRY 2 @@ -302,4 +301,25 @@ struct sdio_mmc_card { struct mwifiex_sdio_mpa_tx mpa_tx; struct mwifiex_sdio_mpa_rx mpa_rx; }; + +/* + * .cmdrsp_complete handler + */ +static inline int mwifiex_sdio_cmdrsp_complete(struct mwifiex_adapter *adapter, + struct sk_buff *skb) +{ + dev_kfree_skb_any(skb); + return 0; +} + +/* + * .event_complete handler + */ +static inline int mwifiex_sdio_event_complete(struct mwifiex_adapter *adapter, + struct sk_buff *skb) +{ + dev_kfree_skb_any(skb); + return 0; +} + #endif /* _MWIFIEX_SDIO_H */ diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index 8af3a78..ea6518d 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -67,10 +67,9 @@ mwifiex_cmd_802_11_rssi_info(struct mwifiex_private *priv, */ static int mwifiex_cmd_mac_control(struct mwifiex_private *priv, struct host_cmd_ds_command *cmd, - u16 cmd_action, void *data_buf) + u16 cmd_action, u16 *action) { struct host_cmd_ds_mac_control *mac_ctrl = &cmd->params.mac_ctrl; - u16 action = *((u16 *) data_buf); if (cmd_action != HostCmd_ACT_GEN_SET) { dev_err(priv->adapter->dev, @@ -81,7 +80,7 @@ static int mwifiex_cmd_mac_control(struct mwifiex_private *priv, cmd->command = cpu_to_le16(HostCmd_CMD_MAC_CONTROL); cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_mac_control) + S_DS_GEN); - mac_ctrl->action = cpu_to_le16(action); + mac_ctrl->action = cpu_to_le16(*action); return 0; } @@ -104,10 +103,9 @@ static int mwifiex_cmd_mac_control(struct mwifiex_private *priv, static int mwifiex_cmd_802_11_snmp_mib(struct mwifiex_private *priv, struct host_cmd_ds_command *cmd, u16 cmd_action, u32 cmd_oid, - void *data_buf) + u32 *ul_temp) { struct host_cmd_ds_802_11_snmp_mib *snmp_mib = &cmd->params.smib; - u32 ul_temp; dev_dbg(priv->adapter->dev, "cmd: SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid); cmd->command = cpu_to_le16(HostCmd_CMD_802_11_SNMP_MIB); @@ -127,9 +125,8 @@ static int mwifiex_cmd_802_11_snmp_mib(struct mwifiex_private *priv, if (cmd_action == HostCmd_ACT_GEN_SET) { snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_SET); snmp_mib->buf_size = cpu_to_le16(sizeof(u16)); - ul_temp = *((u32 *) data_buf); *((__le16 *) (snmp_mib->value)) = - cpu_to_le16((u16) ul_temp); + cpu_to_le16((u16) *ul_temp); cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) + sizeof(u16)); } @@ -139,9 +136,8 @@ static int mwifiex_cmd_802_11_snmp_mib(struct mwifiex_private *priv, if (cmd_action == HostCmd_ACT_GEN_SET) { snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_SET); snmp_mib->buf_size = cpu_to_le16(sizeof(u16)); - ul_temp = *((u32 *) data_buf); *(__le16 *) (snmp_mib->value) = - cpu_to_le16((u16) ul_temp); + cpu_to_le16((u16) *ul_temp); cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) + sizeof(u16)); } @@ -152,9 +148,8 @@ static int mwifiex_cmd_802_11_snmp_mib(struct mwifiex_private *priv, if (cmd_action == HostCmd_ACT_GEN_SET) { snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_SET); snmp_mib->buf_size = cpu_to_le16(sizeof(u16)); - ul_temp = (*(u32 *) data_buf); *((__le16 *) (snmp_mib->value)) = - cpu_to_le16((u16) ul_temp); + cpu_to_le16((u16) *ul_temp); cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) + sizeof(u16)); } @@ -164,9 +159,8 @@ static int mwifiex_cmd_802_11_snmp_mib(struct mwifiex_private *priv, if (cmd_action == HostCmd_ACT_GEN_SET) { snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_SET); snmp_mib->buf_size = cpu_to_le16(sizeof(u16)); - ul_temp = *(u32 *) data_buf; *((__le16 *) (snmp_mib->value)) = - cpu_to_le16((u16) ul_temp); + cpu_to_le16((u16) *ul_temp); cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) + sizeof(u16)); } @@ -209,13 +203,11 @@ mwifiex_cmd_802_11_get_log(struct host_cmd_ds_command *cmd) */ static int mwifiex_cmd_tx_rate_cfg(struct mwifiex_private *priv, struct host_cmd_ds_command *cmd, - u16 cmd_action, void *data_buf) + u16 cmd_action, u16 *pbitmap_rates) { struct host_cmd_ds_tx_rate_cfg *rate_cfg = &cmd->params.tx_rate_cfg; struct mwifiex_rate_scope *rate_scope; struct mwifiex_rate_drop_pattern *rate_drop; - u16 *pbitmap_rates = (u16 *) data_buf; - u32 i; cmd->command = cpu_to_le16(HostCmd_CMD_TX_RATE_CFG); @@ -272,10 +264,10 @@ static int mwifiex_cmd_tx_rate_cfg(struct mwifiex_private *priv, * - Ensuring correct endian-ness */ static int mwifiex_cmd_tx_power_cfg(struct host_cmd_ds_command *cmd, - u16 cmd_action, void *data_buf) + u16 cmd_action, + struct host_cmd_ds_txpwr_cfg *txp) { struct mwifiex_types_power_group *pg_tlv; - struct host_cmd_ds_txpwr_cfg *txp; struct host_cmd_ds_txpwr_cfg *cmd_txp_cfg = &cmd->params.txp_cfg; cmd->command = cpu_to_le16(HostCmd_CMD_TXPWR_CFG); @@ -283,12 +275,11 @@ static int mwifiex_cmd_tx_power_cfg(struct host_cmd_ds_command *cmd, cpu_to_le16(S_DS_GEN + sizeof(struct host_cmd_ds_txpwr_cfg)); switch (cmd_action) { case HostCmd_ACT_GEN_SET: - txp = (struct host_cmd_ds_txpwr_cfg *) data_buf; if (txp->mode) { pg_tlv = (struct mwifiex_types_power_group - *) ((unsigned long) data_buf + + *) ((unsigned long) txp + sizeof(struct host_cmd_ds_txpwr_cfg)); - memmove(cmd_txp_cfg, data_buf, + memmove(cmd_txp_cfg, txp, sizeof(struct host_cmd_ds_txpwr_cfg) + sizeof(struct mwifiex_types_power_group) + pg_tlv->length); @@ -300,8 +291,7 @@ static int mwifiex_cmd_tx_power_cfg(struct host_cmd_ds_command *cmd, sizeof(struct mwifiex_types_power_group) + pg_tlv->length); } else { - memmove(cmd_txp_cfg, data_buf, - sizeof(struct host_cmd_ds_txpwr_cfg)); + memmove(cmd_txp_cfg, txp, sizeof(*txp)); } cmd_txp_cfg->action = cpu_to_le16(cmd_action); break; @@ -322,22 +312,23 @@ static int mwifiex_cmd_tx_power_cfg(struct host_cmd_ds_command *cmd, * (as required) * - Ensuring correct endian-ness */ -static int mwifiex_cmd_802_11_hs_cfg(struct mwifiex_private *priv, - struct host_cmd_ds_command *cmd, - u16 cmd_action, - struct mwifiex_hs_config_param *data_buf) +static int +mwifiex_cmd_802_11_hs_cfg(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, + struct mwifiex_hs_config_param *hscfg_param) { struct mwifiex_adapter *adapter = priv->adapter; struct host_cmd_ds_802_11_hs_cfg_enh *hs_cfg = &cmd->params.opt_hs_cfg; u16 hs_activate = false; - if (data_buf == NULL) + if (!hscfg_param) /* New Activate command */ hs_activate = true; cmd->command = cpu_to_le16(HostCmd_CMD_802_11_HS_CFG_ENH); if (!hs_activate && - (data_buf->conditions + (hscfg_param->conditions != cpu_to_le32(HOST_SLEEP_CFG_CANCEL)) && ((adapter->arp_filter_size > 0) && (adapter->arp_filter_size <= ARP_FILTER_MAX_BUF_SIZE))) { @@ -359,9 +350,9 @@ static int mwifiex_cmd_802_11_hs_cfg(struct mwifiex_private *priv, hs_cfg->params.hs_activate.resp_ctrl = RESP_NEEDED; } else { hs_cfg->action = cpu_to_le16(HS_CONFIGURE); - hs_cfg->params.hs_config.conditions = data_buf->conditions; - hs_cfg->params.hs_config.gpio = data_buf->gpio; - hs_cfg->params.hs_config.gap = data_buf->gap; + hs_cfg->params.hs_config.conditions = hscfg_param->conditions; + hs_cfg->params.hs_config.gpio = hscfg_param->gpio; + hs_cfg->params.hs_config.gap = hscfg_param->gap; dev_dbg(adapter->dev, "cmd: HS_CFG_CMD: condition:0x%x gpio:0x%x gap:0x%x\n", hs_cfg->params.hs_config.conditions, @@ -405,11 +396,11 @@ static int mwifiex_cmd_802_11_mac_address(struct mwifiex_private *priv, * - Setting MAC multicast address * - Ensuring correct endian-ness */ -static int mwifiex_cmd_mac_multicast_adr(struct host_cmd_ds_command *cmd, - u16 cmd_action, void *data_buf) +static int +mwifiex_cmd_mac_multicast_adr(struct host_cmd_ds_command *cmd, + u16 cmd_action, + struct mwifiex_multicast_list *mcast_list) { - struct mwifiex_multicast_list *mcast_list = - (struct mwifiex_multicast_list *) data_buf; struct host_cmd_ds_mac_multicast_adr *mcast_addr = &cmd->params.mc_addr; cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_mac_multicast_adr) + @@ -435,7 +426,7 @@ static int mwifiex_cmd_mac_multicast_adr(struct host_cmd_ds_command *cmd, */ static int mwifiex_cmd_802_11_deauthenticate(struct mwifiex_private *priv, struct host_cmd_ds_command *cmd, - void *data_buf) + u8 *mac) { struct host_cmd_ds_802_11_deauthenticate *deauth = &cmd->params.deauth; @@ -444,7 +435,7 @@ static int mwifiex_cmd_802_11_deauthenticate(struct mwifiex_private *priv, + S_DS_GEN); /* Set AP MAC address */ - memcpy(deauth->mac_addr, (u8 *) data_buf, ETH_ALEN); + memcpy(deauth->mac_addr, mac, ETH_ALEN); dev_dbg(priv->adapter->dev, "cmd: Deauth: %pM\n", deauth->mac_addr); @@ -543,15 +534,14 @@ mwifiex_set_keyparamset_wep(struct mwifiex_private *priv, * encryption (TKIP, AES) (as required) * - Ensuring correct endian-ness */ -static int mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv, - struct host_cmd_ds_command *cmd, - u16 cmd_action, - u32 cmd_oid, void *data_buf) +static int +mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, u32 cmd_oid, + struct mwifiex_ds_encrypt_key *enc_key) { struct host_cmd_ds_802_11_key_material *key_material = &cmd->params.key_material; - struct mwifiex_ds_encrypt_key *enc_key = - (struct mwifiex_ds_encrypt_key *) data_buf; u16 key_param_len = 0; int ret = 0; const u8 bc_mac[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; @@ -741,7 +731,7 @@ static int mwifiex_cmd_802_11d_domain_info(struct mwifiex_private *priv, */ static int mwifiex_cmd_802_11_rf_channel(struct mwifiex_private *priv, struct host_cmd_ds_command *cmd, - u16 cmd_action, void *data_buf) + u16 cmd_action, u16 *channel) { struct host_cmd_ds_802_11_rf_channel *rf_chan = &cmd->params.rf_channel; @@ -759,7 +749,7 @@ static int mwifiex_cmd_802_11_rf_channel(struct mwifiex_private *priv, rf_type = le16_to_cpu(rf_chan->rf_type); SET_SECONDARYCHAN(rf_type, priv->adapter->chan_offset); - rf_chan->current_channel = cpu_to_le16(*((u16 *) data_buf)); + rf_chan->current_channel = cpu_to_le16(*channel); } rf_chan->action = cpu_to_le16(cmd_action); return 0; @@ -774,11 +764,10 @@ static int mwifiex_cmd_802_11_rf_channel(struct mwifiex_private *priv, * - Ensuring correct endian-ness */ static int mwifiex_cmd_ibss_coalescing_status(struct host_cmd_ds_command *cmd, - u16 cmd_action, void *data_buf) + u16 cmd_action, u16 *enable) { struct host_cmd_ds_802_11_ibss_status *ibss_coal = &(cmd->params.ibss_coalescing); - u16 enable = 0; cmd->command = cpu_to_le16(HostCmd_CMD_802_11_IBSS_COALESCING_STATUS); cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_ibss_status) + @@ -788,9 +777,10 @@ static int mwifiex_cmd_ibss_coalescing_status(struct host_cmd_ds_command *cmd, switch (cmd_action) { case HostCmd_ACT_GEN_SET: - if (data_buf != NULL) - enable = *(u16 *) data_buf; - ibss_coal->enable = cpu_to_le16(enable); + if (enable) + ibss_coal->enable = cpu_to_le16(*enable); + else + ibss_coal->enable = 0; break; /* In other case.. Nothing to do */ @@ -822,9 +812,8 @@ static int mwifiex_cmd_ibss_coalescing_status(struct host_cmd_ds_command *cmd, static int mwifiex_cmd_reg_access(struct host_cmd_ds_command *cmd, u16 cmd_action, void *data_buf) { - struct mwifiex_ds_reg_rw *reg_rw; + struct mwifiex_ds_reg_rw *reg_rw = data_buf; - reg_rw = (struct mwifiex_ds_reg_rw *) data_buf; switch (le16_to_cpu(cmd->command)) { case HostCmd_CMD_MAC_REG_ACCESS: { @@ -893,8 +882,7 @@ static int mwifiex_cmd_reg_access(struct host_cmd_ds_command *cmd, } case HostCmd_CMD_802_11_EEPROM_ACCESS: { - struct mwifiex_ds_read_eeprom *rd_eeprom = - (struct mwifiex_ds_read_eeprom *) data_buf; + struct mwifiex_ds_read_eeprom *rd_eeprom = data_buf; struct host_cmd_ds_802_11_eeprom_access *cmd_eeprom = (struct host_cmd_ds_802_11_eeprom_access *) &cmd->params.eeprom; @@ -914,6 +902,59 @@ static int mwifiex_cmd_reg_access(struct host_cmd_ds_command *cmd, } /* + * This function prepares command to set PCI-Express + * host buffer configuration + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting host buffer configuration + * - Ensuring correct endian-ness + */ +static int +mwifiex_cmd_pcie_host_spec(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, u16 action) +{ + struct host_cmd_ds_pcie_details *host_spec = + &cmd->params.pcie_host_spec; + struct pcie_service_card *card = priv->adapter->card; + phys_addr_t *buf_pa; + + cmd->command = cpu_to_le16(HostCmd_CMD_PCIE_DESC_DETAILS); + cmd->size = cpu_to_le16(sizeof(struct + host_cmd_ds_pcie_details) + S_DS_GEN); + cmd->result = 0; + + memset(host_spec, 0, sizeof(struct host_cmd_ds_pcie_details)); + + if (action == HostCmd_ACT_GEN_SET) { + /* Send the ring base addresses and count to firmware */ + host_spec->txbd_addr_lo = (u32)(card->txbd_ring_pbase); + host_spec->txbd_addr_hi = + (u32)(((u64)card->txbd_ring_pbase)>>32); + host_spec->txbd_count = MWIFIEX_MAX_TXRX_BD; + host_spec->rxbd_addr_lo = (u32)(card->rxbd_ring_pbase); + host_spec->rxbd_addr_hi = + (u32)(((u64)card->rxbd_ring_pbase)>>32); + host_spec->rxbd_count = MWIFIEX_MAX_TXRX_BD; + host_spec->evtbd_addr_lo = + (u32)(card->evtbd_ring_pbase); + host_spec->evtbd_addr_hi = + (u32)(((u64)card->evtbd_ring_pbase)>>32); + host_spec->evtbd_count = MWIFIEX_MAX_EVT_BD; + if (card->sleep_cookie) { + buf_pa = MWIFIEX_SKB_PACB(card->sleep_cookie); + host_spec->sleep_cookie_addr_lo = (u32) *buf_pa; + host_spec->sleep_cookie_addr_hi = + (u32) (((u64)*buf_pa) >> 32); + dev_dbg(priv->adapter->dev, "sleep_cook_lo phy addr: " + "0x%x\n", host_spec->sleep_cookie_addr_lo); + } + } + + return 0; +} + +/* * This function prepares the commands before sending them to the firmware. * * This is a generic function which calls specific command preparation @@ -923,8 +964,7 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, u16 cmd_action, u32 cmd_oid, void *data_buf, void *cmd_buf) { - struct host_cmd_ds_command *cmd_ptr = - (struct host_cmd_ds_command *) cmd_buf; + struct host_cmd_ds_command *cmd_ptr = cmd_buf; int ret = 0; /* Prepare command */ @@ -1092,6 +1132,9 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, host_cmd_ds_set_bss_mode) + S_DS_GEN); ret = 0; break; + case HostCmd_CMD_PCIE_DESC_DETAILS: + ret = mwifiex_cmd_pcie_host_spec(priv, cmd_ptr, cmd_action); + break; default: dev_err(priv->adapter->dev, "PREP_CMD: unknown cmd- %#x\n", cmd_no); @@ -1108,6 +1151,7 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, * working state. * * The following commands are issued sequentially - + * - Set PCI-Express host buffer configuration (PCIE only) * - Function init (for first interface only) * - Read MAC address (for first interface only) * - Reconfigure Tx buffer size (for first interface only) @@ -1126,8 +1170,16 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta) struct mwifiex_ds_11n_amsdu_aggr_ctrl amsdu_aggr_ctrl; struct mwifiex_ds_auto_ds auto_ds; enum state_11d_t state_11d; + struct mwifiex_ds_11n_tx_cfg tx_cfg; if (first_sta) { + if (priv->adapter->iface_type == MWIFIEX_PCIE) { + ret = mwifiex_send_cmd_async(priv, + HostCmd_CMD_PCIE_DESC_DETAILS, + HostCmd_ACT_GEN_SET, 0, NULL); + if (ret) + return -1; + } ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_FUNC_INIT, HostCmd_ACT_GEN_SET, 0, NULL); @@ -1181,7 +1233,7 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta) /* Send request to firmware */ ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_AMSDU_AGGR_CTRL, HostCmd_ACT_GEN_SET, 0, - (void *) &amsdu_aggr_ctrl); + &amsdu_aggr_ctrl); if (ret) return -1; /* MAC Control must be the last command in init_fw */ @@ -1211,8 +1263,15 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta) if (ret) dev_err(priv->adapter->dev, "11D: failed to enable 11D\n"); + /* Send cmd to FW to configure 11n specific configuration + * (Short GI, Channel BW, Green field support etc.) for transmit + */ + tx_cfg.tx_htcap = MWIFIEX_FW_DEF_HTTXCFG; + ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_CFG, + HostCmd_ACT_GEN_SET, 0, &tx_cfg); + /* set last_init_cmd */ - priv->adapter->last_init_cmd = HostCmd_CMD_802_11_SNMP_MIB; + priv->adapter->last_init_cmd = HostCmd_CMD_11N_CFG; ret = -EINPROGRESS; return ret; diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index d08f764..7a16b0c 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -120,11 +120,10 @@ mwifiex_process_cmdresp_error(struct mwifiex_private *priv, */ static int mwifiex_ret_802_11_rssi_info(struct mwifiex_private *priv, struct host_cmd_ds_command *resp, - void *data_buf) + struct mwifiex_ds_get_signal *signal) { struct host_cmd_ds_802_11_rssi_info_rsp *rssi_info_rsp = &resp->params.rssi_info_rsp; - struct mwifiex_ds_get_signal *signal; priv->data_rssi_last = le16_to_cpu(rssi_info_rsp->data_rssi_last); priv->data_nf_last = le16_to_cpu(rssi_info_rsp->data_nf_last); @@ -139,9 +138,8 @@ static int mwifiex_ret_802_11_rssi_info(struct mwifiex_private *priv, priv->bcn_nf_avg = le16_to_cpu(rssi_info_rsp->bcn_nf_avg); /* Need to indicate IOCTL complete */ - if (data_buf) { - signal = (struct mwifiex_ds_get_signal *) data_buf; - memset(signal, 0, sizeof(struct mwifiex_ds_get_signal)); + if (signal) { + memset(signal, 0, sizeof(*signal)); signal->selector = ALL_RSSI_INFO_MASK; @@ -185,7 +183,7 @@ static int mwifiex_ret_802_11_rssi_info(struct mwifiex_private *priv, */ static int mwifiex_ret_802_11_snmp_mib(struct mwifiex_private *priv, struct host_cmd_ds_command *resp, - void *data_buf) + u32 *data_buf) { struct host_cmd_ds_802_11_snmp_mib *smib = &resp->params.smib; u16 oid = le16_to_cpu(smib->oid); @@ -198,7 +196,7 @@ static int mwifiex_ret_802_11_snmp_mib(struct mwifiex_private *priv, if (query_type == HostCmd_ACT_GEN_GET) { ul_temp = le16_to_cpu(*((__le16 *) (smib->value))); if (data_buf) - *(u32 *)data_buf = ul_temp; + *data_buf = ul_temp; switch (oid) { case FRAG_THRESH_I: dev_dbg(priv->adapter->dev, @@ -228,14 +226,12 @@ static int mwifiex_ret_802_11_snmp_mib(struct mwifiex_private *priv, */ static int mwifiex_ret_get_log(struct mwifiex_private *priv, struct host_cmd_ds_command *resp, - void *data_buf) + struct mwifiex_ds_get_stats *stats) { struct host_cmd_ds_802_11_get_log *get_log = (struct host_cmd_ds_802_11_get_log *) &resp->params.get_log; - struct mwifiex_ds_get_stats *stats; - if (data_buf) { - stats = (struct mwifiex_ds_get_stats *) data_buf; + if (stats) { stats->mcast_tx_frame = le32_to_cpu(get_log->mcast_tx_frame); stats->failed = le32_to_cpu(get_log->failed); stats->retry = le32_to_cpu(get_log->retry); @@ -278,9 +274,8 @@ static int mwifiex_ret_get_log(struct mwifiex_private *priv, */ static int mwifiex_ret_tx_rate_cfg(struct mwifiex_private *priv, struct host_cmd_ds_command *resp, - void *data_buf) + struct mwifiex_rate_cfg *ds_rate) { - struct mwifiex_rate_cfg *ds_rate; struct host_cmd_ds_tx_rate_cfg *rate_cfg = &resp->params.tx_rate_cfg; struct mwifiex_rate_scope *rate_scope; struct mwifiex_ie_types_header *head; @@ -329,8 +324,7 @@ static int mwifiex_ret_tx_rate_cfg(struct mwifiex_private *priv, HostCmd_CMD_802_11_TX_RATE_QUERY, HostCmd_ACT_GEN_GET, 0, NULL); - if (data_buf) { - ds_rate = (struct mwifiex_rate_cfg *) data_buf; + if (ds_rate) { if (le16_to_cpu(rate_cfg->action) == HostCmd_ACT_GEN_GET) { if (priv->is_data_rate_auto) { ds_rate->is_rate_auto = 1; @@ -413,8 +407,7 @@ static int mwifiex_get_power_level(struct mwifiex_private *priv, void *data_buf) * and saving the current Tx power level in driver. */ static int mwifiex_ret_tx_power_cfg(struct mwifiex_private *priv, - struct host_cmd_ds_command *resp, - void *data_buf) + struct host_cmd_ds_command *resp) { struct mwifiex_adapter *adapter = priv->adapter; struct host_cmd_ds_txpwr_cfg *txp_cfg = &resp->params.txp_cfg; @@ -631,7 +624,7 @@ static int mwifiex_ret_802_11d_domain_info(struct mwifiex_private *priv, */ static int mwifiex_ret_802_11_rf_channel(struct mwifiex_private *priv, struct host_cmd_ds_command *resp, - void *data_buf) + u16 *data_buf) { struct host_cmd_ds_802_11_rf_channel *rf_channel = &resp->params.rf_channel; @@ -644,8 +637,9 @@ static int mwifiex_ret_802_11_rf_channel(struct mwifiex_private *priv, /* Update the channel again */ priv->curr_bss_params.bss_descriptor.channel = new_channel; } + if (data_buf) - *((u16 *)data_buf) = new_channel; + *data_buf = new_channel; return 0; } @@ -658,13 +652,11 @@ static int mwifiex_ret_802_11_rf_channel(struct mwifiex_private *priv, */ static int mwifiex_ret_ver_ext(struct mwifiex_private *priv, struct host_cmd_ds_command *resp, - void *data_buf) + struct host_cmd_ds_version_ext *version_ext) { struct host_cmd_ds_version_ext *ver_ext = &resp->params.verext; - struct host_cmd_ds_version_ext *version_ext; - if (data_buf) { - version_ext = (struct host_cmd_ds_version_ext *)data_buf; + if (version_ext) { version_ext->version_str_sel = ver_ext->version_str_sel; memcpy(version_ext->version_str, ver_ext->version_str, sizeof(char) * 128); @@ -686,8 +678,8 @@ static int mwifiex_ret_reg_access(u16 type, struct host_cmd_ds_command *resp, struct mwifiex_ds_read_eeprom *eeprom; if (data_buf) { - reg_rw = (struct mwifiex_ds_reg_rw *) data_buf; - eeprom = (struct mwifiex_ds_read_eeprom *) data_buf; + reg_rw = data_buf; + eeprom = data_buf; switch (type) { case HostCmd_CMD_MAC_REG_ACCESS: { @@ -825,13 +817,11 @@ static int mwifiex_ret_ibss_coalescing_status(struct mwifiex_private *priv, * This is a generic function, which calls command specific * response handlers based on the command ID. */ -int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, - u16 cmdresp_no, void *cmd_buf) +int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no, + struct host_cmd_ds_command *resp) { int ret = 0; struct mwifiex_adapter *adapter = priv->adapter; - struct host_cmd_ds_command *resp = - (struct host_cmd_ds_command *) cmd_buf; void *data_buf = adapter->curr_cmd->data_buf; /* If the command is not successful, cleanup and return failure */ @@ -865,7 +855,7 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, "info: CMD_RESP: BG_SCAN result is ready!\n"); break; case HostCmd_CMD_TXPWR_CFG: - ret = mwifiex_ret_tx_power_cfg(priv, resp, data_buf); + ret = mwifiex_ret_tx_power_cfg(priv, resp); break; case HostCmd_CMD_802_11_PS_MODE_ENH: ret = mwifiex_ret_enh_power_mode(priv, resp, data_buf); @@ -962,6 +952,8 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, case HostCmd_CMD_11N_CFG: ret = mwifiex_ret_11n_cfg(resp, data_buf); break; + case HostCmd_CMD_PCIE_DESC_DETAILS: + break; default: dev_err(adapter->dev, "CMD_RESP: unknown cmd response %#x\n", resp->command); diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index fc265ca..f204810 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -130,8 +130,8 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv) if (netif_carrier_ok(priv->netdev)) netif_carrier_off(priv->netdev); /* Reset wireless stats signal info */ - priv->w_stats.qual.level = 0; - priv->w_stats.qual.noise = 0; + priv->qual_level = 0; + priv->qual_noise = 0; } /* @@ -299,11 +299,6 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) case EVENT_BG_SCAN_REPORT: dev_dbg(adapter->dev, "event: BGS_REPORT\n"); - /* Clear the previous scan result */ - memset(adapter->scan_table, 0x00, - sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP); - adapter->num_in_scan_table = 0; - adapter->bcn_buf_end = adapter->bcn_buf; ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_BG_SCAN_QUERY, HostCmd_ACT_GEN_GET, 0, NULL); diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index a677e7b..5c3c62d 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -53,8 +53,14 @@ int mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist, */ int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter) { - bool cancel_flag = false; - int status = adapter->cmd_wait_q.status; + int status; + struct cmd_ctrl_node *cmd_queued; + + if (!adapter->cmd_queued) + return 0; + + cmd_queued = adapter->cmd_queued; + adapter->cmd_queued = NULL; dev_dbg(adapter->dev, "cmd pending\n"); atomic_inc(&adapter->cmd_pending); @@ -63,15 +69,14 @@ int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter) queue_work(adapter->workqueue, &adapter->main_work); /* Wait for completion */ - wait_event_interruptible(adapter->cmd_wait_q.wait, - adapter->cmd_wait_q.condition); - if (!adapter->cmd_wait_q.condition) - cancel_flag = true; - - if (cancel_flag) { - mwifiex_cancel_pending_ioctl(adapter); - dev_dbg(adapter->dev, "cmd cancel\n"); + status = wait_event_interruptible(adapter->cmd_wait_q.wait, + *(cmd_queued->condition)); + if (status) { + dev_err(adapter->dev, "cmd_wait_q terminated: %d\n", status); + return status; } + + status = adapter->cmd_wait_q.status; adapter->cmd_wait_q.status = 0; return status; @@ -133,90 +138,150 @@ int mwifiex_request_set_multicast_list(struct mwifiex_private *priv, } /* + * This function fills bss descriptor structure using provided + * information. + */ +int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv, + u8 *bssid, s32 rssi, u8 *ie_buf, + size_t ie_len, u16 beacon_period, + u16 cap_info_bitmap, u8 band, + struct mwifiex_bssdescriptor *bss_desc) +{ + int ret; + + memcpy(bss_desc->mac_address, bssid, ETH_ALEN); + bss_desc->rssi = rssi; + bss_desc->beacon_buf = ie_buf; + bss_desc->beacon_buf_size = ie_len; + bss_desc->beacon_period = beacon_period; + bss_desc->cap_info_bitmap = cap_info_bitmap; + bss_desc->bss_band = band; + if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_PRIVACY) { + dev_dbg(priv->adapter->dev, "info: InterpretIE: AP WEP enabled\n"); + bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP; + } else { + bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL; + } + if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_IBSS) + bss_desc->bss_mode = NL80211_IFTYPE_ADHOC; + else + bss_desc->bss_mode = NL80211_IFTYPE_STATION; + + ret = mwifiex_update_bss_desc_with_ie(priv->adapter, bss_desc, + ie_buf, ie_len); + + return ret; +} + +/* * In Ad-Hoc mode, the IBSS is created if not found in scan list. * In both Ad-Hoc and infra mode, an deauthentication is performed * first. */ -int mwifiex_bss_start(struct mwifiex_private *priv, - struct mwifiex_ssid_bssid *ssid_bssid) +int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, + struct mwifiex_802_11_ssid *req_ssid) { int ret; struct mwifiex_adapter *adapter = priv->adapter; - s32 i = -1; + struct mwifiex_bssdescriptor *bss_desc = NULL; + u8 *beacon_ie = NULL; priv->scan_block = false; - if (!ssid_bssid) - return -1; + + if (bss) { + /* Allocate and fill new bss descriptor */ + bss_desc = kzalloc(sizeof(struct mwifiex_bssdescriptor), + GFP_KERNEL); + if (!bss_desc) { + dev_err(priv->adapter->dev, " failed to alloc bss_desc\n"); + return -ENOMEM; + } + + beacon_ie = kmemdup(bss->information_elements, + bss->len_beacon_ies, GFP_KERNEL); + if (!beacon_ie) { + kfree(bss_desc); + dev_err(priv->adapter->dev, " failed to alloc beacon_ie\n"); + return -ENOMEM; + } + + ret = mwifiex_fill_new_bss_desc(priv, bss->bssid, bss->signal, + beacon_ie, bss->len_beacon_ies, + bss->beacon_interval, + bss->capability, + *(u8 *)bss->priv, bss_desc); + if (ret) + goto done; + } if (priv->bss_mode == NL80211_IFTYPE_STATION) { /* Infra mode */ ret = mwifiex_deauthenticate(priv, NULL); if (ret) - return ret; + goto done; - /* Search for the requested SSID in the scan table */ - if (ssid_bssid->ssid.ssid_len) - i = mwifiex_find_ssid_in_list(priv, &ssid_bssid->ssid, - NULL, NL80211_IFTYPE_STATION); - else - i = mwifiex_find_bssid_in_list(priv, - (u8 *) &ssid_bssid->bssid, - NL80211_IFTYPE_STATION); - if (i < 0) - return -1; + ret = mwifiex_check_network_compatibility(priv, bss_desc); + if (ret) + goto done; + + dev_dbg(adapter->dev, "info: SSID found in scan list ... " + "associating...\n"); - dev_dbg(adapter->dev, - "info: SSID found in scan list ... associating...\n"); + if (!netif_queue_stopped(priv->netdev)) + netif_stop_queue(priv->netdev); + if (netif_carrier_ok(priv->netdev)) + netif_carrier_off(priv->netdev); /* Clear any past association response stored for * application retrieval */ priv->assoc_rsp_size = 0; - ret = mwifiex_associate(priv, &adapter->scan_table[i]); - if (ret) - return ret; + ret = mwifiex_associate(priv, bss_desc); + if (bss) + cfg80211_put_bss(bss); } else { /* Adhoc mode */ /* If the requested SSID matches current SSID, return */ - if (ssid_bssid->ssid.ssid_len && + if (bss_desc && bss_desc->ssid.ssid_len && (!mwifiex_ssid_cmp (&priv->curr_bss_params.bss_descriptor.ssid, - &ssid_bssid->ssid))) + &bss_desc->ssid))) { + kfree(bss_desc); + kfree(beacon_ie); return 0; + } /* Exit Adhoc mode first */ dev_dbg(adapter->dev, "info: Sending Adhoc Stop\n"); ret = mwifiex_deauthenticate(priv, NULL); if (ret) - return ret; + goto done; priv->adhoc_is_link_sensed = false; - /* Search for the requested network in the scan table */ - if (ssid_bssid->ssid.ssid_len) - i = mwifiex_find_ssid_in_list(priv, - &ssid_bssid->ssid, NULL, - NL80211_IFTYPE_ADHOC); - else - i = mwifiex_find_bssid_in_list(priv, - (u8 *)&ssid_bssid->bssid, - NL80211_IFTYPE_ADHOC); + ret = mwifiex_check_network_compatibility(priv, bss_desc); + + if (!netif_queue_stopped(priv->netdev)) + netif_stop_queue(priv->netdev); + if (netif_carrier_ok(priv->netdev)) + netif_carrier_off(priv->netdev); - if (i >= 0) { + if (!ret) { dev_dbg(adapter->dev, "info: network found in scan" " list. Joining...\n"); - ret = mwifiex_adhoc_join(priv, &adapter->scan_table[i]); - if (ret) - return ret; + ret = mwifiex_adhoc_join(priv, bss_desc); + if (bss) + cfg80211_put_bss(bss); } else { dev_dbg(adapter->dev, "info: Network not found in " "the list, creating adhoc with ssid = %s\n", - ssid_bssid->ssid.ssid); - ret = mwifiex_adhoc_start(priv, &ssid_bssid->ssid); - if (ret) - return ret; + req_ssid->ssid); + ret = mwifiex_adhoc_start(priv, req_ssid); } } +done: + kfree(bss_desc); + kfree(beacon_ie); return ret; } @@ -226,8 +291,8 @@ int mwifiex_bss_start(struct mwifiex_private *priv, * This function prepares the correct firmware command and * issues it. */ -int mwifiex_set_hs_params(struct mwifiex_private *priv, u16 action, - int cmd_type, struct mwifiex_ds_hs_cfg *hs_cfg) +static int mwifiex_set_hs_params(struct mwifiex_private *priv, u16 action, + int cmd_type, struct mwifiex_ds_hs_cfg *hs_cfg) { struct mwifiex_adapter *adapter = priv->adapter; @@ -349,8 +414,11 @@ int mwifiex_enable_hs(struct mwifiex_adapter *adapter) return false; } - wait_event_interruptible(adapter->hs_activate_wait_q, - adapter->hs_activate_wait_q_woken); + if (wait_event_interruptible(adapter->hs_activate_wait_q, + adapter->hs_activate_wait_q_woken)) { + dev_err(adapter->dev, "hs_activate_wait_q terminated\n"); + return false; + } return true; } @@ -367,7 +435,6 @@ int mwifiex_get_bss_info(struct mwifiex_private *priv, { struct mwifiex_adapter *adapter = priv->adapter; struct mwifiex_bssdescriptor *bss_desc; - s32 tbl_idx; if (!info) return -1; @@ -385,17 +452,6 @@ int mwifiex_get_bss_info(struct mwifiex_private *priv, info->region_code = adapter->region_code; - /* Scan table index if connected */ - info->scan_table_idx = 0; - if (priv->media_connected) { - tbl_idx = - mwifiex_find_ssid_in_list(priv, &bss_desc->ssid, - bss_desc->mac_address, - priv->bss_mode); - if (tbl_idx >= 0) - info->scan_table_idx = tbl_idx; - } - info->media_connected = priv->media_connected; info->max_power_level = priv->max_tx_power_level; @@ -478,6 +534,20 @@ int mwifiex_set_radio_band_cfg(struct mwifiex_private *priv, } /* + * The function disables auto deep sleep mode. + */ +int mwifiex_disable_auto_ds(struct mwifiex_private *priv) +{ + struct mwifiex_ds_auto_ds auto_ds; + + auto_ds.auto_ds = DEEP_SLEEP_OFF; + + return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_PS_MODE_ENH, + DIS_AUTO_PS, BITMAP_AUTO_DS, &auto_ds); +} +EXPORT_SYMBOL_GPL(mwifiex_disable_auto_ds); + +/* * IOCTL request handler to set/get active channel. * * This function performs validity checking on channel/frequency @@ -563,50 +633,6 @@ static int mwifiex_bss_ioctl_ibss_channel(struct mwifiex_private *priv, } /* - * IOCTL request handler to find a particular BSS. - * - * The BSS can be searched with either a BSSID or a SSID. If none of - * these are provided, just the best BSS (best RSSI) is returned. - */ -int mwifiex_bss_ioctl_find_bss(struct mwifiex_private *priv, - struct mwifiex_ssid_bssid *ssid_bssid) -{ - struct mwifiex_adapter *adapter = priv->adapter; - struct mwifiex_bssdescriptor *bss_desc; - u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; - u8 mac[ETH_ALEN]; - int i = 0; - - if (memcmp(ssid_bssid->bssid, zero_mac, sizeof(zero_mac))) { - i = mwifiex_find_bssid_in_list(priv, - (u8 *) ssid_bssid->bssid, - priv->bss_mode); - if (i < 0) { - memcpy(mac, ssid_bssid->bssid, sizeof(mac)); - dev_err(adapter->dev, "cannot find bssid %pM\n", mac); - return -1; - } - bss_desc = &adapter->scan_table[i]; - memcpy(&ssid_bssid->ssid, &bss_desc->ssid, - sizeof(struct mwifiex_802_11_ssid)); - } else if (ssid_bssid->ssid.ssid_len) { - i = mwifiex_find_ssid_in_list(priv, &ssid_bssid->ssid, NULL, - priv->bss_mode); - if (i < 0) { - dev_err(adapter->dev, "cannot find ssid %s\n", - ssid_bssid->ssid.ssid); - return -1; - } - bss_desc = &adapter->scan_table[i]; - memcpy(ssid_bssid->bssid, bss_desc->mac_address, ETH_ALEN); - } else { - return mwifiex_find_best_network(priv, ssid_bssid); - } - - return 0; -} - -/* * IOCTL request handler to change Ad-Hoc channel. * * This function allocates the IOCTL request buffer, fills it @@ -630,6 +656,9 @@ mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel) struct mwifiex_bss_info bss_info; struct mwifiex_ssid_bssid ssid_bssid; u16 curr_chan = 0; + struct cfg80211_bss *bss = NULL; + struct ieee80211_channel *chan; + enum ieee80211_band band; memset(&bss_info, 0, sizeof(bss_info)); @@ -665,12 +694,20 @@ mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel) ret = -1; goto done; } - /* Start/Join Adhoc network */ - memset(&ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid)); - memcpy(&ssid_bssid.ssid, &bss_info.ssid, - sizeof(struct mwifiex_802_11_ssid)); - ret = mwifiex_bss_start(priv, &ssid_bssid); + band = mwifiex_band_to_radio_type(priv->curr_bss_params.band); + chan = __ieee80211_get_channel(priv->wdev->wiphy, + ieee80211_channel_to_frequency(channel, band)); + + /* Find the BSS we want using available scan results */ + bss = cfg80211_get_bss(priv->wdev->wiphy, chan, bss_info.bssid, + bss_info.ssid.ssid, bss_info.ssid.ssid_len, + WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); + if (!bss) + wiphy_warn(priv->wdev->wiphy, "assoc: bss %pM not in scan results\n", + bss_info.bssid); + + ret = mwifiex_bss_start(priv, bss, &bss_info.ssid); done: return ret; } @@ -686,51 +723,9 @@ done: static int mwifiex_rate_ioctl_get_rate_value(struct mwifiex_private *priv, struct mwifiex_rate_cfg *rate_cfg) { - struct mwifiex_adapter *adapter = priv->adapter; - rate_cfg->is_rate_auto = priv->is_data_rate_auto; - if (!priv->media_connected) { - switch (adapter->config_bands) { - case BAND_B: - /* Return the lowest supported rate for B band */ - rate_cfg->rate = supported_rates_b[0] & 0x7f; - break; - case BAND_G: - case BAND_G | BAND_GN: - /* Return the lowest supported rate for G band */ - rate_cfg->rate = supported_rates_g[0] & 0x7f; - break; - case BAND_B | BAND_G: - case BAND_A | BAND_B | BAND_G: - case BAND_A | BAND_B: - case BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN: - case BAND_B | BAND_G | BAND_GN: - /* Return the lowest supported rate for BG band */ - rate_cfg->rate = supported_rates_bg[0] & 0x7f; - break; - case BAND_A: - case BAND_A | BAND_G: - case BAND_A | BAND_G | BAND_AN | BAND_GN: - case BAND_A | BAND_AN: - /* Return the lowest supported rate for A band */ - rate_cfg->rate = supported_rates_a[0] & 0x7f; - break; - case BAND_GN: - /* Return the lowest supported rate for N band */ - rate_cfg->rate = supported_rates_n[0] & 0x7f; - break; - default: - dev_warn(adapter->dev, "invalid band %#x\n", - adapter->config_bands); - break; - } - } else { - return mwifiex_send_cmd_sync(priv, - HostCmd_CMD_802_11_TX_RATE_QUERY, - HostCmd_ACT_GEN_GET, 0, NULL); - } - - return 0; + return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_TX_RATE_QUERY, + HostCmd_ACT_GEN_GET, 0, NULL); } /* @@ -771,7 +766,7 @@ static int mwifiex_rate_ioctl_set_rate_value(struct mwifiex_private *priv, if ((rate[i] & 0x7f) == (rate_cfg->rate & 0x7f)) break; } - if (!rate[i] || (i == MWIFIEX_SUPPORTED_RATES)) { + if ((i == MWIFIEX_SUPPORTED_RATES) || !rate[i]) { dev_err(adapter->dev, "fixed data rate %#x is out " "of range\n", rate_cfg->rate); return -1; @@ -837,10 +832,10 @@ int mwifiex_drv_get_data_rate(struct mwifiex_private *priv, ret = mwifiex_rate_ioctl_cfg(priv, rate); if (!ret) { - if (rate && rate->is_rate_auto) + if (rate->is_rate_auto) rate->rate = mwifiex_index_to_data_rate(priv->tx_rate, priv->tx_htinfo); - else if (rate) + else rate->rate = priv->data_rate; } else { ret = -1; @@ -1257,9 +1252,9 @@ int mwifiex_get_signal_info(struct mwifiex_private *priv, if (!status) { if (signal->selector & BCN_RSSI_AVG_MASK) - priv->w_stats.qual.level = signal->bcn_rssi_avg; + priv->qual_level = signal->bcn_rssi_avg; if (signal->selector & BCN_NF_AVG_MASK) - priv->w_stats.qual.noise = signal->bcn_nf_avg; + priv->qual_noise = signal->bcn_nf_avg; } return status; @@ -1318,18 +1313,8 @@ int mwifiex_get_stats_info(struct mwifiex_private *priv, struct mwifiex_ds_get_stats *log) { - int ret; - - ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_GET_LOG, + return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_GET_LOG, HostCmd_ACT_GEN_GET, 0, log); - - if (!ret) { - priv->w_stats.discard.fragment = log->fcs_error; - priv->w_stats.discard.retries = log->retry; - priv->w_stats.discard.misc = log->ack_failure; - } - - return ret; } /* @@ -1571,7 +1556,7 @@ mwifiex_set_gen_ie(struct mwifiex_private *priv, u8 *ie, int ie_len) { struct mwifiex_ds_misc_gen_ie gen_ie; - if (ie_len > IW_CUSTOM_MAX) + if (ie_len > IEEE_MAX_IE_SIZE) return -EFAULT; gen_ie.type = MWIFIEX_IE_TYPE_GEN_IE; diff --git a/drivers/net/wireless/mwifiex/sta_rx.c b/drivers/net/wireless/mwifiex/sta_rx.c index 1fdddec..2743051 100644 --- a/drivers/net/wireless/mwifiex/sta_rx.c +++ b/drivers/net/wireless/mwifiex/sta_rx.c @@ -187,7 +187,7 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *adapter, ret = mwifiex_11n_rx_reorder_pkt(priv, local_rx_pd->seq_num, local_rx_pd->priority, ta, (u8) local_rx_pd->rx_pkt_type, - (void *) skb); + skb); if (ret || (rx_pkt_type == PKT_TYPE_BAR)) { if (priv && (ret == -1)) diff --git a/drivers/net/wireless/mwifiex/sta_tx.c b/drivers/net/wireless/mwifiex/sta_tx.c index fa6221b..d97facd 100644 --- a/drivers/net/wireless/mwifiex/sta_tx.c +++ b/drivers/net/wireless/mwifiex/sta_tx.c @@ -47,6 +47,7 @@ void *mwifiex_process_sta_txpd(struct mwifiex_private *priv, struct mwifiex_adapter *adapter = priv->adapter; struct txpd *local_tx_pd; struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb); + u8 pad; if (!skb->len) { dev_err(adapter->dev, "Tx: bad packet length: %d\n", @@ -55,15 +56,19 @@ void *mwifiex_process_sta_txpd(struct mwifiex_private *priv, return skb->data; } - BUG_ON(skb_headroom(skb) < (sizeof(*local_tx_pd) + INTF_HEADER_LEN)); - skb_push(skb, sizeof(*local_tx_pd)); + /* If skb->data is not aligned; add padding */ + pad = (4 - (((void *)skb->data - NULL) & 0x3)) % 4; + + BUG_ON(skb_headroom(skb) < (sizeof(*local_tx_pd) + INTF_HEADER_LEN + + pad)); + skb_push(skb, sizeof(*local_tx_pd) + pad); local_tx_pd = (struct txpd *) skb->data; memset(local_tx_pd, 0, sizeof(struct txpd)); local_tx_pd->bss_num = priv->bss_num; local_tx_pd->bss_type = priv->bss_type; local_tx_pd->tx_pkt_length = cpu_to_le16((u16) (skb->len - - sizeof(struct txpd))); + (sizeof(struct txpd) + pad))); local_tx_pd->priority = (u8) skb->priority; local_tx_pd->pkt_delay_2ms = @@ -88,7 +93,7 @@ void *mwifiex_process_sta_txpd(struct mwifiex_private *priv, } /* Offset of actual data */ - local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd)); + local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd) + pad); /* make space for INTF_HEADER_LEN */ skb_push(skb, INTF_HEADER_LEN); @@ -146,7 +151,7 @@ int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags) skb_push(skb, INTF_HEADER_LEN); ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, - skb->data, skb->len, NULL); + skb, NULL); switch (ret) { case -EBUSY: adapter->data_sent = true; diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c index aaa50c0..a206f41 100644 --- a/drivers/net/wireless/mwifiex/txrx.c +++ b/drivers/net/wireless/mwifiex/txrx.c @@ -71,14 +71,14 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb, u8 *head_ptr; struct txpd *local_tx_pd = NULL; - head_ptr = (u8 *) mwifiex_process_sta_txpd(priv, skb); + head_ptr = 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); + skb, tx_param); } switch (ret) { @@ -87,7 +87,8 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb, (adapter->pps_uapsd_mode) && (adapter->tx_lock_flag)) { priv->adapter->tx_lock_flag = false; - local_tx_pd->flags = 0; + if (local_tx_pd) + local_tx_pd->flags = 0; } dev_dbg(adapter->dev, "data: -EBUSY is returned\n"); break; @@ -160,43 +161,3 @@ done: return 0; } -/* - * Packet receive completion callback handler. - * - * This function calls another completion callback handler which - * updates the statistics, and optionally updates the parent buffer - * use count before freeing the received packet. - */ -int mwifiex_recv_packet_complete(struct mwifiex_adapter *adapter, - struct sk_buff *skb, int status) -{ - struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); - struct mwifiex_rxinfo *rx_info_parent; - struct mwifiex_private *priv; - struct sk_buff *skb_parent; - unsigned long flags; - - priv = adapter->priv[rx_info->bss_index]; - - if (priv && (status == -1)) - priv->stats.rx_dropped++; - - if (rx_info->parent) { - skb_parent = rx_info->parent; - rx_info_parent = MWIFIEX_SKB_RXCB(skb_parent); - - spin_lock_irqsave(&priv->rx_pkt_lock, flags); - --rx_info_parent->use_count; - - if (!rx_info_parent->use_count) { - spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); - dev_kfree_skb_any(skb_parent); - } else { - spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); - } - } else { - dev_kfree_skb_any(skb); - } - - return 0; -} diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c index d412915..06976f5 100644 --- a/drivers/net/wireless/mwifiex/util.c +++ b/drivers/net/wireless/mwifiex/util.c @@ -185,13 +185,14 @@ int mwifiex_recv_packet(struct mwifiex_adapter *adapter, struct sk_buff *skb) * corresponding waiting function. Otherwise, it processes the * IOCTL response and frees the response buffer. */ -int mwifiex_complete_cmd(struct mwifiex_adapter *adapter) +int mwifiex_complete_cmd(struct mwifiex_adapter *adapter, + struct cmd_ctrl_node *cmd_node) { atomic_dec(&adapter->cmd_pending); dev_dbg(adapter->dev, "cmd completed: status=%d\n", adapter->cmd_wait_q.status); - adapter->cmd_wait_q.condition = true; + *(cmd_node->condition) = true; if (adapter->cmd_wait_q.status == -ETIMEDOUT) dev_err(adapter->dev, "cmd timeout\n"); diff --git a/drivers/net/wireless/mwifiex/util.h b/drivers/net/wireless/mwifiex/util.h index 9506afc..f6d36b9 100644 --- a/drivers/net/wireless/mwifiex/util.h +++ b/drivers/net/wireless/mwifiex/util.h @@ -22,11 +22,16 @@ static inline struct mwifiex_rxinfo *MWIFIEX_SKB_RXCB(struct sk_buff *skb) { - return (struct mwifiex_rxinfo *)skb->cb; + return (struct mwifiex_rxinfo *)(skb->cb + sizeof(phys_addr_t)); } static inline struct mwifiex_txinfo *MWIFIEX_SKB_TXCB(struct sk_buff *skb) { - return (struct mwifiex_txinfo *)skb->cb; + return (struct mwifiex_txinfo *)(skb->cb + sizeof(phys_addr_t)); +} + +static inline phys_addr_t *MWIFIEX_SKB_PACB(struct sk_buff *skb) +{ + return (phys_addr_t *)skb->cb; } #endif /* !_MWIFIEX_UTIL_H_ */ diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index 2cdb41a..06fcf1e 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -635,6 +635,8 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_adapter *adapter, ra_list = NULL; } else { memcpy(ra, skb->data, ETH_ALEN); + if (ra[0] & 0x01) + memset(ra, 0xff, ETH_ALEN); ra_list = mwifiex_wmm_get_queue_raptr(priv, tid_down, ra); } @@ -973,25 +975,25 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter, } /* - * This function gets the number of packets in the Tx queue of a - * particular RA list. + * This function checks if 11n aggregation is possible. */ static int -mwifiex_num_pkts_in_txq(struct mwifiex_private *priv, - struct mwifiex_ra_list_tbl *ptr, int max_buf_size) +mwifiex_is_11n_aggragation_possible(struct mwifiex_private *priv, + struct mwifiex_ra_list_tbl *ptr, + int max_buf_size) { int count = 0, total_size = 0; struct sk_buff *skb, *tmp; skb_queue_walk_safe(&ptr->skb_head, skb, tmp) { total_size += skb->len; - if (total_size < max_buf_size) - ++count; - else + if (total_size >= max_buf_size) break; + if (++count >= MIN_NUM_AMSDU) + return true; } - return count; + return false; } /* @@ -1125,8 +1127,8 @@ mwifiex_send_processed_packet(struct mwifiex_private *priv, tx_param.next_pkt_len = ((skb_next) ? skb_next->len + sizeof(struct txpd) : 0); - ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, - skb->data, skb->len, &tx_param); + ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, skb, + &tx_param); switch (ret) { case -EBUSY: dev_dbg(adapter->dev, "data: -EBUSY is returned\n"); @@ -1209,10 +1211,12 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter) return 0; } - if (!ptr->is_11n_enabled || mwifiex_is_ba_stream_setup(priv, ptr, tid) - || ((priv->sec_info.wpa_enabled - || priv->sec_info.wpa2_enabled) && !priv->wpa_is_gtk_set) - ) { + if (!ptr->is_11n_enabled || + mwifiex_is_ba_stream_setup(priv, ptr, tid) || + priv->wps.session_enable || + ((priv->sec_info.wpa_enabled || + priv->sec_info.wpa2_enabled) && + !priv->wpa_is_gtk_set)) { mwifiex_send_single_packet(priv, ptr, ptr_index, flags); /* ra_list_spinlock has been freed in mwifiex_send_single_packet() */ @@ -1231,11 +1235,9 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter) mwifiex_send_delba(priv, tid_del, ra, 1); } } -/* Minimum number of AMSDU */ -#define MIN_NUM_AMSDU 2 if (mwifiex_is_amsdu_allowed(priv, tid) && - (mwifiex_num_pkts_in_txq(priv, ptr, adapter->tx_buf_size) >= - MIN_NUM_AMSDU)) + mwifiex_is_11n_aggragation_possible(priv, ptr, + adapter->tx_buf_size)) mwifiex_11n_aggregate_pkt(priv, ptr, INTF_HEADER_LEN, ptr_index, flags); /* ra_list_spinlock has been freed in |