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