}
/*
- * 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
*/
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
* 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,
*/
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
* 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,
*/
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
&& 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,
* 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)
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)
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,
}
/*
- * 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.
*
}
/*
- * 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;
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:
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;
}
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.
*/
}
/*
- * 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.
*
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;
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) * MWIFIEX_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);
}
/*
+ * 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)
+{
+ struct mwifiex_bssdescriptor *bss_desc = NULL;
+ 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 = kzalloc(ie_len, GFP_KERNEL);
+ if (!bss_desc) {
+ dev_err(priv->adapter->dev, " failed to alloc bss_desc\n");
+ return -ENOMEM;
+ }
+ memcpy(beacon_ie, ie_buf, ie_len);
+
+ ret = mwifiex_fill_new_bss_desc(priv, bssid, rssi, beacon_ie,
+ ie_len, beacon_period,
+ cap_info_bitmap, 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;
+}
+
+/*
* This function handles the command response of scan.
*
* The response buffer for the scan command has the following
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;
"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;
/*
(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);
}
- /* 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);
+ if (!beacon_size || beacon_size > bytes_left) {
+ bss_info += bytes_left;
+ bytes_left = 0;
+ return -1;
+ }
- /* 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;
+ /* Initialize the current working beacon pointer for this BSS
+ * iteration */
+ current_ptr = bss_info;
+
+ /* 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 done;
}
- /*
- * 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 == MWIFIEX_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)));
- }
-
- /* 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);
+ 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)));
+ }
- if (cfp)
- bss_new_entry->freq = cfp->freq;
- else
- bss_new_entry->freq = 0;
+ cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211(
+ priv, (u8)band, (u16)channel);
- /* 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]));
+ freq = cfp ? cfp->freq : 0;
- }
+ chan = ieee80211_get_channel(priv->wdev->wiphy, freq);
- 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);
+ if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) {
+ cfg80211_inform_bss(priv->wdev->wiphy, chan,
+ bssid, network_tsf, cap_info_bitmap,
+ beacon_period, ie_buf, ie_len, rssi,
+ GFP_KERNEL);
- /* 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);
+ }
+ } else {
+ dev_dbg(adapter->dev, "missing BSS channel IE\n");
+ }
+ }
spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
if (list_empty(&adapter->scan_pending_q)) {
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) {
}
done:
- kfree((u8 *) bss_new_entry);
return ret;
}
}
/*
- * 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
}
/*
- * 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.
*/
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");
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);
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);
}
/*