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