2 * WPA Supplicant - Basic mesh mode routines
3 * Copyright (c) 2013-2014, cozybit, Inc. All rights reserved.
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
9 #include "utils/includes.h"
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"
21 #include "wpa_supplicant_i.h"
30 static void wpa_supplicant_mesh_deinit(struct wpa_supplicant
*wpa_s
)
32 wpa_supplicant_mesh_iface_deinit(wpa_s
, wpa_s
->ifmsh
);
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 */
44 void wpa_supplicant_mesh_iface_deinit(struct wpa_supplicant
*wpa_s
,
45 struct hostapd_iface
*ifmsh
)
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.
61 os_free(ifmsh
->mconf
);
65 /* take care of shared data */
66 hostapd_interface_deinit(ifmsh
);
67 hostapd_interface_free(ifmsh
);
71 static struct mesh_conf
* mesh_config_create(struct wpa_supplicant
*wpa_s
,
72 struct wpa_ssid
*ssid
)
74 struct mesh_conf
*conf
;
77 conf
= os_zalloc(sizeof(struct mesh_conf
));
81 os_memcpy(conf
->meshid
, ssid
->ssid
, ssid
->ssid_len
);
82 conf
->meshid_len
= ssid
->ssid_len
;
84 if (ssid
->key_mgmt
& WPA_KEY_MGMT_SAE
)
85 conf
->security
|= MESH_CONF_SEC_AUTH
|
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
;
95 conf
->ieee80211w
= NO_MGMT_FRAME_PROTECTION
;
97 #endif /* CONFIG_IEEE80211W */
99 conf
->ocv
= ssid
->ocv
;
100 #endif /* CONFIG_OCV */
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");
108 conf
->pairwise_cipher
= cipher
;
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");
118 conf
->group_cipher
= cipher
;
119 if (conf
->ieee80211w
!= NO_MGMT_FRAME_PROTECTION
)
120 conf
->mgmt_group_cipher
= WPA_CIPHER_AES_128_CMAC
;
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
;
137 static void wpas_mesh_copy_groups(struct hostapd_data
*bss
,
138 struct wpa_supplicant
*wpa_s
)
143 for (num_groups
= 0; wpa_s
->conf
->sae_groups
[num_groups
] > 0;
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
,
155 static int wpas_mesh_init_rsn(struct wpa_supplicant
*wpa_s
)
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
;
164 password
= ssid
->sae_password
;
166 password
= ssid
->passphrase
;
168 wpa_printf(MSG_ERROR
,
169 "mesh: Passphrase for SAE not configured");
173 bss
->conf
->wpa
= ssid
->proto
;
174 bss
->conf
->wpa_key_mgmt
= ssid
->key_mgmt
;
176 if (wpa_s
->conf
->sae_groups
&& wpa_s
->conf
->sae_groups
[0] > 0) {
177 wpas_mesh_copy_groups(bss
, wpa_s
);
179 bss
->conf
->sae_groups
= os_memdup(default_groups
,
180 sizeof(default_groups
));
181 if (!bss
->conf
->sae_groups
)
185 len
= os_strlen(password
);
186 bss
->conf
->ssid
.wpa_passphrase
= dup_binstr(password
, len
);
188 wpa_s
->mesh_rsn
= mesh_rsn_auth_init(wpa_s
, ifmsh
->mconf
);
189 return !wpa_s
->mesh_rsn
? -1 : 0;
193 static int wpas_mesh_complete(struct wpa_supplicant
*wpa_s
)
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
;
200 if (!params
|| !ssid
) {
201 wpa_printf(MSG_ERROR
, "mesh: %s called without active mesh",
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
);
214 if (ssid
->key_mgmt
& WPA_KEY_MGMT_SAE
) {
215 wpa_s
->pairwise_cipher
= wpa_s
->mesh_rsn
->pairwise_cipher
;
216 wpa_s
->group_cipher
= wpa_s
->mesh_rsn
->group_cipher
;
217 wpa_s
->mgmt_group_cipher
= wpa_s
->mesh_rsn
->mgmt_group_cipher
;
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
;
228 wpa_msg(wpa_s
, MSG_INFO
, "joining mesh %s",
229 wpa_ssid_txt(ssid
->ssid
, ssid
->ssid_len
));
230 ret
= wpa_drv_join_mesh(wpa_s
, params
);
232 wpa_msg(wpa_s
, MSG_ERROR
, "mesh join error=%d", ret
);
234 /* hostapd sets the interface down until we associate */
235 wpa_drv_set_operstate(wpa_s
, 1);
238 wpa_supplicant_set_state(wpa_s
, WPA_COMPLETED
);
244 static int wpa_supplicant_mesh_init(struct wpa_supplicant
*wpa_s
,
245 struct wpa_ssid
*ssid
,
246 struct hostapd_freq_params
*freq
)
248 struct hostapd_iface
*ifmsh
;
249 struct hostapd_data
*bss
;
250 struct hostapd_config
*conf
;
251 struct mesh_conf
*mconf
;
252 int basic_rates_erp
[] = { 10, 20, 55, 60, 110, 120, 240, -1 };
254 int frequency
, saved_freq
;
256 if (!wpa_s
->conf
->user_mpm
) {
257 /* not much for us to do here */
258 wpa_msg(wpa_s
, MSG_WARNING
,
259 "user_mpm is not enabled in configuration");
263 wpa_s
->ifmsh
= ifmsh
= hostapd_alloc_iface();
267 ifmsh
->drv_flags
= wpa_s
->drv_flags
;
269 ifmsh
->bss
= os_calloc(wpa_s
->ifmsh
->num_bss
,
270 sizeof(struct hostapd_data
*));
274 ifmsh
->bss
[0] = bss
= hostapd_alloc_bss_data(NULL
, NULL
, NULL
);
278 ifmsh
->bss
[0]->msg_ctx
= wpa_s
;
279 os_memcpy(bss
->own_addr
, wpa_s
->own_addr
, ETH_ALEN
);
280 bss
->driver
= wpa_s
->driver
;
281 bss
->drv_priv
= wpa_s
->drv_priv
;
283 bss
->mesh_sta_free_cb
= mesh_mpm_free_sta
;
284 frequency
= ssid
->frequency
;
285 if (frequency
!= freq
->freq
&&
286 frequency
== freq
->freq
+ freq
->sec_channel_offset
* 20) {
287 wpa_printf(MSG_DEBUG
, "mesh: pri/sec channels switched");
288 frequency
= freq
->freq
;
290 wpa_s
->assoc_freq
= frequency
;
291 wpa_s
->current_ssid
= ssid
;
293 /* setup an AP config for auth processing */
294 conf
= hostapd_config_defaults();
298 bss
->conf
= *conf
->bss
;
299 bss
->conf
->start_disabled
= 1;
300 bss
->conf
->mesh
= MESH_ENABLED
;
301 bss
->conf
->ap_max_inactivity
= wpa_s
->conf
->mesh_max_inactivity
;
303 if (ieee80211_is_dfs(ssid
->frequency
, wpa_s
->hw
.modes
,
304 wpa_s
->hw
.num_modes
) && wpa_s
->conf
->country
[0]) {
305 conf
->ieee80211h
= 1;
306 conf
->ieee80211d
= 1;
307 conf
->country
[0] = wpa_s
->conf
->country
[0];
308 conf
->country
[1] = wpa_s
->conf
->country
[1];
309 conf
->country
[2] = ' ';
315 ifmsh
->bss
[0]->max_plinks
= wpa_s
->conf
->max_peer_links
;
316 ifmsh
->bss
[0]->dot11RSNASAERetransPeriod
=
317 wpa_s
->conf
->dot11RSNASAERetransPeriod
;
318 os_strlcpy(bss
->conf
->iface
, wpa_s
->ifname
, sizeof(bss
->conf
->iface
));
320 mconf
= mesh_config_create(wpa_s
, ssid
);
323 ifmsh
->mconf
= mconf
;
325 /* need conf->hw_mode for supported rates. */
326 conf
->hw_mode
= ieee80211_freq_to_chan(frequency
, &conf
->channel
);
327 if (conf
->hw_mode
== NUM_HOSTAPD_MODES
) {
328 wpa_printf(MSG_ERROR
, "Unsupported mesh mode frequency: %d MHz",
333 conf
->secondary_channel
= ssid
->ht40
;
334 if (conf
->hw_mode
== HOSTAPD_MODE_IEEE80211A
&& ssid
->vht
) {
335 if (ssid
->max_oper_chwidth
!= DEFAULT_MAX_OPER_CHWIDTH
)
336 conf
->vht_oper_chwidth
= ssid
->max_oper_chwidth
;
337 switch (conf
->vht_oper_chwidth
) {
338 case VHT_CHANWIDTH_80MHZ
:
339 case VHT_CHANWIDTH_80P80MHZ
:
340 ieee80211_freq_to_chan(
342 &conf
->vht_oper_centr_freq_seg0_idx
);
343 conf
->vht_oper_centr_freq_seg0_idx
+= ssid
->ht40
* 2;
345 case VHT_CHANWIDTH_160MHZ
:
346 ieee80211_freq_to_chan(
348 &conf
->vht_oper_centr_freq_seg0_idx
);
349 conf
->vht_oper_centr_freq_seg0_idx
+= ssid
->ht40
* 2;
350 conf
->vht_oper_centr_freq_seg0_idx
+= 40 / 5;
353 ieee80211_freq_to_chan(ssid
->vht_center_freq2
,
354 &conf
->vht_oper_centr_freq_seg1_idx
);
357 if (ssid
->mesh_basic_rates
== NULL
) {
359 * XXX: Hack! This is so an MPM which correctly sets the ERP
360 * mandatory rates as BSSBasicRateSet doesn't reject us. We
361 * could add a new hw_mode HOSTAPD_MODE_IEEE80211G_ERP, but
362 * this is way easier. This also makes our BSSBasicRateSet
363 * advertised in beacons match the one in peering frames, sigh.
365 if (conf
->hw_mode
== HOSTAPD_MODE_IEEE80211G
) {
366 conf
->basic_rates
= os_memdup(basic_rates_erp
,
367 sizeof(basic_rates_erp
));
368 if (!conf
->basic_rates
)
374 if (ssid
->mesh_basic_rates
[rate_len
] < 1)
378 conf
->basic_rates
= os_calloc(rate_len
+ 1, sizeof(int));
379 if (conf
->basic_rates
== NULL
)
381 os_memcpy(conf
->basic_rates
, ssid
->mesh_basic_rates
,
382 rate_len
* sizeof(int));
383 conf
->basic_rates
[rate_len
] = -1;
386 /* Handle pri/sec switch frequency within AP configuration parameter
387 * generation without changing the stored network profile in the end. */
388 saved_freq
= ssid
->frequency
;
389 ssid
->frequency
= frequency
;
390 wpa_supplicant_conf_ap_ht(wpa_s
, ssid
, conf
);
391 ssid
->frequency
= saved_freq
;
393 if (wpa_drv_init_mesh(wpa_s
)) {
394 wpa_msg(wpa_s
, MSG_ERROR
, "Failed to init mesh in driver");
398 if (hostapd_setup_interface(ifmsh
)) {
399 wpa_printf(MSG_ERROR
,
400 "Failed to initialize hostapd interface for mesh");
406 wpa_supplicant_mesh_deinit(wpa_s
);
411 void wpa_mesh_notify_peer(struct wpa_supplicant
*wpa_s
, const u8
*addr
,
412 const u8
*ies
, size_t ie_len
)
414 struct ieee802_11_elems elems
;
416 wpa_msg(wpa_s
, MSG_INFO
,
417 "new peer notification for " MACSTR
, MAC2STR(addr
));
419 if (ieee802_11_parse_elems(ies
, ie_len
, &elems
, 0) == ParseFailed
) {
420 wpa_msg(wpa_s
, MSG_INFO
, "Could not parse beacon from " MACSTR
,
424 wpa_mesh_new_mesh_peer(wpa_s
, addr
, &elems
);
428 void wpa_supplicant_mesh_add_scan_ie(struct wpa_supplicant
*wpa_s
,
429 struct wpabuf
**extra_ie
)
431 /* EID + 0-length (wildcard) mesh-id */
434 if (wpabuf_resize(extra_ie
, ielen
) == 0) {
435 wpabuf_put_u8(*extra_ie
, WLAN_EID_MESH_ID
);
436 wpabuf_put_u8(*extra_ie
, 0);
441 int wpa_supplicant_join_mesh(struct wpa_supplicant
*wpa_s
,
442 struct wpa_ssid
*ssid
)
444 struct wpa_driver_mesh_join_params
*params
= os_zalloc(sizeof(*params
));
447 if (!ssid
|| !ssid
->ssid
|| !ssid
->ssid_len
|| !ssid
->frequency
||
454 wpa_supplicant_mesh_deinit(wpa_s
);
456 wpa_s
->pairwise_cipher
= WPA_CIPHER_NONE
;
457 wpa_s
->group_cipher
= WPA_CIPHER_NONE
;
458 wpa_s
->mgmt_group_cipher
= 0;
460 params
->meshid
= ssid
->ssid
;
461 params
->meshid_len
= ssid
->ssid_len
;
462 ibss_mesh_setup_freq(wpa_s
, ssid
, ¶ms
->freq
);
463 wpa_s
->mesh_ht_enabled
= !!params
->freq
.ht_enabled
;
464 wpa_s
->mesh_vht_enabled
= !!params
->freq
.vht_enabled
;
465 if (params
->freq
.ht_enabled
&& params
->freq
.sec_channel_offset
)
466 ssid
->ht40
= params
->freq
.sec_channel_offset
;
468 if (wpa_s
->mesh_vht_enabled
) {
470 ssid
->vht_center_freq1
= params
->freq
.center_freq1
;
471 switch (params
->freq
.bandwidth
) {
473 if (params
->freq
.center_freq2
) {
474 ssid
->max_oper_chwidth
= VHT_CHANWIDTH_80P80MHZ
;
475 ssid
->vht_center_freq2
=
476 params
->freq
.center_freq2
;
478 ssid
->max_oper_chwidth
= VHT_CHANWIDTH_80MHZ
;
482 ssid
->max_oper_chwidth
= VHT_CHANWIDTH_160MHZ
;
485 ssid
->max_oper_chwidth
= VHT_CHANWIDTH_USE_HT
;
489 if (ssid
->beacon_int
> 0)
490 params
->beacon_int
= ssid
->beacon_int
;
491 else if (wpa_s
->conf
->beacon_int
> 0)
492 params
->beacon_int
= wpa_s
->conf
->beacon_int
;
493 if (ssid
->dtim_period
> 0)
494 params
->dtim_period
= ssid
->dtim_period
;
495 else if (wpa_s
->conf
->dtim_period
> 0)
496 params
->dtim_period
= wpa_s
->conf
->dtim_period
;
497 params
->conf
.max_peer_links
= wpa_s
->conf
->max_peer_links
;
498 if (ssid
->mesh_rssi_threshold
< DEFAULT_MESH_RSSI_THRESHOLD
) {
499 params
->conf
.rssi_threshold
= ssid
->mesh_rssi_threshold
;
500 params
->conf
.flags
|= WPA_DRIVER_MESH_CONF_FLAG_RSSI_THRESHOLD
;
503 if (ssid
->key_mgmt
& WPA_KEY_MGMT_SAE
) {
504 params
->flags
|= WPA_DRIVER_MESH_FLAG_SAE_AUTH
;
505 params
->flags
|= WPA_DRIVER_MESH_FLAG_AMPE
;
506 wpa_s
->conf
->user_mpm
= 1;
509 if (wpa_s
->conf
->user_mpm
) {
510 params
->flags
|= WPA_DRIVER_MESH_FLAG_USER_MPM
;
511 params
->conf
.auto_plinks
= 0;
513 params
->flags
|= WPA_DRIVER_MESH_FLAG_DRIVER_MPM
;
514 params
->conf
.auto_plinks
= 1;
516 params
->conf
.peer_link_timeout
= wpa_s
->conf
->mesh_max_inactivity
;
518 os_free(wpa_s
->mesh_params
);
519 wpa_s
->mesh_params
= params
;
520 if (wpa_supplicant_mesh_init(wpa_s
, ssid
, ¶ms
->freq
)) {
521 wpa_msg(wpa_s
, MSG_ERROR
, "Failed to init mesh");
522 wpa_drv_leave_mesh(wpa_s
);
527 ret
= wpas_mesh_complete(wpa_s
);
533 int wpa_supplicant_leave_mesh(struct wpa_supplicant
*wpa_s
)
537 wpa_msg(wpa_s
, MSG_INFO
, "leaving mesh");
539 /* Need to send peering close messages first */
540 wpa_supplicant_mesh_deinit(wpa_s
);
542 ret
= wpa_drv_leave_mesh(wpa_s
);
544 wpa_msg(wpa_s
, MSG_ERROR
, "mesh leave error=%d", ret
);
546 wpa_drv_set_operstate(wpa_s
, 1);
552 static int mesh_attr_text(const u8
*ies
, size_t ies_len
, char *buf
, char *end
)
554 struct ieee802_11_elems elems
;
555 char *mesh_id
, *pos
= buf
;
556 u8
*bss_basic_rate_set
;
557 int bss_basic_rate_set_len
, ret
, i
;
559 if (ieee802_11_parse_elems(ies
, ies_len
, &elems
, 0) == ParseFailed
)
562 if (elems
.mesh_id_len
< 1)
565 mesh_id
= os_malloc(elems
.mesh_id_len
+ 1);
569 os_memcpy(mesh_id
, elems
.mesh_id
, elems
.mesh_id_len
);
570 mesh_id
[elems
.mesh_id_len
] = '\0';
571 ret
= os_snprintf(pos
, end
- pos
, "mesh_id=%s\n", mesh_id
);
573 if (os_snprintf_error(end
- pos
, ret
))
577 if (elems
.mesh_config_len
> 6) {
578 ret
= os_snprintf(pos
, end
- pos
,
579 "active_path_selection_protocol_id=0x%02x\n"
580 "active_path_selection_metric_id=0x%02x\n"
581 "congestion_control_mode_id=0x%02x\n"
582 "synchronization_method_id=0x%02x\n"
583 "authentication_protocol_id=0x%02x\n"
584 "mesh_formation_info=0x%02x\n"
585 "mesh_capability=0x%02x\n",
586 elems
.mesh_config
[0], elems
.mesh_config
[1],
587 elems
.mesh_config
[2], elems
.mesh_config
[3],
588 elems
.mesh_config
[4], elems
.mesh_config
[5],
589 elems
.mesh_config
[6]);
590 if (os_snprintf_error(end
- pos
, ret
))
595 bss_basic_rate_set
= os_malloc(elems
.supp_rates_len
+
596 elems
.ext_supp_rates_len
);
597 if (bss_basic_rate_set
== NULL
)
600 bss_basic_rate_set_len
= 0;
601 for (i
= 0; i
< elems
.supp_rates_len
; i
++) {
602 if (elems
.supp_rates
[i
] & 0x80) {
603 bss_basic_rate_set
[bss_basic_rate_set_len
++] =
604 (elems
.supp_rates
[i
] & 0x7f) * 5;
607 for (i
= 0; i
< elems
.ext_supp_rates_len
; i
++) {
608 if (elems
.ext_supp_rates
[i
] & 0x80) {
609 bss_basic_rate_set
[bss_basic_rate_set_len
++] =
610 (elems
.ext_supp_rates
[i
] & 0x7f) * 5;
613 if (bss_basic_rate_set_len
> 0) {
614 ret
= os_snprintf(pos
, end
- pos
, "bss_basic_rate_set=%d",
615 bss_basic_rate_set
[0]);
616 if (os_snprintf_error(end
- pos
, ret
))
620 for (i
= 1; i
< bss_basic_rate_set_len
; i
++) {
621 ret
= os_snprintf(pos
, end
- pos
, " %d",
622 bss_basic_rate_set
[i
]);
623 if (os_snprintf_error(end
- pos
, ret
))
628 ret
= os_snprintf(pos
, end
- pos
, "\n");
629 if (os_snprintf_error(end
- pos
, ret
))
634 os_free(bss_basic_rate_set
);
640 int wpas_mesh_scan_result_text(const u8
*ies
, size_t ies_len
, char *buf
,
643 return mesh_attr_text(ies
, ies_len
, buf
, end
);
647 static int wpas_mesh_get_ifname(struct wpa_supplicant
*wpa_s
, char *ifname
,
650 char *ifname_ptr
= wpa_s
->ifname
;
653 res
= os_snprintf(ifname
, len
, "mesh-%s-%d", ifname_ptr
,
655 if (os_snprintf_error(len
, res
) ||
656 (os_strlen(ifname
) >= IFNAMSIZ
&&
657 os_strlen(wpa_s
->ifname
) < IFNAMSIZ
)) {
658 /* Try to avoid going over the IFNAMSIZ length limit */
659 res
= os_snprintf(ifname
, len
, "mesh-%d", wpa_s
->mesh_if_idx
);
660 if (os_snprintf_error(len
, res
))
663 wpa_s
->mesh_if_idx
++;
668 int wpas_mesh_add_interface(struct wpa_supplicant
*wpa_s
, char *ifname
,
671 struct wpa_interface iface
;
672 struct wpa_supplicant
*mesh_wpa_s
;
675 if (ifname
[0] == '\0' && wpas_mesh_get_ifname(wpa_s
, ifname
, len
) < 0)
678 if (wpa_drv_if_add(wpa_s
, WPA_IF_MESH
, ifname
, NULL
, NULL
, NULL
, addr
,
680 wpa_printf(MSG_ERROR
,
681 "mesh: Failed to create new mesh interface");
684 wpa_printf(MSG_INFO
, "mesh: Created virtual interface %s addr "
685 MACSTR
, ifname
, MAC2STR(addr
));
687 os_memset(&iface
, 0, sizeof(iface
));
688 iface
.ifname
= ifname
;
689 iface
.driver
= wpa_s
->driver
->name
;
690 iface
.driver_param
= wpa_s
->conf
->driver_param
;
691 iface
.ctrl_interface
= wpa_s
->conf
->ctrl_interface
;
693 mesh_wpa_s
= wpa_supplicant_add_iface(wpa_s
->global
, &iface
, wpa_s
);
695 wpa_printf(MSG_ERROR
,
696 "mesh: Failed to create new wpa_supplicant interface");
697 wpa_drv_if_remove(wpa_s
, WPA_IF_MESH
, ifname
);
700 mesh_wpa_s
->mesh_if_created
= 1;
705 int wpas_mesh_peer_remove(struct wpa_supplicant
*wpa_s
, const u8
*addr
)
707 return mesh_mpm_close_peer(wpa_s
, addr
);
711 int wpas_mesh_peer_add(struct wpa_supplicant
*wpa_s
, const u8
*addr
,
714 return mesh_mpm_connect_peer(wpa_s
, addr
, duration
);