Line data Source code
1 : /*
2 : * WPA Supplicant - Basic mesh mode routines
3 : * Copyright (c) 2013-2014, cozybit, Inc. All rights reserved.
4 : *
5 : * This software may be distributed under the terms of the BSD license.
6 : * See README for more details.
7 : */
8 :
9 : #include "utils/includes.h"
10 :
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"
20 : #include "config.h"
21 : #include "wpa_supplicant_i.h"
22 : #include "driver_i.h"
23 : #include "notify.h"
24 : #include "ap.h"
25 : #include "mesh_mpm.h"
26 : #include "mesh_rsn.h"
27 : #include "mesh.h"
28 :
29 :
30 379 : static void wpa_supplicant_mesh_deinit(struct wpa_supplicant *wpa_s)
31 : {
32 379 : wpa_supplicant_mesh_iface_deinit(wpa_s, wpa_s->ifmsh);
33 379 : wpa_s->ifmsh = NULL;
34 379 : wpa_s->current_ssid = NULL;
35 379 : os_free(wpa_s->mesh_rsn);
36 379 : wpa_s->mesh_rsn = NULL;
37 : /* TODO: leave mesh (stop beacon). This will happen on link down
38 : * anyway, so it's not urgent */
39 379 : }
40 :
41 :
42 379 : void wpa_supplicant_mesh_iface_deinit(struct wpa_supplicant *wpa_s,
43 : struct hostapd_iface *ifmsh)
44 : {
45 379 : if (!ifmsh)
46 569 : return;
47 :
48 189 : if (ifmsh->mconf) {
49 179 : mesh_mpm_deinit(wpa_s, ifmsh);
50 179 : if (ifmsh->mconf->rsn_ie) {
51 66 : 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.
57 : */
58 : }
59 179 : os_free(ifmsh->mconf);
60 179 : ifmsh->mconf = NULL;
61 : }
62 :
63 : /* take care of shared data */
64 189 : hostapd_interface_deinit(ifmsh);
65 189 : hostapd_interface_free(ifmsh);
66 : }
67 :
68 :
69 183 : static struct mesh_conf * mesh_config_create(struct wpa_supplicant *wpa_s,
70 : struct wpa_ssid *ssid)
71 : {
72 : struct mesh_conf *conf;
73 : int cipher;
74 :
75 183 : conf = os_zalloc(sizeof(struct mesh_conf));
76 183 : if (!conf)
77 2 : return NULL;
78 :
79 181 : os_memcpy(conf->meshid, ssid->ssid, ssid->ssid_len);
80 181 : conf->meshid_len = ssid->ssid_len;
81 :
82 181 : if (ssid->key_mgmt & WPA_KEY_MGMT_SAE)
83 73 : conf->security |= MESH_CONF_SEC_AUTH |
84 : MESH_CONF_SEC_AMPE;
85 : else
86 108 : conf->security |= MESH_CONF_SEC_NONE;
87 181 : conf->ieee80211w = ssid->ieee80211w;
88 181 : if (conf->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT) {
89 177 : if (wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_BIP)
90 177 : conf->ieee80211w = wpa_s->conf->pmf;
91 : else
92 0 : conf->ieee80211w = NO_MGMT_FRAME_PROTECTION;
93 : }
94 :
95 181 : cipher = wpa_pick_pairwise_cipher(ssid->pairwise_cipher, 0);
96 181 : if (cipher < 0 || cipher == WPA_CIPHER_TKIP) {
97 1 : wpa_msg(wpa_s, MSG_INFO, "mesh: Invalid pairwise cipher");
98 1 : os_free(conf);
99 1 : return NULL;
100 : }
101 180 : conf->pairwise_cipher = cipher;
102 :
103 180 : cipher = wpa_pick_group_cipher(ssid->group_cipher);
104 180 : if (cipher < 0 || cipher == WPA_CIPHER_TKIP ||
105 : cipher == WPA_CIPHER_GTK_NOT_USED) {
106 1 : wpa_msg(wpa_s, MSG_INFO, "mesh: Invalid group cipher");
107 1 : os_free(conf);
108 1 : return NULL;
109 : }
110 :
111 179 : conf->group_cipher = cipher;
112 179 : if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION)
113 4 : conf->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
114 :
115 : /* defaults */
116 179 : conf->mesh_pp_id = MESH_PATH_PROTOCOL_HWMP;
117 179 : conf->mesh_pm_id = MESH_PATH_METRIC_AIRTIME;
118 179 : conf->mesh_cc_id = 0;
119 179 : conf->mesh_sp_id = MESH_SYNC_METHOD_NEIGHBOR_OFFSET;
120 179 : conf->mesh_auth_id = (conf->security & MESH_CONF_SEC_AUTH) ? 1 : 0;
121 179 : conf->dot11MeshMaxRetries = ssid->dot11MeshMaxRetries;
122 179 : conf->dot11MeshRetryTimeout = ssid->dot11MeshRetryTimeout;
123 179 : conf->dot11MeshConfirmTimeout = ssid->dot11MeshConfirmTimeout;
124 179 : conf->dot11MeshHoldingTimeout = ssid->dot11MeshHoldingTimeout;
125 :
126 179 : return conf;
127 : }
128 :
129 :
130 9 : static void wpas_mesh_copy_groups(struct hostapd_data *bss,
131 : struct wpa_supplicant *wpa_s)
132 : {
133 : int num_groups;
134 : size_t groups_size;
135 :
136 31 : for (num_groups = 0; wpa_s->conf->sae_groups[num_groups] > 0;
137 13 : num_groups++)
138 : ;
139 :
140 9 : groups_size = (num_groups + 1) * sizeof(wpa_s->conf->sae_groups[0]);
141 9 : bss->conf->sae_groups = os_malloc(groups_size);
142 9 : if (bss->conf->sae_groups)
143 9 : os_memcpy(bss->conf->sae_groups, wpa_s->conf->sae_groups,
144 : groups_size);
145 9 : }
146 :
147 :
148 190 : static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
149 : struct wpa_ssid *ssid)
150 : {
151 : struct hostapd_iface *ifmsh;
152 : struct hostapd_data *bss;
153 : struct hostapd_config *conf;
154 : struct mesh_conf *mconf;
155 190 : int basic_rates_erp[] = { 10, 20, 55, 60, 110, 120, 240, -1 };
156 : static int default_groups[] = { 19, 20, 21, 25, 26, -1 };
157 : size_t len;
158 : int rate_len;
159 :
160 190 : if (!wpa_s->conf->user_mpm) {
161 : /* not much for us to do here */
162 0 : wpa_msg(wpa_s, MSG_WARNING,
163 : "user_mpm is not enabled in configuration");
164 0 : return 0;
165 : }
166 :
167 190 : wpa_s->ifmsh = ifmsh = os_zalloc(sizeof(*wpa_s->ifmsh));
168 190 : if (!ifmsh)
169 1 : return -ENOMEM;
170 :
171 189 : ifmsh->drv_flags = wpa_s->drv_flags;
172 189 : ifmsh->num_bss = 1;
173 189 : ifmsh->bss = os_calloc(wpa_s->ifmsh->num_bss,
174 : sizeof(struct hostapd_data *));
175 189 : if (!ifmsh->bss)
176 1 : goto out_free;
177 :
178 188 : ifmsh->bss[0] = bss = os_zalloc(sizeof(struct hostapd_data));
179 188 : if (!bss)
180 1 : goto out_free;
181 187 : dl_list_init(&bss->nr_db);
182 :
183 187 : os_memcpy(bss->own_addr, wpa_s->own_addr, ETH_ALEN);
184 187 : bss->driver = wpa_s->driver;
185 187 : bss->drv_priv = wpa_s->drv_priv;
186 187 : bss->iface = ifmsh;
187 187 : bss->mesh_sta_free_cb = mesh_mpm_free_sta;
188 187 : wpa_s->assoc_freq = ssid->frequency;
189 187 : wpa_s->current_ssid = ssid;
190 :
191 : /* setup an AP config for auth processing */
192 187 : conf = hostapd_config_defaults();
193 187 : if (!conf)
194 4 : goto out_free;
195 :
196 183 : bss->conf = *conf->bss;
197 183 : bss->conf->start_disabled = 1;
198 183 : bss->conf->mesh = MESH_ENABLED;
199 183 : bss->conf->ap_max_inactivity = wpa_s->conf->mesh_max_inactivity;
200 183 : bss->iconf = conf;
201 183 : ifmsh->conf = conf;
202 :
203 183 : ifmsh->bss[0]->max_plinks = wpa_s->conf->max_peer_links;
204 366 : ifmsh->bss[0]->dot11RSNASAERetransPeriod =
205 183 : wpa_s->conf->dot11RSNASAERetransPeriod;
206 183 : os_strlcpy(bss->conf->iface, wpa_s->ifname, sizeof(bss->conf->iface));
207 :
208 183 : mconf = mesh_config_create(wpa_s, ssid);
209 183 : if (!mconf)
210 4 : goto out_free;
211 179 : ifmsh->mconf = mconf;
212 :
213 : /* need conf->hw_mode for supported rates. */
214 179 : conf->hw_mode = ieee80211_freq_to_chan(ssid->frequency, &conf->channel);
215 179 : if (conf->hw_mode == NUM_HOSTAPD_MODES) {
216 1 : wpa_printf(MSG_ERROR, "Unsupported mesh mode frequency: %d MHz",
217 : ssid->frequency);
218 1 : goto out_free;
219 : }
220 178 : if (ssid->ht40)
221 6 : conf->secondary_channel = ssid->ht40;
222 178 : if (conf->hw_mode == HOSTAPD_MODE_IEEE80211A && ssid->vht) {
223 6 : conf->vht_oper_chwidth = ssid->max_oper_chwidth;
224 6 : switch (conf->vht_oper_chwidth) {
225 : case VHT_CHANWIDTH_80MHZ:
226 : case VHT_CHANWIDTH_80P80MHZ:
227 4 : ieee80211_freq_to_chan(
228 : ssid->frequency,
229 : &conf->vht_oper_centr_freq_seg0_idx);
230 4 : conf->vht_oper_centr_freq_seg0_idx += ssid->ht40 * 2;
231 4 : break;
232 : case VHT_CHANWIDTH_160MHZ:
233 2 : ieee80211_freq_to_chan(
234 : ssid->frequency,
235 : &conf->vht_oper_centr_freq_seg0_idx);
236 2 : conf->vht_oper_centr_freq_seg0_idx += ssid->ht40 * 2;
237 2 : conf->vht_oper_centr_freq_seg0_idx += 40 / 5;
238 2 : break;
239 : }
240 6 : ieee80211_freq_to_chan(ssid->vht_center_freq2,
241 : &conf->vht_oper_centr_freq_seg1_idx);
242 : }
243 :
244 178 : if (ssid->mesh_basic_rates == NULL) {
245 : /*
246 : * XXX: Hack! This is so an MPM which correctly sets the ERP
247 : * mandatory rates as BSSBasicRateSet doesn't reject us. We
248 : * could add a new hw_mode HOSTAPD_MODE_IEEE80211G_ERP, but
249 : * this is way easier. This also makes our BSSBasicRateSet
250 : * advertised in beacons match the one in peering frames, sigh.
251 : */
252 175 : if (conf->hw_mode == HOSTAPD_MODE_IEEE80211G) {
253 169 : conf->basic_rates = os_malloc(sizeof(basic_rates_erp));
254 169 : if (!conf->basic_rates)
255 1 : goto out_free;
256 168 : os_memcpy(conf->basic_rates, basic_rates_erp,
257 : sizeof(basic_rates_erp));
258 : }
259 : } else {
260 3 : rate_len = 0;
261 : while (1) {
262 12 : if (ssid->mesh_basic_rates[rate_len] < 1)
263 3 : break;
264 9 : rate_len++;
265 9 : }
266 3 : conf->basic_rates = os_calloc(rate_len + 1, sizeof(int));
267 3 : if (conf->basic_rates == NULL)
268 1 : goto out_free;
269 2 : os_memcpy(conf->basic_rates, ssid->mesh_basic_rates,
270 : rate_len * sizeof(int));
271 2 : conf->basic_rates[rate_len] = -1;
272 : }
273 :
274 176 : if (hostapd_setup_interface(ifmsh)) {
275 2 : wpa_printf(MSG_ERROR,
276 : "Failed to initialize hostapd interface for mesh");
277 2 : return -1;
278 : }
279 :
280 174 : if (wpa_drv_init_mesh(wpa_s)) {
281 1 : wpa_msg(wpa_s, MSG_ERROR, "Failed to init mesh in driver");
282 1 : return -1;
283 : }
284 :
285 173 : if (mconf->security != MESH_CONF_SEC_NONE) {
286 71 : if (ssid->passphrase == NULL) {
287 1 : wpa_printf(MSG_ERROR,
288 : "mesh: Passphrase for SAE not configured");
289 1 : goto out_free;
290 : }
291 :
292 70 : bss->conf->wpa = ssid->proto;
293 70 : bss->conf->wpa_key_mgmt = ssid->key_mgmt;
294 :
295 139 : if (wpa_s->conf->sae_groups &&
296 69 : wpa_s->conf->sae_groups[0] > 0) {
297 9 : wpas_mesh_copy_groups(bss, wpa_s);
298 : } else {
299 122 : bss->conf->sae_groups =
300 61 : os_malloc(sizeof(default_groups));
301 61 : if (!bss->conf->sae_groups)
302 1 : goto out_free;
303 60 : os_memcpy(bss->conf->sae_groups, default_groups,
304 : sizeof(default_groups));
305 : }
306 :
307 69 : len = os_strlen(ssid->passphrase);
308 138 : bss->conf->ssid.wpa_passphrase =
309 69 : dup_binstr(ssid->passphrase, len);
310 :
311 69 : wpa_s->mesh_rsn = mesh_rsn_auth_init(wpa_s, mconf);
312 69 : if (!wpa_s->mesh_rsn)
313 3 : goto out_free;
314 : }
315 :
316 168 : wpa_supplicant_conf_ap_ht(wpa_s, ssid, conf);
317 :
318 168 : return 0;
319 : out_free:
320 18 : wpa_supplicant_mesh_deinit(wpa_s);
321 18 : return -ENOMEM;
322 : }
323 :
324 :
325 150 : void wpa_mesh_notify_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
326 : const u8 *ies, size_t ie_len)
327 : {
328 : struct ieee802_11_elems elems;
329 :
330 900 : wpa_msg(wpa_s, MSG_INFO,
331 900 : "new peer notification for " MACSTR, MAC2STR(addr));
332 :
333 150 : if (ieee802_11_parse_elems(ies, ie_len, &elems, 0) == ParseFailed) {
334 0 : wpa_msg(wpa_s, MSG_INFO, "Could not parse beacon from " MACSTR,
335 0 : MAC2STR(addr));
336 150 : return;
337 : }
338 150 : wpa_mesh_new_mesh_peer(wpa_s, addr, &elems);
339 : }
340 :
341 :
342 4564 : void wpa_supplicant_mesh_add_scan_ie(struct wpa_supplicant *wpa_s,
343 : struct wpabuf **extra_ie)
344 : {
345 : /* EID + 0-length (wildcard) mesh-id */
346 4564 : size_t ielen = 2;
347 :
348 4564 : if (wpabuf_resize(extra_ie, ielen) == 0) {
349 4564 : wpabuf_put_u8(*extra_ie, WLAN_EID_MESH_ID);
350 4564 : wpabuf_put_u8(*extra_ie, 0);
351 : }
352 4564 : }
353 :
354 :
355 191 : int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s,
356 : struct wpa_ssid *ssid)
357 : {
358 : struct wpa_driver_mesh_join_params params;
359 191 : int ret = 0;
360 :
361 191 : if (!ssid || !ssid->ssid || !ssid->ssid_len || !ssid->frequency) {
362 1 : ret = -ENOENT;
363 1 : goto out;
364 : }
365 :
366 190 : wpa_supplicant_mesh_deinit(wpa_s);
367 :
368 190 : wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
369 190 : wpa_s->group_cipher = WPA_CIPHER_NONE;
370 190 : wpa_s->mgmt_group_cipher = 0;
371 :
372 190 : os_memset(¶ms, 0, sizeof(params));
373 190 : params.meshid = ssid->ssid;
374 190 : params.meshid_len = ssid->ssid_len;
375 190 : ibss_mesh_setup_freq(wpa_s, ssid, ¶ms.freq);
376 190 : wpa_s->mesh_ht_enabled = !!params.freq.ht_enabled;
377 190 : wpa_s->mesh_vht_enabled = !!params.freq.vht_enabled;
378 190 : if (params.freq.ht_enabled && params.freq.sec_channel_offset)
379 6 : ssid->ht40 = params.freq.sec_channel_offset;
380 190 : if (wpa_s->mesh_vht_enabled) {
381 6 : ssid->vht = 1;
382 6 : switch (params.freq.bandwidth) {
383 : case 80:
384 4 : if (params.freq.center_freq2) {
385 2 : ssid->max_oper_chwidth = VHT_CHANWIDTH_80P80MHZ;
386 2 : ssid->vht_center_freq2 =
387 2 : params.freq.center_freq2;
388 : } else {
389 2 : ssid->max_oper_chwidth = VHT_CHANWIDTH_80MHZ;
390 : }
391 4 : break;
392 : case 160:
393 2 : ssid->max_oper_chwidth = VHT_CHANWIDTH_160MHZ;
394 2 : break;
395 : default:
396 0 : ssid->max_oper_chwidth = VHT_CHANWIDTH_USE_HT;
397 0 : break;
398 : }
399 : }
400 190 : if (ssid->beacon_int > 0)
401 6 : params.beacon_int = ssid->beacon_int;
402 184 : else if (wpa_s->conf->beacon_int > 0)
403 1 : params.beacon_int = wpa_s->conf->beacon_int;
404 190 : if (ssid->dtim_period > 0)
405 0 : params.dtim_period = ssid->dtim_period;
406 190 : else if (wpa_s->conf->dtim_period > 0)
407 0 : params.dtim_period = wpa_s->conf->dtim_period;
408 190 : params.conf.max_peer_links = wpa_s->conf->max_peer_links;
409 :
410 190 : if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
411 73 : params.flags |= WPA_DRIVER_MESH_FLAG_SAE_AUTH;
412 73 : params.flags |= WPA_DRIVER_MESH_FLAG_AMPE;
413 73 : wpa_s->conf->user_mpm = 1;
414 : }
415 :
416 190 : if (wpa_s->conf->user_mpm) {
417 190 : params.flags |= WPA_DRIVER_MESH_FLAG_USER_MPM;
418 190 : params.conf.auto_plinks = 0;
419 : } else {
420 0 : params.flags |= WPA_DRIVER_MESH_FLAG_DRIVER_MPM;
421 0 : params.conf.auto_plinks = 1;
422 : }
423 190 : params.conf.peer_link_timeout = wpa_s->conf->mesh_max_inactivity;
424 :
425 190 : if (wpa_supplicant_mesh_init(wpa_s, ssid)) {
426 22 : wpa_msg(wpa_s, MSG_ERROR, "Failed to init mesh");
427 22 : wpa_drv_leave_mesh(wpa_s);
428 22 : ret = -1;
429 22 : goto out;
430 : }
431 :
432 168 : if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
433 66 : wpa_s->pairwise_cipher = wpa_s->mesh_rsn->pairwise_cipher;
434 66 : wpa_s->group_cipher = wpa_s->mesh_rsn->group_cipher;
435 66 : wpa_s->mgmt_group_cipher = wpa_s->mesh_rsn->mgmt_group_cipher;
436 : }
437 :
438 168 : if (wpa_s->ifmsh) {
439 168 : params.ies = wpa_s->ifmsh->mconf->rsn_ie;
440 168 : params.ie_len = wpa_s->ifmsh->mconf->rsn_ie_len;
441 168 : params.basic_rates = wpa_s->ifmsh->basic_rates;
442 168 : params.conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_HT_OP_MODE;
443 168 : params.conf.ht_opmode = wpa_s->ifmsh->bss[0]->iface->ht_op_mode;
444 : }
445 :
446 336 : wpa_msg(wpa_s, MSG_INFO, "joining mesh %s",
447 168 : wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
448 168 : ret = wpa_drv_join_mesh(wpa_s, ¶ms);
449 168 : if (ret)
450 1 : wpa_msg(wpa_s, MSG_ERROR, "mesh join error=%d", ret);
451 :
452 : /* hostapd sets the interface down until we associate */
453 168 : wpa_drv_set_operstate(wpa_s, 1);
454 :
455 168 : if (!ret)
456 167 : wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
457 :
458 : out:
459 191 : return ret;
460 : }
461 :
462 :
463 171 : int wpa_supplicant_leave_mesh(struct wpa_supplicant *wpa_s)
464 : {
465 171 : int ret = 0;
466 :
467 171 : wpa_msg(wpa_s, MSG_INFO, "leaving mesh");
468 :
469 : /* Need to send peering close messages first */
470 171 : wpa_supplicant_mesh_deinit(wpa_s);
471 :
472 171 : ret = wpa_drv_leave_mesh(wpa_s);
473 171 : if (ret)
474 4 : wpa_msg(wpa_s, MSG_ERROR, "mesh leave error=%d", ret);
475 :
476 171 : wpa_drv_set_operstate(wpa_s, 1);
477 :
478 171 : return ret;
479 : }
480 :
481 :
482 2342 : static int mesh_attr_text(const u8 *ies, size_t ies_len, char *buf, char *end)
483 : {
484 : struct ieee802_11_elems elems;
485 2342 : char *mesh_id, *pos = buf;
486 : u8 *bss_basic_rate_set;
487 : int bss_basic_rate_set_len, ret, i;
488 :
489 2342 : if (ieee802_11_parse_elems(ies, ies_len, &elems, 0) == ParseFailed)
490 1 : return -1;
491 :
492 2341 : if (elems.mesh_id_len < 1)
493 2337 : return 0;
494 :
495 4 : mesh_id = os_malloc(elems.mesh_id_len + 1);
496 4 : if (mesh_id == NULL)
497 1 : return -1;
498 :
499 3 : os_memcpy(mesh_id, elems.mesh_id, elems.mesh_id_len);
500 3 : mesh_id[elems.mesh_id_len] = '\0';
501 3 : ret = os_snprintf(pos, end - pos, "mesh_id=%s\n", mesh_id);
502 3 : os_free(mesh_id);
503 3 : if (os_snprintf_error(end - pos, ret))
504 0 : return pos - buf;
505 3 : pos += ret;
506 :
507 3 : if (elems.mesh_config_len > 6) {
508 21 : ret = os_snprintf(pos, end - pos,
509 : "active_path_selection_protocol_id=0x%02x\n"
510 : "active_path_selection_metric_id=0x%02x\n"
511 : "congestion_control_mode_id=0x%02x\n"
512 : "synchronization_method_id=0x%02x\n"
513 : "authentication_protocol_id=0x%02x\n"
514 : "mesh_formation_info=0x%02x\n"
515 : "mesh_capability=0x%02x\n",
516 6 : elems.mesh_config[0], elems.mesh_config[1],
517 6 : elems.mesh_config[2], elems.mesh_config[3],
518 6 : elems.mesh_config[4], elems.mesh_config[5],
519 3 : elems.mesh_config[6]);
520 3 : if (os_snprintf_error(end - pos, ret))
521 0 : return pos - buf;
522 3 : pos += ret;
523 : }
524 :
525 6 : bss_basic_rate_set = os_malloc(elems.supp_rates_len +
526 3 : elems.ext_supp_rates_len);
527 3 : if (bss_basic_rate_set == NULL)
528 1 : return -1;
529 :
530 2 : bss_basic_rate_set_len = 0;
531 18 : for (i = 0; i < elems.supp_rates_len; i++) {
532 16 : if (elems.supp_rates[i] & 0x80) {
533 24 : bss_basic_rate_set[bss_basic_rate_set_len++] =
534 12 : (elems.supp_rates[i] & 0x7f) * 5;
535 : }
536 : }
537 10 : for (i = 0; i < elems.ext_supp_rates_len; i++) {
538 8 : if (elems.ext_supp_rates[i] & 0x80) {
539 4 : bss_basic_rate_set[bss_basic_rate_set_len++] =
540 2 : (elems.ext_supp_rates[i] & 0x7f) * 5;
541 : }
542 : }
543 2 : if (bss_basic_rate_set_len > 0) {
544 2 : ret = os_snprintf(pos, end - pos, "bss_basic_rate_set=%d",
545 2 : bss_basic_rate_set[0]);
546 2 : if (os_snprintf_error(end - pos, ret))
547 0 : goto fail;
548 2 : pos += ret;
549 :
550 14 : for (i = 1; i < bss_basic_rate_set_len; i++) {
551 12 : ret = os_snprintf(pos, end - pos, " %d",
552 12 : bss_basic_rate_set[i]);
553 12 : if (os_snprintf_error(end - pos, ret))
554 0 : goto fail;
555 12 : pos += ret;
556 : }
557 :
558 2 : ret = os_snprintf(pos, end - pos, "\n");
559 2 : if (os_snprintf_error(end - pos, ret))
560 0 : goto fail;
561 2 : pos += ret;
562 : }
563 : fail:
564 2 : os_free(bss_basic_rate_set);
565 :
566 2 : return pos - buf;
567 : }
568 :
569 :
570 2342 : int wpas_mesh_scan_result_text(const u8 *ies, size_t ies_len, char *buf,
571 : char *end)
572 : {
573 2342 : return mesh_attr_text(ies, ies_len, buf, end);
574 : }
575 :
576 :
577 5 : static int wpas_mesh_get_ifname(struct wpa_supplicant *wpa_s, char *ifname,
578 : size_t len)
579 : {
580 5 : char *ifname_ptr = wpa_s->ifname;
581 : int res;
582 :
583 5 : res = os_snprintf(ifname, len, "mesh-%s-%d", ifname_ptr,
584 : wpa_s->mesh_if_idx);
585 10 : if (os_snprintf_error(len, res) ||
586 5 : (os_strlen(ifname) >= IFNAMSIZ &&
587 0 : os_strlen(wpa_s->ifname) < IFNAMSIZ)) {
588 : /* Try to avoid going over the IFNAMSIZ length limit */
589 0 : res = os_snprintf(ifname, len, "mesh-%d", wpa_s->mesh_if_idx);
590 0 : if (os_snprintf_error(len, res))
591 0 : return -1;
592 : }
593 5 : wpa_s->mesh_if_idx++;
594 5 : return 0;
595 : }
596 :
597 :
598 7 : int wpas_mesh_add_interface(struct wpa_supplicant *wpa_s, char *ifname,
599 : size_t len)
600 : {
601 : struct wpa_interface iface;
602 : struct wpa_supplicant *mesh_wpa_s;
603 : u8 addr[ETH_ALEN];
604 :
605 7 : if (ifname[0] == '\0' && wpas_mesh_get_ifname(wpa_s, ifname, len) < 0)
606 0 : return -1;
607 :
608 7 : if (wpa_drv_if_add(wpa_s, WPA_IF_MESH, ifname, NULL, NULL, NULL, addr,
609 : NULL) < 0) {
610 1 : wpa_printf(MSG_ERROR,
611 : "mesh: Failed to create new mesh interface");
612 1 : return -1;
613 : }
614 36 : wpa_printf(MSG_INFO, "mesh: Created virtual interface %s addr "
615 36 : MACSTR, ifname, MAC2STR(addr));
616 :
617 6 : os_memset(&iface, 0, sizeof(iface));
618 6 : iface.ifname = ifname;
619 6 : iface.driver = wpa_s->driver->name;
620 6 : iface.driver_param = wpa_s->conf->driver_param;
621 6 : iface.ctrl_interface = wpa_s->conf->ctrl_interface;
622 :
623 6 : mesh_wpa_s = wpa_supplicant_add_iface(wpa_s->global, &iface, wpa_s);
624 6 : if (!mesh_wpa_s) {
625 2 : wpa_printf(MSG_ERROR,
626 : "mesh: Failed to create new wpa_supplicant interface");
627 2 : wpa_drv_if_remove(wpa_s, WPA_IF_MESH, ifname);
628 2 : return -1;
629 : }
630 4 : mesh_wpa_s->mesh_if_created = 1;
631 4 : return 0;
632 : }
633 :
634 :
635 9 : int wpas_mesh_peer_remove(struct wpa_supplicant *wpa_s, const u8 *addr)
636 : {
637 9 : return mesh_mpm_close_peer(wpa_s, addr);
638 : }
639 :
640 :
641 13 : int wpas_mesh_peer_add(struct wpa_supplicant *wpa_s, const u8 *addr,
642 : int duration)
643 : {
644 13 : return mesh_mpm_connect_peer(wpa_s, addr, duration);
645 : }
|