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