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 /* TODO: leave mesh (stop beacon). This will happen on link down
38 * anyway, so it's not urgent */
42 void wpa_supplicant_mesh_iface_deinit(struct wpa_supplicant
*wpa_s
,
43 struct hostapd_iface
*ifmsh
)
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.
59 os_free(ifmsh
->mconf
);
63 /* take care of shared data */
64 hostapd_interface_deinit(ifmsh
);
65 hostapd_interface_free(ifmsh
);
69 static struct mesh_conf
* mesh_config_create(struct wpa_supplicant
*wpa_s
,
70 struct wpa_ssid
*ssid
)
72 struct mesh_conf
*conf
;
75 conf
= os_zalloc(sizeof(struct mesh_conf
));
79 os_memcpy(conf
->meshid
, ssid
->ssid
, ssid
->ssid_len
);
80 conf
->meshid_len
= ssid
->ssid_len
;
82 if (ssid
->key_mgmt
& WPA_KEY_MGMT_SAE
)
83 conf
->security
|= MESH_CONF_SEC_AUTH
|
86 conf
->security
|= MESH_CONF_SEC_NONE
;
87 #ifdef CONFIG_IEEE80211W
88 conf
->ieee80211w
= ssid
->ieee80211w
;
89 if (conf
->ieee80211w
== MGMT_FRAME_PROTECTION_DEFAULT
) {
90 if (wpa_s
->drv_enc
& WPA_DRIVER_CAPA_ENC_BIP
)
91 conf
->ieee80211w
= wpa_s
->conf
->pmf
;
93 conf
->ieee80211w
= NO_MGMT_FRAME_PROTECTION
;
95 #endif /* CONFIG_IEEE80211W */
97 cipher
= wpa_pick_pairwise_cipher(ssid
->pairwise_cipher
, 0);
98 if (cipher
< 0 || cipher
== WPA_CIPHER_TKIP
) {
99 wpa_msg(wpa_s
, MSG_INFO
, "mesh: Invalid pairwise cipher");
103 conf
->pairwise_cipher
= cipher
;
105 cipher
= wpa_pick_group_cipher(ssid
->group_cipher
);
106 if (cipher
< 0 || cipher
== WPA_CIPHER_TKIP
||
107 cipher
== WPA_CIPHER_GTK_NOT_USED
) {
108 wpa_msg(wpa_s
, MSG_INFO
, "mesh: Invalid group cipher");
113 conf
->group_cipher
= cipher
;
114 if (conf
->ieee80211w
!= NO_MGMT_FRAME_PROTECTION
)
115 conf
->mgmt_group_cipher
= WPA_CIPHER_AES_128_CMAC
;
118 conf
->mesh_pp_id
= MESH_PATH_PROTOCOL_HWMP
;
119 conf
->mesh_pm_id
= MESH_PATH_METRIC_AIRTIME
;
120 conf
->mesh_cc_id
= 0;
121 conf
->mesh_sp_id
= MESH_SYNC_METHOD_NEIGHBOR_OFFSET
;
122 conf
->mesh_auth_id
= (conf
->security
& MESH_CONF_SEC_AUTH
) ? 1 : 0;
123 conf
->dot11MeshMaxRetries
= ssid
->dot11MeshMaxRetries
;
124 conf
->dot11MeshRetryTimeout
= ssid
->dot11MeshRetryTimeout
;
125 conf
->dot11MeshConfirmTimeout
= ssid
->dot11MeshConfirmTimeout
;
126 conf
->dot11MeshHoldingTimeout
= ssid
->dot11MeshHoldingTimeout
;
132 static void wpas_mesh_copy_groups(struct hostapd_data
*bss
,
133 struct wpa_supplicant
*wpa_s
)
138 for (num_groups
= 0; wpa_s
->conf
->sae_groups
[num_groups
] > 0;
142 groups_size
= (num_groups
+ 1) * sizeof(wpa_s
->conf
->sae_groups
[0]);
143 bss
->conf
->sae_groups
= os_malloc(groups_size
);
144 if (bss
->conf
->sae_groups
)
145 os_memcpy(bss
->conf
->sae_groups
, wpa_s
->conf
->sae_groups
,
150 static int wpa_supplicant_mesh_init(struct wpa_supplicant
*wpa_s
,
151 struct wpa_ssid
*ssid
,
152 struct hostapd_freq_params
*freq
)
154 struct hostapd_iface
*ifmsh
;
155 struct hostapd_data
*bss
;
156 struct hostapd_config
*conf
;
157 struct mesh_conf
*mconf
;
158 int basic_rates_erp
[] = { 10, 20, 55, 60, 110, 120, 240, -1 };
159 static int default_groups
[] = { 19, 20, 21, 25, 26, -1 };
164 if (!wpa_s
->conf
->user_mpm
) {
165 /* not much for us to do here */
166 wpa_msg(wpa_s
, MSG_WARNING
,
167 "user_mpm is not enabled in configuration");
171 wpa_s
->ifmsh
= ifmsh
= os_zalloc(sizeof(*wpa_s
->ifmsh
));
175 ifmsh
->drv_flags
= wpa_s
->drv_flags
;
177 ifmsh
->bss
= os_calloc(wpa_s
->ifmsh
->num_bss
,
178 sizeof(struct hostapd_data
*));
182 ifmsh
->bss
[0] = bss
= hostapd_alloc_bss_data(NULL
, NULL
, NULL
);
186 os_memcpy(bss
->own_addr
, wpa_s
->own_addr
, ETH_ALEN
);
187 bss
->driver
= wpa_s
->driver
;
188 bss
->drv_priv
= wpa_s
->drv_priv
;
190 bss
->mesh_sta_free_cb
= mesh_mpm_free_sta
;
191 frequency
= ssid
->frequency
;
192 if (frequency
!= freq
->freq
&&
193 frequency
== freq
->freq
+ freq
->sec_channel_offset
* 20) {
194 wpa_printf(MSG_DEBUG
, "mesh: pri/sec channels switched");
195 frequency
= freq
->freq
;
197 wpa_s
->assoc_freq
= frequency
;
198 wpa_s
->current_ssid
= ssid
;
200 /* setup an AP config for auth processing */
201 conf
= hostapd_config_defaults();
205 bss
->conf
= *conf
->bss
;
206 bss
->conf
->start_disabled
= 1;
207 bss
->conf
->mesh
= MESH_ENABLED
;
208 bss
->conf
->ap_max_inactivity
= wpa_s
->conf
->mesh_max_inactivity
;
212 ifmsh
->bss
[0]->max_plinks
= wpa_s
->conf
->max_peer_links
;
213 ifmsh
->bss
[0]->dot11RSNASAERetransPeriod
=
214 wpa_s
->conf
->dot11RSNASAERetransPeriod
;
215 os_strlcpy(bss
->conf
->iface
, wpa_s
->ifname
, sizeof(bss
->conf
->iface
));
217 mconf
= mesh_config_create(wpa_s
, ssid
);
220 ifmsh
->mconf
= mconf
;
222 /* need conf->hw_mode for supported rates. */
223 conf
->hw_mode
= ieee80211_freq_to_chan(frequency
, &conf
->channel
);
224 if (conf
->hw_mode
== NUM_HOSTAPD_MODES
) {
225 wpa_printf(MSG_ERROR
, "Unsupported mesh mode frequency: %d MHz",
230 conf
->secondary_channel
= ssid
->ht40
;
231 if (conf
->hw_mode
== HOSTAPD_MODE_IEEE80211A
&& ssid
->vht
) {
232 conf
->vht_oper_chwidth
= ssid
->max_oper_chwidth
;
233 switch (conf
->vht_oper_chwidth
) {
234 case VHT_CHANWIDTH_80MHZ
:
235 case VHT_CHANWIDTH_80P80MHZ
:
236 ieee80211_freq_to_chan(
238 &conf
->vht_oper_centr_freq_seg0_idx
);
239 conf
->vht_oper_centr_freq_seg0_idx
+= ssid
->ht40
* 2;
241 case VHT_CHANWIDTH_160MHZ
:
242 ieee80211_freq_to_chan(
244 &conf
->vht_oper_centr_freq_seg0_idx
);
245 conf
->vht_oper_centr_freq_seg0_idx
+= ssid
->ht40
* 2;
246 conf
->vht_oper_centr_freq_seg0_idx
+= 40 / 5;
249 ieee80211_freq_to_chan(ssid
->vht_center_freq2
,
250 &conf
->vht_oper_centr_freq_seg1_idx
);
253 if (ssid
->mesh_basic_rates
== NULL
) {
255 * XXX: Hack! This is so an MPM which correctly sets the ERP
256 * mandatory rates as BSSBasicRateSet doesn't reject us. We
257 * could add a new hw_mode HOSTAPD_MODE_IEEE80211G_ERP, but
258 * this is way easier. This also makes our BSSBasicRateSet
259 * advertised in beacons match the one in peering frames, sigh.
261 if (conf
->hw_mode
== HOSTAPD_MODE_IEEE80211G
) {
262 conf
->basic_rates
= os_memdup(basic_rates_erp
,
263 sizeof(basic_rates_erp
));
264 if (!conf
->basic_rates
)
270 if (ssid
->mesh_basic_rates
[rate_len
] < 1)
274 conf
->basic_rates
= os_calloc(rate_len
+ 1, sizeof(int));
275 if (conf
->basic_rates
== NULL
)
277 os_memcpy(conf
->basic_rates
, ssid
->mesh_basic_rates
,
278 rate_len
* sizeof(int));
279 conf
->basic_rates
[rate_len
] = -1;
282 if (hostapd_setup_interface(ifmsh
)) {
283 wpa_printf(MSG_ERROR
,
284 "Failed to initialize hostapd interface for mesh");
288 if (wpa_drv_init_mesh(wpa_s
)) {
289 wpa_msg(wpa_s
, MSG_ERROR
, "Failed to init mesh in driver");
293 if (mconf
->security
!= MESH_CONF_SEC_NONE
) {
294 if (ssid
->passphrase
== NULL
) {
295 wpa_printf(MSG_ERROR
,
296 "mesh: Passphrase for SAE not configured");
300 bss
->conf
->wpa
= ssid
->proto
;
301 bss
->conf
->wpa_key_mgmt
= ssid
->key_mgmt
;
303 if (wpa_s
->conf
->sae_groups
&&
304 wpa_s
->conf
->sae_groups
[0] > 0) {
305 wpas_mesh_copy_groups(bss
, wpa_s
);
307 bss
->conf
->sae_groups
=
308 os_memdup(default_groups
,
309 sizeof(default_groups
));
310 if (!bss
->conf
->sae_groups
)
314 len
= os_strlen(ssid
->passphrase
);
315 bss
->conf
->ssid
.wpa_passphrase
=
316 dup_binstr(ssid
->passphrase
, len
);
318 wpa_s
->mesh_rsn
= mesh_rsn_auth_init(wpa_s
, mconf
);
319 if (!wpa_s
->mesh_rsn
)
323 wpa_supplicant_conf_ap_ht(wpa_s
, ssid
, conf
);
327 wpa_supplicant_mesh_deinit(wpa_s
);
332 void wpa_mesh_notify_peer(struct wpa_supplicant
*wpa_s
, const u8
*addr
,
333 const u8
*ies
, size_t ie_len
)
335 struct ieee802_11_elems elems
;
337 wpa_msg(wpa_s
, MSG_INFO
,
338 "new peer notification for " MACSTR
, MAC2STR(addr
));
340 if (ieee802_11_parse_elems(ies
, ie_len
, &elems
, 0) == ParseFailed
) {
341 wpa_msg(wpa_s
, MSG_INFO
, "Could not parse beacon from " MACSTR
,
345 wpa_mesh_new_mesh_peer(wpa_s
, addr
, &elems
);
349 void wpa_supplicant_mesh_add_scan_ie(struct wpa_supplicant
*wpa_s
,
350 struct wpabuf
**extra_ie
)
352 /* EID + 0-length (wildcard) mesh-id */
355 if (wpabuf_resize(extra_ie
, ielen
) == 0) {
356 wpabuf_put_u8(*extra_ie
, WLAN_EID_MESH_ID
);
357 wpabuf_put_u8(*extra_ie
, 0);
362 int wpa_supplicant_join_mesh(struct wpa_supplicant
*wpa_s
,
363 struct wpa_ssid
*ssid
)
365 struct wpa_driver_mesh_join_params params
;
368 if (!ssid
|| !ssid
->ssid
|| !ssid
->ssid_len
|| !ssid
->frequency
) {
373 wpa_supplicant_mesh_deinit(wpa_s
);
375 wpa_s
->pairwise_cipher
= WPA_CIPHER_NONE
;
376 wpa_s
->group_cipher
= WPA_CIPHER_NONE
;
377 wpa_s
->mgmt_group_cipher
= 0;
379 os_memset(¶ms
, 0, sizeof(params
));
380 params
.meshid
= ssid
->ssid
;
381 params
.meshid_len
= ssid
->ssid_len
;
382 ibss_mesh_setup_freq(wpa_s
, ssid
, ¶ms
.freq
);
383 wpa_s
->mesh_ht_enabled
= !!params
.freq
.ht_enabled
;
384 wpa_s
->mesh_vht_enabled
= !!params
.freq
.vht_enabled
;
385 if (params
.freq
.ht_enabled
&& params
.freq
.sec_channel_offset
)
386 ssid
->ht40
= params
.freq
.sec_channel_offset
;
387 if (wpa_s
->mesh_vht_enabled
) {
389 switch (params
.freq
.bandwidth
) {
391 if (params
.freq
.center_freq2
) {
392 ssid
->max_oper_chwidth
= VHT_CHANWIDTH_80P80MHZ
;
393 ssid
->vht_center_freq2
=
394 params
.freq
.center_freq2
;
396 ssid
->max_oper_chwidth
= VHT_CHANWIDTH_80MHZ
;
400 ssid
->max_oper_chwidth
= VHT_CHANWIDTH_160MHZ
;
403 ssid
->max_oper_chwidth
= VHT_CHANWIDTH_USE_HT
;
407 if (ssid
->beacon_int
> 0)
408 params
.beacon_int
= ssid
->beacon_int
;
409 else if (wpa_s
->conf
->beacon_int
> 0)
410 params
.beacon_int
= wpa_s
->conf
->beacon_int
;
411 if (ssid
->dtim_period
> 0)
412 params
.dtim_period
= ssid
->dtim_period
;
413 else if (wpa_s
->conf
->dtim_period
> 0)
414 params
.dtim_period
= wpa_s
->conf
->dtim_period
;
415 params
.conf
.max_peer_links
= wpa_s
->conf
->max_peer_links
;
417 if (ssid
->key_mgmt
& WPA_KEY_MGMT_SAE
) {
418 params
.flags
|= WPA_DRIVER_MESH_FLAG_SAE_AUTH
;
419 params
.flags
|= WPA_DRIVER_MESH_FLAG_AMPE
;
420 wpa_s
->conf
->user_mpm
= 1;
423 if (wpa_s
->conf
->user_mpm
) {
424 params
.flags
|= WPA_DRIVER_MESH_FLAG_USER_MPM
;
425 params
.conf
.auto_plinks
= 0;
427 params
.flags
|= WPA_DRIVER_MESH_FLAG_DRIVER_MPM
;
428 params
.conf
.auto_plinks
= 1;
430 params
.conf
.peer_link_timeout
= wpa_s
->conf
->mesh_max_inactivity
;
432 if (wpa_supplicant_mesh_init(wpa_s
, ssid
, ¶ms
.freq
)) {
433 wpa_msg(wpa_s
, MSG_ERROR
, "Failed to init mesh");
434 wpa_drv_leave_mesh(wpa_s
);
439 if (ssid
->key_mgmt
& WPA_KEY_MGMT_SAE
) {
440 wpa_s
->pairwise_cipher
= wpa_s
->mesh_rsn
->pairwise_cipher
;
441 wpa_s
->group_cipher
= wpa_s
->mesh_rsn
->group_cipher
;
442 wpa_s
->mgmt_group_cipher
= wpa_s
->mesh_rsn
->mgmt_group_cipher
;
446 params
.ies
= wpa_s
->ifmsh
->mconf
->rsn_ie
;
447 params
.ie_len
= wpa_s
->ifmsh
->mconf
->rsn_ie_len
;
448 params
.basic_rates
= wpa_s
->ifmsh
->basic_rates
;
449 params
.conf
.flags
|= WPA_DRIVER_MESH_CONF_FLAG_HT_OP_MODE
;
450 params
.conf
.ht_opmode
= wpa_s
->ifmsh
->bss
[0]->iface
->ht_op_mode
;
453 wpa_msg(wpa_s
, MSG_INFO
, "joining mesh %s",
454 wpa_ssid_txt(ssid
->ssid
, ssid
->ssid_len
));
455 ret
= wpa_drv_join_mesh(wpa_s
, ¶ms
);
457 wpa_msg(wpa_s
, MSG_ERROR
, "mesh join error=%d", ret
);
459 /* hostapd sets the interface down until we associate */
460 wpa_drv_set_operstate(wpa_s
, 1);
463 wpa_supplicant_set_state(wpa_s
, WPA_COMPLETED
);
470 int wpa_supplicant_leave_mesh(struct wpa_supplicant
*wpa_s
)
474 wpa_msg(wpa_s
, MSG_INFO
, "leaving mesh");
476 /* Need to send peering close messages first */
477 wpa_supplicant_mesh_deinit(wpa_s
);
479 ret
= wpa_drv_leave_mesh(wpa_s
);
481 wpa_msg(wpa_s
, MSG_ERROR
, "mesh leave error=%d", ret
);
483 wpa_drv_set_operstate(wpa_s
, 1);
489 static int mesh_attr_text(const u8
*ies
, size_t ies_len
, char *buf
, char *end
)
491 struct ieee802_11_elems elems
;
492 char *mesh_id
, *pos
= buf
;
493 u8
*bss_basic_rate_set
;
494 int bss_basic_rate_set_len
, ret
, i
;
496 if (ieee802_11_parse_elems(ies
, ies_len
, &elems
, 0) == ParseFailed
)
499 if (elems
.mesh_id_len
< 1)
502 mesh_id
= os_malloc(elems
.mesh_id_len
+ 1);
506 os_memcpy(mesh_id
, elems
.mesh_id
, elems
.mesh_id_len
);
507 mesh_id
[elems
.mesh_id_len
] = '\0';
508 ret
= os_snprintf(pos
, end
- pos
, "mesh_id=%s\n", mesh_id
);
510 if (os_snprintf_error(end
- pos
, ret
))
514 if (elems
.mesh_config_len
> 6) {
515 ret
= os_snprintf(pos
, end
- pos
,
516 "active_path_selection_protocol_id=0x%02x\n"
517 "active_path_selection_metric_id=0x%02x\n"
518 "congestion_control_mode_id=0x%02x\n"
519 "synchronization_method_id=0x%02x\n"
520 "authentication_protocol_id=0x%02x\n"
521 "mesh_formation_info=0x%02x\n"
522 "mesh_capability=0x%02x\n",
523 elems
.mesh_config
[0], elems
.mesh_config
[1],
524 elems
.mesh_config
[2], elems
.mesh_config
[3],
525 elems
.mesh_config
[4], elems
.mesh_config
[5],
526 elems
.mesh_config
[6]);
527 if (os_snprintf_error(end
- pos
, ret
))
532 bss_basic_rate_set
= os_malloc(elems
.supp_rates_len
+
533 elems
.ext_supp_rates_len
);
534 if (bss_basic_rate_set
== NULL
)
537 bss_basic_rate_set_len
= 0;
538 for (i
= 0; i
< elems
.supp_rates_len
; i
++) {
539 if (elems
.supp_rates
[i
] & 0x80) {
540 bss_basic_rate_set
[bss_basic_rate_set_len
++] =
541 (elems
.supp_rates
[i
] & 0x7f) * 5;
544 for (i
= 0; i
< elems
.ext_supp_rates_len
; i
++) {
545 if (elems
.ext_supp_rates
[i
] & 0x80) {
546 bss_basic_rate_set
[bss_basic_rate_set_len
++] =
547 (elems
.ext_supp_rates
[i
] & 0x7f) * 5;
550 if (bss_basic_rate_set_len
> 0) {
551 ret
= os_snprintf(pos
, end
- pos
, "bss_basic_rate_set=%d",
552 bss_basic_rate_set
[0]);
553 if (os_snprintf_error(end
- pos
, ret
))
557 for (i
= 1; i
< bss_basic_rate_set_len
; i
++) {
558 ret
= os_snprintf(pos
, end
- pos
, " %d",
559 bss_basic_rate_set
[i
]);
560 if (os_snprintf_error(end
- pos
, ret
))
565 ret
= os_snprintf(pos
, end
- pos
, "\n");
566 if (os_snprintf_error(end
- pos
, ret
))
571 os_free(bss_basic_rate_set
);
577 int wpas_mesh_scan_result_text(const u8
*ies
, size_t ies_len
, char *buf
,
580 return mesh_attr_text(ies
, ies_len
, buf
, end
);
584 static int wpas_mesh_get_ifname(struct wpa_supplicant
*wpa_s
, char *ifname
,
587 char *ifname_ptr
= wpa_s
->ifname
;
590 res
= os_snprintf(ifname
, len
, "mesh-%s-%d", ifname_ptr
,
592 if (os_snprintf_error(len
, res
) ||
593 (os_strlen(ifname
) >= IFNAMSIZ
&&
594 os_strlen(wpa_s
->ifname
) < IFNAMSIZ
)) {
595 /* Try to avoid going over the IFNAMSIZ length limit */
596 res
= os_snprintf(ifname
, len
, "mesh-%d", wpa_s
->mesh_if_idx
);
597 if (os_snprintf_error(len
, res
))
600 wpa_s
->mesh_if_idx
++;
605 int wpas_mesh_add_interface(struct wpa_supplicant
*wpa_s
, char *ifname
,
608 struct wpa_interface iface
;
609 struct wpa_supplicant
*mesh_wpa_s
;
612 if (ifname
[0] == '\0' && wpas_mesh_get_ifname(wpa_s
, ifname
, len
) < 0)
615 if (wpa_drv_if_add(wpa_s
, WPA_IF_MESH
, ifname
, NULL
, NULL
, NULL
, addr
,
617 wpa_printf(MSG_ERROR
,
618 "mesh: Failed to create new mesh interface");
621 wpa_printf(MSG_INFO
, "mesh: Created virtual interface %s addr "
622 MACSTR
, ifname
, MAC2STR(addr
));
624 os_memset(&iface
, 0, sizeof(iface
));
625 iface
.ifname
= ifname
;
626 iface
.driver
= wpa_s
->driver
->name
;
627 iface
.driver_param
= wpa_s
->conf
->driver_param
;
628 iface
.ctrl_interface
= wpa_s
->conf
->ctrl_interface
;
630 mesh_wpa_s
= wpa_supplicant_add_iface(wpa_s
->global
, &iface
, wpa_s
);
632 wpa_printf(MSG_ERROR
,
633 "mesh: Failed to create new wpa_supplicant interface");
634 wpa_drv_if_remove(wpa_s
, WPA_IF_MESH
, ifname
);
637 mesh_wpa_s
->mesh_if_created
= 1;
642 int wpas_mesh_peer_remove(struct wpa_supplicant
*wpa_s
, const u8
*addr
)
644 return mesh_mpm_close_peer(wpa_s
, addr
);
648 int wpas_mesh_peer_add(struct wpa_supplicant
*wpa_s
, const u8
*addr
,
651 return mesh_mpm_connect_peer(wpa_s
, addr
, duration
);