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

Generated by: LCOV version 1.10