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_ssid
*ssid
)
71 struct mesh_conf
*conf
;
73 conf
= os_zalloc(sizeof(struct mesh_conf
));
77 os_memcpy(conf
->meshid
, ssid
->ssid
, ssid
->ssid_len
);
78 conf
->meshid_len
= ssid
->ssid_len
;
80 if (ssid
->key_mgmt
& WPA_KEY_MGMT_SAE
)
81 conf
->security
|= MESH_CONF_SEC_AUTH
|
84 conf
->security
|= MESH_CONF_SEC_NONE
;
87 conf
->mesh_pp_id
= MESH_PATH_PROTOCOL_HWMP
;
88 conf
->mesh_pm_id
= MESH_PATH_METRIC_AIRTIME
;
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
;
101 static void wpas_mesh_copy_groups(struct hostapd_data
*bss
,
102 struct wpa_supplicant
*wpa_s
)
107 for (num_groups
= 0; wpa_s
->conf
->sae_groups
[num_groups
] > 0;
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
,
119 static int wpa_supplicant_mesh_init(struct wpa_supplicant
*wpa_s
,
120 struct wpa_ssid
*ssid
)
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 };
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");
138 wpa_s
->ifmsh
= ifmsh
= os_zalloc(sizeof(*wpa_s
->ifmsh
));
142 ifmsh
->drv_flags
= wpa_s
->drv_flags
;
144 ifmsh
->bss
= os_calloc(wpa_s
->ifmsh
->num_bss
,
145 sizeof(struct hostapd_data
*));
149 ifmsh
->bss
[0] = bss
= os_zalloc(sizeof(struct hostapd_data
));
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
;
157 bss
->mesh_sta_free_cb
= mesh_mpm_free_sta
;
158 wpa_s
->assoc_freq
= ssid
->frequency
;
159 wpa_s
->current_ssid
= ssid
;
161 /* setup an AP config for auth processing */
162 conf
= hostapd_config_defaults();
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
;
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
));
178 mconf
= mesh_config_create(ssid
);
181 ifmsh
->mconf
= mconf
;
183 /* need conf->hw_mode for supported rates. */
184 if (ssid
->frequency
== 0) {
185 conf
->hw_mode
= HOSTAPD_MODE_IEEE80211G
;
188 conf
->hw_mode
= ieee80211_freq_to_chan(ssid
->frequency
,
191 if (conf
->hw_mode
== NUM_HOSTAPD_MODES
) {
192 wpa_printf(MSG_ERROR
, "Unsupported mesh mode frequency: %d MHz",
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(
205 &conf
->vht_oper_centr_freq_seg0_idx
);
206 conf
->vht_oper_centr_freq_seg0_idx
+= ssid
->ht40
* 2;
208 case VHT_CHANWIDTH_160MHZ
:
209 ieee80211_freq_to_chan(
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;
216 ieee80211_freq_to_chan(ssid
->vht_center_freq2
,
217 &conf
->vht_oper_centr_freq_seg1_idx
);
220 if (ssid
->mesh_basic_rates
== NULL
) {
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.
228 if (conf
->hw_mode
== HOSTAPD_MODE_IEEE80211G
) {
229 conf
->basic_rates
= os_malloc(sizeof(basic_rates_erp
));
230 if (!conf
->basic_rates
)
232 os_memcpy(conf
->basic_rates
, basic_rates_erp
,
233 sizeof(basic_rates_erp
));
238 if (ssid
->mesh_basic_rates
[rate_len
] < 1)
242 conf
->basic_rates
= os_calloc(rate_len
+ 1, sizeof(int));
243 if (conf
->basic_rates
== NULL
)
245 os_memcpy(conf
->basic_rates
, ssid
->mesh_basic_rates
,
246 rate_len
* sizeof(int));
247 conf
->basic_rates
[rate_len
] = -1;
250 if (hostapd_setup_interface(ifmsh
)) {
251 wpa_printf(MSG_ERROR
,
252 "Failed to initialize hostapd interface for mesh");
256 if (wpa_drv_init_mesh(wpa_s
)) {
257 wpa_msg(wpa_s
, MSG_ERROR
, "Failed to init mesh in driver");
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");
268 bss
->conf
->wpa
= ssid
->proto
;
269 bss
->conf
->wpa_key_mgmt
= ssid
->key_mgmt
;
271 if (wpa_s
->conf
->sae_groups
&&
272 wpa_s
->conf
->sae_groups
[0] > 0) {
273 wpas_mesh_copy_groups(bss
, wpa_s
);
275 bss
->conf
->sae_groups
=
276 os_malloc(sizeof(default_groups
));
277 if (!bss
->conf
->sae_groups
)
279 os_memcpy(bss
->conf
->sae_groups
, default_groups
,
280 sizeof(default_groups
));
283 len
= os_strlen(ssid
->passphrase
);
284 bss
->conf
->ssid
.wpa_passphrase
=
285 dup_binstr(ssid
->passphrase
, len
);
287 wpa_s
->mesh_rsn
= mesh_rsn_auth_init(wpa_s
, mconf
);
288 if (!wpa_s
->mesh_rsn
)
292 wpa_supplicant_conf_ap_ht(wpa_s
, ssid
, conf
);
296 wpa_supplicant_mesh_deinit(wpa_s
);
301 void wpa_mesh_notify_peer(struct wpa_supplicant
*wpa_s
, const u8
*addr
,
302 const u8
*ies
, size_t ie_len
)
304 struct ieee802_11_elems elems
;
306 wpa_msg(wpa_s
, MSG_INFO
,
307 "new peer notification for " MACSTR
, MAC2STR(addr
));
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
,
314 wpa_mesh_new_mesh_peer(wpa_s
, addr
, &elems
);
318 void wpa_supplicant_mesh_add_scan_ie(struct wpa_supplicant
*wpa_s
,
319 struct wpabuf
**extra_ie
)
321 /* EID + 0-length (wildcard) mesh-id */
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);
331 int wpa_supplicant_join_mesh(struct wpa_supplicant
*wpa_s
,
332 struct wpa_ssid
*ssid
)
334 struct wpa_driver_mesh_join_params params
;
337 if (!ssid
|| !ssid
->ssid
|| !ssid
->ssid_len
|| !ssid
->frequency
) {
342 wpa_supplicant_mesh_deinit(wpa_s
);
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;
349 wpa_s
->pairwise_cipher
= WPA_CIPHER_NONE
;
350 wpa_s
->group_cipher
= WPA_CIPHER_NONE
;
351 wpa_s
->mgmt_group_cipher
= 0;
354 os_memset(¶ms
, 0, sizeof(params
));
355 params
.meshid
= ssid
->ssid
;
356 params
.meshid_len
= ssid
->ssid_len
;
357 ibss_mesh_setup_freq(wpa_s
, ssid
, ¶ms
.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
) {
364 switch (params
.freq
.bandwidth
) {
366 if (params
.freq
.center_freq2
) {
367 ssid
->max_oper_chwidth
= VHT_CHANWIDTH_80P80MHZ
;
368 ssid
->vht_center_freq2
=
369 params
.freq
.center_freq2
;
371 ssid
->max_oper_chwidth
= VHT_CHANWIDTH_80MHZ
;
375 ssid
->max_oper_chwidth
= VHT_CHANWIDTH_160MHZ
;
378 ssid
->max_oper_chwidth
= VHT_CHANWIDTH_USE_HT
;
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
;
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;
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
;
398 params
.flags
|= WPA_DRIVER_MESH_FLAG_DRIVER_MPM
;
399 params
.conf
.flags
|= WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS
;
401 params
.conf
.peer_link_timeout
= wpa_s
->conf
->mesh_max_inactivity
;
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
);
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
;
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
, ¶ms
);
420 wpa_msg(wpa_s
, MSG_ERROR
, "mesh join error=%d\n", ret
);
422 /* hostapd sets the interface down until we associate */
423 wpa_drv_set_operstate(wpa_s
, 1);
430 int wpa_supplicant_leave_mesh(struct wpa_supplicant
*wpa_s
)
434 wpa_msg(wpa_s
, MSG_INFO
, "leaving mesh");
436 /* Need to send peering close messages first */
437 wpa_supplicant_mesh_deinit(wpa_s
);
439 ret
= wpa_drv_leave_mesh(wpa_s
);
441 wpa_msg(wpa_s
, MSG_ERROR
, "mesh leave error=%d", ret
);
443 wpa_drv_set_operstate(wpa_s
, 1);
449 static int mesh_attr_text(const u8
*ies
, size_t ies_len
, char *buf
, char *end
)
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
;
456 if (ieee802_11_parse_elems(ies
, ies_len
, &elems
, 0) == ParseFailed
)
459 if (elems
.mesh_id_len
< 1)
462 mesh_id
= os_malloc(elems
.mesh_id_len
+ 1);
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
);
470 if (os_snprintf_error(end
- pos
, ret
))
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
))
492 bss_basic_rate_set
= os_malloc(elems
.supp_rates_len
+
493 elems
.ext_supp_rates_len
);
494 if (bss_basic_rate_set
== NULL
)
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;
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;
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
))
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
))
525 ret
= os_snprintf(pos
, end
- pos
, "\n");
526 if (os_snprintf_error(end
- pos
, ret
))
531 os_free(bss_basic_rate_set
);
537 int wpas_mesh_scan_result_text(const u8
*ies
, size_t ies_len
, char *buf
,
540 return mesh_attr_text(ies
, ies_len
, buf
, end
);
544 static int wpas_mesh_get_ifname(struct wpa_supplicant
*wpa_s
, char *ifname
,
547 char *ifname_ptr
= wpa_s
->ifname
;
550 res
= os_snprintf(ifname
, len
, "mesh-%s-%d", ifname_ptr
,
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
))
560 wpa_s
->mesh_if_idx
++;
565 int wpas_mesh_add_interface(struct wpa_supplicant
*wpa_s
, char *ifname
,
568 struct wpa_interface iface
;
569 struct wpa_supplicant
*mesh_wpa_s
;
572 if (ifname
[0] == '\0' && wpas_mesh_get_ifname(wpa_s
, ifname
, len
) < 0)
575 if (wpa_drv_if_add(wpa_s
, WPA_IF_MESH
, ifname
, NULL
, NULL
, NULL
, addr
,
577 wpa_printf(MSG_ERROR
,
578 "mesh: Failed to create new mesh interface");
581 wpa_printf(MSG_INFO
, "mesh: Created virtual interface %s addr "
582 MACSTR
, ifname
, MAC2STR(addr
));
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
;
590 mesh_wpa_s
= wpa_supplicant_add_iface(wpa_s
->global
, &iface
, 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);
597 mesh_wpa_s
->mesh_if_created
= 1;
602 int wpas_mesh_peer_remove(struct wpa_supplicant
*wpa_s
, const u8
*addr
)
604 return mesh_mpm_close_peer(wpa_s
, addr
);
608 int wpas_mesh_peer_add(struct wpa_supplicant
*wpa_s
, const u8
*addr
,
611 return mesh_mpm_connect_peer(wpa_s
, addr
, duration
);