LCOV - code coverage report
Current view: top level - src/drivers - driver_nl80211_scan.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1422976643 Lines: 247 380 65.0 %
Date: 2015-02-03 Functions: 10 15 66.7 %

          Line data    Source code
       1             : /*
       2             :  * Driver interaction with Linux nl80211/cfg80211 - Scanning
       3             :  * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
       4             :  * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
       5             :  * Copyright (c) 2009-2010, Atheros Communications
       6             :  *
       7             :  * This software may be distributed under the terms of the BSD license.
       8             :  * See README for more details.
       9             :  */
      10             : 
      11             : #include "includes.h"
      12             : #include <netlink/genl/genl.h>
      13             : 
      14             : #include "utils/common.h"
      15             : #include "utils/eloop.h"
      16             : #include "common/ieee802_11_defs.h"
      17             : #include "driver_nl80211.h"
      18             : 
      19             : 
      20        2790 : static int get_noise_for_scan_results(struct nl_msg *msg, void *arg)
      21             : {
      22             :         struct nlattr *tb[NL80211_ATTR_MAX + 1];
      23        2790 :         struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
      24             :         struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
      25             :         static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
      26             :                 [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
      27             :                 [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
      28             :         };
      29        2790 :         struct wpa_scan_results *scan_results = arg;
      30             :         struct wpa_scan_res *scan_res;
      31             :         size_t i;
      32             : 
      33        2790 :         nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
      34             :                   genlmsg_attrlen(gnlh, 0), NULL);
      35             : 
      36        2790 :         if (!tb[NL80211_ATTR_SURVEY_INFO]) {
      37           0 :                 wpa_printf(MSG_DEBUG, "nl80211: Survey data missing");
      38           0 :                 return NL_SKIP;
      39             :         }
      40             : 
      41        2790 :         if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
      42             :                              tb[NL80211_ATTR_SURVEY_INFO],
      43             :                              survey_policy)) {
      44           0 :                 wpa_printf(MSG_DEBUG, "nl80211: Failed to parse nested "
      45             :                            "attributes");
      46           0 :                 return NL_SKIP;
      47             :         }
      48             : 
      49        2790 :         if (!sinfo[NL80211_SURVEY_INFO_NOISE])
      50           0 :                 return NL_SKIP;
      51             : 
      52        2790 :         if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY])
      53           0 :                 return NL_SKIP;
      54             : 
      55        6484 :         for (i = 0; i < scan_results->num; ++i) {
      56        3694 :                 scan_res = scan_results->res[i];
      57        3694 :                 if (!scan_res)
      58           0 :                         continue;
      59        7388 :                 if ((int) nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) !=
      60        3694 :                     scan_res->freq)
      61        1322 :                         continue;
      62        2372 :                 if (!(scan_res->flags & WPA_SCAN_NOISE_INVALID))
      63           0 :                         continue;
      64        2372 :                 scan_res->noise = (s8)
      65        2372 :                         nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
      66        2372 :                 scan_res->flags &= ~WPA_SCAN_NOISE_INVALID;
      67             :         }
      68             : 
      69        2790 :         return NL_SKIP;
      70             : }
      71             : 
      72             : 
      73        2811 : static int nl80211_get_noise_for_scan_results(
      74             :         struct wpa_driver_nl80211_data *drv,
      75             :         struct wpa_scan_results *scan_res)
      76             : {
      77             :         struct nl_msg *msg;
      78             : 
      79        2811 :         msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
      80        2811 :         return send_and_recv_msgs(drv, msg, get_noise_for_scan_results,
      81             :                                   scan_res);
      82             : }
      83             : 
      84             : 
      85             : /**
      86             :  * wpa_driver_nl80211_scan_timeout - Scan timeout to report scan completion
      87             :  * @eloop_ctx: Driver private data
      88             :  * @timeout_ctx: ctx argument given to wpa_driver_nl80211_init()
      89             :  *
      90             :  * This function can be used as registered timeout when starting a scan to
      91             :  * generate a scan completed event if the driver does not report this.
      92             :  */
      93           0 : void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx)
      94             : {
      95           0 :         struct wpa_driver_nl80211_data *drv = eloop_ctx;
      96           0 :         if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED) {
      97           0 :                 wpa_driver_nl80211_set_mode(drv->first_bss,
      98             :                                             drv->ap_scan_as_station);
      99           0 :                 drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
     100             :         }
     101           0 :         wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
     102           0 :         wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
     103           0 : }
     104             : 
     105             : 
     106             : static struct nl_msg *
     107        2848 : nl80211_scan_common(struct i802_bss *bss, u8 cmd,
     108             :                     struct wpa_driver_scan_params *params)
     109             : {
     110        2848 :         struct wpa_driver_nl80211_data *drv = bss->drv;
     111             :         struct nl_msg *msg;
     112             :         size_t i;
     113        2848 :         u32 scan_flags = 0;
     114             : 
     115        2848 :         msg = nl80211_cmd_msg(bss, 0, cmd);
     116        2848 :         if (!msg)
     117           0 :                 return NULL;
     118             : 
     119        2848 :         if (params->num_ssids) {
     120             :                 struct nlattr *ssids;
     121             : 
     122        2713 :                 ssids = nla_nest_start(msg, NL80211_ATTR_SCAN_SSIDS);
     123        2713 :                 if (ssids == NULL)
     124           0 :                         goto fail;
     125        5441 :                 for (i = 0; i < params->num_ssids; i++) {
     126        5456 :                         wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan SSID",
     127        2728 :                                           params->ssids[i].ssid,
     128             :                                           params->ssids[i].ssid_len);
     129        2728 :                         if (nla_put(msg, i + 1, params->ssids[i].ssid_len,
     130        2728 :                                     params->ssids[i].ssid))
     131           0 :                                 goto fail;
     132             :                 }
     133        2713 :                 nla_nest_end(msg, ssids);
     134             :         }
     135             : 
     136        2848 :         if (params->extra_ies) {
     137        5442 :                 wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan extra IEs",
     138        2721 :                             params->extra_ies, params->extra_ies_len);
     139        2721 :                 if (nla_put(msg, NL80211_ATTR_IE, params->extra_ies_len,
     140        2721 :                             params->extra_ies))
     141           0 :                         goto fail;
     142             :         }
     143             : 
     144        2848 :         if (params->freqs) {
     145             :                 struct nlattr *freqs;
     146        2639 :                 freqs = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES);
     147        2639 :                 if (freqs == NULL)
     148           0 :                         goto fail;
     149        7571 :                 for (i = 0; params->freqs[i]; i++) {
     150        4932 :                         wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u "
     151        4932 :                                    "MHz", params->freqs[i]);
     152        4932 :                         if (nla_put_u32(msg, i + 1, params->freqs[i]))
     153           0 :                                 goto fail;
     154             :                 }
     155        2639 :                 nla_nest_end(msg, freqs);
     156             :         }
     157             : 
     158        2848 :         os_free(drv->filter_ssids);
     159        2848 :         drv->filter_ssids = params->filter_ssids;
     160        2848 :         params->filter_ssids = NULL;
     161        2848 :         drv->num_filter_ssids = params->num_filter_ssids;
     162             : 
     163        2848 :         if (params->only_new_results) {
     164        1186 :                 wpa_printf(MSG_DEBUG, "nl80211: Add NL80211_SCAN_FLAG_FLUSH");
     165        1186 :                 scan_flags |= NL80211_SCAN_FLAG_FLUSH;
     166             :         }
     167             : 
     168        2848 :         if (params->low_priority && drv->have_low_prio_scan) {
     169           4 :                 wpa_printf(MSG_DEBUG,
     170             :                            "nl80211: Add NL80211_SCAN_FLAG_LOW_PRIORITY");
     171           4 :                 scan_flags |= NL80211_SCAN_FLAG_LOW_PRIORITY;
     172             :         }
     173             : 
     174        2848 :         if (params->mac_addr_rand) {
     175           3 :                 wpa_printf(MSG_DEBUG,
     176             :                            "nl80211: Add NL80211_SCAN_FLAG_RANDOM_ADDR");
     177           3 :                 scan_flags |= NL80211_SCAN_FLAG_RANDOM_ADDR;
     178             : 
     179           3 :                 if (params->mac_addr) {
     180          12 :                         wpa_printf(MSG_DEBUG, "nl80211: MAC address: " MACSTR,
     181          12 :                                    MAC2STR(params->mac_addr));
     182           2 :                         if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN,
     183           2 :                                     params->mac_addr))
     184           0 :                                 goto fail;
     185             :                 }
     186             : 
     187           3 :                 if (params->mac_addr_mask) {
     188          12 :                         wpa_printf(MSG_DEBUG, "nl80211: MAC address mask: "
     189          12 :                                    MACSTR, MAC2STR(params->mac_addr_mask));
     190           2 :                         if (nla_put(msg, NL80211_ATTR_MAC_MASK, ETH_ALEN,
     191           2 :                                     params->mac_addr_mask))
     192           0 :                                 goto fail;
     193             :                 }
     194             :         }
     195             : 
     196        4040 :         if (scan_flags &&
     197        1192 :             nla_put_u32(msg, NL80211_ATTR_SCAN_FLAGS, scan_flags))
     198           0 :                 goto fail;
     199             : 
     200        2848 :         return msg;
     201             : 
     202             : fail:
     203           0 :         nlmsg_free(msg);
     204           0 :         return NULL;
     205             : }
     206             : 
     207             : 
     208             : /**
     209             :  * wpa_driver_nl80211_scan - Request the driver to initiate scan
     210             :  * @bss: Pointer to private driver data from wpa_driver_nl80211_init()
     211             :  * @params: Scan parameters
     212             :  * Returns: 0 on success, -1 on failure
     213             :  */
     214        2848 : int wpa_driver_nl80211_scan(struct i802_bss *bss,
     215             :                             struct wpa_driver_scan_params *params)
     216             : {
     217        2848 :         struct wpa_driver_nl80211_data *drv = bss->drv;
     218        2848 :         int ret = -1, timeout;
     219        2848 :         struct nl_msg *msg = NULL;
     220             : 
     221        2848 :         wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: scan request");
     222        2848 :         drv->scan_for_auth = 0;
     223             : 
     224        2848 :         msg = nl80211_scan_common(bss, NL80211_CMD_TRIGGER_SCAN, params);
     225        2848 :         if (!msg)
     226           0 :                 return -1;
     227             : 
     228        2848 :         if (params->p2p_probe) {
     229             :                 struct nlattr *rates;
     230             : 
     231        1030 :                 wpa_printf(MSG_DEBUG, "nl80211: P2P probe - mask SuppRates");
     232             : 
     233        1030 :                 rates = nla_nest_start(msg, NL80211_ATTR_SCAN_SUPP_RATES);
     234        1030 :                 if (rates == NULL)
     235           0 :                         goto fail;
     236             : 
     237             :                 /*
     238             :                  * Remove 2.4 GHz rates 1, 2, 5.5, 11 Mbps from supported rates
     239             :                  * by masking out everything else apart from the OFDM rates 6,
     240             :                  * 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS rates. All 5 GHz
     241             :                  * rates are left enabled.
     242             :                  */
     243        1030 :                 if (nla_put(msg, NL80211_BAND_2GHZ, 8,
     244             :                             "\x0c\x12\x18\x24\x30\x48\x60\x6c"))
     245           0 :                         goto fail;
     246        1030 :                 nla_nest_end(msg, rates);
     247             : 
     248        1030 :                 if (nla_put_flag(msg, NL80211_ATTR_TX_NO_CCK_RATE))
     249           0 :                         goto fail;
     250             :         }
     251             : 
     252        2848 :         ret = send_and_recv_msgs(drv, msg, NULL, NULL);
     253        2848 :         msg = NULL;
     254        2848 :         if (ret) {
     255          34 :                 wpa_printf(MSG_DEBUG, "nl80211: Scan trigger failed: ret=%d "
     256             :                            "(%s)", ret, strerror(-ret));
     257          34 :                 if (drv->hostapd && is_ap_interface(drv->nlmode)) {
     258          15 :                         enum nl80211_iftype old_mode = drv->nlmode;
     259             : 
     260             :                         /*
     261             :                          * mac80211 does not allow scan requests in AP mode, so
     262             :                          * try to do this in station mode.
     263             :                          */
     264          15 :                         if (wpa_driver_nl80211_set_mode(
     265             :                                     bss, NL80211_IFTYPE_STATION))
     266           0 :                                 goto fail;
     267             : 
     268          15 :                         if (wpa_driver_nl80211_scan(bss, params)) {
     269          15 :                                 wpa_driver_nl80211_set_mode(bss, old_mode);
     270          15 :                                 goto fail;
     271             :                         }
     272             : 
     273             :                         /* Restore AP mode when processing scan results */
     274           0 :                         drv->ap_scan_as_station = old_mode;
     275           0 :                         ret = 0;
     276             :                 } else
     277             :                         goto fail;
     278             :         }
     279             : 
     280        2814 :         drv->scan_state = SCAN_REQUESTED;
     281             :         /* Not all drivers generate "scan completed" wireless event, so try to
     282             :          * read results after a timeout. */
     283        2814 :         timeout = 10;
     284        2814 :         if (drv->scan_complete_events) {
     285             :                 /*
     286             :                  * The driver seems to deliver events to notify when scan is
     287             :                  * complete, so use longer timeout to avoid race conditions
     288             :                  * with scanning and following association request.
     289             :                  */
     290        2673 :                 timeout = 30;
     291             :         }
     292        2814 :         wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d "
     293             :                    "seconds", ret, timeout);
     294        2814 :         eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
     295        2814 :         eloop_register_timeout(timeout, 0, wpa_driver_nl80211_scan_timeout,
     296             :                                drv, drv->ctx);
     297             : 
     298             : fail:
     299        2848 :         nlmsg_free(msg);
     300        2848 :         return ret;
     301             : }
     302             : 
     303             : 
     304             : /**
     305             :  * wpa_driver_nl80211_sched_scan - Initiate a scheduled scan
     306             :  * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
     307             :  * @params: Scan parameters
     308             :  * @interval: Interval between scan cycles in milliseconds
     309             :  * Returns: 0 on success, -1 on failure or if not supported
     310             :  */
     311           0 : int wpa_driver_nl80211_sched_scan(void *priv,
     312             :                                   struct wpa_driver_scan_params *params,
     313             :                                   u32 interval)
     314             : {
     315           0 :         struct i802_bss *bss = priv;
     316           0 :         struct wpa_driver_nl80211_data *drv = bss->drv;
     317           0 :         int ret = -1;
     318             :         struct nl_msg *msg;
     319             :         size_t i;
     320             : 
     321           0 :         wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: sched_scan request");
     322             : 
     323             : #ifdef ANDROID
     324             :         if (!drv->capa.sched_scan_supported)
     325             :                 return android_pno_start(bss, params);
     326             : #endif /* ANDROID */
     327             : 
     328           0 :         msg = nl80211_scan_common(bss, NL80211_CMD_START_SCHED_SCAN, params);
     329           0 :         if (!msg ||
     330           0 :             nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL, interval))
     331             :                 goto fail;
     332             : 
     333           0 :         if ((drv->num_filter_ssids &&
     334           0 :             (int) drv->num_filter_ssids <= drv->capa.max_match_sets) ||
     335           0 :             params->filter_rssi) {
     336             :                 struct nlattr *match_sets;
     337           0 :                 match_sets = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_MATCH);
     338           0 :                 if (match_sets == NULL)
     339           0 :                         goto fail;
     340             : 
     341           0 :                 for (i = 0; i < drv->num_filter_ssids; i++) {
     342             :                         struct nlattr *match_set_ssid;
     343           0 :                         wpa_hexdump_ascii(MSG_MSGDUMP,
     344             :                                           "nl80211: Sched scan filter SSID",
     345           0 :                                           drv->filter_ssids[i].ssid,
     346           0 :                                           drv->filter_ssids[i].ssid_len);
     347             : 
     348           0 :                         match_set_ssid = nla_nest_start(msg, i + 1);
     349           0 :                         if (match_set_ssid == NULL ||
     350           0 :                             nla_put(msg, NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
     351           0 :                                     drv->filter_ssids[i].ssid_len,
     352           0 :                                     drv->filter_ssids[i].ssid) ||
     353           0 :                             (params->filter_rssi &&
     354           0 :                              nla_put_u32(msg,
     355             :                                          NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
     356           0 :                                          params->filter_rssi)))
     357             :                                 goto fail;
     358             : 
     359           0 :                         nla_nest_end(msg, match_set_ssid);
     360             :                 }
     361             : 
     362             :                 /*
     363             :                  * Due to backward compatibility code, newer kernels treat this
     364             :                  * matchset (with only an RSSI filter) as the default for all
     365             :                  * other matchsets, unless it's the only one, in which case the
     366             :                  * matchset will actually allow all SSIDs above the RSSI.
     367             :                  */
     368           0 :                 if (params->filter_rssi) {
     369             :                         struct nlattr *match_set_rssi;
     370           0 :                         match_set_rssi = nla_nest_start(msg, 0);
     371           0 :                         if (match_set_rssi == NULL ||
     372           0 :                             nla_put_u32(msg, NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
     373           0 :                                         params->filter_rssi))
     374             :                                 goto fail;
     375           0 :                         wpa_printf(MSG_MSGDUMP,
     376             :                                    "nl80211: Sched scan RSSI filter %d dBm",
     377             :                                    params->filter_rssi);
     378           0 :                         nla_nest_end(msg, match_set_rssi);
     379             :                 }
     380             : 
     381           0 :                 nla_nest_end(msg, match_sets);
     382             :         }
     383             : 
     384           0 :         ret = send_and_recv_msgs(drv, msg, NULL, NULL);
     385             : 
     386             :         /* TODO: if we get an error here, we should fall back to normal scan */
     387             : 
     388           0 :         msg = NULL;
     389           0 :         if (ret) {
     390           0 :                 wpa_printf(MSG_DEBUG, "nl80211: Sched scan start failed: "
     391             :                            "ret=%d (%s)", ret, strerror(-ret));
     392           0 :                 goto fail;
     393             :         }
     394             : 
     395           0 :         wpa_printf(MSG_DEBUG, "nl80211: Sched scan requested (ret=%d) - "
     396             :                    "scan interval %d msec", ret, interval);
     397             : 
     398             : fail:
     399           0 :         nlmsg_free(msg);
     400           0 :         return ret;
     401             : }
     402             : 
     403             : 
     404             : /**
     405             :  * wpa_driver_nl80211_stop_sched_scan - Stop a scheduled scan
     406             :  * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
     407             :  * Returns: 0 on success, -1 on failure or if not supported
     408             :  */
     409           0 : int wpa_driver_nl80211_stop_sched_scan(void *priv)
     410             : {
     411           0 :         struct i802_bss *bss = priv;
     412           0 :         struct wpa_driver_nl80211_data *drv = bss->drv;
     413             :         int ret;
     414             :         struct nl_msg *msg;
     415             : 
     416             : #ifdef ANDROID
     417             :         if (!drv->capa.sched_scan_supported)
     418             :                 return android_pno_stop(bss);
     419             : #endif /* ANDROID */
     420             : 
     421           0 :         msg = nl80211_drv_msg(drv, 0, NL80211_CMD_STOP_SCHED_SCAN);
     422           0 :         ret = send_and_recv_msgs(drv, msg, NULL, NULL);
     423           0 :         if (ret) {
     424           0 :                 wpa_printf(MSG_DEBUG,
     425             :                            "nl80211: Sched scan stop failed: ret=%d (%s)",
     426             :                            ret, strerror(-ret));
     427             :         } else {
     428           0 :                 wpa_printf(MSG_DEBUG,
     429             :                            "nl80211: Sched scan stop sent");
     430             :         }
     431             : 
     432           0 :         return ret;
     433             : }
     434             : 
     435             : 
     436         702 : static const u8 * nl80211_get_ie(const u8 *ies, size_t ies_len, u8 ie)
     437             : {
     438             :         const u8 *end, *pos;
     439             : 
     440         702 :         if (ies == NULL)
     441           0 :                 return NULL;
     442             : 
     443         702 :         pos = ies;
     444         702 :         end = ies + ies_len;
     445             : 
     446        1404 :         while (pos + 1 < end) {
     447         702 :                 if (pos + 2 + pos[1] > end)
     448           0 :                         break;
     449         702 :                 if (pos[0] == ie)
     450         702 :                         return pos;
     451           0 :                 pos += 2 + pos[1];
     452             :         }
     453             : 
     454           0 :         return NULL;
     455             : }
     456             : 
     457             : 
     458        3746 : static int nl80211_scan_filtered(struct wpa_driver_nl80211_data *drv,
     459             :                                  const u8 *ie, size_t ie_len)
     460             : {
     461             :         const u8 *ssid;
     462             :         size_t i;
     463             : 
     464        3746 :         if (drv->filter_ssids == NULL)
     465        3742 :                 return 0;
     466             : 
     467           4 :         ssid = nl80211_get_ie(ie, ie_len, WLAN_EID_SSID);
     468           4 :         if (ssid == NULL)
     469           0 :                 return 1;
     470             : 
     471           7 :         for (i = 0; i < drv->num_filter_ssids; i++) {
     472           5 :                 if (ssid[1] == drv->filter_ssids[i].ssid_len &&
     473           1 :                     os_memcmp(ssid + 2, drv->filter_ssids[i].ssid, ssid[1]) ==
     474             :                     0)
     475           1 :                         return 0;
     476             :         }
     477             : 
     478           3 :         return 1;
     479             : }
     480             : 
     481             : 
     482        3822 : int bss_info_handler(struct nl_msg *msg, void *arg)
     483             : {
     484             :         struct nlattr *tb[NL80211_ATTR_MAX + 1];
     485        3822 :         struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
     486             :         struct nlattr *bss[NL80211_BSS_MAX + 1];
     487             :         static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
     488             :                 [NL80211_BSS_BSSID] = { .type = NLA_UNSPEC },
     489             :                 [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
     490             :                 [NL80211_BSS_TSF] = { .type = NLA_U64 },
     491             :                 [NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 },
     492             :                 [NL80211_BSS_CAPABILITY] = { .type = NLA_U16 },
     493             :                 [NL80211_BSS_INFORMATION_ELEMENTS] = { .type = NLA_UNSPEC },
     494             :                 [NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 },
     495             :                 [NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 },
     496             :                 [NL80211_BSS_STATUS] = { .type = NLA_U32 },
     497             :                 [NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 },
     498             :                 [NL80211_BSS_BEACON_IES] = { .type = NLA_UNSPEC },
     499             :         };
     500        3822 :         struct nl80211_bss_info_arg *_arg = arg;
     501        3822 :         struct wpa_scan_results *res = _arg->res;
     502             :         struct wpa_scan_res **tmp;
     503             :         struct wpa_scan_res *r;
     504             :         const u8 *ie, *beacon_ie;
     505             :         size_t ie_len, beacon_ie_len;
     506             :         u8 *pos;
     507             :         size_t i;
     508             : 
     509        3822 :         nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
     510             :                   genlmsg_attrlen(gnlh, 0), NULL);
     511        3822 :         if (!tb[NL80211_ATTR_BSS])
     512           0 :                 return NL_SKIP;
     513        3822 :         if (nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS],
     514             :                              bss_policy))
     515           0 :                 return NL_SKIP;
     516        3822 :         if (bss[NL80211_BSS_STATUS]) {
     517             :                 enum nl80211_bss_status status;
     518         178 :                 status = nla_get_u32(bss[NL80211_BSS_STATUS]);
     519         309 :                 if (status == NL80211_BSS_STATUS_ASSOCIATED &&
     520         131 :                     bss[NL80211_BSS_FREQUENCY]) {
     521         131 :                         _arg->assoc_freq =
     522         131 :                                 nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
     523         131 :                         wpa_printf(MSG_DEBUG, "nl80211: Associated on %u MHz",
     524             :                                    _arg->assoc_freq);
     525             :                 }
     526         225 :                 if (status == NL80211_BSS_STATUS_IBSS_JOINED &&
     527          47 :                     bss[NL80211_BSS_FREQUENCY]) {
     528          47 :                         _arg->ibss_freq =
     529          47 :                                 nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
     530          47 :                         wpa_printf(MSG_DEBUG, "nl80211: IBSS-joined on %u MHz",
     531             :                                    _arg->ibss_freq);
     532             :                 }
     533         309 :                 if (status == NL80211_BSS_STATUS_ASSOCIATED &&
     534         131 :                     bss[NL80211_BSS_BSSID]) {
     535         131 :                         os_memcpy(_arg->assoc_bssid,
     536             :                                   nla_data(bss[NL80211_BSS_BSSID]), ETH_ALEN);
     537         786 :                         wpa_printf(MSG_DEBUG, "nl80211: Associated with "
     538         786 :                                    MACSTR, MAC2STR(_arg->assoc_bssid));
     539             :                 }
     540             :         }
     541        3822 :         if (!res)
     542          76 :                 return NL_SKIP;
     543        3746 :         if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) {
     544        3746 :                 ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
     545        3746 :                 ie_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
     546             :         } else {
     547           0 :                 ie = NULL;
     548           0 :                 ie_len = 0;
     549             :         }
     550        3746 :         if (bss[NL80211_BSS_BEACON_IES]) {
     551        2049 :                 beacon_ie = nla_data(bss[NL80211_BSS_BEACON_IES]);
     552        2049 :                 beacon_ie_len = nla_len(bss[NL80211_BSS_BEACON_IES]);
     553             :         } else {
     554        1697 :                 beacon_ie = NULL;
     555        1697 :                 beacon_ie_len = 0;
     556             :         }
     557             : 
     558        3746 :         if (nl80211_scan_filtered(_arg->drv, ie ? ie : beacon_ie,
     559             :                                   ie ? ie_len : beacon_ie_len))
     560           3 :                 return NL_SKIP;
     561             : 
     562        3743 :         r = os_zalloc(sizeof(*r) + ie_len + beacon_ie_len);
     563        3743 :         if (r == NULL)
     564           0 :                 return NL_SKIP;
     565        3743 :         if (bss[NL80211_BSS_BSSID])
     566        3743 :                 os_memcpy(r->bssid, nla_data(bss[NL80211_BSS_BSSID]),
     567             :                           ETH_ALEN);
     568        3743 :         if (bss[NL80211_BSS_FREQUENCY])
     569        3743 :                 r->freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
     570        3743 :         if (bss[NL80211_BSS_BEACON_INTERVAL])
     571        3743 :                 r->beacon_int = nla_get_u16(bss[NL80211_BSS_BEACON_INTERVAL]);
     572        3743 :         if (bss[NL80211_BSS_CAPABILITY])
     573        3743 :                 r->caps = nla_get_u16(bss[NL80211_BSS_CAPABILITY]);
     574        3743 :         r->flags |= WPA_SCAN_NOISE_INVALID;
     575        3743 :         if (bss[NL80211_BSS_SIGNAL_MBM]) {
     576        3743 :                 r->level = nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]);
     577        3743 :                 r->level /= 100; /* mBm to dBm */
     578        3743 :                 r->flags |= WPA_SCAN_LEVEL_DBM | WPA_SCAN_QUAL_INVALID;
     579           0 :         } else if (bss[NL80211_BSS_SIGNAL_UNSPEC]) {
     580           0 :                 r->level = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]);
     581           0 :                 r->flags |= WPA_SCAN_QUAL_INVALID;
     582             :         } else
     583           0 :                 r->flags |= WPA_SCAN_LEVEL_INVALID | WPA_SCAN_QUAL_INVALID;
     584        3743 :         if (bss[NL80211_BSS_TSF])
     585        3743 :                 r->tsf = nla_get_u64(bss[NL80211_BSS_TSF]);
     586        3743 :         if (bss[NL80211_BSS_SEEN_MS_AGO])
     587        3743 :                 r->age = nla_get_u32(bss[NL80211_BSS_SEEN_MS_AGO]);
     588        3743 :         r->ie_len = ie_len;
     589        3743 :         pos = (u8 *) (r + 1);
     590        3743 :         if (ie) {
     591        3743 :                 os_memcpy(pos, ie, ie_len);
     592        3743 :                 pos += ie_len;
     593             :         }
     594        3743 :         r->beacon_ie_len = beacon_ie_len;
     595        3743 :         if (beacon_ie)
     596        2049 :                 os_memcpy(pos, beacon_ie, beacon_ie_len);
     597             : 
     598        3743 :         if (bss[NL80211_BSS_STATUS]) {
     599             :                 enum nl80211_bss_status status;
     600         121 :                 status = nla_get_u32(bss[NL80211_BSS_STATUS]);
     601         121 :                 switch (status) {
     602             :                 case NL80211_BSS_STATUS_ASSOCIATED:
     603         109 :                         r->flags |= WPA_SCAN_ASSOCIATED;
     604         109 :                         break;
     605             :                 default:
     606          12 :                         break;
     607             :                 }
     608             :         }
     609             : 
     610             :         /*
     611             :          * cfg80211 maintains separate BSS table entries for APs if the same
     612             :          * BSSID,SSID pair is seen on multiple channels. wpa_supplicant does
     613             :          * not use frequency as a separate key in the BSS table, so filter out
     614             :          * duplicated entries. Prefer associated BSS entry in such a case in
     615             :          * order to get the correct frequency into the BSS table. Similarly,
     616             :          * prefer newer entries over older.
     617             :          */
     618        5318 :         for (i = 0; i < res->num; i++) {
     619             :                 const u8 *s1, *s2;
     620        1600 :                 if (os_memcmp(res->res[i]->bssid, r->bssid, ETH_ALEN) != 0)
     621        1251 :                         continue;
     622             : 
     623         349 :                 s1 = nl80211_get_ie((u8 *) (res->res[i] + 1),
     624         349 :                                     res->res[i]->ie_len, WLAN_EID_SSID);
     625         349 :                 s2 = nl80211_get_ie((u8 *) (r + 1), r->ie_len, WLAN_EID_SSID);
     626         483 :                 if (s1 == NULL || s2 == NULL || s1[1] != s2[1] ||
     627         134 :                     os_memcmp(s1, s2, 2 + s1[1]) != 0)
     628         324 :                         continue;
     629             : 
     630             :                 /* Same BSSID,SSID was already included in scan results */
     631         150 :                 wpa_printf(MSG_DEBUG, "nl80211: Remove duplicated scan result "
     632         150 :                            "for " MACSTR, MAC2STR(r->bssid));
     633             : 
     634          25 :                 if (((r->flags & WPA_SCAN_ASSOCIATED) &&
     635          25 :                      !(res->res[i]->flags & WPA_SCAN_ASSOCIATED)) ||
     636          25 :                     r->age < res->res[i]->age) {
     637          25 :                         os_free(res->res[i]);
     638          25 :                         res->res[i] = r;
     639             :                 } else
     640           0 :                         os_free(r);
     641          25 :                 return NL_SKIP;
     642             :         }
     643             : 
     644        3718 :         tmp = os_realloc_array(res->res, res->num + 1,
     645             :                                sizeof(struct wpa_scan_res *));
     646        3718 :         if (tmp == NULL) {
     647           0 :                 os_free(r);
     648           0 :                 return NL_SKIP;
     649             :         }
     650        3718 :         tmp[res->num++] = r;
     651        3718 :         res->res = tmp;
     652             : 
     653        3718 :         return NL_SKIP;
     654             : }
     655             : 
     656             : 
     657           0 : static void clear_state_mismatch(struct wpa_driver_nl80211_data *drv,
     658             :                                  const u8 *addr)
     659             : {
     660           0 :         if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
     661           0 :                 wpa_printf(MSG_DEBUG, "nl80211: Clear possible state "
     662           0 :                            "mismatch (" MACSTR ")", MAC2STR(addr));
     663           0 :                 wpa_driver_nl80211_mlme(drv, addr,
     664             :                                         NL80211_CMD_DEAUTHENTICATE,
     665             :                                         WLAN_REASON_PREV_AUTH_NOT_VALID, 1);
     666             :         }
     667           0 : }
     668             : 
     669             : 
     670        2811 : static void wpa_driver_nl80211_check_bss_status(
     671             :         struct wpa_driver_nl80211_data *drv, struct wpa_scan_results *res)
     672             : {
     673             :         size_t i;
     674             : 
     675        6529 :         for (i = 0; i < res->num; i++) {
     676        3718 :                 struct wpa_scan_res *r = res->res[i];
     677             : 
     678        3718 :                 if (r->flags & WPA_SCAN_ASSOCIATED) {
     679         654 :                         wpa_printf(MSG_DEBUG, "nl80211: Scan results "
     680             :                                    "indicate BSS status with " MACSTR
     681             :                                    " as associated",
     682         654 :                                    MAC2STR(r->bssid));
     683         218 :                         if (is_sta_interface(drv->nlmode) &&
     684         109 :                             !drv->associated) {
     685           0 :                                 wpa_printf(MSG_DEBUG, "nl80211: Local state "
     686             :                                            "(not associated) does not match "
     687             :                                            "with BSS state");
     688           0 :                                 clear_state_mismatch(drv, r->bssid);
     689         218 :                         } else if (is_sta_interface(drv->nlmode) &&
     690         109 :                                    os_memcmp(drv->bssid, r->bssid, ETH_ALEN) !=
     691             :                                    0) {
     692           0 :                                 wpa_printf(MSG_DEBUG, "nl80211: Local state "
     693             :                                            "(associated with " MACSTR ") does "
     694             :                                            "not match with BSS state",
     695           0 :                                            MAC2STR(drv->bssid));
     696           0 :                                 clear_state_mismatch(drv, r->bssid);
     697           0 :                                 clear_state_mismatch(drv, drv->bssid);
     698             :                         }
     699             :                 }
     700             :         }
     701        2811 : }
     702             : 
     703             : 
     704             : static struct wpa_scan_results *
     705        2811 : nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv)
     706             : {
     707             :         struct nl_msg *msg;
     708             :         struct wpa_scan_results *res;
     709             :         int ret;
     710             :         struct nl80211_bss_info_arg arg;
     711             : 
     712        2811 :         res = os_zalloc(sizeof(*res));
     713        2811 :         if (res == NULL)
     714           0 :                 return NULL;
     715        2811 :         if (!(msg = nl80211_cmd_msg(drv->first_bss, NLM_F_DUMP,
     716             :                                     NL80211_CMD_GET_SCAN))) {
     717           0 :                 wpa_scan_results_free(res);
     718           0 :                 return NULL;
     719             :         }
     720             : 
     721        2811 :         arg.drv = drv;
     722        2811 :         arg.res = res;
     723        2811 :         ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
     724        2811 :         if (ret == 0) {
     725        2811 :                 wpa_printf(MSG_DEBUG, "nl80211: Received scan results (%lu "
     726             :                            "BSSes)", (unsigned long) res->num);
     727        2811 :                 nl80211_get_noise_for_scan_results(drv, res);
     728        2811 :                 return res;
     729             :         }
     730           0 :         wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
     731             :                    "(%s)", ret, strerror(-ret));
     732           0 :         wpa_scan_results_free(res);
     733           0 :         return NULL;
     734             : }
     735             : 
     736             : 
     737             : /**
     738             :  * wpa_driver_nl80211_get_scan_results - Fetch the latest scan results
     739             :  * @priv: Pointer to private wext data from wpa_driver_nl80211_init()
     740             :  * Returns: Scan results on success, -1 on failure
     741             :  */
     742        2811 : struct wpa_scan_results * wpa_driver_nl80211_get_scan_results(void *priv)
     743             : {
     744        2811 :         struct i802_bss *bss = priv;
     745        2811 :         struct wpa_driver_nl80211_data *drv = bss->drv;
     746             :         struct wpa_scan_results *res;
     747             : 
     748        2811 :         res = nl80211_get_scan_results(drv);
     749        2811 :         if (res)
     750        2811 :                 wpa_driver_nl80211_check_bss_status(drv, res);
     751        2811 :         return res;
     752             : }
     753             : 
     754             : 
     755           0 : void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv)
     756             : {
     757             :         struct wpa_scan_results *res;
     758             :         size_t i;
     759             : 
     760           0 :         res = nl80211_get_scan_results(drv);
     761           0 :         if (res == NULL) {
     762           0 :                 wpa_printf(MSG_DEBUG, "nl80211: Failed to get scan results");
     763           0 :                 return;
     764             :         }
     765             : 
     766           0 :         wpa_printf(MSG_DEBUG, "nl80211: Scan result dump");
     767           0 :         for (i = 0; i < res->num; i++) {
     768           0 :                 struct wpa_scan_res *r = res->res[i];
     769           0 :                 wpa_printf(MSG_DEBUG, "nl80211: %d/%d " MACSTR "%s",
     770           0 :                            (int) i, (int) res->num, MAC2STR(r->bssid),
     771           0 :                            r->flags & WPA_SCAN_ASSOCIATED ? " [assoc]" : "");
     772             :         }
     773             : 
     774           0 :         wpa_scan_results_free(res);
     775             : }

Generated by: LCOV version 1.10