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 1443382998 Lines: 237 292 81.2 %
Date: 2015-09-27 Functions: 13 13 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          70 : static void wpa_supplicant_mesh_deinit(struct wpa_supplicant *wpa_s)
      31             : {
      32          70 :         wpa_supplicant_mesh_iface_deinit(wpa_s, wpa_s->ifmsh);
      33          70 :         wpa_s->ifmsh = NULL;
      34          70 :         wpa_s->current_ssid = NULL;
      35          70 :         os_free(wpa_s->mesh_rsn);
      36          70 :         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          70 : }
      40             : 
      41             : 
      42          70 : void wpa_supplicant_mesh_iface_deinit(struct wpa_supplicant *wpa_s,
      43             :                                       struct hostapd_iface *ifmsh)
      44             : {
      45          70 :         if (!ifmsh)
      46         105 :                 return;
      47             : 
      48          35 :         if (ifmsh->mconf) {
      49          35 :                 mesh_mpm_deinit(wpa_s, ifmsh);
      50          35 :                 if (ifmsh->mconf->rsn_ie) {
      51          12 :                         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          35 :                 os_free(ifmsh->mconf);
      60          35 :                 ifmsh->mconf = NULL;
      61             :         }
      62             : 
      63             :         /* take care of shared data */
      64          35 :         hostapd_interface_deinit(ifmsh);
      65          35 :         hostapd_interface_free(ifmsh);
      66             : }
      67             : 
      68             : 
      69          35 : static struct mesh_conf * mesh_config_create(struct wpa_ssid *ssid)
      70             : {
      71             :         struct mesh_conf *conf;
      72             : 
      73          35 :         conf = os_zalloc(sizeof(struct mesh_conf));
      74          35 :         if (!conf)
      75           0 :                 return NULL;
      76             : 
      77          35 :         os_memcpy(conf->meshid, ssid->ssid, ssid->ssid_len);
      78          35 :         conf->meshid_len = ssid->ssid_len;
      79             : 
      80          35 :         if (ssid->key_mgmt & WPA_KEY_MGMT_SAE)
      81          14 :                 conf->security |= MESH_CONF_SEC_AUTH |
      82             :                         MESH_CONF_SEC_AMPE;
      83             :         else
      84          21 :                 conf->security |= MESH_CONF_SEC_NONE;
      85             : 
      86             :         /* defaults */
      87          35 :         conf->mesh_pp_id = MESH_PATH_PROTOCOL_HWMP;
      88          35 :         conf->mesh_pm_id = MESH_PATH_METRIC_AIRTIME;
      89          35 :         conf->mesh_cc_id = 0;
      90          35 :         conf->mesh_sp_id = MESH_SYNC_METHOD_NEIGHBOR_OFFSET;
      91          35 :         conf->mesh_auth_id = (conf->security & MESH_CONF_SEC_AUTH) ? 1 : 0;
      92          35 :         conf->dot11MeshMaxRetries = ssid->dot11MeshMaxRetries;
      93          35 :         conf->dot11MeshRetryTimeout = ssid->dot11MeshRetryTimeout;
      94          35 :         conf->dot11MeshConfirmTimeout = ssid->dot11MeshConfirmTimeout;
      95          35 :         conf->dot11MeshHoldingTimeout = ssid->dot11MeshHoldingTimeout;
      96             : 
      97          35 :         return conf;
      98             : }
      99             : 
     100             : 
     101           5 : static void wpas_mesh_copy_groups(struct hostapd_data *bss,
     102             :                                   struct wpa_supplicant *wpa_s)
     103             : {
     104             :         int num_groups;
     105             :         size_t groups_size;
     106             : 
     107          16 :         for (num_groups = 0; wpa_s->conf->sae_groups[num_groups] > 0;
     108           6 :              num_groups++)
     109             :                 ;
     110             : 
     111           5 :         groups_size = (num_groups + 1) * sizeof(wpa_s->conf->sae_groups[0]);
     112           5 :         bss->conf->sae_groups = os_malloc(groups_size);
     113           5 :         if (bss->conf->sae_groups)
     114           5 :                 os_memcpy(bss->conf->sae_groups, wpa_s->conf->sae_groups,
     115             :                           groups_size);
     116           5 : }
     117             : 
     118             : 
     119          35 : static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
     120             :                                     struct wpa_ssid *ssid)
     121             : {
     122             :         struct hostapd_iface *ifmsh;
     123             :         struct hostapd_data *bss;
     124             :         struct hostapd_config *conf;
     125             :         struct mesh_conf *mconf;
     126          35 :         int basic_rates_erp[] = { 10, 20, 55, 60, 110, 120, 240, -1 };
     127             :         static int default_groups[] = { 19, 20, 21, 25, 26, -1 };
     128             :         size_t len;
     129             :         int rate_len;
     130             : 
     131          35 :         if (!wpa_s->conf->user_mpm) {
     132             :                 /* not much for us to do here */
     133           0 :                 wpa_msg(wpa_s, MSG_WARNING,
     134             :                         "user_mpm is not enabled in configuration");
     135           0 :                 return 0;
     136             :         }
     137             : 
     138          35 :         wpa_s->ifmsh = ifmsh = os_zalloc(sizeof(*wpa_s->ifmsh));
     139          35 :         if (!ifmsh)
     140           0 :                 return -ENOMEM;
     141             : 
     142          35 :         ifmsh->drv_flags = wpa_s->drv_flags;
     143          35 :         ifmsh->num_bss = 1;
     144          35 :         ifmsh->bss = os_calloc(wpa_s->ifmsh->num_bss,
     145             :                                sizeof(struct hostapd_data *));
     146          35 :         if (!ifmsh->bss)
     147           0 :                 goto out_free;
     148             : 
     149          35 :         ifmsh->bss[0] = bss = os_zalloc(sizeof(struct hostapd_data));
     150          35 :         if (!bss)
     151           0 :                 goto out_free;
     152             : 
     153          35 :         os_memcpy(bss->own_addr, wpa_s->own_addr, ETH_ALEN);
     154          35 :         bss->driver = wpa_s->driver;
     155          35 :         bss->drv_priv = wpa_s->drv_priv;
     156          35 :         bss->iface = ifmsh;
     157          35 :         bss->mesh_sta_free_cb = mesh_mpm_free_sta;
     158          35 :         wpa_s->assoc_freq = ssid->frequency;
     159          35 :         wpa_s->current_ssid = ssid;
     160             : 
     161             :         /* setup an AP config for auth processing */
     162          35 :         conf = hostapd_config_defaults();
     163          35 :         if (!conf)
     164           0 :                 goto out_free;
     165             : 
     166          35 :         bss->conf = *conf->bss;
     167          35 :         bss->conf->start_disabled = 1;
     168          35 :         bss->conf->mesh = MESH_ENABLED;
     169          35 :         bss->conf->ap_max_inactivity = wpa_s->conf->mesh_max_inactivity;
     170          35 :         bss->iconf = conf;
     171          35 :         ifmsh->conf = conf;
     172             : 
     173          35 :         ifmsh->bss[0]->max_plinks = wpa_s->conf->max_peer_links;
     174          70 :         ifmsh->bss[0]->dot11RSNASAERetransPeriod =
     175          35 :                 wpa_s->conf->dot11RSNASAERetransPeriod;
     176          35 :         os_strlcpy(bss->conf->iface, wpa_s->ifname, sizeof(bss->conf->iface));
     177             : 
     178          35 :         mconf = mesh_config_create(ssid);
     179          35 :         if (!mconf)
     180           0 :                 goto out_free;
     181          35 :         ifmsh->mconf = mconf;
     182             : 
     183             :         /* need conf->hw_mode for supported rates. */
     184          35 :         if (ssid->frequency == 0) {
     185           0 :                 conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
     186           0 :                 conf->channel = 1;
     187             :         } else {
     188          35 :                 conf->hw_mode = ieee80211_freq_to_chan(ssid->frequency,
     189             :                                                        &conf->channel);
     190             :         }
     191          35 :         if (conf->hw_mode == NUM_HOSTAPD_MODES) {
     192           0 :                 wpa_printf(MSG_ERROR, "Unsupported mesh mode frequency: %d MHz",
     193             :                            ssid->frequency);
     194           0 :                 goto out_free;
     195             :         }
     196             : 
     197          35 :         if (ssid->mesh_basic_rates == NULL) {
     198             :                 /*
     199             :                  * XXX: Hack! This is so an MPM which correctly sets the ERP
     200             :                  * mandatory rates as BSSBasicRateSet doesn't reject us. We
     201             :                  * could add a new hw_mode HOSTAPD_MODE_IEEE80211G_ERP, but
     202             :                  * this is way easier. This also makes our BSSBasicRateSet
     203             :                  * advertised in beacons match the one in peering frames, sigh.
     204             :                  */
     205          35 :                 if (conf->hw_mode == HOSTAPD_MODE_IEEE80211G) {
     206          33 :                         conf->basic_rates = os_malloc(sizeof(basic_rates_erp));
     207          33 :                         if (!conf->basic_rates)
     208           0 :                                 goto out_free;
     209          33 :                         os_memcpy(conf->basic_rates, basic_rates_erp,
     210             :                                   sizeof(basic_rates_erp));
     211             :                 }
     212             :         } else {
     213           0 :                 rate_len = 0;
     214             :                 while (1) {
     215           0 :                         if (ssid->mesh_basic_rates[rate_len] < 1)
     216           0 :                                 break;
     217           0 :                         rate_len++;
     218           0 :                 }
     219           0 :                 conf->basic_rates = os_calloc(rate_len + 1, sizeof(int));
     220           0 :                 if (conf->basic_rates == NULL)
     221           0 :                         goto out_free;
     222           0 :                 os_memcpy(conf->basic_rates, ssid->mesh_basic_rates,
     223             :                           rate_len * sizeof(int));
     224           0 :                 conf->basic_rates[rate_len] = -1;
     225             :         }
     226             : 
     227          35 :         if (hostapd_setup_interface(ifmsh)) {
     228           0 :                 wpa_printf(MSG_ERROR,
     229             :                            "Failed to initialize hostapd interface for mesh");
     230           0 :                 return -1;
     231             :         }
     232             : 
     233          35 :         if (wpa_drv_init_mesh(wpa_s)) {
     234           0 :                 wpa_msg(wpa_s, MSG_ERROR, "Failed to init mesh in driver");
     235           0 :                 return -1;
     236             :         }
     237             : 
     238          35 :         if (mconf->security != MESH_CONF_SEC_NONE) {
     239          14 :                 if (ssid->passphrase == NULL) {
     240           1 :                         wpa_printf(MSG_ERROR,
     241             :                                    "mesh: Passphrase for SAE not configured");
     242           1 :                         goto out_free;
     243             :                 }
     244             : 
     245          13 :                 bss->conf->wpa = ssid->proto;
     246          13 :                 bss->conf->wpa_key_mgmt = ssid->key_mgmt;
     247             : 
     248          26 :                 if (wpa_s->conf->sae_groups &&
     249          13 :                     wpa_s->conf->sae_groups[0] > 0) {
     250           5 :                         wpas_mesh_copy_groups(bss, wpa_s);
     251             :                 } else {
     252          16 :                         bss->conf->sae_groups =
     253           8 :                                 os_malloc(sizeof(default_groups));
     254           8 :                         if (!bss->conf->sae_groups)
     255           0 :                                 goto out_free;
     256           8 :                         os_memcpy(bss->conf->sae_groups, default_groups,
     257             :                                   sizeof(default_groups));
     258             :                 }
     259             : 
     260          13 :                 len = os_strlen(ssid->passphrase);
     261          26 :                 bss->conf->ssid.wpa_passphrase =
     262          13 :                         dup_binstr(ssid->passphrase, len);
     263             : 
     264          13 :                 wpa_s->mesh_rsn = mesh_rsn_auth_init(wpa_s, mconf);
     265          13 :                 if (!wpa_s->mesh_rsn)
     266           1 :                         goto out_free;
     267             :         }
     268             : 
     269          33 :         wpa_supplicant_conf_ap_ht(wpa_s, ssid, conf);
     270             : 
     271          33 :         return 0;
     272             : out_free:
     273           2 :         wpa_supplicant_mesh_deinit(wpa_s);
     274           2 :         return -ENOMEM;
     275             : }
     276             : 
     277             : 
     278          53 : void wpa_mesh_notify_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
     279             :                           const u8 *ies, size_t ie_len)
     280             : {
     281             :         struct ieee802_11_elems elems;
     282             : 
     283         318 :         wpa_msg(wpa_s, MSG_INFO,
     284         318 :                 "new peer notification for " MACSTR, MAC2STR(addr));
     285             : 
     286          53 :         if (ieee802_11_parse_elems(ies, ie_len, &elems, 0) == ParseFailed) {
     287           0 :                 wpa_msg(wpa_s, MSG_INFO, "Could not parse beacon from " MACSTR,
     288           0 :                         MAC2STR(addr));
     289          53 :                 return;
     290             :         }
     291          53 :         wpa_mesh_new_mesh_peer(wpa_s, addr, &elems);
     292             : }
     293             : 
     294             : 
     295        3703 : void wpa_supplicant_mesh_add_scan_ie(struct wpa_supplicant *wpa_s,
     296             :                                      struct wpabuf **extra_ie)
     297             : {
     298             :         /* EID + 0-length (wildcard) mesh-id */
     299        3703 :         size_t ielen = 2;
     300             : 
     301        3703 :         if (wpabuf_resize(extra_ie, ielen) == 0) {
     302        3703 :                 wpabuf_put_u8(*extra_ie, WLAN_EID_MESH_ID);
     303        3703 :                 wpabuf_put_u8(*extra_ie, 0);
     304             :         }
     305        3703 : }
     306             : 
     307             : 
     308          35 : int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s,
     309             :                              struct wpa_ssid *ssid)
     310             : {
     311             :         struct wpa_driver_mesh_join_params params;
     312          35 :         int ret = 0;
     313             : 
     314          35 :         if (!ssid || !ssid->ssid || !ssid->ssid_len || !ssid->frequency) {
     315           0 :                 ret = -ENOENT;
     316           0 :                 goto out;
     317             :         }
     318             : 
     319          35 :         wpa_supplicant_mesh_deinit(wpa_s);
     320             : 
     321          35 :         os_memset(&params, 0, sizeof(params));
     322          35 :         params.meshid = ssid->ssid;
     323          35 :         params.meshid_len = ssid->ssid_len;
     324          35 :         ibss_mesh_setup_freq(wpa_s, ssid, &params.freq);
     325          35 :         wpa_s->mesh_ht_enabled = !!params.freq.ht_enabled;
     326          35 :         if (ssid->beacon_int > 0)
     327           3 :                 params.beacon_int = ssid->beacon_int;
     328          32 :         else if (wpa_s->conf->beacon_int > 0)
     329           0 :                 params.beacon_int = wpa_s->conf->beacon_int;
     330          35 :         params.max_peer_links = wpa_s->conf->max_peer_links;
     331             : 
     332          35 :         if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
     333          14 :                 params.flags |= WPA_DRIVER_MESH_FLAG_SAE_AUTH;
     334          14 :                 params.flags |= WPA_DRIVER_MESH_FLAG_AMPE;
     335          14 :                 wpa_s->conf->user_mpm = 1;
     336             :         }
     337             : 
     338          35 :         if (wpa_s->conf->user_mpm) {
     339          35 :                 params.flags |= WPA_DRIVER_MESH_FLAG_USER_MPM;
     340          35 :                 params.conf.flags &= ~WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS;
     341             :         } else {
     342           0 :                 params.flags |= WPA_DRIVER_MESH_FLAG_DRIVER_MPM;
     343           0 :                 params.conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS;
     344             :         }
     345          35 :         params.conf.peer_link_timeout = wpa_s->conf->mesh_max_inactivity;
     346             : 
     347          35 :         if (wpa_supplicant_mesh_init(wpa_s, ssid)) {
     348           2 :                 wpa_msg(wpa_s, MSG_ERROR, "Failed to init mesh");
     349           2 :                 wpa_drv_leave_mesh(wpa_s);
     350           2 :                 ret = -1;
     351           2 :                 goto out;
     352             :         }
     353             : 
     354          33 :         if (wpa_s->ifmsh) {
     355          33 :                 params.ies = wpa_s->ifmsh->mconf->rsn_ie;
     356          33 :                 params.ie_len = wpa_s->ifmsh->mconf->rsn_ie_len;
     357          33 :                 params.basic_rates = wpa_s->ifmsh->basic_rates;
     358             :         }
     359             : 
     360          66 :         wpa_msg(wpa_s, MSG_INFO, "joining mesh %s",
     361          33 :                 wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
     362          33 :         ret = wpa_drv_join_mesh(wpa_s, &params);
     363          33 :         if (ret)
     364           0 :                 wpa_msg(wpa_s, MSG_ERROR, "mesh join error=%d\n", ret);
     365             : 
     366             :         /* hostapd sets the interface down until we associate */
     367          33 :         wpa_drv_set_operstate(wpa_s, 1);
     368             : 
     369             : out:
     370          35 :         return ret;
     371             : }
     372             : 
     373             : 
     374          33 : int wpa_supplicant_leave_mesh(struct wpa_supplicant *wpa_s)
     375             : {
     376          33 :         int ret = 0;
     377             : 
     378          33 :         wpa_msg(wpa_s, MSG_INFO, "leaving mesh");
     379             : 
     380             :         /* Need to send peering close messages first */
     381          33 :         wpa_supplicant_mesh_deinit(wpa_s);
     382             : 
     383          33 :         ret = wpa_drv_leave_mesh(wpa_s);
     384          33 :         if (ret)
     385           0 :                 wpa_msg(wpa_s, MSG_ERROR, "mesh leave error=%d", ret);
     386             : 
     387          33 :         wpa_drv_set_operstate(wpa_s, 1);
     388             : 
     389          33 :         return ret;
     390             : }
     391             : 
     392             : 
     393        2205 : static int mesh_attr_text(const u8 *ies, size_t ies_len, char *buf, char *end)
     394             : {
     395             :         struct ieee802_11_elems elems;
     396        2205 :         char *mesh_id, *pos = buf;
     397             :         u8 *bss_basic_rate_set;
     398             :         int bss_basic_rate_set_len, ret, i;
     399             : 
     400        2205 :         if (ieee802_11_parse_elems(ies, ies_len, &elems, 0) == ParseFailed)
     401           0 :                 return -1;
     402             : 
     403        2205 :         if (elems.mesh_id_len < 1)
     404        2204 :                 return 0;
     405             : 
     406           1 :         mesh_id = os_malloc(elems.mesh_id_len + 1);
     407           1 :         if (mesh_id == NULL)
     408           0 :                 return -1;
     409             : 
     410           1 :         os_memcpy(mesh_id, elems.mesh_id, elems.mesh_id_len);
     411           1 :         mesh_id[elems.mesh_id_len] = '\0';
     412           1 :         ret = os_snprintf(pos, end - pos, "mesh_id=%s\n", mesh_id);
     413           1 :         os_free(mesh_id);
     414           1 :         if (os_snprintf_error(end - pos, ret))
     415           0 :                 return pos - buf;
     416           1 :         pos += ret;
     417             : 
     418           1 :         if (elems.mesh_config_len > 6) {
     419           7 :                 ret = os_snprintf(pos, end - pos,
     420             :                                   "active_path_selection_protocol_id=0x%02x\n"
     421             :                                   "active_path_selection_metric_id=0x%02x\n"
     422             :                                   "congestion_control_mode_id=0x%02x\n"
     423             :                                   "synchronization_method_id=0x%02x\n"
     424             :                                   "authentication_protocol_id=0x%02x\n"
     425             :                                   "mesh_formation_info=0x%02x\n"
     426             :                                   "mesh_capability=0x%02x\n",
     427           2 :                                   elems.mesh_config[0], elems.mesh_config[1],
     428           2 :                                   elems.mesh_config[2], elems.mesh_config[3],
     429           2 :                                   elems.mesh_config[4], elems.mesh_config[5],
     430           1 :                                   elems.mesh_config[6]);
     431           1 :                 if (os_snprintf_error(end - pos, ret))
     432           0 :                         return pos - buf;
     433           1 :                 pos += ret;
     434             :         }
     435             : 
     436           2 :         bss_basic_rate_set = os_malloc(elems.supp_rates_len +
     437           1 :                 elems.ext_supp_rates_len);
     438           1 :         if (bss_basic_rate_set == NULL)
     439           0 :                 return -1;
     440             : 
     441           1 :         bss_basic_rate_set_len = 0;
     442           9 :         for (i = 0; i < elems.supp_rates_len; i++) {
     443           8 :                 if (elems.supp_rates[i] & 0x80) {
     444          12 :                         bss_basic_rate_set[bss_basic_rate_set_len++] =
     445           6 :                                 (elems.supp_rates[i] & 0x7f) * 5;
     446             :                 }
     447             :         }
     448           5 :         for (i = 0; i < elems.ext_supp_rates_len; i++) {
     449           4 :                 if (elems.ext_supp_rates[i] & 0x80) {
     450           2 :                         bss_basic_rate_set[bss_basic_rate_set_len++] =
     451           1 :                                 (elems.ext_supp_rates[i] & 0x7f) * 5;
     452             :                 }
     453             :         }
     454           1 :         if (bss_basic_rate_set_len > 0) {
     455           1 :                 ret = os_snprintf(pos, end - pos, "bss_basic_rate_set=%d",
     456           1 :                                   bss_basic_rate_set[0]);
     457           1 :                 if (os_snprintf_error(end - pos, ret))
     458           0 :                         goto fail;
     459           1 :                 pos += ret;
     460             : 
     461           7 :                 for (i = 1; i < bss_basic_rate_set_len; i++) {
     462           6 :                         ret = os_snprintf(pos, end - pos, " %d",
     463           6 :                                           bss_basic_rate_set[i]);
     464           6 :                         if (os_snprintf_error(end - pos, ret))
     465           0 :                                 goto fail;
     466           6 :                         pos += ret;
     467             :                 }
     468             : 
     469           1 :                 ret = os_snprintf(pos, end - pos, "\n");
     470           1 :                 if (os_snprintf_error(end - pos, ret))
     471           0 :                         goto fail;
     472           1 :                 pos += ret;
     473             :         }
     474             : fail:
     475           1 :         os_free(bss_basic_rate_set);
     476             : 
     477           1 :         return pos - buf;
     478             : }
     479             : 
     480             : 
     481        2205 : int wpas_mesh_scan_result_text(const u8 *ies, size_t ies_len, char *buf,
     482             :                                char *end)
     483             : {
     484        2205 :         return mesh_attr_text(ies, ies_len, buf, end);
     485             : }
     486             : 
     487             : 
     488           2 : static int wpas_mesh_get_ifname(struct wpa_supplicant *wpa_s, char *ifname,
     489             :                                 size_t len)
     490             : {
     491           2 :         char *ifname_ptr = wpa_s->ifname;
     492             :         int res;
     493             : 
     494           2 :         res = os_snprintf(ifname, len, "mesh-%s-%d", ifname_ptr,
     495             :                           wpa_s->mesh_if_idx);
     496           4 :         if (os_snprintf_error(len, res) ||
     497           2 :             (os_strlen(ifname) >= IFNAMSIZ &&
     498           0 :              os_strlen(wpa_s->ifname) < IFNAMSIZ)) {
     499             :                 /* Try to avoid going over the IFNAMSIZ length limit */
     500           0 :                 res = os_snprintf(ifname, len, "mesh-%d", wpa_s->mesh_if_idx);
     501           0 :                 if (os_snprintf_error(len, res))
     502           0 :                         return -1;
     503             :         }
     504           2 :         wpa_s->mesh_if_idx++;
     505           2 :         return 0;
     506             : }
     507             : 
     508             : 
     509           4 : int wpas_mesh_add_interface(struct wpa_supplicant *wpa_s, char *ifname,
     510             :                             size_t len)
     511             : {
     512             :         struct wpa_interface iface;
     513             :         struct wpa_supplicant *mesh_wpa_s;
     514             :         u8 addr[ETH_ALEN];
     515             : 
     516           4 :         if (ifname[0] == '\0' && wpas_mesh_get_ifname(wpa_s, ifname, len) < 0)
     517           0 :                 return -1;
     518             : 
     519           4 :         if (wpa_drv_if_add(wpa_s, WPA_IF_MESH, ifname, NULL, NULL, NULL, addr,
     520             :                            NULL) < 0) {
     521           0 :                 wpa_printf(MSG_ERROR,
     522             :                            "mesh: Failed to create new mesh interface");
     523           0 :                 return -1;
     524             :         }
     525          24 :         wpa_printf(MSG_INFO, "mesh: Created virtual interface %s addr "
     526          24 :                    MACSTR, ifname, MAC2STR(addr));
     527             : 
     528           4 :         os_memset(&iface, 0, sizeof(iface));
     529           4 :         iface.ifname = ifname;
     530           4 :         iface.driver = wpa_s->driver->name;
     531           4 :         iface.driver_param = wpa_s->conf->driver_param;
     532           4 :         iface.ctrl_interface = wpa_s->conf->ctrl_interface;
     533             : 
     534           4 :         mesh_wpa_s = wpa_supplicant_add_iface(wpa_s->global, &iface, wpa_s);
     535           4 :         if (!mesh_wpa_s) {
     536           0 :                 wpa_printf(MSG_ERROR,
     537             :                            "mesh: Failed to create new wpa_supplicant interface");
     538           0 :                 wpa_supplicant_remove_iface(wpa_s->global, wpa_s, 0);
     539           0 :                 return -1;
     540             :         }
     541           4 :         mesh_wpa_s->mesh_if_created = 1;
     542           4 :         return 0;
     543             : }

Generated by: LCOV version 1.10