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"
27 static void wpa_supplicant_mesh_deinit(struct wpa_supplicant
*wpa_s
)
29 wpa_supplicant_mesh_iface_deinit(wpa_s
, wpa_s
->ifmsh
);
31 wpa_s
->current_ssid
= NULL
;
32 /* TODO: leave mesh (stop beacon). This will happen on link down
33 * anyway, so it's not urgent */
37 void wpa_supplicant_mesh_iface_deinit(struct wpa_supplicant
*wpa_s
,
38 struct hostapd_iface
*ifmsh
)
44 if (ifmsh
->mconf
->ies
) {
45 ifmsh
->mconf
->ies
= NULL
;
46 /* We cannot free this struct
47 * because wpa_authenticator on
48 * hostapd side is also using it
49 * for now just set to NULL and
50 * let hostapd code free it.
53 os_free(ifmsh
->mconf
);
57 /* take care of shared data */
58 hostapd_interface_deinit(ifmsh
);
59 hostapd_interface_free(ifmsh
);
63 static struct mesh_conf
* mesh_config_create(struct wpa_ssid
*ssid
)
65 struct mesh_conf
*conf
;
67 conf
= os_zalloc(sizeof(struct mesh_conf
));
71 os_memcpy(conf
->meshid
, ssid
->ssid
, ssid
->ssid_len
);
72 conf
->meshid_len
= ssid
->ssid_len
;
74 if (ssid
->key_mgmt
& WPA_KEY_MGMT_SAE
)
75 conf
->security
|= MESH_CONF_SEC_AUTH
|
78 conf
->security
|= MESH_CONF_SEC_NONE
;
81 conf
->mesh_pp_id
= MESH_PATH_PROTOCOL_HWMP
;
82 conf
->mesh_pm_id
= MESH_PATH_METRIC_AIRTIME
;
84 conf
->mesh_sp_id
= MESH_SYNC_METHOD_NEIGHBOR_OFFSET
;
85 conf
->mesh_auth_id
= (conf
->security
& MESH_CONF_SEC_AUTH
) ? 1 : 0;
91 static void wpas_mesh_copy_groups(struct hostapd_data
*bss
,
92 struct wpa_supplicant
*wpa_s
)
97 for (num_groups
= 0; wpa_s
->conf
->sae_groups
[num_groups
] > 0;
101 groups_size
= (num_groups
+ 1) * sizeof(wpa_s
->conf
->sae_groups
[0]);
102 bss
->conf
->sae_groups
= os_malloc(groups_size
);
103 if (bss
->conf
->sae_groups
)
104 os_memcpy(bss
->conf
->sae_groups
, wpa_s
->conf
->sae_groups
,
109 static int wpa_supplicant_mesh_init(struct wpa_supplicant
*wpa_s
,
110 struct wpa_ssid
*ssid
)
112 struct hostapd_iface
*ifmsh
;
113 struct hostapd_data
*bss
;
114 struct hostapd_config
*conf
;
115 struct mesh_conf
*mconf
;
116 int basic_rates_erp
[] = { 10, 20, 55, 60, 110, 120, 240, -1 };
117 static int default_groups
[] = { 19, 20, 21, 25, 26, -1 };
120 wpa_s
->ifmsh
= ifmsh
= os_zalloc(sizeof(*wpa_s
->ifmsh
));
125 ifmsh
->bss
= os_calloc(wpa_s
->ifmsh
->num_bss
,
126 sizeof(struct hostapd_data
*));
130 ifmsh
->bss
[0] = bss
= os_zalloc(sizeof(struct hostapd_data
));
134 os_memcpy(bss
->own_addr
, wpa_s
->own_addr
, ETH_ALEN
);
135 bss
->driver
= wpa_s
->driver
;
136 bss
->drv_priv
= wpa_s
->drv_priv
;
138 wpa_s
->assoc_freq
= ssid
->frequency
;
139 wpa_s
->current_ssid
= ssid
;
141 /* setup an AP config for auth processing */
142 conf
= hostapd_config_defaults();
146 bss
->conf
= *conf
->bss
;
147 bss
->conf
->start_disabled
= 1;
148 bss
->conf
->mesh
= MESH_ENABLED
;
152 os_strlcpy(bss
->conf
->iface
, wpa_s
->ifname
, sizeof(bss
->conf
->iface
));
154 mconf
= mesh_config_create(ssid
);
157 ifmsh
->mconf
= mconf
;
159 /* need conf->hw_mode for supported rates. */
160 if (ssid
->frequency
== 0) {
161 conf
->hw_mode
= HOSTAPD_MODE_IEEE80211G
;
164 conf
->hw_mode
= ieee80211_freq_to_chan(ssid
->frequency
,
167 if (conf
->hw_mode
== NUM_HOSTAPD_MODES
) {
168 wpa_printf(MSG_ERROR
, "Unsupported mesh mode frequency: %d MHz",
174 * XXX: Hack! This is so an MPM which correctly sets the ERP mandatory
175 * rates as BSSBasicRateSet doesn't reject us. We could add a new
176 * hw_mode HOSTAPD_MODE_IEEE80211G_ERP, but this is way easier. This
177 * also makes our BSSBasicRateSet advertised in Beacon frames match the
178 * one in peering frames, sigh.
180 if (conf
->hw_mode
== HOSTAPD_MODE_IEEE80211G
) {
181 conf
->basic_rates
= os_malloc(sizeof(basic_rates_erp
));
182 if (!conf
->basic_rates
)
184 os_memcpy(conf
->basic_rates
, basic_rates_erp
,
185 sizeof(basic_rates_erp
));
188 if (hostapd_setup_interface(ifmsh
)) {
189 wpa_printf(MSG_ERROR
,
190 "Failed to initialize hostapd interface for mesh");
194 if (wpa_drv_init_mesh(wpa_s
)) {
195 wpa_msg(wpa_s
, MSG_ERROR
, "Failed to init mesh in driver");
199 if (mconf
->security
!= MESH_CONF_SEC_NONE
) {
200 if (ssid
->passphrase
== NULL
) {
201 wpa_printf(MSG_ERROR
,
202 "mesh: Passphrase for SAE not configured");
206 bss
->conf
->wpa
= ssid
->proto
;
207 bss
->conf
->wpa_key_mgmt
= ssid
->key_mgmt
;
209 if (wpa_s
->conf
->sae_groups
&&
210 wpa_s
->conf
->sae_groups
[0] > 0) {
211 wpas_mesh_copy_groups(bss
, wpa_s
);
213 bss
->conf
->sae_groups
=
214 os_malloc(sizeof(default_groups
));
215 if (!bss
->conf
->sae_groups
)
217 os_memcpy(bss
->conf
->sae_groups
, default_groups
,
218 sizeof(default_groups
));
221 len
= os_strlen(ssid
->passphrase
);
222 bss
->conf
->ssid
.wpa_passphrase
=
223 dup_binstr(ssid
->passphrase
, len
);
228 wpa_supplicant_mesh_deinit(wpa_s
);
233 void wpa_mesh_notify_peer(struct wpa_supplicant
*wpa_s
, const u8
*addr
,
234 const u8
*ies
, size_t ie_len
)
236 struct ieee802_11_elems elems
;
238 wpa_msg(wpa_s
, MSG_INFO
,
239 "new peer notification for " MACSTR
, MAC2STR(addr
));
241 if (ieee802_11_parse_elems(ies
, ie_len
, &elems
, 0) == ParseFailed
) {
242 wpa_msg(wpa_s
, MSG_INFO
, "Could not parse beacon from " MACSTR
,
248 int wpa_supplicant_join_mesh(struct wpa_supplicant
*wpa_s
,
249 struct wpa_ssid
*ssid
)
251 struct wpa_driver_mesh_join_params params
;
254 if (!ssid
|| !ssid
->ssid
|| !ssid
->ssid_len
|| !ssid
->frequency
) {
259 wpa_supplicant_mesh_deinit(wpa_s
);
261 os_memset(¶ms
, 0, sizeof(params
));
262 params
.meshid
= ssid
->ssid
;
263 params
.meshid_len
= ssid
->ssid_len
;
264 params
.freq
= ssid
->frequency
;
266 if (ssid
->key_mgmt
& WPA_KEY_MGMT_SAE
) {
267 params
.flags
|= WPA_DRIVER_MESH_FLAG_SAE_AUTH
;
268 params
.flags
|= WPA_DRIVER_MESH_FLAG_AMPE
;
271 params
.flags
|= WPA_DRIVER_MESH_FLAG_DRIVER_MPM
;
272 params
.conf
.flags
|= WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS
;
274 if (wpa_supplicant_mesh_init(wpa_s
, ssid
)) {
275 wpa_msg(wpa_s
, MSG_ERROR
, "Failed to init mesh");
281 params
.ies
= wpa_s
->ifmsh
->mconf
->ies
;
282 params
.ie_len
= wpa_s
->ifmsh
->mconf
->ie_len
;
283 params
.basic_rates
= wpa_s
->ifmsh
->basic_rates
;
286 wpa_msg(wpa_s
, MSG_INFO
, "joining mesh %s",
287 wpa_ssid_txt(ssid
->ssid
, ssid
->ssid_len
));
288 ret
= wpa_drv_join_mesh(wpa_s
, ¶ms
);
290 wpa_msg(wpa_s
, MSG_ERROR
, "mesh join error=%d\n", ret
);
292 /* hostapd sets the interface down until we associate */
293 wpa_drv_set_operstate(wpa_s
, 1);
300 int wpa_supplicant_leave_mesh(struct wpa_supplicant
*wpa_s
)
304 wpa_msg(wpa_s
, MSG_INFO
, "leaving mesh");
306 ret
= wpa_drv_leave_mesh(wpa_s
);
308 wpa_msg(wpa_s
, MSG_ERROR
, "mesh leave error=%d", ret
);
310 wpa_drv_set_operstate(wpa_s
, 1);
312 wpa_supplicant_mesh_deinit(wpa_s
);