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
->ies
) {
51 ifmsh
->mconf
->ies
= 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
;
172 ifmsh
->bss
[0]->max_plinks
= 99;
173 os_strlcpy(bss
->conf
->iface
, wpa_s
->ifname
, sizeof(bss
->conf
->iface
));
175 mconf
= mesh_config_create(ssid
);
178 ifmsh
->mconf
= mconf
;
180 /* need conf->hw_mode for supported rates. */
181 if (ssid
->frequency
== 0) {
182 conf
->hw_mode
= HOSTAPD_MODE_IEEE80211G
;
185 conf
->hw_mode
= ieee80211_freq_to_chan(ssid
->frequency
,
188 if (conf
->hw_mode
== NUM_HOSTAPD_MODES
) {
189 wpa_printf(MSG_ERROR
, "Unsupported mesh mode frequency: %d MHz",
194 if (ssid
->mesh_basic_rates
== NULL
) {
196 * XXX: Hack! This is so an MPM which correctly sets the ERP
197 * mandatory rates as BSSBasicRateSet doesn't reject us. We
198 * could add a new hw_mode HOSTAPD_MODE_IEEE80211G_ERP, but
199 * this is way easier. This also makes our BSSBasicRateSet
200 * advertised in beacons match the one in peering frames, sigh.
202 if (conf
->hw_mode
== HOSTAPD_MODE_IEEE80211G
) {
203 conf
->basic_rates
= os_malloc(sizeof(basic_rates_erp
));
204 if (!conf
->basic_rates
)
206 os_memcpy(conf
->basic_rates
, basic_rates_erp
,
207 sizeof(basic_rates_erp
));
212 if (ssid
->mesh_basic_rates
[rate_len
] < 1)
216 conf
->basic_rates
= os_calloc(rate_len
+ 1, sizeof(int));
217 if (conf
->basic_rates
== NULL
)
219 os_memcpy(conf
->basic_rates
, ssid
->mesh_basic_rates
,
220 rate_len
* sizeof(int));
221 conf
->basic_rates
[rate_len
] = -1;
224 if (hostapd_setup_interface(ifmsh
)) {
225 wpa_printf(MSG_ERROR
,
226 "Failed to initialize hostapd interface for mesh");
230 if (wpa_drv_init_mesh(wpa_s
)) {
231 wpa_msg(wpa_s
, MSG_ERROR
, "Failed to init mesh in driver");
235 if (mconf
->security
!= MESH_CONF_SEC_NONE
) {
236 if (ssid
->passphrase
== NULL
) {
237 wpa_printf(MSG_ERROR
,
238 "mesh: Passphrase for SAE not configured");
242 bss
->conf
->wpa
= ssid
->proto
;
243 bss
->conf
->wpa_key_mgmt
= ssid
->key_mgmt
;
245 if (wpa_s
->conf
->sae_groups
&&
246 wpa_s
->conf
->sae_groups
[0] > 0) {
247 wpas_mesh_copy_groups(bss
, wpa_s
);
249 bss
->conf
->sae_groups
=
250 os_malloc(sizeof(default_groups
));
251 if (!bss
->conf
->sae_groups
)
253 os_memcpy(bss
->conf
->sae_groups
, default_groups
,
254 sizeof(default_groups
));
257 len
= os_strlen(ssid
->passphrase
);
258 bss
->conf
->ssid
.wpa_passphrase
=
259 dup_binstr(ssid
->passphrase
, len
);
261 wpa_s
->mesh_rsn
= mesh_rsn_auth_init(wpa_s
, mconf
);
262 if (!wpa_s
->mesh_rsn
)
266 wpa_supplicant_conf_ap_ht(wpa_s
, ssid
, conf
);
270 wpa_supplicant_mesh_deinit(wpa_s
);
275 void wpa_mesh_notify_peer(struct wpa_supplicant
*wpa_s
, const u8
*addr
,
276 const u8
*ies
, size_t ie_len
)
278 struct ieee802_11_elems elems
;
280 wpa_msg(wpa_s
, MSG_INFO
,
281 "new peer notification for " MACSTR
, MAC2STR(addr
));
283 if (ieee802_11_parse_elems(ies
, ie_len
, &elems
, 0) == ParseFailed
) {
284 wpa_msg(wpa_s
, MSG_INFO
, "Could not parse beacon from " MACSTR
,
288 wpa_mesh_new_mesh_peer(wpa_s
, addr
, &elems
);
292 void wpa_supplicant_mesh_add_scan_ie(struct wpa_supplicant
*wpa_s
,
293 struct wpabuf
**extra_ie
)
295 /* EID + 0-length (wildcard) mesh-id */
298 if (wpabuf_resize(extra_ie
, ielen
) == 0) {
299 wpabuf_put_u8(*extra_ie
, WLAN_EID_MESH_ID
);
300 wpabuf_put_u8(*extra_ie
, 0);
305 int wpa_supplicant_join_mesh(struct wpa_supplicant
*wpa_s
,
306 struct wpa_ssid
*ssid
)
308 struct wpa_driver_mesh_join_params params
;
311 if (!ssid
|| !ssid
->ssid
|| !ssid
->ssid_len
|| !ssid
->frequency
) {
316 wpa_supplicant_mesh_deinit(wpa_s
);
318 os_memset(¶ms
, 0, sizeof(params
));
319 params
.meshid
= ssid
->ssid
;
320 params
.meshid_len
= ssid
->ssid_len
;
321 params
.freq
= ssid
->frequency
;
322 #ifdef CONFIG_IEEE80211N
323 params
.ht_mode
= ssid
->mesh_ht_mode
;
324 #endif /* CONFIG_IEEE80211N */
326 if (ssid
->key_mgmt
& WPA_KEY_MGMT_SAE
) {
327 params
.flags
|= WPA_DRIVER_MESH_FLAG_SAE_AUTH
;
328 params
.flags
|= WPA_DRIVER_MESH_FLAG_AMPE
;
329 wpa_s
->conf
->user_mpm
= 1;
332 if (wpa_s
->conf
->user_mpm
) {
333 params
.flags
|= WPA_DRIVER_MESH_FLAG_USER_MPM
;
334 params
.conf
.flags
&= ~WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS
;
336 params
.flags
|= WPA_DRIVER_MESH_FLAG_DRIVER_MPM
;
337 params
.conf
.flags
|= WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS
;
340 if (wpa_supplicant_mesh_init(wpa_s
, ssid
)) {
341 wpa_msg(wpa_s
, MSG_ERROR
, "Failed to init mesh");
347 params
.ies
= wpa_s
->ifmsh
->mconf
->ies
;
348 params
.ie_len
= wpa_s
->ifmsh
->mconf
->ie_len
;
349 params
.basic_rates
= wpa_s
->ifmsh
->basic_rates
;
352 wpa_msg(wpa_s
, MSG_INFO
, "joining mesh %s",
353 wpa_ssid_txt(ssid
->ssid
, ssid
->ssid_len
));
354 ret
= wpa_drv_join_mesh(wpa_s
, ¶ms
);
356 wpa_msg(wpa_s
, MSG_ERROR
, "mesh join error=%d\n", ret
);
358 /* hostapd sets the interface down until we associate */
359 wpa_drv_set_operstate(wpa_s
, 1);
366 int wpa_supplicant_leave_mesh(struct wpa_supplicant
*wpa_s
)
370 wpa_msg(wpa_s
, MSG_INFO
, "leaving mesh");
372 /* Need to send peering close messages first */
373 wpa_supplicant_mesh_deinit(wpa_s
);
375 ret
= wpa_drv_leave_mesh(wpa_s
);
377 wpa_msg(wpa_s
, MSG_ERROR
, "mesh leave error=%d", ret
);
379 wpa_drv_set_operstate(wpa_s
, 1);
385 static int mesh_attr_text(const u8
*ies
, size_t ies_len
, char *buf
, char *end
)
387 struct ieee802_11_elems elems
;
388 char *mesh_id
, *pos
= buf
;
389 u8
*bss_basic_rate_set
;
390 int bss_basic_rate_set_len
, ret
, i
;
392 if (ieee802_11_parse_elems(ies
, ies_len
, &elems
, 0) == ParseFailed
)
395 if (elems
.mesh_id_len
< 1)
398 mesh_id
= os_malloc(elems
.mesh_id_len
+ 1);
402 os_memcpy(mesh_id
, elems
.mesh_id
, elems
.mesh_id_len
);
403 mesh_id
[elems
.mesh_id_len
] = '\0';
404 ret
= os_snprintf(pos
, end
- pos
, "mesh_id=%s\n", mesh_id
);
406 if (os_snprintf_error(end
- pos
, ret
))
410 if (elems
.mesh_config_len
> 6) {
411 ret
= os_snprintf(pos
, end
- pos
,
412 "active_path_selection_protocol_id=0x%02x\n"
413 "active_path_selection_metric_id=0x%02x\n"
414 "congestion_control_mode_id=0x%02x\n"
415 "synchronization_method_id=0x%02x\n"
416 "authentication_protocol_id=0x%02x\n"
417 "mesh_formation_info=0x%02x\n"
418 "mesh_capability=0x%02x\n",
419 elems
.mesh_config
[0], elems
.mesh_config
[1],
420 elems
.mesh_config
[2], elems
.mesh_config
[3],
421 elems
.mesh_config
[4], elems
.mesh_config
[5],
422 elems
.mesh_config
[6]);
423 if (os_snprintf_error(end
- pos
, ret
))
428 bss_basic_rate_set
= os_malloc(elems
.supp_rates_len
+
429 elems
.ext_supp_rates_len
);
430 if (bss_basic_rate_set
== NULL
)
433 bss_basic_rate_set_len
= 0;
434 for (i
= 0; i
< elems
.supp_rates_len
; i
++) {
435 if (elems
.supp_rates
[i
] & 0x80) {
436 bss_basic_rate_set
[bss_basic_rate_set_len
++] =
437 (elems
.supp_rates
[i
] & 0x7f) * 5;
440 for (i
= 0; i
< elems
.ext_supp_rates_len
; i
++) {
441 if (elems
.ext_supp_rates
[i
] & 0x80) {
442 bss_basic_rate_set
[bss_basic_rate_set_len
++] =
443 (elems
.ext_supp_rates
[i
] & 0x7f) * 5;
446 if (bss_basic_rate_set_len
> 0) {
447 ret
= os_snprintf(pos
, end
- pos
, "bss_basic_rate_set=%d",
448 bss_basic_rate_set
[0]);
449 if (os_snprintf_error(end
- pos
, ret
))
453 for (i
= 1; i
< bss_basic_rate_set_len
; i
++) {
454 ret
= os_snprintf(pos
, end
- pos
, " %d",
455 bss_basic_rate_set
[i
]);
456 if (os_snprintf_error(end
- pos
, ret
))
461 ret
= os_snprintf(pos
, end
- pos
, "\n");
462 if (os_snprintf_error(end
- pos
, ret
))
466 os_free(bss_basic_rate_set
);
472 int wpas_mesh_scan_result_text(const u8
*ies
, size_t ies_len
, char *buf
,
475 return mesh_attr_text(ies
, ies_len
, buf
, end
);