]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/wpa/wpa_supplicant/mesh.c
Update hostapd/wpa_supplicant to 2.8 to fix multiple vulnerabilities.
[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                 return -1;
212         }
213
214         if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
215                 wpa_s->pairwise_cipher = wpa_s->mesh_rsn->pairwise_cipher;
216                 wpa_s->group_cipher = wpa_s->mesh_rsn->group_cipher;
217                 wpa_s->mgmt_group_cipher = wpa_s->mesh_rsn->mgmt_group_cipher;
218         }
219
220         params->ies = ifmsh->mconf->rsn_ie;
221         params->ie_len = ifmsh->mconf->rsn_ie_len;
222         params->basic_rates = ifmsh->basic_rates;
223         params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_HT_OP_MODE;
224         params->conf.ht_opmode = ifmsh->bss[0]->iface->ht_op_mode;
225
226         wpa_msg(wpa_s, MSG_INFO, "joining mesh %s",
227                 wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
228         ret = wpa_drv_join_mesh(wpa_s, params);
229         if (ret)
230                 wpa_msg(wpa_s, MSG_ERROR, "mesh join error=%d", ret);
231
232         /* hostapd sets the interface down until we associate */
233         wpa_drv_set_operstate(wpa_s, 1);
234
235         if (!ret)
236                 wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
237
238         return ret;
239 }
240
241
242 static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
243                                     struct wpa_ssid *ssid,
244                                     struct hostapd_freq_params *freq)
245 {
246         struct hostapd_iface *ifmsh;
247         struct hostapd_data *bss;
248         struct hostapd_config *conf;
249         struct mesh_conf *mconf;
250         int basic_rates_erp[] = { 10, 20, 55, 60, 110, 120, 240, -1 };
251         int rate_len;
252         int frequency;
253
254         if (!wpa_s->conf->user_mpm) {
255                 /* not much for us to do here */
256                 wpa_msg(wpa_s, MSG_WARNING,
257                         "user_mpm is not enabled in configuration");
258                 return 0;
259         }
260
261         wpa_s->ifmsh = ifmsh = hostapd_alloc_iface();
262         if (!ifmsh)
263                 return -ENOMEM;
264
265         ifmsh->drv_flags = wpa_s->drv_flags;
266         ifmsh->num_bss = 1;
267         ifmsh->bss = os_calloc(wpa_s->ifmsh->num_bss,
268                                sizeof(struct hostapd_data *));
269         if (!ifmsh->bss)
270                 goto out_free;
271
272         ifmsh->bss[0] = bss = hostapd_alloc_bss_data(NULL, NULL, NULL);
273         if (!bss)
274                 goto out_free;
275
276         ifmsh->bss[0]->msg_ctx = wpa_s;
277         os_memcpy(bss->own_addr, wpa_s->own_addr, ETH_ALEN);
278         bss->driver = wpa_s->driver;
279         bss->drv_priv = wpa_s->drv_priv;
280         bss->iface = ifmsh;
281         bss->mesh_sta_free_cb = mesh_mpm_free_sta;
282         frequency = ssid->frequency;
283         if (frequency != freq->freq &&
284             frequency == freq->freq + freq->sec_channel_offset * 20) {
285                 wpa_printf(MSG_DEBUG, "mesh: pri/sec channels switched");
286                 frequency = freq->freq;
287         }
288         wpa_s->assoc_freq = frequency;
289         wpa_s->current_ssid = ssid;
290
291         /* setup an AP config for auth processing */
292         conf = hostapd_config_defaults();
293         if (!conf)
294                 goto out_free;
295
296         bss->conf = *conf->bss;
297         bss->conf->start_disabled = 1;
298         bss->conf->mesh = MESH_ENABLED;
299         bss->conf->ap_max_inactivity = wpa_s->conf->mesh_max_inactivity;
300
301         if (ieee80211_is_dfs(ssid->frequency, wpa_s->hw.modes,
302                              wpa_s->hw.num_modes) && wpa_s->conf->country[0]) {
303                 conf->ieee80211h = 1;
304                 conf->ieee80211d = 1;
305                 conf->country[0] = wpa_s->conf->country[0];
306                 conf->country[1] = wpa_s->conf->country[1];
307                 conf->country[2] = ' ';
308         }
309
310         bss->iconf = conf;
311         ifmsh->conf = conf;
312
313         ifmsh->bss[0]->max_plinks = wpa_s->conf->max_peer_links;
314         ifmsh->bss[0]->dot11RSNASAERetransPeriod =
315                 wpa_s->conf->dot11RSNASAERetransPeriod;
316         os_strlcpy(bss->conf->iface, wpa_s->ifname, sizeof(bss->conf->iface));
317
318         mconf = mesh_config_create(wpa_s, ssid);
319         if (!mconf)
320                 goto out_free;
321         ifmsh->mconf = mconf;
322
323         /* need conf->hw_mode for supported rates. */
324         conf->hw_mode = ieee80211_freq_to_chan(frequency, &conf->channel);
325         if (conf->hw_mode == NUM_HOSTAPD_MODES) {
326                 wpa_printf(MSG_ERROR, "Unsupported mesh mode frequency: %d MHz",
327                            frequency);
328                 goto out_free;
329         }
330         if (ssid->ht40)
331                 conf->secondary_channel = ssid->ht40;
332         if (conf->hw_mode == HOSTAPD_MODE_IEEE80211A && ssid->vht) {
333                 if (ssid->max_oper_chwidth != DEFAULT_MAX_OPER_CHWIDTH)
334                         conf->vht_oper_chwidth = ssid->max_oper_chwidth;
335                 switch (conf->vht_oper_chwidth) {
336                 case VHT_CHANWIDTH_80MHZ:
337                 case VHT_CHANWIDTH_80P80MHZ:
338                         ieee80211_freq_to_chan(
339                                 frequency,
340                                 &conf->vht_oper_centr_freq_seg0_idx);
341                         conf->vht_oper_centr_freq_seg0_idx += ssid->ht40 * 2;
342                         break;
343                 case VHT_CHANWIDTH_160MHZ:
344                         ieee80211_freq_to_chan(
345                                 frequency,
346                                 &conf->vht_oper_centr_freq_seg0_idx);
347                         conf->vht_oper_centr_freq_seg0_idx += ssid->ht40 * 2;
348                         conf->vht_oper_centr_freq_seg0_idx += 40 / 5;
349                         break;
350                 }
351                 ieee80211_freq_to_chan(ssid->vht_center_freq2,
352                                        &conf->vht_oper_centr_freq_seg1_idx);
353         }
354
355         if (ssid->mesh_basic_rates == NULL) {
356                 /*
357                  * XXX: Hack! This is so an MPM which correctly sets the ERP
358                  * mandatory rates as BSSBasicRateSet doesn't reject us. We
359                  * could add a new hw_mode HOSTAPD_MODE_IEEE80211G_ERP, but
360                  * this is way easier. This also makes our BSSBasicRateSet
361                  * advertised in beacons match the one in peering frames, sigh.
362                  */
363                 if (conf->hw_mode == HOSTAPD_MODE_IEEE80211G) {
364                         conf->basic_rates = os_memdup(basic_rates_erp,
365                                                       sizeof(basic_rates_erp));
366                         if (!conf->basic_rates)
367                                 goto out_free;
368                 }
369         } else {
370                 rate_len = 0;
371                 while (1) {
372                         if (ssid->mesh_basic_rates[rate_len] < 1)
373                                 break;
374                         rate_len++;
375                 }
376                 conf->basic_rates = os_calloc(rate_len + 1, sizeof(int));
377                 if (conf->basic_rates == NULL)
378                         goto out_free;
379                 os_memcpy(conf->basic_rates, ssid->mesh_basic_rates,
380                           rate_len * sizeof(int));
381                 conf->basic_rates[rate_len] = -1;
382         }
383
384         if (wpa_drv_init_mesh(wpa_s)) {
385                 wpa_msg(wpa_s, MSG_ERROR, "Failed to init mesh in driver");
386                 return -1;
387         }
388
389         if (hostapd_setup_interface(ifmsh)) {
390                 wpa_printf(MSG_ERROR,
391                            "Failed to initialize hostapd interface for mesh");
392                 return -1;
393         }
394
395         wpa_supplicant_conf_ap_ht(wpa_s, ssid, conf);
396
397         return 0;
398 out_free:
399         wpa_supplicant_mesh_deinit(wpa_s);
400         return -ENOMEM;
401 }
402
403
404 void wpa_mesh_notify_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
405                           const u8 *ies, size_t ie_len)
406 {
407         struct ieee802_11_elems elems;
408
409         wpa_msg(wpa_s, MSG_INFO,
410                 "new peer notification for " MACSTR, MAC2STR(addr));
411
412         if (ieee802_11_parse_elems(ies, ie_len, &elems, 0) == ParseFailed) {
413                 wpa_msg(wpa_s, MSG_INFO, "Could not parse beacon from " MACSTR,
414                         MAC2STR(addr));
415                 return;
416         }
417         wpa_mesh_new_mesh_peer(wpa_s, addr, &elems);
418 }
419
420
421 void wpa_supplicant_mesh_add_scan_ie(struct wpa_supplicant *wpa_s,
422                                      struct wpabuf **extra_ie)
423 {
424         /* EID + 0-length (wildcard) mesh-id */
425         size_t ielen = 2;
426
427         if (wpabuf_resize(extra_ie, ielen) == 0) {
428                 wpabuf_put_u8(*extra_ie, WLAN_EID_MESH_ID);
429                 wpabuf_put_u8(*extra_ie, 0);
430         }
431 }
432
433
434 int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s,
435                              struct wpa_ssid *ssid)
436 {
437         struct wpa_driver_mesh_join_params *params = os_zalloc(sizeof(*params));
438         int ret = 0;
439
440         if (!ssid || !ssid->ssid || !ssid->ssid_len || !ssid->frequency ||
441             !params) {
442                 ret = -ENOENT;
443                 os_free(params);
444                 goto out;
445         }
446
447         wpa_supplicant_mesh_deinit(wpa_s);
448
449         wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
450         wpa_s->group_cipher = WPA_CIPHER_NONE;
451         wpa_s->mgmt_group_cipher = 0;
452
453         params->meshid = ssid->ssid;
454         params->meshid_len = ssid->ssid_len;
455         ibss_mesh_setup_freq(wpa_s, ssid, &params->freq);
456         wpa_s->mesh_ht_enabled = !!params->freq.ht_enabled;
457         wpa_s->mesh_vht_enabled = !!params->freq.vht_enabled;
458         if (params->freq.ht_enabled && params->freq.sec_channel_offset)
459                 ssid->ht40 = params->freq.sec_channel_offset;
460
461         if (wpa_s->mesh_vht_enabled) {
462                 ssid->vht = 1;
463                 ssid->vht_center_freq1 = params->freq.center_freq1;
464                 switch (params->freq.bandwidth) {
465                 case 80:
466                         if (params->freq.center_freq2) {
467                                 ssid->max_oper_chwidth = VHT_CHANWIDTH_80P80MHZ;
468                                 ssid->vht_center_freq2 =
469                                         params->freq.center_freq2;
470                         } else {
471                                 ssid->max_oper_chwidth = VHT_CHANWIDTH_80MHZ;
472                         }
473                         break;
474                 case 160:
475                         ssid->max_oper_chwidth = VHT_CHANWIDTH_160MHZ;
476                         break;
477                 default:
478                         ssid->max_oper_chwidth = VHT_CHANWIDTH_USE_HT;
479                         break;
480                 }
481         }
482         if (ssid->beacon_int > 0)
483                 params->beacon_int = ssid->beacon_int;
484         else if (wpa_s->conf->beacon_int > 0)
485                 params->beacon_int = wpa_s->conf->beacon_int;
486         if (ssid->dtim_period > 0)
487                 params->dtim_period = ssid->dtim_period;
488         else if (wpa_s->conf->dtim_period > 0)
489                 params->dtim_period = wpa_s->conf->dtim_period;
490         params->conf.max_peer_links = wpa_s->conf->max_peer_links;
491         if (ssid->mesh_rssi_threshold < DEFAULT_MESH_RSSI_THRESHOLD) {
492                 params->conf.rssi_threshold = ssid->mesh_rssi_threshold;
493                 params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_RSSI_THRESHOLD;
494         }
495
496         if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
497                 params->flags |= WPA_DRIVER_MESH_FLAG_SAE_AUTH;
498                 params->flags |= WPA_DRIVER_MESH_FLAG_AMPE;
499                 wpa_s->conf->user_mpm = 1;
500         }
501
502         if (wpa_s->conf->user_mpm) {
503                 params->flags |= WPA_DRIVER_MESH_FLAG_USER_MPM;
504                 params->conf.auto_plinks = 0;
505         } else {
506                 params->flags |= WPA_DRIVER_MESH_FLAG_DRIVER_MPM;
507                 params->conf.auto_plinks = 1;
508         }
509         params->conf.peer_link_timeout = wpa_s->conf->mesh_max_inactivity;
510
511         os_free(wpa_s->mesh_params);
512         wpa_s->mesh_params = params;
513         if (wpa_supplicant_mesh_init(wpa_s, ssid, &params->freq)) {
514                 wpa_msg(wpa_s, MSG_ERROR, "Failed to init mesh");
515                 wpa_drv_leave_mesh(wpa_s);
516                 ret = -1;
517                 goto out;
518         }
519
520         ret = wpas_mesh_complete(wpa_s);
521 out:
522         return ret;
523 }
524
525
526 int wpa_supplicant_leave_mesh(struct wpa_supplicant *wpa_s)
527 {
528         int ret = 0;
529
530         wpa_msg(wpa_s, MSG_INFO, "leaving mesh");
531
532         /* Need to send peering close messages first */
533         wpa_supplicant_mesh_deinit(wpa_s);
534
535         ret = wpa_drv_leave_mesh(wpa_s);
536         if (ret)
537                 wpa_msg(wpa_s, MSG_ERROR, "mesh leave error=%d", ret);
538
539         wpa_drv_set_operstate(wpa_s, 1);
540
541         return ret;
542 }
543
544
545 static int mesh_attr_text(const u8 *ies, size_t ies_len, char *buf, char *end)
546 {
547         struct ieee802_11_elems elems;
548         char *mesh_id, *pos = buf;
549         u8 *bss_basic_rate_set;
550         int bss_basic_rate_set_len, ret, i;
551
552         if (ieee802_11_parse_elems(ies, ies_len, &elems, 0) == ParseFailed)
553                 return -1;
554
555         if (elems.mesh_id_len < 1)
556                 return 0;
557
558         mesh_id = os_malloc(elems.mesh_id_len + 1);
559         if (mesh_id == NULL)
560                 return -1;
561
562         os_memcpy(mesh_id, elems.mesh_id, elems.mesh_id_len);
563         mesh_id[elems.mesh_id_len] = '\0';
564         ret = os_snprintf(pos, end - pos, "mesh_id=%s\n", mesh_id);
565         os_free(mesh_id);
566         if (os_snprintf_error(end - pos, ret))
567                 return pos - buf;
568         pos += ret;
569
570         if (elems.mesh_config_len > 6) {
571                 ret = os_snprintf(pos, end - pos,
572                                   "active_path_selection_protocol_id=0x%02x\n"
573                                   "active_path_selection_metric_id=0x%02x\n"
574                                   "congestion_control_mode_id=0x%02x\n"
575                                   "synchronization_method_id=0x%02x\n"
576                                   "authentication_protocol_id=0x%02x\n"
577                                   "mesh_formation_info=0x%02x\n"
578                                   "mesh_capability=0x%02x\n",
579                                   elems.mesh_config[0], elems.mesh_config[1],
580                                   elems.mesh_config[2], elems.mesh_config[3],
581                                   elems.mesh_config[4], elems.mesh_config[5],
582                                   elems.mesh_config[6]);
583                 if (os_snprintf_error(end - pos, ret))
584                         return pos - buf;
585                 pos += ret;
586         }
587
588         bss_basic_rate_set = os_malloc(elems.supp_rates_len +
589                 elems.ext_supp_rates_len);
590         if (bss_basic_rate_set == NULL)
591                 return -1;
592
593         bss_basic_rate_set_len = 0;
594         for (i = 0; i < elems.supp_rates_len; i++) {
595                 if (elems.supp_rates[i] & 0x80) {
596                         bss_basic_rate_set[bss_basic_rate_set_len++] =
597                                 (elems.supp_rates[i] & 0x7f) * 5;
598                 }
599         }
600         for (i = 0; i < elems.ext_supp_rates_len; i++) {
601                 if (elems.ext_supp_rates[i] & 0x80) {
602                         bss_basic_rate_set[bss_basic_rate_set_len++] =
603                                 (elems.ext_supp_rates[i] & 0x7f) * 5;
604                 }
605         }
606         if (bss_basic_rate_set_len > 0) {
607                 ret = os_snprintf(pos, end - pos, "bss_basic_rate_set=%d",
608                                   bss_basic_rate_set[0]);
609                 if (os_snprintf_error(end - pos, ret))
610                         goto fail;
611                 pos += ret;
612
613                 for (i = 1; i < bss_basic_rate_set_len; i++) {
614                         ret = os_snprintf(pos, end - pos, " %d",
615                                           bss_basic_rate_set[i]);
616                         if (os_snprintf_error(end - pos, ret))
617                                 goto fail;
618                         pos += ret;
619                 }
620
621                 ret = os_snprintf(pos, end - pos, "\n");
622                 if (os_snprintf_error(end - pos, ret))
623                         goto fail;
624                 pos += ret;
625         }
626 fail:
627         os_free(bss_basic_rate_set);
628
629         return pos - buf;
630 }
631
632
633 int wpas_mesh_scan_result_text(const u8 *ies, size_t ies_len, char *buf,
634                                char *end)
635 {
636         return mesh_attr_text(ies, ies_len, buf, end);
637 }
638
639
640 static int wpas_mesh_get_ifname(struct wpa_supplicant *wpa_s, char *ifname,
641                                 size_t len)
642 {
643         char *ifname_ptr = wpa_s->ifname;
644         int res;
645
646         res = os_snprintf(ifname, len, "mesh-%s-%d", ifname_ptr,
647                           wpa_s->mesh_if_idx);
648         if (os_snprintf_error(len, res) ||
649             (os_strlen(ifname) >= IFNAMSIZ &&
650              os_strlen(wpa_s->ifname) < IFNAMSIZ)) {
651                 /* Try to avoid going over the IFNAMSIZ length limit */
652                 res = os_snprintf(ifname, len, "mesh-%d", wpa_s->mesh_if_idx);
653                 if (os_snprintf_error(len, res))
654                         return -1;
655         }
656         wpa_s->mesh_if_idx++;
657         return 0;
658 }
659
660
661 int wpas_mesh_add_interface(struct wpa_supplicant *wpa_s, char *ifname,
662                             size_t len)
663 {
664         struct wpa_interface iface;
665         struct wpa_supplicant *mesh_wpa_s;
666         u8 addr[ETH_ALEN];
667
668         if (ifname[0] == '\0' && wpas_mesh_get_ifname(wpa_s, ifname, len) < 0)
669                 return -1;
670
671         if (wpa_drv_if_add(wpa_s, WPA_IF_MESH, ifname, NULL, NULL, NULL, addr,
672                            NULL) < 0) {
673                 wpa_printf(MSG_ERROR,
674                            "mesh: Failed to create new mesh interface");
675                 return -1;
676         }
677         wpa_printf(MSG_INFO, "mesh: Created virtual interface %s addr "
678                    MACSTR, ifname, MAC2STR(addr));
679
680         os_memset(&iface, 0, sizeof(iface));
681         iface.ifname = ifname;
682         iface.driver = wpa_s->driver->name;
683         iface.driver_param = wpa_s->conf->driver_param;
684         iface.ctrl_interface = wpa_s->conf->ctrl_interface;
685
686         mesh_wpa_s = wpa_supplicant_add_iface(wpa_s->global, &iface, wpa_s);
687         if (!mesh_wpa_s) {
688                 wpa_printf(MSG_ERROR,
689                            "mesh: Failed to create new wpa_supplicant interface");
690                 wpa_drv_if_remove(wpa_s, WPA_IF_MESH, ifname);
691                 return -1;
692         }
693         mesh_wpa_s->mesh_if_created = 1;
694         return 0;
695 }
696
697
698 int wpas_mesh_peer_remove(struct wpa_supplicant *wpa_s, const u8 *addr)
699 {
700         return mesh_mpm_close_peer(wpa_s, addr);
701 }
702
703
704 int wpas_mesh_peer_add(struct wpa_supplicant *wpa_s, const u8 *addr,
705                        int duration)
706 {
707         return mesh_mpm_connect_peer(wpa_s, addr, duration);
708 }