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 conf
->ieee80211w
= ssid
->ieee80211w
;
90 if (conf
->ieee80211w
== MGMT_FRAME_PROTECTION_DEFAULT
) {
91 if (wpa_s
->drv_enc
& WPA_DRIVER_CAPA_ENC_BIP
)
92 conf
->ieee80211w
= wpa_s
->conf
->pmf
;
94 conf
->ieee80211w
= NO_MGMT_FRAME_PROTECTION
;
97 conf
->ocv
= ssid
->ocv
;
98 #endif /* CONFIG_OCV */
100 cipher
= wpa_pick_pairwise_cipher(ssid
->pairwise_cipher
, 0);
101 if (cipher
< 0 || cipher
== WPA_CIPHER_TKIP
) {
102 wpa_msg(wpa_s
, MSG_INFO
, "mesh: Invalid pairwise cipher");
106 conf
->pairwise_cipher
= cipher
;
108 cipher
= wpa_pick_group_cipher(ssid
->group_cipher
);
109 if (cipher
< 0 || cipher
== WPA_CIPHER_TKIP
||
110 cipher
== WPA_CIPHER_GTK_NOT_USED
) {
111 wpa_msg(wpa_s
, MSG_INFO
, "mesh: Invalid group cipher");
116 conf
->group_cipher
= cipher
;
117 if (conf
->ieee80211w
!= NO_MGMT_FRAME_PROTECTION
)
118 conf
->mgmt_group_cipher
= WPA_CIPHER_AES_128_CMAC
;
121 conf
->mesh_pp_id
= MESH_PATH_PROTOCOL_HWMP
;
122 conf
->mesh_pm_id
= MESH_PATH_METRIC_AIRTIME
;
123 conf
->mesh_cc_id
= 0;
124 conf
->mesh_sp_id
= MESH_SYNC_METHOD_NEIGHBOR_OFFSET
;
125 conf
->mesh_auth_id
= (conf
->security
& MESH_CONF_SEC_AUTH
) ? 1 : 0;
126 conf
->dot11MeshMaxRetries
= ssid
->dot11MeshMaxRetries
;
127 conf
->dot11MeshRetryTimeout
= ssid
->dot11MeshRetryTimeout
;
128 conf
->dot11MeshConfirmTimeout
= ssid
->dot11MeshConfirmTimeout
;
129 conf
->dot11MeshHoldingTimeout
= ssid
->dot11MeshHoldingTimeout
;
135 static void wpas_mesh_copy_groups(struct hostapd_data
*bss
,
136 struct wpa_supplicant
*wpa_s
)
141 for (num_groups
= 0; wpa_s
->conf
->sae_groups
[num_groups
] > 0;
145 groups_size
= (num_groups
+ 1) * sizeof(wpa_s
->conf
->sae_groups
[0]);
146 bss
->conf
->sae_groups
= os_malloc(groups_size
);
147 if (bss
->conf
->sae_groups
)
148 os_memcpy(bss
->conf
->sae_groups
, wpa_s
->conf
->sae_groups
,
153 static int wpas_mesh_init_rsn(struct wpa_supplicant
*wpa_s
)
155 struct hostapd_iface
*ifmsh
= wpa_s
->ifmsh
;
156 struct wpa_ssid
*ssid
= wpa_s
->current_ssid
;
157 struct hostapd_data
*bss
= ifmsh
->bss
[0];
158 static int default_groups
[] = { 19, 20, 21, 25, 26, -1 };
159 const char *password
;
162 password
= ssid
->sae_password
;
164 password
= ssid
->passphrase
;
166 wpa_printf(MSG_ERROR
,
167 "mesh: Passphrase for SAE not configured");
171 bss
->conf
->wpa
= ssid
->proto
;
172 bss
->conf
->wpa_key_mgmt
= ssid
->key_mgmt
;
174 if (wpa_s
->conf
->sae_groups
&& wpa_s
->conf
->sae_groups
[0] > 0) {
175 wpas_mesh_copy_groups(bss
, wpa_s
);
177 bss
->conf
->sae_groups
= os_memdup(default_groups
,
178 sizeof(default_groups
));
179 if (!bss
->conf
->sae_groups
)
183 len
= os_strlen(password
);
184 bss
->conf
->ssid
.wpa_passphrase
= dup_binstr(password
, len
);
186 wpa_s
->mesh_rsn
= mesh_rsn_auth_init(wpa_s
, ifmsh
->mconf
);
187 return !wpa_s
->mesh_rsn
? -1 : 0;
191 static int wpas_mesh_complete(struct wpa_supplicant
*wpa_s
)
193 struct hostapd_iface
*ifmsh
= wpa_s
->ifmsh
;
194 struct wpa_driver_mesh_join_params
*params
= wpa_s
->mesh_params
;
195 struct wpa_ssid
*ssid
= wpa_s
->current_ssid
;
198 if (!params
|| !ssid
|| !ifmsh
) {
199 wpa_printf(MSG_ERROR
, "mesh: %s called without active mesh",
204 if (ifmsh
->mconf
->security
!= MESH_CONF_SEC_NONE
&&
205 wpas_mesh_init_rsn(wpa_s
)) {
206 wpa_printf(MSG_ERROR
,
207 "mesh: RSN initialization failed - deinit mesh");
208 wpa_supplicant_mesh_deinit(wpa_s
);
209 wpa_drv_leave_mesh(wpa_s
);
213 if (ssid
->key_mgmt
& WPA_KEY_MGMT_SAE
) {
214 wpa_s
->pairwise_cipher
= wpa_s
->mesh_rsn
->pairwise_cipher
;
215 wpa_s
->group_cipher
= wpa_s
->mesh_rsn
->group_cipher
;
216 wpa_s
->mgmt_group_cipher
= wpa_s
->mesh_rsn
->mgmt_group_cipher
;
219 params
->ies
= ifmsh
->mconf
->rsn_ie
;
220 params
->ie_len
= ifmsh
->mconf
->rsn_ie_len
;
221 params
->basic_rates
= ifmsh
->basic_rates
;
222 params
->conf
.flags
|= WPA_DRIVER_MESH_CONF_FLAG_HT_OP_MODE
;
223 params
->conf
.ht_opmode
= ifmsh
->bss
[0]->iface
->ht_op_mode
;
225 wpa_msg(wpa_s
, MSG_INFO
, "joining mesh %s",
226 wpa_ssid_txt(ssid
->ssid
, ssid
->ssid_len
));
227 ret
= wpa_drv_join_mesh(wpa_s
, params
);
229 wpa_msg(wpa_s
, MSG_ERROR
, "mesh join error=%d", ret
);
231 /* hostapd sets the interface down until we associate */
232 wpa_drv_set_operstate(wpa_s
, 1);
235 wpa_supplicant_set_state(wpa_s
, WPA_COMPLETED
);
241 static int wpa_supplicant_mesh_init(struct wpa_supplicant
*wpa_s
,
242 struct wpa_ssid
*ssid
,
243 struct hostapd_freq_params
*freq
)
245 struct hostapd_iface
*ifmsh
;
246 struct hostapd_data
*bss
;
247 struct hostapd_config
*conf
;
248 struct mesh_conf
*mconf
;
249 int basic_rates_erp
[] = { 10, 20, 55, 60, 110, 120, 240, -1 };
253 if (!wpa_s
->conf
->user_mpm
) {
254 /* not much for us to do here */
255 wpa_msg(wpa_s
, MSG_WARNING
,
256 "user_mpm is not enabled in configuration");
260 wpa_s
->ifmsh
= ifmsh
= hostapd_alloc_iface();
264 ifmsh
->drv_flags
= wpa_s
->drv_flags
;
266 ifmsh
->bss
= os_calloc(wpa_s
->ifmsh
->num_bss
,
267 sizeof(struct hostapd_data
*));
271 ifmsh
->bss
[0] = bss
= hostapd_alloc_bss_data(NULL
, NULL
, NULL
);
275 ifmsh
->bss
[0]->msg_ctx
= wpa_s
;
276 os_memcpy(bss
->own_addr
, wpa_s
->own_addr
, ETH_ALEN
);
277 bss
->driver
= wpa_s
->driver
;
278 bss
->drv_priv
= wpa_s
->drv_priv
;
280 bss
->mesh_sta_free_cb
= mesh_mpm_free_sta
;
281 frequency
= ssid
->frequency
;
282 if (frequency
!= freq
->freq
&&
283 frequency
== freq
->freq
+ freq
->sec_channel_offset
* 20) {
284 wpa_printf(MSG_DEBUG
, "mesh: pri/sec channels switched");
285 frequency
= freq
->freq
;
287 wpa_s
->assoc_freq
= frequency
;
288 wpa_s
->current_ssid
= ssid
;
290 /* setup an AP config for auth processing */
291 conf
= hostapd_config_defaults();
295 bss
->conf
= *conf
->bss
;
296 bss
->conf
->start_disabled
= 1;
297 bss
->conf
->mesh
= MESH_ENABLED
;
298 bss
->conf
->ap_max_inactivity
= wpa_s
->conf
->mesh_max_inactivity
;
300 if (ieee80211_is_dfs(ssid
->frequency
, wpa_s
->hw
.modes
,
301 wpa_s
->hw
.num_modes
) && wpa_s
->conf
->country
[0]) {
302 conf
->ieee80211h
= 1;
303 conf
->ieee80211d
= 1;
304 conf
->country
[0] = wpa_s
->conf
->country
[0];
305 conf
->country
[1] = wpa_s
->conf
->country
[1];
306 conf
->country
[2] = ' ';
312 ifmsh
->bss
[0]->max_plinks
= wpa_s
->conf
->max_peer_links
;
313 ifmsh
->bss
[0]->dot11RSNASAERetransPeriod
=
314 wpa_s
->conf
->dot11RSNASAERetransPeriod
;
315 os_strlcpy(bss
->conf
->iface
, wpa_s
->ifname
, sizeof(bss
->conf
->iface
));
317 mconf
= mesh_config_create(wpa_s
, ssid
);
320 ifmsh
->mconf
= mconf
;
322 /* need conf->hw_mode for supported rates. */
323 conf
->hw_mode
= ieee80211_freq_to_chan(frequency
, &conf
->channel
);
324 if (conf
->hw_mode
== NUM_HOSTAPD_MODES
) {
325 wpa_printf(MSG_ERROR
, "Unsupported mesh mode frequency: %d MHz",
330 conf
->secondary_channel
= ssid
->ht40
;
331 if (conf
->hw_mode
== HOSTAPD_MODE_IEEE80211A
&& ssid
->vht
) {
332 if (ssid
->max_oper_chwidth
!= DEFAULT_MAX_OPER_CHWIDTH
)
333 conf
->vht_oper_chwidth
= ssid
->max_oper_chwidth
;
334 switch (conf
->vht_oper_chwidth
) {
335 case CHANWIDTH_80MHZ
:
336 case CHANWIDTH_80P80MHZ
:
337 ieee80211_freq_to_chan(
339 &conf
->vht_oper_centr_freq_seg0_idx
);
340 conf
->vht_oper_centr_freq_seg0_idx
+= ssid
->ht40
* 2;
342 case CHANWIDTH_160MHZ
:
343 ieee80211_freq_to_chan(
345 &conf
->vht_oper_centr_freq_seg0_idx
);
346 conf
->vht_oper_centr_freq_seg0_idx
+= ssid
->ht40
* 2;
347 conf
->vht_oper_centr_freq_seg0_idx
+= 40 / 5;
350 ieee80211_freq_to_chan(ssid
->vht_center_freq2
,
351 &conf
->vht_oper_centr_freq_seg1_idx
);
354 if (ssid
->mesh_basic_rates
== NULL
) {
356 * XXX: Hack! This is so an MPM which correctly sets the ERP
357 * mandatory rates as BSSBasicRateSet doesn't reject us. We
358 * could add a new hw_mode HOSTAPD_MODE_IEEE80211G_ERP, but
359 * this is way easier. This also makes our BSSBasicRateSet
360 * advertised in beacons match the one in peering frames, sigh.
362 if (conf
->hw_mode
== HOSTAPD_MODE_IEEE80211G
) {
363 conf
->basic_rates
= os_memdup(basic_rates_erp
,
364 sizeof(basic_rates_erp
));
365 if (!conf
->basic_rates
)
371 if (ssid
->mesh_basic_rates
[rate_len
] < 1)
375 conf
->basic_rates
= os_calloc(rate_len
+ 1, sizeof(int));
376 if (conf
->basic_rates
== NULL
)
378 os_memcpy(conf
->basic_rates
, ssid
->mesh_basic_rates
,
379 rate_len
* sizeof(int));
380 conf
->basic_rates
[rate_len
] = -1;
383 if (wpa_drv_init_mesh(wpa_s
)) {
384 wpa_msg(wpa_s
, MSG_ERROR
, "Failed to init mesh in driver");
388 if (hostapd_setup_interface(ifmsh
)) {
389 wpa_printf(MSG_ERROR
,
390 "Failed to initialize hostapd interface for mesh");
394 wpa_supplicant_conf_ap_ht(wpa_s
, ssid
, conf
);
398 wpa_supplicant_mesh_deinit(wpa_s
);
403 void wpa_mesh_notify_peer(struct wpa_supplicant
*wpa_s
, const u8
*addr
,
404 const u8
*ies
, size_t ie_len
)
406 struct ieee802_11_elems elems
;
408 wpa_msg(wpa_s
, MSG_INFO
,
409 "new peer notification for " MACSTR
, MAC2STR(addr
));
411 if (ieee802_11_parse_elems(ies
, ie_len
, &elems
, 0) == ParseFailed
) {
412 wpa_msg(wpa_s
, MSG_INFO
, "Could not parse beacon from " MACSTR
,
416 wpa_mesh_new_mesh_peer(wpa_s
, addr
, &elems
);
420 void wpa_supplicant_mesh_add_scan_ie(struct wpa_supplicant
*wpa_s
,
421 struct wpabuf
**extra_ie
)
423 /* EID + 0-length (wildcard) mesh-id */
426 if (wpabuf_resize(extra_ie
, ielen
) == 0) {
427 wpabuf_put_u8(*extra_ie
, WLAN_EID_MESH_ID
);
428 wpabuf_put_u8(*extra_ie
, 0);
433 int wpa_supplicant_join_mesh(struct wpa_supplicant
*wpa_s
,
434 struct wpa_ssid
*ssid
)
436 struct wpa_driver_mesh_join_params
*params
= os_zalloc(sizeof(*params
));
439 if (!ssid
|| !ssid
->ssid
|| !ssid
->ssid_len
|| !ssid
->frequency
||
446 wpa_supplicant_mesh_deinit(wpa_s
);
448 wpa_s
->pairwise_cipher
= WPA_CIPHER_NONE
;
449 wpa_s
->group_cipher
= WPA_CIPHER_NONE
;
450 wpa_s
->mgmt_group_cipher
= 0;
452 params
->meshid
= ssid
->ssid
;
453 params
->meshid_len
= ssid
->ssid_len
;
454 ibss_mesh_setup_freq(wpa_s
, ssid
, ¶ms
->freq
);
455 wpa_s
->mesh_ht_enabled
= !!params
->freq
.ht_enabled
;
456 wpa_s
->mesh_vht_enabled
= !!params
->freq
.vht_enabled
;
457 wpa_s
->mesh_he_enabled
= !!params
->freq
.he_enabled
;
458 if (params
->freq
.ht_enabled
&& params
->freq
.sec_channel_offset
)
459 ssid
->ht40
= params
->freq
.sec_channel_offset
;
461 if (wpa_s
->mesh_vht_enabled
) {
463 ssid
->vht_center_freq1
= params
->freq
.center_freq1
;
464 switch (params
->freq
.bandwidth
) {
466 if (params
->freq
.center_freq2
) {
467 ssid
->max_oper_chwidth
= CHANWIDTH_80P80MHZ
;
468 ssid
->vht_center_freq2
=
469 params
->freq
.center_freq2
;
471 ssid
->max_oper_chwidth
= CHANWIDTH_80MHZ
;
475 ssid
->max_oper_chwidth
= CHANWIDTH_160MHZ
;
478 ssid
->max_oper_chwidth
= CHANWIDTH_USE_HT
;
482 if (wpa_s
->mesh_he_enabled
)
484 if (ssid
->beacon_int
> 0)
485 params
->beacon_int
= ssid
->beacon_int
;
486 else if (wpa_s
->conf
->beacon_int
> 0)
487 params
->beacon_int
= wpa_s
->conf
->beacon_int
;
488 if (ssid
->dtim_period
> 0)
489 params
->dtim_period
= ssid
->dtim_period
;
490 else if (wpa_s
->conf
->dtim_period
> 0)
491 params
->dtim_period
= wpa_s
->conf
->dtim_period
;
492 params
->conf
.max_peer_links
= wpa_s
->conf
->max_peer_links
;
493 if (ssid
->mesh_rssi_threshold
< DEFAULT_MESH_RSSI_THRESHOLD
) {
494 params
->conf
.rssi_threshold
= ssid
->mesh_rssi_threshold
;
495 params
->conf
.flags
|= WPA_DRIVER_MESH_CONF_FLAG_RSSI_THRESHOLD
;
498 if (ssid
->key_mgmt
& WPA_KEY_MGMT_SAE
) {
499 params
->flags
|= WPA_DRIVER_MESH_FLAG_SAE_AUTH
;
500 params
->flags
|= WPA_DRIVER_MESH_FLAG_AMPE
;
501 wpa_s
->conf
->user_mpm
= 1;
504 if (wpa_s
->conf
->user_mpm
) {
505 params
->flags
|= WPA_DRIVER_MESH_FLAG_USER_MPM
;
506 params
->conf
.auto_plinks
= 0;
508 params
->flags
|= WPA_DRIVER_MESH_FLAG_DRIVER_MPM
;
509 params
->conf
.auto_plinks
= 1;
511 params
->conf
.peer_link_timeout
= wpa_s
->conf
->mesh_max_inactivity
;
513 os_free(wpa_s
->mesh_params
);
514 wpa_s
->mesh_params
= params
;
515 if (wpa_supplicant_mesh_init(wpa_s
, ssid
, ¶ms
->freq
)) {
516 wpa_msg(wpa_s
, MSG_ERROR
, "Failed to init mesh");
517 wpa_drv_leave_mesh(wpa_s
);
522 ret
= wpas_mesh_complete(wpa_s
);
528 int wpa_supplicant_leave_mesh(struct wpa_supplicant
*wpa_s
)
532 wpa_msg(wpa_s
, MSG_INFO
, "leaving mesh");
534 /* Need to send peering close messages first */
535 wpa_supplicant_mesh_deinit(wpa_s
);
537 ret
= wpa_drv_leave_mesh(wpa_s
);
539 wpa_msg(wpa_s
, MSG_ERROR
, "mesh leave error=%d", ret
);
541 wpa_drv_set_operstate(wpa_s
, 1);
547 static int mesh_attr_text(const u8
*ies
, size_t ies_len
, char *buf
, char *end
)
549 struct ieee802_11_elems elems
;
550 char *mesh_id
, *pos
= buf
;
551 u8
*bss_basic_rate_set
;
552 int bss_basic_rate_set_len
, ret
, i
;
554 if (ieee802_11_parse_elems(ies
, ies_len
, &elems
, 0) == ParseFailed
)
557 if (elems
.mesh_id_len
< 1)
560 mesh_id
= os_malloc(elems
.mesh_id_len
+ 1);
564 os_memcpy(mesh_id
, elems
.mesh_id
, elems
.mesh_id_len
);
565 mesh_id
[elems
.mesh_id_len
] = '\0';
566 ret
= os_snprintf(pos
, end
- pos
, "mesh_id=%s\n", mesh_id
);
568 if (os_snprintf_error(end
- pos
, ret
))
572 if (elems
.mesh_config_len
> 6) {
573 ret
= os_snprintf(pos
, end
- pos
,
574 "active_path_selection_protocol_id=0x%02x\n"
575 "active_path_selection_metric_id=0x%02x\n"
576 "congestion_control_mode_id=0x%02x\n"
577 "synchronization_method_id=0x%02x\n"
578 "authentication_protocol_id=0x%02x\n"
579 "mesh_formation_info=0x%02x\n"
580 "mesh_capability=0x%02x\n",
581 elems
.mesh_config
[0], elems
.mesh_config
[1],
582 elems
.mesh_config
[2], elems
.mesh_config
[3],
583 elems
.mesh_config
[4], elems
.mesh_config
[5],
584 elems
.mesh_config
[6]);
585 if (os_snprintf_error(end
- pos
, ret
))
590 bss_basic_rate_set
= os_malloc(elems
.supp_rates_len
+
591 elems
.ext_supp_rates_len
);
592 if (bss_basic_rate_set
== NULL
)
595 bss_basic_rate_set_len
= 0;
596 for (i
= 0; i
< elems
.supp_rates_len
; i
++) {
597 if (elems
.supp_rates
[i
] & 0x80) {
598 bss_basic_rate_set
[bss_basic_rate_set_len
++] =
599 (elems
.supp_rates
[i
] & 0x7f) * 5;
602 for (i
= 0; i
< elems
.ext_supp_rates_len
; i
++) {
603 if (elems
.ext_supp_rates
[i
] & 0x80) {
604 bss_basic_rate_set
[bss_basic_rate_set_len
++] =
605 (elems
.ext_supp_rates
[i
] & 0x7f) * 5;
608 if (bss_basic_rate_set_len
> 0) {
609 ret
= os_snprintf(pos
, end
- pos
, "bss_basic_rate_set=%d",
610 bss_basic_rate_set
[0]);
611 if (os_snprintf_error(end
- pos
, ret
))
615 for (i
= 1; i
< bss_basic_rate_set_len
; i
++) {
616 ret
= os_snprintf(pos
, end
- pos
, " %d",
617 bss_basic_rate_set
[i
]);
618 if (os_snprintf_error(end
- pos
, ret
))
623 ret
= os_snprintf(pos
, end
- pos
, "\n");
624 if (os_snprintf_error(end
- pos
, ret
))
629 os_free(bss_basic_rate_set
);
635 int wpas_mesh_scan_result_text(const u8
*ies
, size_t ies_len
, char *buf
,
638 return mesh_attr_text(ies
, ies_len
, buf
, end
);
642 static int wpas_mesh_get_ifname(struct wpa_supplicant
*wpa_s
, char *ifname
,
645 char *ifname_ptr
= wpa_s
->ifname
;
648 res
= os_snprintf(ifname
, len
, "mesh-%s-%d", ifname_ptr
,
650 if (os_snprintf_error(len
, res
) ||
651 (os_strlen(ifname
) >= IFNAMSIZ
&&
652 os_strlen(wpa_s
->ifname
) < IFNAMSIZ
)) {
653 /* Try to avoid going over the IFNAMSIZ length limit */
654 res
= os_snprintf(ifname
, len
, "mesh-%d", wpa_s
->mesh_if_idx
);
655 if (os_snprintf_error(len
, res
))
658 wpa_s
->mesh_if_idx
++;
663 int wpas_mesh_add_interface(struct wpa_supplicant
*wpa_s
, char *ifname
,
666 struct wpa_interface iface
;
667 struct wpa_supplicant
*mesh_wpa_s
;
670 if (ifname
[0] == '\0' && wpas_mesh_get_ifname(wpa_s
, ifname
, len
) < 0)
673 if (wpa_drv_if_add(wpa_s
, WPA_IF_MESH
, ifname
, NULL
, NULL
, NULL
, addr
,
675 wpa_printf(MSG_ERROR
,
676 "mesh: Failed to create new mesh interface");
679 wpa_printf(MSG_INFO
, "mesh: Created virtual interface %s addr "
680 MACSTR
, ifname
, MAC2STR(addr
));
682 os_memset(&iface
, 0, sizeof(iface
));
683 iface
.ifname
= ifname
;
684 iface
.driver
= wpa_s
->driver
->name
;
685 iface
.driver_param
= wpa_s
->conf
->driver_param
;
686 iface
.ctrl_interface
= wpa_s
->conf
->ctrl_interface
;
688 mesh_wpa_s
= wpa_supplicant_add_iface(wpa_s
->global
, &iface
, wpa_s
);
690 wpa_printf(MSG_ERROR
,
691 "mesh: Failed to create new wpa_supplicant interface");
692 wpa_drv_if_remove(wpa_s
, WPA_IF_MESH
, ifname
);
695 mesh_wpa_s
->mesh_if_created
= 1;
700 int wpas_mesh_peer_remove(struct wpa_supplicant
*wpa_s
, const u8
*addr
)
702 return mesh_mpm_close_peer(wpa_s
, addr
);
706 int wpas_mesh_peer_add(struct wpa_supplicant
*wpa_s
, const u8
*addr
,
709 return mesh_mpm_connect_peer(wpa_s
, addr
, duration
);