15b9c547cSRui Paulo /*
25b9c547cSRui Paulo * WPA Supplicant - Basic mesh mode routines
35b9c547cSRui Paulo * Copyright (c) 2013-2014, cozybit, Inc. All rights reserved.
45b9c547cSRui Paulo *
55b9c547cSRui Paulo * This software may be distributed under the terms of the BSD license.
65b9c547cSRui Paulo * See README for more details.
75b9c547cSRui Paulo */
85b9c547cSRui Paulo
95b9c547cSRui Paulo #include "utils/includes.h"
105b9c547cSRui Paulo
115b9c547cSRui Paulo #include "utils/common.h"
125b9c547cSRui Paulo #include "utils/eloop.h"
135b9c547cSRui Paulo #include "utils/uuid.h"
145b9c547cSRui Paulo #include "common/ieee802_11_defs.h"
155b9c547cSRui Paulo #include "common/wpa_ctrl.h"
16c1d255d3SCy Schubert #include "common/hw_features_common.h"
175b9c547cSRui Paulo #include "ap/sta_info.h"
185b9c547cSRui Paulo #include "ap/hostapd.h"
195b9c547cSRui Paulo #include "ap/ieee802_11.h"
205b9c547cSRui Paulo #include "config_ssid.h"
215b9c547cSRui Paulo #include "config.h"
225b9c547cSRui Paulo #include "wpa_supplicant_i.h"
235b9c547cSRui Paulo #include "driver_i.h"
245b9c547cSRui Paulo #include "notify.h"
255b9c547cSRui Paulo #include "ap.h"
265b9c547cSRui Paulo #include "mesh_mpm.h"
275b9c547cSRui Paulo #include "mesh_rsn.h"
285b9c547cSRui Paulo #include "mesh.h"
295b9c547cSRui Paulo
305b9c547cSRui Paulo
wpa_supplicant_mesh_deinit(struct wpa_supplicant * wpa_s,bool also_clear_hostapd)31c1d255d3SCy Schubert static void wpa_supplicant_mesh_deinit(struct wpa_supplicant *wpa_s,
32c1d255d3SCy Schubert bool also_clear_hostapd)
335b9c547cSRui Paulo {
34c1d255d3SCy Schubert wpa_supplicant_mesh_iface_deinit(wpa_s, wpa_s->ifmsh,
35c1d255d3SCy Schubert also_clear_hostapd);
36c1d255d3SCy Schubert
37c1d255d3SCy Schubert if (also_clear_hostapd) {
385b9c547cSRui Paulo wpa_s->ifmsh = NULL;
395b9c547cSRui Paulo wpa_s->current_ssid = NULL;
404bc52338SCy Schubert os_free(wpa_s->mesh_params);
414bc52338SCy Schubert wpa_s->mesh_params = NULL;
42c1d255d3SCy Schubert }
43c1d255d3SCy Schubert
44c1d255d3SCy Schubert os_free(wpa_s->mesh_rsn);
45c1d255d3SCy Schubert wpa_s->mesh_rsn = NULL;
46c1d255d3SCy Schubert
47c1d255d3SCy Schubert if (!also_clear_hostapd)
48c1d255d3SCy Schubert wpa_supplicant_leave_mesh(wpa_s, false);
495b9c547cSRui Paulo }
505b9c547cSRui Paulo
515b9c547cSRui Paulo
wpa_supplicant_mesh_iface_deinit(struct wpa_supplicant * wpa_s,struct hostapd_iface * ifmsh,bool also_clear_hostapd)525b9c547cSRui Paulo void wpa_supplicant_mesh_iface_deinit(struct wpa_supplicant *wpa_s,
53c1d255d3SCy Schubert struct hostapd_iface *ifmsh,
54c1d255d3SCy Schubert bool also_clear_hostapd)
555b9c547cSRui Paulo {
565b9c547cSRui Paulo if (!ifmsh)
575b9c547cSRui Paulo return;
585b9c547cSRui Paulo
595b9c547cSRui Paulo if (ifmsh->mconf) {
605b9c547cSRui Paulo mesh_mpm_deinit(wpa_s, ifmsh);
61325151a3SRui Paulo if (ifmsh->mconf->rsn_ie) {
62325151a3SRui Paulo ifmsh->mconf->rsn_ie = NULL;
635b9c547cSRui Paulo /* We cannot free this struct
645b9c547cSRui Paulo * because wpa_authenticator on
655b9c547cSRui Paulo * hostapd side is also using it
665b9c547cSRui Paulo * for now just set to NULL and
675b9c547cSRui Paulo * let hostapd code free it.
685b9c547cSRui Paulo */
695b9c547cSRui Paulo }
705b9c547cSRui Paulo os_free(ifmsh->mconf);
715b9c547cSRui Paulo ifmsh->mconf = NULL;
725b9c547cSRui Paulo }
735b9c547cSRui Paulo
745b9c547cSRui Paulo /* take care of shared data */
75c1d255d3SCy Schubert if (also_clear_hostapd) {
765b9c547cSRui Paulo hostapd_interface_deinit(ifmsh);
775b9c547cSRui Paulo hostapd_interface_free(ifmsh);
785b9c547cSRui Paulo }
79c1d255d3SCy Schubert }
805b9c547cSRui Paulo
815b9c547cSRui Paulo
mesh_config_create(struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid)82780fb4a2SCy Schubert static struct mesh_conf * mesh_config_create(struct wpa_supplicant *wpa_s,
83780fb4a2SCy Schubert struct wpa_ssid *ssid)
845b9c547cSRui Paulo {
855b9c547cSRui Paulo struct mesh_conf *conf;
86780fb4a2SCy Schubert int cipher;
875b9c547cSRui Paulo
885b9c547cSRui Paulo conf = os_zalloc(sizeof(struct mesh_conf));
895b9c547cSRui Paulo if (!conf)
905b9c547cSRui Paulo return NULL;
915b9c547cSRui Paulo
925b9c547cSRui Paulo os_memcpy(conf->meshid, ssid->ssid, ssid->ssid_len);
935b9c547cSRui Paulo conf->meshid_len = ssid->ssid_len;
945b9c547cSRui Paulo
955b9c547cSRui Paulo if (ssid->key_mgmt & WPA_KEY_MGMT_SAE)
965b9c547cSRui Paulo conf->security |= MESH_CONF_SEC_AUTH |
975b9c547cSRui Paulo MESH_CONF_SEC_AMPE;
985b9c547cSRui Paulo else
995b9c547cSRui Paulo conf->security |= MESH_CONF_SEC_NONE;
100780fb4a2SCy Schubert conf->ieee80211w = ssid->ieee80211w;
101780fb4a2SCy Schubert if (conf->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT) {
102780fb4a2SCy Schubert if (wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_BIP)
103780fb4a2SCy Schubert conf->ieee80211w = wpa_s->conf->pmf;
104780fb4a2SCy Schubert else
105780fb4a2SCy Schubert conf->ieee80211w = NO_MGMT_FRAME_PROTECTION;
106780fb4a2SCy Schubert }
1074bc52338SCy Schubert #ifdef CONFIG_OCV
1084bc52338SCy Schubert conf->ocv = ssid->ocv;
1094bc52338SCy Schubert #endif /* CONFIG_OCV */
110780fb4a2SCy Schubert
111780fb4a2SCy Schubert cipher = wpa_pick_pairwise_cipher(ssid->pairwise_cipher, 0);
112780fb4a2SCy Schubert if (cipher < 0 || cipher == WPA_CIPHER_TKIP) {
113780fb4a2SCy Schubert wpa_msg(wpa_s, MSG_INFO, "mesh: Invalid pairwise cipher");
114780fb4a2SCy Schubert os_free(conf);
115780fb4a2SCy Schubert return NULL;
116780fb4a2SCy Schubert }
117780fb4a2SCy Schubert conf->pairwise_cipher = cipher;
118780fb4a2SCy Schubert
119780fb4a2SCy Schubert cipher = wpa_pick_group_cipher(ssid->group_cipher);
120780fb4a2SCy Schubert if (cipher < 0 || cipher == WPA_CIPHER_TKIP ||
121780fb4a2SCy Schubert cipher == WPA_CIPHER_GTK_NOT_USED) {
122780fb4a2SCy Schubert wpa_msg(wpa_s, MSG_INFO, "mesh: Invalid group cipher");
123780fb4a2SCy Schubert os_free(conf);
124780fb4a2SCy Schubert return NULL;
125780fb4a2SCy Schubert }
126780fb4a2SCy Schubert
127780fb4a2SCy Schubert conf->group_cipher = cipher;
128c1d255d3SCy Schubert if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
129c1d255d3SCy Schubert if (ssid->group_mgmt_cipher == WPA_CIPHER_BIP_GMAC_128 ||
130c1d255d3SCy Schubert ssid->group_mgmt_cipher == WPA_CIPHER_BIP_GMAC_256 ||
131c1d255d3SCy Schubert ssid->group_mgmt_cipher == WPA_CIPHER_BIP_CMAC_256)
132c1d255d3SCy Schubert conf->mgmt_group_cipher = ssid->group_mgmt_cipher;
133c1d255d3SCy Schubert else
134780fb4a2SCy Schubert conf->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
135c1d255d3SCy Schubert }
1365b9c547cSRui Paulo
1375b9c547cSRui Paulo /* defaults */
1385b9c547cSRui Paulo conf->mesh_pp_id = MESH_PATH_PROTOCOL_HWMP;
1395b9c547cSRui Paulo conf->mesh_pm_id = MESH_PATH_METRIC_AIRTIME;
1405b9c547cSRui Paulo conf->mesh_cc_id = 0;
1415b9c547cSRui Paulo conf->mesh_sp_id = MESH_SYNC_METHOD_NEIGHBOR_OFFSET;
1425b9c547cSRui Paulo conf->mesh_auth_id = (conf->security & MESH_CONF_SEC_AUTH) ? 1 : 0;
14332a95656SCy Schubert conf->mesh_fwding = ssid->mesh_fwding;
1445b9c547cSRui Paulo conf->dot11MeshMaxRetries = ssid->dot11MeshMaxRetries;
1455b9c547cSRui Paulo conf->dot11MeshRetryTimeout = ssid->dot11MeshRetryTimeout;
1465b9c547cSRui Paulo conf->dot11MeshConfirmTimeout = ssid->dot11MeshConfirmTimeout;
1475b9c547cSRui Paulo conf->dot11MeshHoldingTimeout = ssid->dot11MeshHoldingTimeout;
1485b9c547cSRui Paulo
1495b9c547cSRui Paulo return conf;
1505b9c547cSRui Paulo }
1515b9c547cSRui Paulo
1525b9c547cSRui Paulo
wpas_mesh_copy_groups(struct hostapd_data * bss,struct wpa_supplicant * wpa_s)1535b9c547cSRui Paulo static void wpas_mesh_copy_groups(struct hostapd_data *bss,
1545b9c547cSRui Paulo struct wpa_supplicant *wpa_s)
1555b9c547cSRui Paulo {
1565b9c547cSRui Paulo int num_groups;
1575b9c547cSRui Paulo size_t groups_size;
1585b9c547cSRui Paulo
1595b9c547cSRui Paulo for (num_groups = 0; wpa_s->conf->sae_groups[num_groups] > 0;
1605b9c547cSRui Paulo num_groups++)
1615b9c547cSRui Paulo ;
1625b9c547cSRui Paulo
1635b9c547cSRui Paulo groups_size = (num_groups + 1) * sizeof(wpa_s->conf->sae_groups[0]);
1645b9c547cSRui Paulo bss->conf->sae_groups = os_malloc(groups_size);
1655b9c547cSRui Paulo if (bss->conf->sae_groups)
1665b9c547cSRui Paulo os_memcpy(bss->conf->sae_groups, wpa_s->conf->sae_groups,
1675b9c547cSRui Paulo groups_size);
1685b9c547cSRui Paulo }
1695b9c547cSRui Paulo
1705b9c547cSRui Paulo
wpas_mesh_init_rsn(struct wpa_supplicant * wpa_s)1714bc52338SCy Schubert static int wpas_mesh_init_rsn(struct wpa_supplicant *wpa_s)
1724bc52338SCy Schubert {
1734bc52338SCy Schubert struct hostapd_iface *ifmsh = wpa_s->ifmsh;
1744bc52338SCy Schubert struct wpa_ssid *ssid = wpa_s->current_ssid;
1754bc52338SCy Schubert struct hostapd_data *bss = ifmsh->bss[0];
1764bc52338SCy Schubert static int default_groups[] = { 19, 20, 21, 25, 26, -1 };
1774bc52338SCy Schubert const char *password;
1784bc52338SCy Schubert size_t len;
1794bc52338SCy Schubert
1804bc52338SCy Schubert password = ssid->sae_password;
1814bc52338SCy Schubert if (!password)
1824bc52338SCy Schubert password = ssid->passphrase;
1834bc52338SCy Schubert if (!password) {
1844bc52338SCy Schubert wpa_printf(MSG_ERROR,
1854bc52338SCy Schubert "mesh: Passphrase for SAE not configured");
1864bc52338SCy Schubert return -1;
1874bc52338SCy Schubert }
1884bc52338SCy Schubert
1894bc52338SCy Schubert bss->conf->wpa = ssid->proto;
1904bc52338SCy Schubert bss->conf->wpa_key_mgmt = ssid->key_mgmt;
1914bc52338SCy Schubert
1924bc52338SCy Schubert if (wpa_s->conf->sae_groups && wpa_s->conf->sae_groups[0] > 0) {
1934bc52338SCy Schubert wpas_mesh_copy_groups(bss, wpa_s);
1944bc52338SCy Schubert } else {
1954bc52338SCy Schubert bss->conf->sae_groups = os_memdup(default_groups,
1964bc52338SCy Schubert sizeof(default_groups));
1974bc52338SCy Schubert if (!bss->conf->sae_groups)
1984bc52338SCy Schubert return -1;
1994bc52338SCy Schubert }
2004bc52338SCy Schubert
2014bc52338SCy Schubert len = os_strlen(password);
2024bc52338SCy Schubert bss->conf->ssid.wpa_passphrase = dup_binstr(password, len);
2034bc52338SCy Schubert
2044bc52338SCy Schubert wpa_s->mesh_rsn = mesh_rsn_auth_init(wpa_s, ifmsh->mconf);
2054bc52338SCy Schubert return !wpa_s->mesh_rsn ? -1 : 0;
2064bc52338SCy Schubert }
2074bc52338SCy Schubert
2084bc52338SCy Schubert
wpas_mesh_update_freq_params(struct wpa_supplicant * wpa_s)209c1d255d3SCy Schubert static int wpas_mesh_update_freq_params(struct wpa_supplicant *wpa_s)
210c1d255d3SCy Schubert {
211c1d255d3SCy Schubert struct wpa_driver_mesh_join_params *params = wpa_s->mesh_params;
212c1d255d3SCy Schubert struct hostapd_iface *ifmsh = wpa_s->ifmsh;
213c1d255d3SCy Schubert struct he_capabilities *he_capab = NULL;
214c1d255d3SCy Schubert
215c1d255d3SCy Schubert if (ifmsh->current_mode)
216c1d255d3SCy Schubert he_capab = &ifmsh->current_mode->he_capab[IEEE80211_MODE_MESH];
217c1d255d3SCy Schubert
218c1d255d3SCy Schubert if (hostapd_set_freq_params(
219c1d255d3SCy Schubert ¶ms->freq,
220c1d255d3SCy Schubert ifmsh->conf->hw_mode,
221c1d255d3SCy Schubert ifmsh->freq,
222c1d255d3SCy Schubert ifmsh->conf->channel,
223c1d255d3SCy Schubert ifmsh->conf->enable_edmg,
224c1d255d3SCy Schubert ifmsh->conf->edmg_channel,
225c1d255d3SCy Schubert ifmsh->conf->ieee80211n,
226c1d255d3SCy Schubert ifmsh->conf->ieee80211ac,
227c1d255d3SCy Schubert ifmsh->conf->ieee80211ax,
228*a90b9d01SCy Schubert ifmsh->conf->ieee80211be,
229c1d255d3SCy Schubert ifmsh->conf->secondary_channel,
230c1d255d3SCy Schubert hostapd_get_oper_chwidth(ifmsh->conf),
231c1d255d3SCy Schubert hostapd_get_oper_centr_freq_seg0_idx(ifmsh->conf),
232c1d255d3SCy Schubert hostapd_get_oper_centr_freq_seg1_idx(ifmsh->conf),
233c1d255d3SCy Schubert ifmsh->conf->vht_capab,
234*a90b9d01SCy Schubert he_capab, NULL, 0)) {
235c1d255d3SCy Schubert wpa_printf(MSG_ERROR, "Error updating mesh frequency params");
236c1d255d3SCy Schubert wpa_supplicant_mesh_deinit(wpa_s, true);
237c1d255d3SCy Schubert return -1;
238c1d255d3SCy Schubert }
239c1d255d3SCy Schubert
240c1d255d3SCy Schubert return 0;
241c1d255d3SCy Schubert }
242c1d255d3SCy Schubert
243c1d255d3SCy Schubert
wpas_mesh_complete(struct wpa_supplicant * wpa_s)2444bc52338SCy Schubert static int wpas_mesh_complete(struct wpa_supplicant *wpa_s)
2454bc52338SCy Schubert {
2464bc52338SCy Schubert struct hostapd_iface *ifmsh = wpa_s->ifmsh;
2474bc52338SCy Schubert struct wpa_driver_mesh_join_params *params = wpa_s->mesh_params;
2484bc52338SCy Schubert struct wpa_ssid *ssid = wpa_s->current_ssid;
2494bc52338SCy Schubert int ret;
2504bc52338SCy Schubert
2514bc52338SCy Schubert if (!params || !ssid || !ifmsh) {
2524bc52338SCy Schubert wpa_printf(MSG_ERROR, "mesh: %s called without active mesh",
2534bc52338SCy Schubert __func__);
2544bc52338SCy Schubert return -1;
2554bc52338SCy Schubert }
2564bc52338SCy Schubert
257c1d255d3SCy Schubert /*
258c1d255d3SCy Schubert * Update channel configuration if the channel has changed since the
259c1d255d3SCy Schubert * initial setting, i.e., due to DFS radar detection during CAC.
260c1d255d3SCy Schubert */
261c1d255d3SCy Schubert if (ifmsh->freq > 0 && ifmsh->freq != params->freq.freq) {
262c1d255d3SCy Schubert wpa_s->assoc_freq = ifmsh->freq;
263c1d255d3SCy Schubert ssid->frequency = ifmsh->freq;
264c1d255d3SCy Schubert if (wpas_mesh_update_freq_params(wpa_s) < 0)
265c1d255d3SCy Schubert return -1;
266c1d255d3SCy Schubert }
267c1d255d3SCy Schubert
2684bc52338SCy Schubert if (ifmsh->mconf->security != MESH_CONF_SEC_NONE &&
2694bc52338SCy Schubert wpas_mesh_init_rsn(wpa_s)) {
2704bc52338SCy Schubert wpa_printf(MSG_ERROR,
2714bc52338SCy Schubert "mesh: RSN initialization failed - deinit mesh");
272c1d255d3SCy Schubert wpa_supplicant_mesh_deinit(wpa_s, false);
2734bc52338SCy Schubert return -1;
2744bc52338SCy Schubert }
2754bc52338SCy Schubert
2764bc52338SCy Schubert if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
2774bc52338SCy Schubert wpa_s->pairwise_cipher = wpa_s->mesh_rsn->pairwise_cipher;
2784bc52338SCy Schubert wpa_s->group_cipher = wpa_s->mesh_rsn->group_cipher;
2794bc52338SCy Schubert wpa_s->mgmt_group_cipher = wpa_s->mesh_rsn->mgmt_group_cipher;
2804bc52338SCy Schubert }
2814bc52338SCy Schubert
2824bc52338SCy Schubert params->ies = ifmsh->mconf->rsn_ie;
2834bc52338SCy Schubert params->ie_len = ifmsh->mconf->rsn_ie_len;
2844bc52338SCy Schubert params->basic_rates = ifmsh->basic_rates;
2854bc52338SCy Schubert params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_HT_OP_MODE;
2864bc52338SCy Schubert params->conf.ht_opmode = ifmsh->bss[0]->iface->ht_op_mode;
2874bc52338SCy Schubert
2884bc52338SCy Schubert wpa_msg(wpa_s, MSG_INFO, "joining mesh %s",
2894bc52338SCy Schubert wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
2904bc52338SCy Schubert ret = wpa_drv_join_mesh(wpa_s, params);
2914bc52338SCy Schubert if (ret)
2924bc52338SCy Schubert wpa_msg(wpa_s, MSG_ERROR, "mesh join error=%d", ret);
2934bc52338SCy Schubert
2944bc52338SCy Schubert /* hostapd sets the interface down until we associate */
2954bc52338SCy Schubert wpa_drv_set_operstate(wpa_s, 1);
2964bc52338SCy Schubert
297c1d255d3SCy Schubert if (!ret) {
2984bc52338SCy Schubert wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
2994bc52338SCy Schubert
300c1d255d3SCy Schubert wpa_msg(wpa_s, MSG_INFO, MESH_GROUP_STARTED "ssid=\"%s\" id=%d",
301c1d255d3SCy Schubert wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
302c1d255d3SCy Schubert ssid->id);
303c1d255d3SCy Schubert wpas_notify_mesh_group_started(wpa_s, ssid);
304c1d255d3SCy Schubert }
305c1d255d3SCy Schubert
3064bc52338SCy Schubert return ret;
3074bc52338SCy Schubert }
3084bc52338SCy Schubert
3094bc52338SCy Schubert
wpas_mesh_complete_cb(void * arg)310c1d255d3SCy Schubert static void wpas_mesh_complete_cb(void *arg)
311c1d255d3SCy Schubert {
312c1d255d3SCy Schubert struct wpa_supplicant *wpa_s = arg;
313c1d255d3SCy Schubert
314c1d255d3SCy Schubert wpas_mesh_complete(wpa_s);
315c1d255d3SCy Schubert }
316c1d255d3SCy Schubert
317c1d255d3SCy Schubert
wpa_supplicant_mesh_enable_iface_cb(struct hostapd_iface * ifmsh)318c1d255d3SCy Schubert static int wpa_supplicant_mesh_enable_iface_cb(struct hostapd_iface *ifmsh)
319c1d255d3SCy Schubert {
320c1d255d3SCy Schubert struct wpa_supplicant *wpa_s = ifmsh->owner;
321c1d255d3SCy Schubert struct hostapd_data *bss;
322c1d255d3SCy Schubert
323c1d255d3SCy Schubert ifmsh->mconf = mesh_config_create(wpa_s, wpa_s->current_ssid);
324c1d255d3SCy Schubert
325c1d255d3SCy Schubert bss = ifmsh->bss[0];
326c1d255d3SCy Schubert bss->msg_ctx = wpa_s;
327c1d255d3SCy Schubert os_memcpy(bss->own_addr, wpa_s->own_addr, ETH_ALEN);
328c1d255d3SCy Schubert bss->driver = wpa_s->driver;
329c1d255d3SCy Schubert bss->drv_priv = wpa_s->drv_priv;
330c1d255d3SCy Schubert bss->iface = ifmsh;
331c1d255d3SCy Schubert bss->mesh_sta_free_cb = mesh_mpm_free_sta;
332c1d255d3SCy Schubert bss->setup_complete_cb = wpas_mesh_complete_cb;
333c1d255d3SCy Schubert bss->setup_complete_cb_ctx = wpa_s;
334c1d255d3SCy Schubert
335c1d255d3SCy Schubert bss->conf->start_disabled = 1;
336c1d255d3SCy Schubert bss->conf->mesh = MESH_ENABLED;
337c1d255d3SCy Schubert bss->conf->ap_max_inactivity = wpa_s->conf->mesh_max_inactivity;
338c1d255d3SCy Schubert
339c1d255d3SCy Schubert if (wpa_drv_init_mesh(wpa_s)) {
340c1d255d3SCy Schubert wpa_msg(wpa_s, MSG_ERROR, "Failed to init mesh in driver");
341c1d255d3SCy Schubert return -1;
342c1d255d3SCy Schubert }
343c1d255d3SCy Schubert
344c1d255d3SCy Schubert if (hostapd_setup_interface(ifmsh)) {
345c1d255d3SCy Schubert wpa_printf(MSG_ERROR,
346c1d255d3SCy Schubert "Failed to initialize hostapd interface for mesh");
347c1d255d3SCy Schubert return -1;
348c1d255d3SCy Schubert }
349c1d255d3SCy Schubert
350c1d255d3SCy Schubert return 0;
351c1d255d3SCy Schubert }
352c1d255d3SCy Schubert
353c1d255d3SCy Schubert
wpa_supplicant_mesh_disable_iface_cb(struct hostapd_iface * ifmsh)354c1d255d3SCy Schubert static int wpa_supplicant_mesh_disable_iface_cb(struct hostapd_iface *ifmsh)
355c1d255d3SCy Schubert {
356c1d255d3SCy Schubert struct wpa_supplicant *wpa_s = ifmsh->owner;
357c1d255d3SCy Schubert size_t j;
358c1d255d3SCy Schubert
359c1d255d3SCy Schubert wpa_supplicant_mesh_deinit(wpa_s, false);
360c1d255d3SCy Schubert
361c1d255d3SCy Schubert #ifdef NEED_AP_MLME
362c1d255d3SCy Schubert for (j = 0; j < ifmsh->num_bss; j++)
363c1d255d3SCy Schubert hostapd_cleanup_cs_params(ifmsh->bss[j]);
364c1d255d3SCy Schubert #endif /* NEED_AP_MLME */
365c1d255d3SCy Schubert
366c1d255d3SCy Schubert /* Same as hostapd_interface_deinit() without deinitializing control
367c1d255d3SCy Schubert * interface */
368c1d255d3SCy Schubert for (j = 0; j < ifmsh->num_bss; j++) {
369c1d255d3SCy Schubert struct hostapd_data *hapd = ifmsh->bss[j];
370c1d255d3SCy Schubert
371c1d255d3SCy Schubert hostapd_bss_deinit_no_free(hapd);
372c1d255d3SCy Schubert hostapd_free_hapd_data(hapd);
373c1d255d3SCy Schubert }
374c1d255d3SCy Schubert
375c1d255d3SCy Schubert hostapd_cleanup_iface_partial(ifmsh);
376c1d255d3SCy Schubert
377c1d255d3SCy Schubert return 0;
378c1d255d3SCy Schubert }
379c1d255d3SCy Schubert
380c1d255d3SCy Schubert
wpa_supplicant_mesh_init(struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid,struct hostapd_freq_params * freq)3815b9c547cSRui Paulo static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
38285732ac8SCy Schubert struct wpa_ssid *ssid,
38385732ac8SCy Schubert struct hostapd_freq_params *freq)
3845b9c547cSRui Paulo {
3855b9c547cSRui Paulo struct hostapd_iface *ifmsh;
3865b9c547cSRui Paulo struct hostapd_data *bss;
3875b9c547cSRui Paulo struct hostapd_config *conf;
3885b9c547cSRui Paulo struct mesh_conf *mconf;
3895b9c547cSRui Paulo int basic_rates_erp[] = { 10, 20, 55, 60, 110, 120, 240, -1 };
3905b9c547cSRui Paulo int rate_len;
39185732ac8SCy Schubert int frequency;
3925b9c547cSRui Paulo
3935b9c547cSRui Paulo if (!wpa_s->conf->user_mpm) {
3945b9c547cSRui Paulo /* not much for us to do here */
3955b9c547cSRui Paulo wpa_msg(wpa_s, MSG_WARNING,
3965b9c547cSRui Paulo "user_mpm is not enabled in configuration");
3975b9c547cSRui Paulo return 0;
3985b9c547cSRui Paulo }
3995b9c547cSRui Paulo
40085732ac8SCy Schubert wpa_s->ifmsh = ifmsh = hostapd_alloc_iface();
4015b9c547cSRui Paulo if (!ifmsh)
4025b9c547cSRui Paulo return -ENOMEM;
4035b9c547cSRui Paulo
404c1d255d3SCy Schubert ifmsh->owner = wpa_s;
4055b9c547cSRui Paulo ifmsh->drv_flags = wpa_s->drv_flags;
406c1d255d3SCy Schubert ifmsh->drv_flags2 = wpa_s->drv_flags2;
4075b9c547cSRui Paulo ifmsh->num_bss = 1;
408c1d255d3SCy Schubert ifmsh->enable_iface_cb = wpa_supplicant_mesh_enable_iface_cb;
409c1d255d3SCy Schubert ifmsh->disable_iface_cb = wpa_supplicant_mesh_disable_iface_cb;
4105b9c547cSRui Paulo ifmsh->bss = os_calloc(wpa_s->ifmsh->num_bss,
4115b9c547cSRui Paulo sizeof(struct hostapd_data *));
4125b9c547cSRui Paulo if (!ifmsh->bss)
4135b9c547cSRui Paulo goto out_free;
4145b9c547cSRui Paulo
41585732ac8SCy Schubert ifmsh->bss[0] = bss = hostapd_alloc_bss_data(NULL, NULL, NULL);
4165b9c547cSRui Paulo if (!bss)
4175b9c547cSRui Paulo goto out_free;
4185b9c547cSRui Paulo
41985732ac8SCy Schubert ifmsh->bss[0]->msg_ctx = wpa_s;
4205b9c547cSRui Paulo os_memcpy(bss->own_addr, wpa_s->own_addr, ETH_ALEN);
4215b9c547cSRui Paulo bss->driver = wpa_s->driver;
4225b9c547cSRui Paulo bss->drv_priv = wpa_s->drv_priv;
4235b9c547cSRui Paulo bss->iface = ifmsh;
4245b9c547cSRui Paulo bss->mesh_sta_free_cb = mesh_mpm_free_sta;
425c1d255d3SCy Schubert bss->setup_complete_cb = wpas_mesh_complete_cb;
426c1d255d3SCy Schubert bss->setup_complete_cb_ctx = wpa_s;
42785732ac8SCy Schubert frequency = ssid->frequency;
42885732ac8SCy Schubert if (frequency != freq->freq &&
42985732ac8SCy Schubert frequency == freq->freq + freq->sec_channel_offset * 20) {
43085732ac8SCy Schubert wpa_printf(MSG_DEBUG, "mesh: pri/sec channels switched");
43185732ac8SCy Schubert frequency = freq->freq;
432c1d255d3SCy Schubert ssid->frequency = frequency;
43385732ac8SCy Schubert }
43485732ac8SCy Schubert wpa_s->assoc_freq = frequency;
4355b9c547cSRui Paulo wpa_s->current_ssid = ssid;
4365b9c547cSRui Paulo
4375b9c547cSRui Paulo /* setup an AP config for auth processing */
4385b9c547cSRui Paulo conf = hostapd_config_defaults();
4395b9c547cSRui Paulo if (!conf)
4405b9c547cSRui Paulo goto out_free;
4415b9c547cSRui Paulo
4424b72b91aSCy Schubert if (is_6ghz_freq(freq->freq)) {
4434b72b91aSCy Schubert /*
4444b72b91aSCy Schubert * IEEE Std 802.11ax-2021, 12.12.2:
4454b72b91aSCy Schubert * The STA shall use management frame protection (MFPR=1) when
4464b72b91aSCy Schubert * using RSN.
4474b72b91aSCy Schubert */
4484b72b91aSCy Schubert ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED;
4494b72b91aSCy Schubert
4504b72b91aSCy Schubert /* Set mandatory op_class parameter for setting up BSS */
4514b72b91aSCy Schubert switch (freq->bandwidth) {
4524b72b91aSCy Schubert case 20:
4534b72b91aSCy Schubert if (freq->freq == 5935)
4544b72b91aSCy Schubert conf->op_class = 136;
4554b72b91aSCy Schubert else
4564b72b91aSCy Schubert conf->op_class = 131;
4574b72b91aSCy Schubert break;
4584b72b91aSCy Schubert case 40:
4594b72b91aSCy Schubert conf->op_class = 132;
4604b72b91aSCy Schubert break;
4614b72b91aSCy Schubert case 80:
4624b72b91aSCy Schubert conf->op_class = 133;
4634b72b91aSCy Schubert break;
4644b72b91aSCy Schubert case 160:
4654b72b91aSCy Schubert conf->op_class = 134;
4664b72b91aSCy Schubert break;
4674b72b91aSCy Schubert default:
4684b72b91aSCy Schubert conf->op_class = 131;
4694b72b91aSCy Schubert break;
4704b72b91aSCy Schubert }
4714b72b91aSCy Schubert }
4724b72b91aSCy Schubert
4735b9c547cSRui Paulo bss->conf = *conf->bss;
4745b9c547cSRui Paulo bss->conf->start_disabled = 1;
4755b9c547cSRui Paulo bss->conf->mesh = MESH_ENABLED;
4765b9c547cSRui Paulo bss->conf->ap_max_inactivity = wpa_s->conf->mesh_max_inactivity;
47732a95656SCy Schubert bss->conf->mesh_fwding = wpa_s->conf->mesh_fwding;
4784bc52338SCy Schubert
4794bc52338SCy Schubert if (ieee80211_is_dfs(ssid->frequency, wpa_s->hw.modes,
4804bc52338SCy Schubert wpa_s->hw.num_modes) && wpa_s->conf->country[0]) {
4814bc52338SCy Schubert conf->ieee80211h = 1;
4824bc52338SCy Schubert conf->ieee80211d = 1;
4834bc52338SCy Schubert conf->country[0] = wpa_s->conf->country[0];
4844bc52338SCy Schubert conf->country[1] = wpa_s->conf->country[1];
4854bc52338SCy Schubert conf->country[2] = ' ';
486c1d255d3SCy Schubert wpa_s->mesh_params->handle_dfs = true;
4874bc52338SCy Schubert }
4884bc52338SCy Schubert
4895b9c547cSRui Paulo bss->iconf = conf;
4905b9c547cSRui Paulo ifmsh->conf = conf;
4915b9c547cSRui Paulo
4925b9c547cSRui Paulo ifmsh->bss[0]->max_plinks = wpa_s->conf->max_peer_links;
493325151a3SRui Paulo ifmsh->bss[0]->dot11RSNASAERetransPeriod =
494325151a3SRui Paulo wpa_s->conf->dot11RSNASAERetransPeriod;
4955b9c547cSRui Paulo os_strlcpy(bss->conf->iface, wpa_s->ifname, sizeof(bss->conf->iface));
4965b9c547cSRui Paulo
497780fb4a2SCy Schubert mconf = mesh_config_create(wpa_s, ssid);
4985b9c547cSRui Paulo if (!mconf)
4995b9c547cSRui Paulo goto out_free;
5005b9c547cSRui Paulo ifmsh->mconf = mconf;
5015b9c547cSRui Paulo
5025b9c547cSRui Paulo /* need conf->hw_mode for supported rates. */
50385732ac8SCy Schubert conf->hw_mode = ieee80211_freq_to_chan(frequency, &conf->channel);
5045b9c547cSRui Paulo if (conf->hw_mode == NUM_HOSTAPD_MODES) {
5055b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Unsupported mesh mode frequency: %d MHz",
50685732ac8SCy Schubert frequency);
5075b9c547cSRui Paulo goto out_free;
5085b9c547cSRui Paulo }
5095b9c547cSRui Paulo
5105b9c547cSRui Paulo if (ssid->mesh_basic_rates == NULL) {
5115b9c547cSRui Paulo /*
5125b9c547cSRui Paulo * XXX: Hack! This is so an MPM which correctly sets the ERP
5135b9c547cSRui Paulo * mandatory rates as BSSBasicRateSet doesn't reject us. We
5145b9c547cSRui Paulo * could add a new hw_mode HOSTAPD_MODE_IEEE80211G_ERP, but
5155b9c547cSRui Paulo * this is way easier. This also makes our BSSBasicRateSet
5165b9c547cSRui Paulo * advertised in beacons match the one in peering frames, sigh.
5175b9c547cSRui Paulo */
5185b9c547cSRui Paulo if (conf->hw_mode == HOSTAPD_MODE_IEEE80211G) {
51985732ac8SCy Schubert conf->basic_rates = os_memdup(basic_rates_erp,
52085732ac8SCy Schubert sizeof(basic_rates_erp));
5215b9c547cSRui Paulo if (!conf->basic_rates)
5225b9c547cSRui Paulo goto out_free;
5235b9c547cSRui Paulo }
5245b9c547cSRui Paulo } else {
5255b9c547cSRui Paulo rate_len = 0;
5265b9c547cSRui Paulo while (1) {
5275b9c547cSRui Paulo if (ssid->mesh_basic_rates[rate_len] < 1)
5285b9c547cSRui Paulo break;
5295b9c547cSRui Paulo rate_len++;
5305b9c547cSRui Paulo }
5315b9c547cSRui Paulo conf->basic_rates = os_calloc(rate_len + 1, sizeof(int));
5325b9c547cSRui Paulo if (conf->basic_rates == NULL)
5335b9c547cSRui Paulo goto out_free;
5345b9c547cSRui Paulo os_memcpy(conf->basic_rates, ssid->mesh_basic_rates,
5355b9c547cSRui Paulo rate_len * sizeof(int));
5365b9c547cSRui Paulo conf->basic_rates[rate_len] = -1;
5375b9c547cSRui Paulo }
5385b9c547cSRui Paulo
539c1d255d3SCy Schubert /* While it can enhance performance to switch the primary channel, which
540c1d255d3SCy Schubert * is also the secondary channel of another network at the same time),
541c1d255d3SCy Schubert * to the other primary channel, problems exist with this in mesh
542c1d255d3SCy Schubert * networks.
543c1d255d3SCy Schubert *
544c1d255d3SCy Schubert * Example with problems:
545c1d255d3SCy Schubert * - 3 mesh nodes M1-M3, freq (5200, 5180)
546c1d255d3SCy Schubert * - other node O1, e.g. AP mode, freq (5180, 5200),
547c1d255d3SCy Schubert * Locations: O1 M1 M2 M3
548c1d255d3SCy Schubert *
549c1d255d3SCy Schubert * M3 can only send frames to M1 over M2, no direct connection is
550c1d255d3SCy Schubert * possible
551c1d255d3SCy Schubert * Start O1, M1 and M3 first, M1 or O1 will switch channels to align
552c1d255d3SCy Schubert * with* each other. M3 does not swap, because M1 or O1 cannot be
553c1d255d3SCy Schubert * reached. M2 is started afterwards and can either connect to M3 or M1
554c1d255d3SCy Schubert * because of this primary secondary channel switch.
555c1d255d3SCy Schubert *
556c1d255d3SCy Schubert * Solutions: (1) central coordination -> not always possible
557c1d255d3SCy Schubert * (2) disable pri/sec channel switch in mesh networks
558c1d255d3SCy Schubert *
559c1d255d3SCy Schubert * In AP mode, when all nodes can work independently, this poses of
560c1d255d3SCy Schubert * course no problem, therefore disable it only in mesh mode. */
561c1d255d3SCy Schubert conf->no_pri_sec_switch = 1;
562c1d255d3SCy Schubert wpa_supplicant_conf_ap_ht(wpa_s, ssid, conf);
563c1d255d3SCy Schubert
5645b9c547cSRui Paulo if (wpa_drv_init_mesh(wpa_s)) {
5655b9c547cSRui Paulo wpa_msg(wpa_s, MSG_ERROR, "Failed to init mesh in driver");
5665b9c547cSRui Paulo return -1;
5675b9c547cSRui Paulo }
5685b9c547cSRui Paulo
5694bc52338SCy Schubert if (hostapd_setup_interface(ifmsh)) {
5705b9c547cSRui Paulo wpa_printf(MSG_ERROR,
5714bc52338SCy Schubert "Failed to initialize hostapd interface for mesh");
5724bc52338SCy Schubert return -1;
5735b9c547cSRui Paulo }
5745b9c547cSRui Paulo
5755b9c547cSRui Paulo return 0;
5765b9c547cSRui Paulo out_free:
577c1d255d3SCy Schubert wpa_supplicant_mesh_deinit(wpa_s, true);
5785b9c547cSRui Paulo return -ENOMEM;
5795b9c547cSRui Paulo }
5805b9c547cSRui Paulo
5815b9c547cSRui Paulo
wpa_mesh_notify_peer(struct wpa_supplicant * wpa_s,const u8 * addr,const u8 * ies,size_t ie_len)5825b9c547cSRui Paulo void wpa_mesh_notify_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
5835b9c547cSRui Paulo const u8 *ies, size_t ie_len)
5845b9c547cSRui Paulo {
5855b9c547cSRui Paulo struct ieee802_11_elems elems;
5865b9c547cSRui Paulo
5875b9c547cSRui Paulo wpa_msg(wpa_s, MSG_INFO,
5885b9c547cSRui Paulo "new peer notification for " MACSTR, MAC2STR(addr));
5895b9c547cSRui Paulo
5905b9c547cSRui Paulo if (ieee802_11_parse_elems(ies, ie_len, &elems, 0) == ParseFailed) {
5915b9c547cSRui Paulo wpa_msg(wpa_s, MSG_INFO, "Could not parse beacon from " MACSTR,
5925b9c547cSRui Paulo MAC2STR(addr));
5935b9c547cSRui Paulo return;
5945b9c547cSRui Paulo }
5955b9c547cSRui Paulo wpa_mesh_new_mesh_peer(wpa_s, addr, &elems);
5965b9c547cSRui Paulo }
5975b9c547cSRui Paulo
5985b9c547cSRui Paulo
wpa_supplicant_mesh_add_scan_ie(struct wpa_supplicant * wpa_s,struct wpabuf ** extra_ie)5995b9c547cSRui Paulo void wpa_supplicant_mesh_add_scan_ie(struct wpa_supplicant *wpa_s,
6005b9c547cSRui Paulo struct wpabuf **extra_ie)
6015b9c547cSRui Paulo {
6025b9c547cSRui Paulo /* EID + 0-length (wildcard) mesh-id */
6035b9c547cSRui Paulo size_t ielen = 2;
6045b9c547cSRui Paulo
6055b9c547cSRui Paulo if (wpabuf_resize(extra_ie, ielen) == 0) {
6065b9c547cSRui Paulo wpabuf_put_u8(*extra_ie, WLAN_EID_MESH_ID);
6075b9c547cSRui Paulo wpabuf_put_u8(*extra_ie, 0);
6085b9c547cSRui Paulo }
6095b9c547cSRui Paulo }
6105b9c547cSRui Paulo
6115b9c547cSRui Paulo
wpa_supplicant_join_mesh(struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid)6125b9c547cSRui Paulo int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s,
6135b9c547cSRui Paulo struct wpa_ssid *ssid)
6145b9c547cSRui Paulo {
6154bc52338SCy Schubert struct wpa_driver_mesh_join_params *params = os_zalloc(sizeof(*params));
6165b9c547cSRui Paulo int ret = 0;
6175b9c547cSRui Paulo
6184bc52338SCy Schubert if (!ssid || !ssid->ssid || !ssid->ssid_len || !ssid->frequency ||
6194bc52338SCy Schubert !params) {
6205b9c547cSRui Paulo ret = -ENOENT;
6214bc52338SCy Schubert os_free(params);
6225b9c547cSRui Paulo goto out;
6235b9c547cSRui Paulo }
6245b9c547cSRui Paulo
625c1d255d3SCy Schubert wpa_supplicant_mesh_deinit(wpa_s, true);
6265b9c547cSRui Paulo
627780fb4a2SCy Schubert wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
628780fb4a2SCy Schubert wpa_s->group_cipher = WPA_CIPHER_NONE;
629780fb4a2SCy Schubert wpa_s->mgmt_group_cipher = 0;
630780fb4a2SCy Schubert
6314bc52338SCy Schubert params->meshid = ssid->ssid;
6324bc52338SCy Schubert params->meshid_len = ssid->ssid_len;
6334bc52338SCy Schubert ibss_mesh_setup_freq(wpa_s, ssid, ¶ms->freq);
6344bc52338SCy Schubert wpa_s->mesh_ht_enabled = !!params->freq.ht_enabled;
6354bc52338SCy Schubert wpa_s->mesh_vht_enabled = !!params->freq.vht_enabled;
636206b73d0SCy Schubert wpa_s->mesh_he_enabled = !!params->freq.he_enabled;
637*a90b9d01SCy Schubert wpa_s->mesh_eht_enabled = !!params->freq.eht_enabled;
6384bc52338SCy Schubert if (params->freq.ht_enabled && params->freq.sec_channel_offset)
6394bc52338SCy Schubert ssid->ht40 = params->freq.sec_channel_offset;
6404bc52338SCy Schubert
641780fb4a2SCy Schubert if (wpa_s->mesh_vht_enabled) {
642780fb4a2SCy Schubert ssid->vht = 1;
6434bc52338SCy Schubert ssid->vht_center_freq1 = params->freq.center_freq1;
6444bc52338SCy Schubert switch (params->freq.bandwidth) {
645780fb4a2SCy Schubert case 80:
6464bc52338SCy Schubert if (params->freq.center_freq2) {
647*a90b9d01SCy Schubert ssid->max_oper_chwidth =
648*a90b9d01SCy Schubert CONF_OPER_CHWIDTH_80P80MHZ;
649780fb4a2SCy Schubert ssid->vht_center_freq2 =
6504bc52338SCy Schubert params->freq.center_freq2;
651780fb4a2SCy Schubert } else {
652*a90b9d01SCy Schubert ssid->max_oper_chwidth =
653*a90b9d01SCy Schubert CONF_OPER_CHWIDTH_80MHZ;
654780fb4a2SCy Schubert }
655780fb4a2SCy Schubert break;
656780fb4a2SCy Schubert case 160:
657*a90b9d01SCy Schubert ssid->max_oper_chwidth = CONF_OPER_CHWIDTH_160MHZ;
658780fb4a2SCy Schubert break;
659780fb4a2SCy Schubert default:
660*a90b9d01SCy Schubert ssid->max_oper_chwidth = CONF_OPER_CHWIDTH_USE_HT;
661780fb4a2SCy Schubert break;
662780fb4a2SCy Schubert }
663780fb4a2SCy Schubert }
664206b73d0SCy Schubert if (wpa_s->mesh_he_enabled)
665206b73d0SCy Schubert ssid->he = 1;
666*a90b9d01SCy Schubert if (wpa_s->mesh_eht_enabled)
667*a90b9d01SCy Schubert ssid->eht = 1;
6685b9c547cSRui Paulo if (ssid->beacon_int > 0)
6694bc52338SCy Schubert params->beacon_int = ssid->beacon_int;
6705b9c547cSRui Paulo else if (wpa_s->conf->beacon_int > 0)
6714bc52338SCy Schubert params->beacon_int = wpa_s->conf->beacon_int;
672780fb4a2SCy Schubert if (ssid->dtim_period > 0)
6734bc52338SCy Schubert params->dtim_period = ssid->dtim_period;
674780fb4a2SCy Schubert else if (wpa_s->conf->dtim_period > 0)
6754bc52338SCy Schubert params->dtim_period = wpa_s->conf->dtim_period;
6764bc52338SCy Schubert params->conf.max_peer_links = wpa_s->conf->max_peer_links;
67785732ac8SCy Schubert if (ssid->mesh_rssi_threshold < DEFAULT_MESH_RSSI_THRESHOLD) {
6784bc52338SCy Schubert params->conf.rssi_threshold = ssid->mesh_rssi_threshold;
6794bc52338SCy Schubert params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_RSSI_THRESHOLD;
68085732ac8SCy Schubert }
6815b9c547cSRui Paulo
6825b9c547cSRui Paulo if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
6834bc52338SCy Schubert params->flags |= WPA_DRIVER_MESH_FLAG_SAE_AUTH;
6844bc52338SCy Schubert params->flags |= WPA_DRIVER_MESH_FLAG_AMPE;
6855b9c547cSRui Paulo wpa_s->conf->user_mpm = 1;
6865b9c547cSRui Paulo }
6875b9c547cSRui Paulo
6885b9c547cSRui Paulo if (wpa_s->conf->user_mpm) {
6894bc52338SCy Schubert params->flags |= WPA_DRIVER_MESH_FLAG_USER_MPM;
6904bc52338SCy Schubert params->conf.auto_plinks = 0;
6915b9c547cSRui Paulo } else {
6924bc52338SCy Schubert params->flags |= WPA_DRIVER_MESH_FLAG_DRIVER_MPM;
6934bc52338SCy Schubert params->conf.auto_plinks = 1;
6945b9c547cSRui Paulo }
6954bc52338SCy Schubert params->conf.peer_link_timeout = wpa_s->conf->mesh_max_inactivity;
6965b9c547cSRui Paulo
69732a95656SCy Schubert /* Always explicitely set forwarding to on or off for now */
69832a95656SCy Schubert params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_FORWARDING;
69932a95656SCy Schubert params->conf.forwarding = ssid->mesh_fwding;
70032a95656SCy Schubert
7014bc52338SCy Schubert os_free(wpa_s->mesh_params);
7024bc52338SCy Schubert wpa_s->mesh_params = params;
7034bc52338SCy Schubert if (wpa_supplicant_mesh_init(wpa_s, ssid, ¶ms->freq)) {
7045b9c547cSRui Paulo wpa_msg(wpa_s, MSG_ERROR, "Failed to init mesh");
705c1d255d3SCy Schubert wpa_supplicant_leave_mesh(wpa_s, true);
7065b9c547cSRui Paulo ret = -1;
7075b9c547cSRui Paulo goto out;
7085b9c547cSRui Paulo }
7095b9c547cSRui Paulo
7105b9c547cSRui Paulo out:
7115b9c547cSRui Paulo return ret;
7125b9c547cSRui Paulo }
7135b9c547cSRui Paulo
7145b9c547cSRui Paulo
wpa_supplicant_leave_mesh(struct wpa_supplicant * wpa_s,bool need_deinit)715c1d255d3SCy Schubert int wpa_supplicant_leave_mesh(struct wpa_supplicant *wpa_s, bool need_deinit)
7165b9c547cSRui Paulo {
7175b9c547cSRui Paulo int ret = 0;
7185b9c547cSRui Paulo
7195b9c547cSRui Paulo wpa_msg(wpa_s, MSG_INFO, "leaving mesh");
7205b9c547cSRui Paulo
7215b9c547cSRui Paulo /* Need to send peering close messages first */
722c1d255d3SCy Schubert if (need_deinit)
723c1d255d3SCy Schubert wpa_supplicant_mesh_deinit(wpa_s, true);
7245b9c547cSRui Paulo
7255b9c547cSRui Paulo ret = wpa_drv_leave_mesh(wpa_s);
7265b9c547cSRui Paulo if (ret)
7275b9c547cSRui Paulo wpa_msg(wpa_s, MSG_ERROR, "mesh leave error=%d", ret);
7285b9c547cSRui Paulo
7295b9c547cSRui Paulo wpa_drv_set_operstate(wpa_s, 1);
7305b9c547cSRui Paulo
7315b9c547cSRui Paulo return ret;
7325b9c547cSRui Paulo }
7335b9c547cSRui Paulo
7345b9c547cSRui Paulo
mesh_attr_text(const u8 * ies,size_t ies_len,char * buf,char * end)7355b9c547cSRui Paulo static int mesh_attr_text(const u8 *ies, size_t ies_len, char *buf, char *end)
7365b9c547cSRui Paulo {
7375b9c547cSRui Paulo struct ieee802_11_elems elems;
7385b9c547cSRui Paulo char *mesh_id, *pos = buf;
7395b9c547cSRui Paulo u8 *bss_basic_rate_set;
7405b9c547cSRui Paulo int bss_basic_rate_set_len, ret, i;
7415b9c547cSRui Paulo
7425b9c547cSRui Paulo if (ieee802_11_parse_elems(ies, ies_len, &elems, 0) == ParseFailed)
7435b9c547cSRui Paulo return -1;
7445b9c547cSRui Paulo
7455b9c547cSRui Paulo if (elems.mesh_id_len < 1)
7465b9c547cSRui Paulo return 0;
7475b9c547cSRui Paulo
7485b9c547cSRui Paulo mesh_id = os_malloc(elems.mesh_id_len + 1);
7495b9c547cSRui Paulo if (mesh_id == NULL)
7505b9c547cSRui Paulo return -1;
7515b9c547cSRui Paulo
7525b9c547cSRui Paulo os_memcpy(mesh_id, elems.mesh_id, elems.mesh_id_len);
7535b9c547cSRui Paulo mesh_id[elems.mesh_id_len] = '\0';
7545b9c547cSRui Paulo ret = os_snprintf(pos, end - pos, "mesh_id=%s\n", mesh_id);
7555b9c547cSRui Paulo os_free(mesh_id);
7565b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret))
7575b9c547cSRui Paulo return pos - buf;
7585b9c547cSRui Paulo pos += ret;
7595b9c547cSRui Paulo
7605b9c547cSRui Paulo if (elems.mesh_config_len > 6) {
7615b9c547cSRui Paulo ret = os_snprintf(pos, end - pos,
7625b9c547cSRui Paulo "active_path_selection_protocol_id=0x%02x\n"
7635b9c547cSRui Paulo "active_path_selection_metric_id=0x%02x\n"
7645b9c547cSRui Paulo "congestion_control_mode_id=0x%02x\n"
7655b9c547cSRui Paulo "synchronization_method_id=0x%02x\n"
7665b9c547cSRui Paulo "authentication_protocol_id=0x%02x\n"
7675b9c547cSRui Paulo "mesh_formation_info=0x%02x\n"
7685b9c547cSRui Paulo "mesh_capability=0x%02x\n",
7695b9c547cSRui Paulo elems.mesh_config[0], elems.mesh_config[1],
7705b9c547cSRui Paulo elems.mesh_config[2], elems.mesh_config[3],
7715b9c547cSRui Paulo elems.mesh_config[4], elems.mesh_config[5],
7725b9c547cSRui Paulo elems.mesh_config[6]);
7735b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret))
7745b9c547cSRui Paulo return pos - buf;
7755b9c547cSRui Paulo pos += ret;
7765b9c547cSRui Paulo }
7775b9c547cSRui Paulo
7785b9c547cSRui Paulo bss_basic_rate_set = os_malloc(elems.supp_rates_len +
7795b9c547cSRui Paulo elems.ext_supp_rates_len);
7805b9c547cSRui Paulo if (bss_basic_rate_set == NULL)
7815b9c547cSRui Paulo return -1;
7825b9c547cSRui Paulo
7835b9c547cSRui Paulo bss_basic_rate_set_len = 0;
7845b9c547cSRui Paulo for (i = 0; i < elems.supp_rates_len; i++) {
7855b9c547cSRui Paulo if (elems.supp_rates[i] & 0x80) {
7865b9c547cSRui Paulo bss_basic_rate_set[bss_basic_rate_set_len++] =
7875b9c547cSRui Paulo (elems.supp_rates[i] & 0x7f) * 5;
7885b9c547cSRui Paulo }
7895b9c547cSRui Paulo }
7905b9c547cSRui Paulo for (i = 0; i < elems.ext_supp_rates_len; i++) {
7915b9c547cSRui Paulo if (elems.ext_supp_rates[i] & 0x80) {
7925b9c547cSRui Paulo bss_basic_rate_set[bss_basic_rate_set_len++] =
7935b9c547cSRui Paulo (elems.ext_supp_rates[i] & 0x7f) * 5;
7945b9c547cSRui Paulo }
7955b9c547cSRui Paulo }
7965b9c547cSRui Paulo if (bss_basic_rate_set_len > 0) {
7975b9c547cSRui Paulo ret = os_snprintf(pos, end - pos, "bss_basic_rate_set=%d",
7985b9c547cSRui Paulo bss_basic_rate_set[0]);
7995b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret))
800325151a3SRui Paulo goto fail;
8015b9c547cSRui Paulo pos += ret;
8025b9c547cSRui Paulo
8035b9c547cSRui Paulo for (i = 1; i < bss_basic_rate_set_len; i++) {
8045b9c547cSRui Paulo ret = os_snprintf(pos, end - pos, " %d",
8055b9c547cSRui Paulo bss_basic_rate_set[i]);
8065b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret))
807325151a3SRui Paulo goto fail;
8085b9c547cSRui Paulo pos += ret;
8095b9c547cSRui Paulo }
8105b9c547cSRui Paulo
8115b9c547cSRui Paulo ret = os_snprintf(pos, end - pos, "\n");
8125b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret))
813325151a3SRui Paulo goto fail;
8145b9c547cSRui Paulo pos += ret;
8155b9c547cSRui Paulo }
816325151a3SRui Paulo fail:
8175b9c547cSRui Paulo os_free(bss_basic_rate_set);
8185b9c547cSRui Paulo
8195b9c547cSRui Paulo return pos - buf;
8205b9c547cSRui Paulo }
8215b9c547cSRui Paulo
8225b9c547cSRui Paulo
wpas_mesh_scan_result_text(const u8 * ies,size_t ies_len,char * buf,char * end)8235b9c547cSRui Paulo int wpas_mesh_scan_result_text(const u8 *ies, size_t ies_len, char *buf,
8245b9c547cSRui Paulo char *end)
8255b9c547cSRui Paulo {
8265b9c547cSRui Paulo return mesh_attr_text(ies, ies_len, buf, end);
8275b9c547cSRui Paulo }
8285b9c547cSRui Paulo
8295b9c547cSRui Paulo
wpas_mesh_get_ifname(struct wpa_supplicant * wpa_s,char * ifname,size_t len)8305b9c547cSRui Paulo static int wpas_mesh_get_ifname(struct wpa_supplicant *wpa_s, char *ifname,
8315b9c547cSRui Paulo size_t len)
8325b9c547cSRui Paulo {
8335b9c547cSRui Paulo char *ifname_ptr = wpa_s->ifname;
8345b9c547cSRui Paulo int res;
8355b9c547cSRui Paulo
8365b9c547cSRui Paulo res = os_snprintf(ifname, len, "mesh-%s-%d", ifname_ptr,
8375b9c547cSRui Paulo wpa_s->mesh_if_idx);
8385b9c547cSRui Paulo if (os_snprintf_error(len, res) ||
8395b9c547cSRui Paulo (os_strlen(ifname) >= IFNAMSIZ &&
8405b9c547cSRui Paulo os_strlen(wpa_s->ifname) < IFNAMSIZ)) {
8415b9c547cSRui Paulo /* Try to avoid going over the IFNAMSIZ length limit */
8425b9c547cSRui Paulo res = os_snprintf(ifname, len, "mesh-%d", wpa_s->mesh_if_idx);
8435b9c547cSRui Paulo if (os_snprintf_error(len, res))
8445b9c547cSRui Paulo return -1;
8455b9c547cSRui Paulo }
8465b9c547cSRui Paulo wpa_s->mesh_if_idx++;
8475b9c547cSRui Paulo return 0;
8485b9c547cSRui Paulo }
8495b9c547cSRui Paulo
8505b9c547cSRui Paulo
wpas_mesh_add_interface(struct wpa_supplicant * wpa_s,char * ifname,size_t len)8515b9c547cSRui Paulo int wpas_mesh_add_interface(struct wpa_supplicant *wpa_s, char *ifname,
8525b9c547cSRui Paulo size_t len)
8535b9c547cSRui Paulo {
8545b9c547cSRui Paulo struct wpa_interface iface;
8555b9c547cSRui Paulo struct wpa_supplicant *mesh_wpa_s;
8565b9c547cSRui Paulo u8 addr[ETH_ALEN];
8575b9c547cSRui Paulo
8585b9c547cSRui Paulo if (ifname[0] == '\0' && wpas_mesh_get_ifname(wpa_s, ifname, len) < 0)
8595b9c547cSRui Paulo return -1;
8605b9c547cSRui Paulo
8615b9c547cSRui Paulo if (wpa_drv_if_add(wpa_s, WPA_IF_MESH, ifname, NULL, NULL, NULL, addr,
8625b9c547cSRui Paulo NULL) < 0) {
8635b9c547cSRui Paulo wpa_printf(MSG_ERROR,
8645b9c547cSRui Paulo "mesh: Failed to create new mesh interface");
8655b9c547cSRui Paulo return -1;
8665b9c547cSRui Paulo }
8675b9c547cSRui Paulo wpa_printf(MSG_INFO, "mesh: Created virtual interface %s addr "
8685b9c547cSRui Paulo MACSTR, ifname, MAC2STR(addr));
8695b9c547cSRui Paulo
8705b9c547cSRui Paulo os_memset(&iface, 0, sizeof(iface));
8715b9c547cSRui Paulo iface.ifname = ifname;
8725b9c547cSRui Paulo iface.driver = wpa_s->driver->name;
8735b9c547cSRui Paulo iface.driver_param = wpa_s->conf->driver_param;
8745b9c547cSRui Paulo iface.ctrl_interface = wpa_s->conf->ctrl_interface;
8755b9c547cSRui Paulo
8765b9c547cSRui Paulo mesh_wpa_s = wpa_supplicant_add_iface(wpa_s->global, &iface, wpa_s);
8775b9c547cSRui Paulo if (!mesh_wpa_s) {
8785b9c547cSRui Paulo wpa_printf(MSG_ERROR,
8795b9c547cSRui Paulo "mesh: Failed to create new wpa_supplicant interface");
880780fb4a2SCy Schubert wpa_drv_if_remove(wpa_s, WPA_IF_MESH, ifname);
8815b9c547cSRui Paulo return -1;
8825b9c547cSRui Paulo }
8835b9c547cSRui Paulo mesh_wpa_s->mesh_if_created = 1;
8845b9c547cSRui Paulo return 0;
8855b9c547cSRui Paulo }
886780fb4a2SCy Schubert
887780fb4a2SCy Schubert
wpas_mesh_peer_remove(struct wpa_supplicant * wpa_s,const u8 * addr)888780fb4a2SCy Schubert int wpas_mesh_peer_remove(struct wpa_supplicant *wpa_s, const u8 *addr)
889780fb4a2SCy Schubert {
890780fb4a2SCy Schubert return mesh_mpm_close_peer(wpa_s, addr);
891780fb4a2SCy Schubert }
892780fb4a2SCy Schubert
893780fb4a2SCy Schubert
wpas_mesh_peer_add(struct wpa_supplicant * wpa_s,const u8 * addr,int duration)894780fb4a2SCy Schubert int wpas_mesh_peer_add(struct wpa_supplicant *wpa_s, const u8 *addr,
895780fb4a2SCy Schubert int duration)
896780fb4a2SCy Schubert {
897780fb4a2SCy Schubert return mesh_mpm_connect_peer(wpa_s, addr, duration);
898780fb4a2SCy Schubert }
899