LCOV - code coverage report
Current view: top level - wpa_supplicant - mesh.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1475438200 Lines: 336 357 94.1 %
Date: 2016-10-02 Functions: 15 15 100.0 %

          Line data    Source code
       1             : /*
       2             :  * WPA Supplicant - Basic mesh mode routines
       3             :  * Copyright (c) 2013-2014, cozybit, Inc.  All rights reserved.
       4             :  *
       5             :  * This software may be distributed under the terms of the BSD license.
       6             :  * See README for more details.
       7             :  */
       8             : 
       9             : #include "utils/includes.h"
      10             : 
      11             : #include "utils/common.h"
      12             : #include "utils/eloop.h"
      13             : #include "utils/uuid.h"
      14             : #include "common/ieee802_11_defs.h"
      15             : #include "common/wpa_ctrl.h"
      16             : #include "ap/sta_info.h"
      17             : #include "ap/hostapd.h"
      18             : #include "ap/ieee802_11.h"
      19             : #include "config_ssid.h"
      20             : #include "config.h"
      21             : #include "wpa_supplicant_i.h"
      22             : #include "driver_i.h"
      23             : #include "notify.h"
      24             : #include "ap.h"
      25             : #include "mesh_mpm.h"
      26             : #include "mesh_rsn.h"
      27             : #include "mesh.h"
      28             : 
      29             : 
      30         379 : static void wpa_supplicant_mesh_deinit(struct wpa_supplicant *wpa_s)
      31             : {
      32         379 :         wpa_supplicant_mesh_iface_deinit(wpa_s, wpa_s->ifmsh);
      33         379 :         wpa_s->ifmsh = NULL;
      34         379 :         wpa_s->current_ssid = NULL;
      35         379 :         os_free(wpa_s->mesh_rsn);
      36         379 :         wpa_s->mesh_rsn = NULL;
      37             :         /* TODO: leave mesh (stop beacon). This will happen on link down
      38             :          * anyway, so it's not urgent */
      39         379 : }
      40             : 
      41             : 
      42         379 : void wpa_supplicant_mesh_iface_deinit(struct wpa_supplicant *wpa_s,
      43             :                                       struct hostapd_iface *ifmsh)
      44             : {
      45         379 :         if (!ifmsh)
      46         569 :                 return;
      47             : 
      48         189 :         if (ifmsh->mconf) {
      49         179 :                 mesh_mpm_deinit(wpa_s, ifmsh);
      50         179 :                 if (ifmsh->mconf->rsn_ie) {
      51          66 :                         ifmsh->mconf->rsn_ie = NULL;
      52             :                         /* We cannot free this struct
      53             :                          * because wpa_authenticator on
      54             :                          * hostapd side is also using it
      55             :                          * for now just set to NULL and
      56             :                          * let hostapd code free it.
      57             :                          */
      58             :                 }
      59         179 :                 os_free(ifmsh->mconf);
      60         179 :                 ifmsh->mconf = NULL;
      61             :         }
      62             : 
      63             :         /* take care of shared data */
      64         189 :         hostapd_interface_deinit(ifmsh);
      65         189 :         hostapd_interface_free(ifmsh);
      66             : }
      67             : 
      68             : 
      69         183 : static struct mesh_conf * mesh_config_create(struct wpa_supplicant *wpa_s,
      70             :                                              struct wpa_ssid *ssid)
      71             : {
      72             :         struct mesh_conf *conf;
      73             :         int cipher;
      74             : 
      75         183 :         conf = os_zalloc(sizeof(struct mesh_conf));
      76         183 :         if (!conf)
      77           2 :                 return NULL;
      78             : 
      79         181 :         os_memcpy(conf->meshid, ssid->ssid, ssid->ssid_len);
      80         181 :         conf->meshid_len = ssid->ssid_len;
      81             : 
      82         181 :         if (ssid->key_mgmt & WPA_KEY_MGMT_SAE)
      83          73 :                 conf->security |= MESH_CONF_SEC_AUTH |
      84             :                         MESH_CONF_SEC_AMPE;
      85             :         else
      86         108 :                 conf->security |= MESH_CONF_SEC_NONE;
      87         181 :         conf->ieee80211w = ssid->ieee80211w;
      88         181 :         if (conf->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT) {
      89         177 :                 if (wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_BIP)
      90         177 :                         conf->ieee80211w = wpa_s->conf->pmf;
      91             :                 else
      92           0 :                         conf->ieee80211w = NO_MGMT_FRAME_PROTECTION;
      93             :         }
      94             : 
      95         181 :         cipher = wpa_pick_pairwise_cipher(ssid->pairwise_cipher, 0);
      96         181 :         if (cipher < 0 || cipher == WPA_CIPHER_TKIP) {
      97           1 :                 wpa_msg(wpa_s, MSG_INFO, "mesh: Invalid pairwise cipher");
      98           1 :                 os_free(conf);
      99           1 :                 return NULL;
     100             :         }
     101         180 :         conf->pairwise_cipher = cipher;
     102             : 
     103         180 :         cipher = wpa_pick_group_cipher(ssid->group_cipher);
     104         180 :         if (cipher < 0 || cipher == WPA_CIPHER_TKIP ||
     105             :             cipher == WPA_CIPHER_GTK_NOT_USED) {
     106           1 :                 wpa_msg(wpa_s, MSG_INFO, "mesh: Invalid group cipher");
     107           1 :                 os_free(conf);
     108           1 :                 return NULL;
     109             :         }
     110             : 
     111         179 :         conf->group_cipher = cipher;
     112         179 :         if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION)
     113           4 :                 conf->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
     114             : 
     115             :         /* defaults */
     116         179 :         conf->mesh_pp_id = MESH_PATH_PROTOCOL_HWMP;
     117         179 :         conf->mesh_pm_id = MESH_PATH_METRIC_AIRTIME;
     118         179 :         conf->mesh_cc_id = 0;
     119         179 :         conf->mesh_sp_id = MESH_SYNC_METHOD_NEIGHBOR_OFFSET;
     120         179 :         conf->mesh_auth_id = (conf->security & MESH_CONF_SEC_AUTH) ? 1 : 0;
     121         179 :         conf->dot11MeshMaxRetries = ssid->dot11MeshMaxRetries;
     122         179 :         conf->dot11MeshRetryTimeout = ssid->dot11MeshRetryTimeout;
     123         179 :         conf->dot11MeshConfirmTimeout = ssid->dot11MeshConfirmTimeout;
     124         179 :         conf->dot11MeshHoldingTimeout = ssid->dot11MeshHoldingTimeout;
     125             : 
     126         179 :         return conf;
     127             : }
     128             : 
     129             : 
     130           9 : static void wpas_mesh_copy_groups(struct hostapd_data *bss,
     131             :                                   struct wpa_supplicant *wpa_s)
     132             : {
     133             :         int num_groups;
     134             :         size_t groups_size;
     135             : 
     136          31 :         for (num_groups = 0; wpa_s->conf->sae_groups[num_groups] > 0;
     137          13 :              num_groups++)
     138             :                 ;
     139             : 
     140           9 :         groups_size = (num_groups + 1) * sizeof(wpa_s->conf->sae_groups[0]);
     141           9 :         bss->conf->sae_groups = os_malloc(groups_size);
     142           9 :         if (bss->conf->sae_groups)
     143           9 :                 os_memcpy(bss->conf->sae_groups, wpa_s->conf->sae_groups,
     144             :                           groups_size);
     145           9 : }
     146             : 
     147             : 
     148         190 : static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
     149             :                                     struct wpa_ssid *ssid)
     150             : {
     151             :         struct hostapd_iface *ifmsh;
     152             :         struct hostapd_data *bss;
     153             :         struct hostapd_config *conf;
     154             :         struct mesh_conf *mconf;
     155         190 :         int basic_rates_erp[] = { 10, 20, 55, 60, 110, 120, 240, -1 };
     156             :         static int default_groups[] = { 19, 20, 21, 25, 26, -1 };
     157             :         size_t len;
     158             :         int rate_len;
     159             : 
     160         190 :         if (!wpa_s->conf->user_mpm) {
     161             :                 /* not much for us to do here */
     162           0 :                 wpa_msg(wpa_s, MSG_WARNING,
     163             :                         "user_mpm is not enabled in configuration");
     164           0 :                 return 0;
     165             :         }
     166             : 
     167         190 :         wpa_s->ifmsh = ifmsh = os_zalloc(sizeof(*wpa_s->ifmsh));
     168         190 :         if (!ifmsh)
     169           1 :                 return -ENOMEM;
     170             : 
     171         189 :         ifmsh->drv_flags = wpa_s->drv_flags;
     172         189 :         ifmsh->num_bss = 1;
     173         189 :         ifmsh->bss = os_calloc(wpa_s->ifmsh->num_bss,
     174             :                                sizeof(struct hostapd_data *));
     175         189 :         if (!ifmsh->bss)
     176           1 :                 goto out_free;
     177             : 
     178         188 :         ifmsh->bss[0] = bss = os_zalloc(sizeof(struct hostapd_data));
     179         188 :         if (!bss)
     180           1 :                 goto out_free;
     181         187 :         dl_list_init(&bss->nr_db);
     182             : 
     183         187 :         os_memcpy(bss->own_addr, wpa_s->own_addr, ETH_ALEN);
     184         187 :         bss->driver = wpa_s->driver;
     185         187 :         bss->drv_priv = wpa_s->drv_priv;
     186         187 :         bss->iface = ifmsh;
     187         187 :         bss->mesh_sta_free_cb = mesh_mpm_free_sta;
     188         187 :         wpa_s->assoc_freq = ssid->frequency;
     189         187 :         wpa_s->current_ssid = ssid;
     190             : 
     191             :         /* setup an AP config for auth processing */
     192         187 :         conf = hostapd_config_defaults();
     193         187 :         if (!conf)
     194           4 :                 goto out_free;
     195             : 
     196         183 :         bss->conf = *conf->bss;
     197         183 :         bss->conf->start_disabled = 1;
     198         183 :         bss->conf->mesh = MESH_ENABLED;
     199         183 :         bss->conf->ap_max_inactivity = wpa_s->conf->mesh_max_inactivity;
     200         183 :         bss->iconf = conf;
     201         183 :         ifmsh->conf = conf;
     202             : 
     203         183 :         ifmsh->bss[0]->max_plinks = wpa_s->conf->max_peer_links;
     204         366 :         ifmsh->bss[0]->dot11RSNASAERetransPeriod =
     205         183 :                 wpa_s->conf->dot11RSNASAERetransPeriod;
     206         183 :         os_strlcpy(bss->conf->iface, wpa_s->ifname, sizeof(bss->conf->iface));
     207             : 
     208         183 :         mconf = mesh_config_create(wpa_s, ssid);
     209         183 :         if (!mconf)
     210           4 :                 goto out_free;
     211         179 :         ifmsh->mconf = mconf;
     212             : 
     213             :         /* need conf->hw_mode for supported rates. */
     214         179 :         conf->hw_mode = ieee80211_freq_to_chan(ssid->frequency, &conf->channel);
     215         179 :         if (conf->hw_mode == NUM_HOSTAPD_MODES) {
     216           1 :                 wpa_printf(MSG_ERROR, "Unsupported mesh mode frequency: %d MHz",
     217             :                            ssid->frequency);
     218           1 :                 goto out_free;
     219             :         }
     220         178 :         if (ssid->ht40)
     221           6 :                 conf->secondary_channel = ssid->ht40;
     222         178 :         if (conf->hw_mode == HOSTAPD_MODE_IEEE80211A && ssid->vht) {
     223           6 :                 conf->vht_oper_chwidth = ssid->max_oper_chwidth;
     224           6 :                 switch (conf->vht_oper_chwidth) {
     225             :                 case VHT_CHANWIDTH_80MHZ:
     226             :                 case VHT_CHANWIDTH_80P80MHZ:
     227           4 :                         ieee80211_freq_to_chan(
     228             :                                 ssid->frequency,
     229             :                                 &conf->vht_oper_centr_freq_seg0_idx);
     230           4 :                         conf->vht_oper_centr_freq_seg0_idx += ssid->ht40 * 2;
     231           4 :                         break;
     232             :                 case VHT_CHANWIDTH_160MHZ:
     233           2 :                         ieee80211_freq_to_chan(
     234             :                                 ssid->frequency,
     235             :                                 &conf->vht_oper_centr_freq_seg0_idx);
     236           2 :                         conf->vht_oper_centr_freq_seg0_idx += ssid->ht40 * 2;
     237           2 :                         conf->vht_oper_centr_freq_seg0_idx += 40 / 5;
     238           2 :                         break;
     239             :                 }
     240           6 :                 ieee80211_freq_to_chan(ssid->vht_center_freq2,
     241             :                                        &conf->vht_oper_centr_freq_seg1_idx);
     242             :         }
     243             : 
     244         178 :         if (ssid->mesh_basic_rates == NULL) {
     245             :                 /*
     246             :                  * XXX: Hack! This is so an MPM which correctly sets the ERP
     247             :                  * mandatory rates as BSSBasicRateSet doesn't reject us. We
     248             :                  * could add a new hw_mode HOSTAPD_MODE_IEEE80211G_ERP, but
     249             :                  * this is way easier. This also makes our BSSBasicRateSet
     250             :                  * advertised in beacons match the one in peering frames, sigh.
     251             :                  */
     252         175 :                 if (conf->hw_mode == HOSTAPD_MODE_IEEE80211G) {
     253         169 :                         conf->basic_rates = os_malloc(sizeof(basic_rates_erp));
     254         169 :                         if (!conf->basic_rates)
     255           1 :                                 goto out_free;
     256         168 :                         os_memcpy(conf->basic_rates, basic_rates_erp,
     257             :                                   sizeof(basic_rates_erp));
     258             :                 }
     259             :         } else {
     260           3 :                 rate_len = 0;
     261             :                 while (1) {
     262          12 :                         if (ssid->mesh_basic_rates[rate_len] < 1)
     263           3 :                                 break;
     264           9 :                         rate_len++;
     265           9 :                 }
     266           3 :                 conf->basic_rates = os_calloc(rate_len + 1, sizeof(int));
     267           3 :                 if (conf->basic_rates == NULL)
     268           1 :                         goto out_free;
     269           2 :                 os_memcpy(conf->basic_rates, ssid->mesh_basic_rates,
     270             :                           rate_len * sizeof(int));
     271           2 :                 conf->basic_rates[rate_len] = -1;
     272             :         }
     273             : 
     274         176 :         if (hostapd_setup_interface(ifmsh)) {
     275           2 :                 wpa_printf(MSG_ERROR,
     276             :                            "Failed to initialize hostapd interface for mesh");
     277           2 :                 return -1;
     278             :         }
     279             : 
     280         174 :         if (wpa_drv_init_mesh(wpa_s)) {
     281           1 :                 wpa_msg(wpa_s, MSG_ERROR, "Failed to init mesh in driver");
     282           1 :                 return -1;
     283             :         }
     284             : 
     285         173 :         if (mconf->security != MESH_CONF_SEC_NONE) {
     286          71 :                 if (ssid->passphrase == NULL) {
     287           1 :                         wpa_printf(MSG_ERROR,
     288             :                                    "mesh: Passphrase for SAE not configured");
     289           1 :                         goto out_free;
     290             :                 }
     291             : 
     292          70 :                 bss->conf->wpa = ssid->proto;
     293          70 :                 bss->conf->wpa_key_mgmt = ssid->key_mgmt;
     294             : 
     295         139 :                 if (wpa_s->conf->sae_groups &&
     296          69 :                     wpa_s->conf->sae_groups[0] > 0) {
     297           9 :                         wpas_mesh_copy_groups(bss, wpa_s);
     298             :                 } else {
     299         122 :                         bss->conf->sae_groups =
     300          61 :                                 os_malloc(sizeof(default_groups));
     301          61 :                         if (!bss->conf->sae_groups)
     302           1 :                                 goto out_free;
     303          60 :                         os_memcpy(bss->conf->sae_groups, default_groups,
     304             :                                   sizeof(default_groups));
     305             :                 }
     306             : 
     307          69 :                 len = os_strlen(ssid->passphrase);
     308         138 :                 bss->conf->ssid.wpa_passphrase =
     309          69 :                         dup_binstr(ssid->passphrase, len);
     310             : 
     311          69 :                 wpa_s->mesh_rsn = mesh_rsn_auth_init(wpa_s, mconf);
     312          69 :                 if (!wpa_s->mesh_rsn)
     313           3 :                         goto out_free;
     314             :         }
     315             : 
     316         168 :         wpa_supplicant_conf_ap_ht(wpa_s, ssid, conf);
     317             : 
     318         168 :         return 0;
     319             : out_free:
     320          18 :         wpa_supplicant_mesh_deinit(wpa_s);
     321          18 :         return -ENOMEM;
     322             : }
     323             : 
     324             : 
     325         150 : void wpa_mesh_notify_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
     326             :                           const u8 *ies, size_t ie_len)
     327             : {
     328             :         struct ieee802_11_elems elems;
     329             : 
     330         900 :         wpa_msg(wpa_s, MSG_INFO,
     331         900 :                 "new peer notification for " MACSTR, MAC2STR(addr));
     332             : 
     333         150 :         if (ieee802_11_parse_elems(ies, ie_len, &elems, 0) == ParseFailed) {
     334           0 :                 wpa_msg(wpa_s, MSG_INFO, "Could not parse beacon from " MACSTR,
     335           0 :                         MAC2STR(addr));
     336         150 :                 return;
     337             :         }
     338         150 :         wpa_mesh_new_mesh_peer(wpa_s, addr, &elems);
     339             : }
     340             : 
     341             : 
     342        4564 : void wpa_supplicant_mesh_add_scan_ie(struct wpa_supplicant *wpa_s,
     343             :                                      struct wpabuf **extra_ie)
     344             : {
     345             :         /* EID + 0-length (wildcard) mesh-id */
     346        4564 :         size_t ielen = 2;
     347             : 
     348        4564 :         if (wpabuf_resize(extra_ie, ielen) == 0) {
     349        4564 :                 wpabuf_put_u8(*extra_ie, WLAN_EID_MESH_ID);
     350        4564 :                 wpabuf_put_u8(*extra_ie, 0);
     351             :         }
     352        4564 : }
     353             : 
     354             : 
     355         191 : int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s,
     356             :                              struct wpa_ssid *ssid)
     357             : {
     358             :         struct wpa_driver_mesh_join_params params;
     359         191 :         int ret = 0;
     360             : 
     361         191 :         if (!ssid || !ssid->ssid || !ssid->ssid_len || !ssid->frequency) {
     362           1 :                 ret = -ENOENT;
     363           1 :                 goto out;
     364             :         }
     365             : 
     366         190 :         wpa_supplicant_mesh_deinit(wpa_s);
     367             : 
     368         190 :         wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
     369         190 :         wpa_s->group_cipher = WPA_CIPHER_NONE;
     370         190 :         wpa_s->mgmt_group_cipher = 0;
     371             : 
     372         190 :         os_memset(&params, 0, sizeof(params));
     373         190 :         params.meshid = ssid->ssid;
     374         190 :         params.meshid_len = ssid->ssid_len;
     375         190 :         ibss_mesh_setup_freq(wpa_s, ssid, &params.freq);
     376         190 :         wpa_s->mesh_ht_enabled = !!params.freq.ht_enabled;
     377         190 :         wpa_s->mesh_vht_enabled = !!params.freq.vht_enabled;
     378         190 :         if (params.freq.ht_enabled && params.freq.sec_channel_offset)
     379           6 :                 ssid->ht40 = params.freq.sec_channel_offset;
     380         190 :         if (wpa_s->mesh_vht_enabled) {
     381           6 :                 ssid->vht = 1;
     382           6 :                 switch (params.freq.bandwidth) {
     383             :                 case 80:
     384           4 :                         if (params.freq.center_freq2) {
     385           2 :                                 ssid->max_oper_chwidth = VHT_CHANWIDTH_80P80MHZ;
     386           2 :                                 ssid->vht_center_freq2 =
     387           2 :                                         params.freq.center_freq2;
     388             :                         } else {
     389           2 :                                 ssid->max_oper_chwidth = VHT_CHANWIDTH_80MHZ;
     390             :                         }
     391           4 :                         break;
     392             :                 case 160:
     393           2 :                         ssid->max_oper_chwidth = VHT_CHANWIDTH_160MHZ;
     394           2 :                         break;
     395             :                 default:
     396           0 :                         ssid->max_oper_chwidth = VHT_CHANWIDTH_USE_HT;
     397           0 :                         break;
     398             :                 }
     399             :         }
     400         190 :         if (ssid->beacon_int > 0)
     401           6 :                 params.beacon_int = ssid->beacon_int;
     402         184 :         else if (wpa_s->conf->beacon_int > 0)
     403           1 :                 params.beacon_int = wpa_s->conf->beacon_int;
     404         190 :         if (ssid->dtim_period > 0)
     405           0 :                 params.dtim_period = ssid->dtim_period;
     406         190 :         else if (wpa_s->conf->dtim_period > 0)
     407           0 :                 params.dtim_period = wpa_s->conf->dtim_period;
     408         190 :         params.conf.max_peer_links = wpa_s->conf->max_peer_links;
     409             : 
     410         190 :         if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
     411          73 :                 params.flags |= WPA_DRIVER_MESH_FLAG_SAE_AUTH;
     412          73 :                 params.flags |= WPA_DRIVER_MESH_FLAG_AMPE;
     413          73 :                 wpa_s->conf->user_mpm = 1;
     414             :         }
     415             : 
     416         190 :         if (wpa_s->conf->user_mpm) {
     417         190 :                 params.flags |= WPA_DRIVER_MESH_FLAG_USER_MPM;
     418         190 :                 params.conf.auto_plinks = 0;
     419             :         } else {
     420           0 :                 params.flags |= WPA_DRIVER_MESH_FLAG_DRIVER_MPM;
     421           0 :                 params.conf.auto_plinks = 1;
     422             :         }
     423         190 :         params.conf.peer_link_timeout = wpa_s->conf->mesh_max_inactivity;
     424             : 
     425         190 :         if (wpa_supplicant_mesh_init(wpa_s, ssid)) {
     426          22 :                 wpa_msg(wpa_s, MSG_ERROR, "Failed to init mesh");
     427          22 :                 wpa_drv_leave_mesh(wpa_s);
     428          22 :                 ret = -1;
     429          22 :                 goto out;
     430             :         }
     431             : 
     432         168 :         if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
     433          66 :                 wpa_s->pairwise_cipher = wpa_s->mesh_rsn->pairwise_cipher;
     434          66 :                 wpa_s->group_cipher = wpa_s->mesh_rsn->group_cipher;
     435          66 :                 wpa_s->mgmt_group_cipher = wpa_s->mesh_rsn->mgmt_group_cipher;
     436             :         }
     437             : 
     438         168 :         if (wpa_s->ifmsh) {
     439         168 :                 params.ies = wpa_s->ifmsh->mconf->rsn_ie;
     440         168 :                 params.ie_len = wpa_s->ifmsh->mconf->rsn_ie_len;
     441         168 :                 params.basic_rates = wpa_s->ifmsh->basic_rates;
     442         168 :                 params.conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_HT_OP_MODE;
     443         168 :                 params.conf.ht_opmode = wpa_s->ifmsh->bss[0]->iface->ht_op_mode;
     444             :         }
     445             : 
     446         336 :         wpa_msg(wpa_s, MSG_INFO, "joining mesh %s",
     447         168 :                 wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
     448         168 :         ret = wpa_drv_join_mesh(wpa_s, &params);
     449         168 :         if (ret)
     450           1 :                 wpa_msg(wpa_s, MSG_ERROR, "mesh join error=%d", ret);
     451             : 
     452             :         /* hostapd sets the interface down until we associate */
     453         168 :         wpa_drv_set_operstate(wpa_s, 1);
     454             : 
     455         168 :         if (!ret)
     456         167 :                 wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
     457             : 
     458             : out:
     459         191 :         return ret;
     460             : }
     461             : 
     462             : 
     463         171 : int wpa_supplicant_leave_mesh(struct wpa_supplicant *wpa_s)
     464             : {
     465         171 :         int ret = 0;
     466             : 
     467         171 :         wpa_msg(wpa_s, MSG_INFO, "leaving mesh");
     468             : 
     469             :         /* Need to send peering close messages first */
     470         171 :         wpa_supplicant_mesh_deinit(wpa_s);
     471             : 
     472         171 :         ret = wpa_drv_leave_mesh(wpa_s);
     473         171 :         if (ret)
     474           4 :                 wpa_msg(wpa_s, MSG_ERROR, "mesh leave error=%d", ret);
     475             : 
     476         171 :         wpa_drv_set_operstate(wpa_s, 1);
     477             : 
     478         171 :         return ret;
     479             : }
     480             : 
     481             : 
     482        2342 : static int mesh_attr_text(const u8 *ies, size_t ies_len, char *buf, char *end)
     483             : {
     484             :         struct ieee802_11_elems elems;
     485        2342 :         char *mesh_id, *pos = buf;
     486             :         u8 *bss_basic_rate_set;
     487             :         int bss_basic_rate_set_len, ret, i;
     488             : 
     489        2342 :         if (ieee802_11_parse_elems(ies, ies_len, &elems, 0) == ParseFailed)
     490           1 :                 return -1;
     491             : 
     492        2341 :         if (elems.mesh_id_len < 1)
     493        2337 :                 return 0;
     494             : 
     495           4 :         mesh_id = os_malloc(elems.mesh_id_len + 1);
     496           4 :         if (mesh_id == NULL)
     497           1 :                 return -1;
     498             : 
     499           3 :         os_memcpy(mesh_id, elems.mesh_id, elems.mesh_id_len);
     500           3 :         mesh_id[elems.mesh_id_len] = '\0';
     501           3 :         ret = os_snprintf(pos, end - pos, "mesh_id=%s\n", mesh_id);
     502           3 :         os_free(mesh_id);
     503           3 :         if (os_snprintf_error(end - pos, ret))
     504           0 :                 return pos - buf;
     505           3 :         pos += ret;
     506             : 
     507           3 :         if (elems.mesh_config_len > 6) {
     508          21 :                 ret = os_snprintf(pos, end - pos,
     509             :                                   "active_path_selection_protocol_id=0x%02x\n"
     510             :                                   "active_path_selection_metric_id=0x%02x\n"
     511             :                                   "congestion_control_mode_id=0x%02x\n"
     512             :                                   "synchronization_method_id=0x%02x\n"
     513             :                                   "authentication_protocol_id=0x%02x\n"
     514             :                                   "mesh_formation_info=0x%02x\n"
     515             :                                   "mesh_capability=0x%02x\n",
     516           6 :                                   elems.mesh_config[0], elems.mesh_config[1],
     517           6 :                                   elems.mesh_config[2], elems.mesh_config[3],
     518           6 :                                   elems.mesh_config[4], elems.mesh_config[5],
     519           3 :                                   elems.mesh_config[6]);
     520           3 :                 if (os_snprintf_error(end - pos, ret))
     521           0 :                         return pos - buf;
     522           3 :                 pos += ret;
     523             :         }
     524             : 
     525           6 :         bss_basic_rate_set = os_malloc(elems.supp_rates_len +
     526           3 :                 elems.ext_supp_rates_len);
     527           3 :         if (bss_basic_rate_set == NULL)
     528           1 :                 return -1;
     529             : 
     530           2 :         bss_basic_rate_set_len = 0;
     531          18 :         for (i = 0; i < elems.supp_rates_len; i++) {
     532          16 :                 if (elems.supp_rates[i] & 0x80) {
     533          24 :                         bss_basic_rate_set[bss_basic_rate_set_len++] =
     534          12 :                                 (elems.supp_rates[i] & 0x7f) * 5;
     535             :                 }
     536             :         }
     537          10 :         for (i = 0; i < elems.ext_supp_rates_len; i++) {
     538           8 :                 if (elems.ext_supp_rates[i] & 0x80) {
     539           4 :                         bss_basic_rate_set[bss_basic_rate_set_len++] =
     540           2 :                                 (elems.ext_supp_rates[i] & 0x7f) * 5;
     541             :                 }
     542             :         }
     543           2 :         if (bss_basic_rate_set_len > 0) {
     544           2 :                 ret = os_snprintf(pos, end - pos, "bss_basic_rate_set=%d",
     545           2 :                                   bss_basic_rate_set[0]);
     546           2 :                 if (os_snprintf_error(end - pos, ret))
     547           0 :                         goto fail;
     548           2 :                 pos += ret;
     549             : 
     550          14 :                 for (i = 1; i < bss_basic_rate_set_len; i++) {
     551          12 :                         ret = os_snprintf(pos, end - pos, " %d",
     552          12 :                                           bss_basic_rate_set[i]);
     553          12 :                         if (os_snprintf_error(end - pos, ret))
     554           0 :                                 goto fail;
     555          12 :                         pos += ret;
     556             :                 }
     557             : 
     558           2 :                 ret = os_snprintf(pos, end - pos, "\n");
     559           2 :                 if (os_snprintf_error(end - pos, ret))
     560           0 :                         goto fail;
     561           2 :                 pos += ret;
     562             :         }
     563             : fail:
     564           2 :         os_free(bss_basic_rate_set);
     565             : 
     566           2 :         return pos - buf;
     567             : }
     568             : 
     569             : 
     570        2342 : int wpas_mesh_scan_result_text(const u8 *ies, size_t ies_len, char *buf,
     571             :                                char *end)
     572             : {
     573        2342 :         return mesh_attr_text(ies, ies_len, buf, end);
     574             : }
     575             : 
     576             : 
     577           5 : static int wpas_mesh_get_ifname(struct wpa_supplicant *wpa_s, char *ifname,
     578             :                                 size_t len)
     579             : {
     580           5 :         char *ifname_ptr = wpa_s->ifname;
     581             :         int res;
     582             : 
     583           5 :         res = os_snprintf(ifname, len, "mesh-%s-%d", ifname_ptr,
     584             :                           wpa_s->mesh_if_idx);
     585          10 :         if (os_snprintf_error(len, res) ||
     586           5 :             (os_strlen(ifname) >= IFNAMSIZ &&
     587           0 :              os_strlen(wpa_s->ifname) < IFNAMSIZ)) {
     588             :                 /* Try to avoid going over the IFNAMSIZ length limit */
     589           0 :                 res = os_snprintf(ifname, len, "mesh-%d", wpa_s->mesh_if_idx);
     590           0 :                 if (os_snprintf_error(len, res))
     591           0 :                         return -1;
     592             :         }
     593           5 :         wpa_s->mesh_if_idx++;
     594           5 :         return 0;
     595             : }
     596             : 
     597             : 
     598           7 : int wpas_mesh_add_interface(struct wpa_supplicant *wpa_s, char *ifname,
     599             :                             size_t len)
     600             : {
     601             :         struct wpa_interface iface;
     602             :         struct wpa_supplicant *mesh_wpa_s;
     603             :         u8 addr[ETH_ALEN];
     604             : 
     605           7 :         if (ifname[0] == '\0' && wpas_mesh_get_ifname(wpa_s, ifname, len) < 0)
     606           0 :                 return -1;
     607             : 
     608           7 :         if (wpa_drv_if_add(wpa_s, WPA_IF_MESH, ifname, NULL, NULL, NULL, addr,
     609             :                            NULL) < 0) {
     610           1 :                 wpa_printf(MSG_ERROR,
     611             :                            "mesh: Failed to create new mesh interface");
     612           1 :                 return -1;
     613             :         }
     614          36 :         wpa_printf(MSG_INFO, "mesh: Created virtual interface %s addr "
     615          36 :                    MACSTR, ifname, MAC2STR(addr));
     616             : 
     617           6 :         os_memset(&iface, 0, sizeof(iface));
     618           6 :         iface.ifname = ifname;
     619           6 :         iface.driver = wpa_s->driver->name;
     620           6 :         iface.driver_param = wpa_s->conf->driver_param;
     621           6 :         iface.ctrl_interface = wpa_s->conf->ctrl_interface;
     622             : 
     623           6 :         mesh_wpa_s = wpa_supplicant_add_iface(wpa_s->global, &iface, wpa_s);
     624           6 :         if (!mesh_wpa_s) {
     625           2 :                 wpa_printf(MSG_ERROR,
     626             :                            "mesh: Failed to create new wpa_supplicant interface");
     627           2 :                 wpa_drv_if_remove(wpa_s, WPA_IF_MESH, ifname);
     628           2 :                 return -1;
     629             :         }
     630           4 :         mesh_wpa_s->mesh_if_created = 1;
     631           4 :         return 0;
     632             : }
     633             : 
     634             : 
     635           9 : int wpas_mesh_peer_remove(struct wpa_supplicant *wpa_s, const u8 *addr)
     636             : {
     637           9 :         return mesh_mpm_close_peer(wpa_s, addr);
     638             : }
     639             : 
     640             : 
     641          13 : int wpas_mesh_peer_add(struct wpa_supplicant *wpa_s, const u8 *addr,
     642             :                        int duration)
     643             : {
     644          13 :         return mesh_mpm_connect_peer(wpa_s, addr, duration);
     645             : }

Generated by: LCOV version 1.10