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