1 1.1 christos /* 2 1.1 christos * WPA Supplicant - Basic mesh mode routines 3 1.1 christos * Copyright (c) 2013-2014, cozybit, Inc. All rights reserved. 4 1.1 christos * 5 1.1 christos * This software may be distributed under the terms of the BSD license. 6 1.1 christos * See README for more details. 7 1.1 christos */ 8 1.1 christos 9 1.1 christos #include "utils/includes.h" 10 1.1 christos 11 1.1 christos #include "utils/common.h" 12 1.1 christos #include "utils/eloop.h" 13 1.1 christos #include "utils/uuid.h" 14 1.1 christos #include "common/ieee802_11_defs.h" 15 1.1 christos #include "common/wpa_ctrl.h" 16 1.1.1.5 christos #include "common/hw_features_common.h" 17 1.1 christos #include "ap/sta_info.h" 18 1.1 christos #include "ap/hostapd.h" 19 1.1 christos #include "ap/ieee802_11.h" 20 1.1 christos #include "config_ssid.h" 21 1.1 christos #include "config.h" 22 1.1 christos #include "wpa_supplicant_i.h" 23 1.1 christos #include "driver_i.h" 24 1.1 christos #include "notify.h" 25 1.1 christos #include "ap.h" 26 1.1 christos #include "mesh_mpm.h" 27 1.1 christos #include "mesh_rsn.h" 28 1.1 christos #include "mesh.h" 29 1.1 christos 30 1.1 christos 31 1.1.1.5 christos static void wpa_supplicant_mesh_deinit(struct wpa_supplicant *wpa_s, 32 1.1.1.5 christos bool also_clear_hostapd) 33 1.1 christos { 34 1.1.1.5 christos wpa_supplicant_mesh_iface_deinit(wpa_s, wpa_s->ifmsh, 35 1.1.1.5 christos also_clear_hostapd); 36 1.1.1.5 christos 37 1.1.1.5 christos if (also_clear_hostapd) { 38 1.1.1.5 christos wpa_s->ifmsh = NULL; 39 1.1.1.5 christos wpa_s->current_ssid = NULL; 40 1.1.1.5 christos os_free(wpa_s->mesh_params); 41 1.1.1.5 christos wpa_s->mesh_params = NULL; 42 1.1.1.5 christos } 43 1.1.1.5 christos 44 1.1 christos os_free(wpa_s->mesh_rsn); 45 1.1 christos wpa_s->mesh_rsn = NULL; 46 1.1.1.5 christos 47 1.1.1.5 christos if (!also_clear_hostapd) 48 1.1.1.5 christos wpa_supplicant_leave_mesh(wpa_s, false); 49 1.1 christos } 50 1.1 christos 51 1.1 christos 52 1.1 christos void wpa_supplicant_mesh_iface_deinit(struct wpa_supplicant *wpa_s, 53 1.1.1.5 christos struct hostapd_iface *ifmsh, 54 1.1.1.5 christos bool also_clear_hostapd) 55 1.1 christos { 56 1.1 christos if (!ifmsh) 57 1.1 christos return; 58 1.1 christos 59 1.1 christos if (ifmsh->mconf) { 60 1.1 christos mesh_mpm_deinit(wpa_s, ifmsh); 61 1.1.1.2 christos if (ifmsh->mconf->rsn_ie) { 62 1.1.1.2 christos ifmsh->mconf->rsn_ie = NULL; 63 1.1 christos /* We cannot free this struct 64 1.1 christos * because wpa_authenticator on 65 1.1 christos * hostapd side is also using it 66 1.1 christos * for now just set to NULL and 67 1.1 christos * let hostapd code free it. 68 1.1 christos */ 69 1.1 christos } 70 1.1 christos os_free(ifmsh->mconf); 71 1.1 christos ifmsh->mconf = NULL; 72 1.1 christos } 73 1.1 christos 74 1.1 christos /* take care of shared data */ 75 1.1.1.5 christos if (also_clear_hostapd) { 76 1.1.1.5 christos hostapd_interface_deinit(ifmsh); 77 1.1.1.5 christos hostapd_interface_free(ifmsh); 78 1.1.1.5 christos } 79 1.1 christos } 80 1.1 christos 81 1.1 christos 82 1.1.1.2 christos static struct mesh_conf * mesh_config_create(struct wpa_supplicant *wpa_s, 83 1.1.1.2 christos struct wpa_ssid *ssid) 84 1.1 christos { 85 1.1 christos struct mesh_conf *conf; 86 1.1.1.2 christos int cipher; 87 1.1 christos 88 1.1 christos conf = os_zalloc(sizeof(struct mesh_conf)); 89 1.1 christos if (!conf) 90 1.1 christos return NULL; 91 1.1 christos 92 1.1 christos os_memcpy(conf->meshid, ssid->ssid, ssid->ssid_len); 93 1.1 christos conf->meshid_len = ssid->ssid_len; 94 1.1 christos 95 1.1 christos if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) 96 1.1 christos conf->security |= MESH_CONF_SEC_AUTH | 97 1.1 christos MESH_CONF_SEC_AMPE; 98 1.1 christos else 99 1.1 christos conf->security |= MESH_CONF_SEC_NONE; 100 1.1.1.2 christos conf->ieee80211w = ssid->ieee80211w; 101 1.1.1.2 christos if (conf->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT) { 102 1.1.1.2 christos if (wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_BIP) 103 1.1.1.2 christos conf->ieee80211w = wpa_s->conf->pmf; 104 1.1.1.2 christos else 105 1.1.1.2 christos conf->ieee80211w = NO_MGMT_FRAME_PROTECTION; 106 1.1.1.2 christos } 107 1.1.1.4 christos #ifdef CONFIG_OCV 108 1.1.1.4 christos conf->ocv = ssid->ocv; 109 1.1.1.4 christos #endif /* CONFIG_OCV */ 110 1.1.1.2 christos 111 1.1.1.2 christos cipher = wpa_pick_pairwise_cipher(ssid->pairwise_cipher, 0); 112 1.1.1.2 christos if (cipher < 0 || cipher == WPA_CIPHER_TKIP) { 113 1.1.1.2 christos wpa_msg(wpa_s, MSG_INFO, "mesh: Invalid pairwise cipher"); 114 1.1.1.2 christos os_free(conf); 115 1.1.1.2 christos return NULL; 116 1.1.1.2 christos } 117 1.1.1.2 christos conf->pairwise_cipher = cipher; 118 1.1.1.2 christos 119 1.1.1.2 christos cipher = wpa_pick_group_cipher(ssid->group_cipher); 120 1.1.1.2 christos if (cipher < 0 || cipher == WPA_CIPHER_TKIP || 121 1.1.1.2 christos cipher == WPA_CIPHER_GTK_NOT_USED) { 122 1.1.1.2 christos wpa_msg(wpa_s, MSG_INFO, "mesh: Invalid group cipher"); 123 1.1.1.2 christos os_free(conf); 124 1.1.1.2 christos return NULL; 125 1.1.1.2 christos } 126 1.1.1.2 christos 127 1.1.1.2 christos conf->group_cipher = cipher; 128 1.1.1.5 christos if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { 129 1.1.1.5 christos if (ssid->group_mgmt_cipher == WPA_CIPHER_BIP_GMAC_128 || 130 1.1.1.5 christos ssid->group_mgmt_cipher == WPA_CIPHER_BIP_GMAC_256 || 131 1.1.1.5 christos ssid->group_mgmt_cipher == WPA_CIPHER_BIP_CMAC_256) 132 1.1.1.5 christos conf->mgmt_group_cipher = ssid->group_mgmt_cipher; 133 1.1.1.5 christos else 134 1.1.1.5 christos conf->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC; 135 1.1.1.5 christos } 136 1.1 christos 137 1.1 christos /* defaults */ 138 1.1 christos conf->mesh_pp_id = MESH_PATH_PROTOCOL_HWMP; 139 1.1 christos conf->mesh_pm_id = MESH_PATH_METRIC_AIRTIME; 140 1.1 christos conf->mesh_cc_id = 0; 141 1.1 christos conf->mesh_sp_id = MESH_SYNC_METHOD_NEIGHBOR_OFFSET; 142 1.1 christos conf->mesh_auth_id = (conf->security & MESH_CONF_SEC_AUTH) ? 1 : 0; 143 1.1.1.5 christos conf->mesh_fwding = ssid->mesh_fwding; 144 1.1 christos conf->dot11MeshMaxRetries = ssid->dot11MeshMaxRetries; 145 1.1 christos conf->dot11MeshRetryTimeout = ssid->dot11MeshRetryTimeout; 146 1.1 christos conf->dot11MeshConfirmTimeout = ssid->dot11MeshConfirmTimeout; 147 1.1 christos conf->dot11MeshHoldingTimeout = ssid->dot11MeshHoldingTimeout; 148 1.1 christos 149 1.1 christos return conf; 150 1.1 christos } 151 1.1 christos 152 1.1 christos 153 1.1 christos static void wpas_mesh_copy_groups(struct hostapd_data *bss, 154 1.1 christos struct wpa_supplicant *wpa_s) 155 1.1 christos { 156 1.1 christos int num_groups; 157 1.1 christos size_t groups_size; 158 1.1 christos 159 1.1 christos for (num_groups = 0; wpa_s->conf->sae_groups[num_groups] > 0; 160 1.1 christos num_groups++) 161 1.1 christos ; 162 1.1 christos 163 1.1 christos groups_size = (num_groups + 1) * sizeof(wpa_s->conf->sae_groups[0]); 164 1.1 christos bss->conf->sae_groups = os_malloc(groups_size); 165 1.1 christos if (bss->conf->sae_groups) 166 1.1 christos os_memcpy(bss->conf->sae_groups, wpa_s->conf->sae_groups, 167 1.1 christos groups_size); 168 1.1 christos } 169 1.1 christos 170 1.1 christos 171 1.1.1.4 christos static int wpas_mesh_init_rsn(struct wpa_supplicant *wpa_s) 172 1.1.1.4 christos { 173 1.1.1.4 christos struct hostapd_iface *ifmsh = wpa_s->ifmsh; 174 1.1.1.4 christos struct wpa_ssid *ssid = wpa_s->current_ssid; 175 1.1.1.4 christos struct hostapd_data *bss = ifmsh->bss[0]; 176 1.1.1.4 christos static int default_groups[] = { 19, 20, 21, 25, 26, -1 }; 177 1.1.1.4 christos const char *password; 178 1.1.1.4 christos size_t len; 179 1.1.1.4 christos 180 1.1.1.4 christos password = ssid->sae_password; 181 1.1.1.4 christos if (!password) 182 1.1.1.4 christos password = ssid->passphrase; 183 1.1.1.4 christos if (!password) { 184 1.1.1.4 christos wpa_printf(MSG_ERROR, 185 1.1.1.4 christos "mesh: Passphrase for SAE not configured"); 186 1.1.1.4 christos return -1; 187 1.1.1.4 christos } 188 1.1.1.4 christos 189 1.1.1.4 christos bss->conf->wpa = ssid->proto; 190 1.1.1.4 christos bss->conf->wpa_key_mgmt = ssid->key_mgmt; 191 1.1.1.4 christos 192 1.1.1.4 christos if (wpa_s->conf->sae_groups && wpa_s->conf->sae_groups[0] > 0) { 193 1.1.1.4 christos wpas_mesh_copy_groups(bss, wpa_s); 194 1.1.1.4 christos } else { 195 1.1.1.4 christos bss->conf->sae_groups = os_memdup(default_groups, 196 1.1.1.4 christos sizeof(default_groups)); 197 1.1.1.4 christos if (!bss->conf->sae_groups) 198 1.1.1.4 christos return -1; 199 1.1.1.4 christos } 200 1.1.1.4 christos 201 1.1.1.4 christos len = os_strlen(password); 202 1.1.1.4 christos bss->conf->ssid.wpa_passphrase = dup_binstr(password, len); 203 1.1.1.4 christos 204 1.1.1.4 christos wpa_s->mesh_rsn = mesh_rsn_auth_init(wpa_s, ifmsh->mconf); 205 1.1.1.4 christos return !wpa_s->mesh_rsn ? -1 : 0; 206 1.1.1.4 christos } 207 1.1.1.4 christos 208 1.1.1.4 christos 209 1.1.1.5 christos static int wpas_mesh_update_freq_params(struct wpa_supplicant *wpa_s) 210 1.1.1.5 christos { 211 1.1.1.5 christos struct wpa_driver_mesh_join_params *params = wpa_s->mesh_params; 212 1.1.1.5 christos struct hostapd_iface *ifmsh = wpa_s->ifmsh; 213 1.1.1.5 christos struct he_capabilities *he_capab = NULL; 214 1.1.1.5 christos 215 1.1.1.5 christos if (ifmsh->current_mode) 216 1.1.1.5 christos he_capab = &ifmsh->current_mode->he_capab[IEEE80211_MODE_MESH]; 217 1.1.1.5 christos 218 1.1.1.5 christos if (hostapd_set_freq_params( 219 1.1.1.5 christos ¶ms->freq, 220 1.1.1.5 christos ifmsh->conf->hw_mode, 221 1.1.1.5 christos ifmsh->freq, 222 1.1.1.5 christos ifmsh->conf->channel, 223 1.1.1.5 christos ifmsh->conf->enable_edmg, 224 1.1.1.5 christos ifmsh->conf->edmg_channel, 225 1.1.1.5 christos ifmsh->conf->ieee80211n, 226 1.1.1.5 christos ifmsh->conf->ieee80211ac, 227 1.1.1.5 christos ifmsh->conf->ieee80211ax, 228 1.1.1.5 christos ifmsh->conf->ieee80211be, 229 1.1.1.5 christos ifmsh->conf->secondary_channel, 230 1.1.1.5 christos hostapd_get_oper_chwidth(ifmsh->conf), 231 1.1.1.5 christos hostapd_get_oper_centr_freq_seg0_idx(ifmsh->conf), 232 1.1.1.5 christos hostapd_get_oper_centr_freq_seg1_idx(ifmsh->conf), 233 1.1.1.5 christos ifmsh->conf->vht_capab, 234 1.1.1.5 christos he_capab, NULL, 0)) { 235 1.1.1.5 christos wpa_printf(MSG_ERROR, "Error updating mesh frequency params"); 236 1.1.1.5 christos wpa_supplicant_mesh_deinit(wpa_s, true); 237 1.1.1.5 christos return -1; 238 1.1.1.5 christos } 239 1.1.1.5 christos 240 1.1.1.5 christos return 0; 241 1.1.1.5 christos } 242 1.1.1.5 christos 243 1.1.1.5 christos 244 1.1.1.4 christos static int wpas_mesh_complete(struct wpa_supplicant *wpa_s) 245 1.1.1.4 christos { 246 1.1.1.4 christos struct hostapd_iface *ifmsh = wpa_s->ifmsh; 247 1.1.1.4 christos struct wpa_driver_mesh_join_params *params = wpa_s->mesh_params; 248 1.1.1.4 christos struct wpa_ssid *ssid = wpa_s->current_ssid; 249 1.1.1.4 christos int ret; 250 1.1.1.4 christos 251 1.1.1.4 christos if (!params || !ssid || !ifmsh) { 252 1.1.1.4 christos wpa_printf(MSG_ERROR, "mesh: %s called without active mesh", 253 1.1.1.4 christos __func__); 254 1.1.1.4 christos return -1; 255 1.1.1.4 christos } 256 1.1.1.4 christos 257 1.1.1.5 christos /* 258 1.1.1.5 christos * Update channel configuration if the channel has changed since the 259 1.1.1.5 christos * initial setting, i.e., due to DFS radar detection during CAC. 260 1.1.1.5 christos */ 261 1.1.1.5 christos if (ifmsh->freq > 0 && ifmsh->freq != params->freq.freq) { 262 1.1.1.5 christos wpa_s->assoc_freq = ifmsh->freq; 263 1.1.1.5 christos ssid->frequency = ifmsh->freq; 264 1.1.1.5 christos if (wpas_mesh_update_freq_params(wpa_s) < 0) 265 1.1.1.5 christos return -1; 266 1.1.1.5 christos } 267 1.1.1.5 christos 268 1.1.1.4 christos if (ifmsh->mconf->security != MESH_CONF_SEC_NONE && 269 1.1.1.4 christos wpas_mesh_init_rsn(wpa_s)) { 270 1.1.1.4 christos wpa_printf(MSG_ERROR, 271 1.1.1.4 christos "mesh: RSN initialization failed - deinit mesh"); 272 1.1.1.5 christos wpa_supplicant_mesh_deinit(wpa_s, false); 273 1.1.1.4 christos return -1; 274 1.1.1.4 christos } 275 1.1.1.4 christos 276 1.1.1.4 christos if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) { 277 1.1.1.4 christos wpa_s->pairwise_cipher = wpa_s->mesh_rsn->pairwise_cipher; 278 1.1.1.4 christos wpa_s->group_cipher = wpa_s->mesh_rsn->group_cipher; 279 1.1.1.4 christos wpa_s->mgmt_group_cipher = wpa_s->mesh_rsn->mgmt_group_cipher; 280 1.1.1.4 christos } 281 1.1.1.4 christos 282 1.1.1.4 christos params->ies = ifmsh->mconf->rsn_ie; 283 1.1.1.4 christos params->ie_len = ifmsh->mconf->rsn_ie_len; 284 1.1.1.4 christos params->basic_rates = ifmsh->basic_rates; 285 1.1.1.4 christos params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_HT_OP_MODE; 286 1.1.1.4 christos params->conf.ht_opmode = ifmsh->bss[0]->iface->ht_op_mode; 287 1.1.1.4 christos 288 1.1.1.4 christos wpa_msg(wpa_s, MSG_INFO, "joining mesh %s", 289 1.1.1.4 christos wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); 290 1.1.1.4 christos ret = wpa_drv_join_mesh(wpa_s, params); 291 1.1.1.4 christos if (ret) 292 1.1.1.4 christos wpa_msg(wpa_s, MSG_ERROR, "mesh join error=%d", ret); 293 1.1.1.4 christos 294 1.1.1.4 christos /* hostapd sets the interface down until we associate */ 295 1.1.1.4 christos wpa_drv_set_operstate(wpa_s, 1); 296 1.1.1.4 christos 297 1.1.1.5 christos if (!ret) { 298 1.1.1.4 christos wpa_supplicant_set_state(wpa_s, WPA_COMPLETED); 299 1.1.1.4 christos 300 1.1.1.5 christos wpa_msg(wpa_s, MSG_INFO, MESH_GROUP_STARTED "ssid=\"%s\" id=%d", 301 1.1.1.5 christos wpa_ssid_txt(ssid->ssid, ssid->ssid_len), 302 1.1.1.5 christos ssid->id); 303 1.1.1.5 christos wpas_notify_mesh_group_started(wpa_s, ssid); 304 1.1.1.5 christos } 305 1.1.1.5 christos 306 1.1.1.4 christos return ret; 307 1.1.1.4 christos } 308 1.1.1.4 christos 309 1.1.1.4 christos 310 1.1.1.5 christos static void wpas_mesh_complete_cb(void *arg) 311 1.1.1.5 christos { 312 1.1.1.5 christos struct wpa_supplicant *wpa_s = arg; 313 1.1.1.5 christos 314 1.1.1.5 christos wpas_mesh_complete(wpa_s); 315 1.1.1.5 christos } 316 1.1.1.5 christos 317 1.1.1.5 christos 318 1.1.1.5 christos static int wpa_supplicant_mesh_enable_iface_cb(struct hostapd_iface *ifmsh) 319 1.1.1.5 christos { 320 1.1.1.5 christos struct wpa_supplicant *wpa_s = ifmsh->owner; 321 1.1.1.5 christos struct hostapd_data *bss; 322 1.1.1.5 christos 323 1.1.1.5 christos ifmsh->mconf = mesh_config_create(wpa_s, wpa_s->current_ssid); 324 1.1.1.5 christos 325 1.1.1.5 christos bss = ifmsh->bss[0]; 326 1.1.1.5 christos bss->msg_ctx = wpa_s; 327 1.1.1.5 christos os_memcpy(bss->own_addr, wpa_s->own_addr, ETH_ALEN); 328 1.1.1.5 christos bss->driver = wpa_s->driver; 329 1.1.1.5 christos bss->drv_priv = wpa_s->drv_priv; 330 1.1.1.5 christos bss->iface = ifmsh; 331 1.1.1.5 christos bss->mesh_sta_free_cb = mesh_mpm_free_sta; 332 1.1.1.5 christos bss->setup_complete_cb = wpas_mesh_complete_cb; 333 1.1.1.5 christos bss->setup_complete_cb_ctx = wpa_s; 334 1.1.1.5 christos 335 1.1.1.5 christos bss->conf->start_disabled = 1; 336 1.1.1.5 christos bss->conf->mesh = MESH_ENABLED; 337 1.1.1.5 christos bss->conf->ap_max_inactivity = wpa_s->conf->mesh_max_inactivity; 338 1.1.1.5 christos 339 1.1.1.5 christos if (wpa_drv_init_mesh(wpa_s)) { 340 1.1.1.5 christos wpa_msg(wpa_s, MSG_ERROR, "Failed to init mesh in driver"); 341 1.1.1.5 christos return -1; 342 1.1.1.5 christos } 343 1.1.1.5 christos 344 1.1.1.5 christos if (hostapd_setup_interface(ifmsh)) { 345 1.1.1.5 christos wpa_printf(MSG_ERROR, 346 1.1.1.5 christos "Failed to initialize hostapd interface for mesh"); 347 1.1.1.5 christos return -1; 348 1.1.1.5 christos } 349 1.1.1.5 christos 350 1.1.1.5 christos return 0; 351 1.1.1.5 christos } 352 1.1.1.5 christos 353 1.1.1.5 christos 354 1.1.1.5 christos static int wpa_supplicant_mesh_disable_iface_cb(struct hostapd_iface *ifmsh) 355 1.1.1.5 christos { 356 1.1.1.5 christos struct wpa_supplicant *wpa_s = ifmsh->owner; 357 1.1.1.5 christos size_t j; 358 1.1.1.5 christos 359 1.1.1.5 christos wpa_supplicant_mesh_deinit(wpa_s, false); 360 1.1.1.5 christos 361 1.1.1.5 christos #ifdef NEED_AP_MLME 362 1.1.1.5 christos for (j = 0; j < ifmsh->num_bss; j++) 363 1.1.1.5 christos hostapd_cleanup_cs_params(ifmsh->bss[j]); 364 1.1.1.5 christos #endif /* NEED_AP_MLME */ 365 1.1.1.5 christos 366 1.1.1.5 christos /* Same as hostapd_interface_deinit() without deinitializing control 367 1.1.1.5 christos * interface */ 368 1.1.1.5 christos for (j = 0; j < ifmsh->num_bss; j++) { 369 1.1.1.5 christos struct hostapd_data *hapd = ifmsh->bss[j]; 370 1.1.1.5 christos 371 1.1.1.5 christos hostapd_bss_deinit_no_free(hapd); 372 1.1.1.5 christos hostapd_free_hapd_data(hapd); 373 1.1.1.5 christos } 374 1.1.1.5 christos 375 1.1.1.5 christos hostapd_cleanup_iface_partial(ifmsh); 376 1.1.1.5 christos 377 1.1.1.5 christos return 0; 378 1.1.1.5 christos } 379 1.1.1.5 christos 380 1.1.1.5 christos 381 1.1 christos static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s, 382 1.1.1.3 christos struct wpa_ssid *ssid, 383 1.1.1.3 christos struct hostapd_freq_params *freq) 384 1.1 christos { 385 1.1 christos struct hostapd_iface *ifmsh; 386 1.1 christos struct hostapd_data *bss; 387 1.1 christos struct hostapd_config *conf; 388 1.1 christos struct mesh_conf *mconf; 389 1.1 christos int basic_rates_erp[] = { 10, 20, 55, 60, 110, 120, 240, -1 }; 390 1.1 christos int rate_len; 391 1.1.1.3 christos int frequency; 392 1.1 christos 393 1.1 christos if (!wpa_s->conf->user_mpm) { 394 1.1 christos /* not much for us to do here */ 395 1.1 christos wpa_msg(wpa_s, MSG_WARNING, 396 1.1 christos "user_mpm is not enabled in configuration"); 397 1.1 christos return 0; 398 1.1 christos } 399 1.1 christos 400 1.1.1.3 christos wpa_s->ifmsh = ifmsh = hostapd_alloc_iface(); 401 1.1 christos if (!ifmsh) 402 1.1 christos return -ENOMEM; 403 1.1 christos 404 1.1.1.5 christos ifmsh->owner = wpa_s; 405 1.1 christos ifmsh->drv_flags = wpa_s->drv_flags; 406 1.1.1.5 christos ifmsh->drv_flags2 = wpa_s->drv_flags2; 407 1.1 christos ifmsh->num_bss = 1; 408 1.1.1.5 christos ifmsh->enable_iface_cb = wpa_supplicant_mesh_enable_iface_cb; 409 1.1.1.5 christos ifmsh->disable_iface_cb = wpa_supplicant_mesh_disable_iface_cb; 410 1.1 christos ifmsh->bss = os_calloc(wpa_s->ifmsh->num_bss, 411 1.1 christos sizeof(struct hostapd_data *)); 412 1.1 christos if (!ifmsh->bss) 413 1.1 christos goto out_free; 414 1.1 christos 415 1.1.1.3 christos ifmsh->bss[0] = bss = hostapd_alloc_bss_data(NULL, NULL, NULL); 416 1.1 christos if (!bss) 417 1.1 christos goto out_free; 418 1.1 christos 419 1.1.1.3 christos ifmsh->bss[0]->msg_ctx = wpa_s; 420 1.1 christos os_memcpy(bss->own_addr, wpa_s->own_addr, ETH_ALEN); 421 1.1 christos bss->driver = wpa_s->driver; 422 1.1 christos bss->drv_priv = wpa_s->drv_priv; 423 1.1 christos bss->iface = ifmsh; 424 1.1 christos bss->mesh_sta_free_cb = mesh_mpm_free_sta; 425 1.1.1.5 christos bss->setup_complete_cb = wpas_mesh_complete_cb; 426 1.1.1.5 christos bss->setup_complete_cb_ctx = wpa_s; 427 1.1.1.3 christos frequency = ssid->frequency; 428 1.1.1.3 christos if (frequency != freq->freq && 429 1.1.1.3 christos frequency == freq->freq + freq->sec_channel_offset * 20) { 430 1.1.1.3 christos wpa_printf(MSG_DEBUG, "mesh: pri/sec channels switched"); 431 1.1.1.3 christos frequency = freq->freq; 432 1.1.1.5 christos ssid->frequency = frequency; 433 1.1.1.3 christos } 434 1.1.1.3 christos wpa_s->assoc_freq = frequency; 435 1.1 christos wpa_s->current_ssid = ssid; 436 1.1 christos 437 1.1 christos /* setup an AP config for auth processing */ 438 1.1 christos conf = hostapd_config_defaults(); 439 1.1 christos if (!conf) 440 1.1 christos goto out_free; 441 1.1 christos 442 1.1.1.5 christos if (is_6ghz_freq(freq->freq)) { 443 1.1.1.5 christos /* 444 1.1.1.5 christos * IEEE Std 802.11ax-2021, 12.12.2: 445 1.1.1.5 christos * The STA shall use management frame protection (MFPR=1) when 446 1.1.1.5 christos * using RSN. 447 1.1.1.5 christos */ 448 1.1.1.5 christos ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED; 449 1.1.1.5 christos 450 1.1.1.5 christos /* Set mandatory op_class parameter for setting up BSS */ 451 1.1.1.5 christos switch (freq->bandwidth) { 452 1.1.1.5 christos case 20: 453 1.1.1.5 christos if (freq->freq == 5935) 454 1.1.1.5 christos conf->op_class = 136; 455 1.1.1.5 christos else 456 1.1.1.5 christos conf->op_class = 131; 457 1.1.1.5 christos break; 458 1.1.1.5 christos case 40: 459 1.1.1.5 christos conf->op_class = 132; 460 1.1.1.5 christos break; 461 1.1.1.5 christos case 80: 462 1.1.1.5 christos conf->op_class = 133; 463 1.1.1.5 christos break; 464 1.1.1.5 christos case 160: 465 1.1.1.5 christos conf->op_class = 134; 466 1.1.1.5 christos break; 467 1.1.1.5 christos default: 468 1.1.1.5 christos conf->op_class = 131; 469 1.1.1.5 christos break; 470 1.1.1.5 christos } 471 1.1.1.5 christos } 472 1.1.1.5 christos 473 1.1 christos bss->conf = *conf->bss; 474 1.1 christos bss->conf->start_disabled = 1; 475 1.1 christos bss->conf->mesh = MESH_ENABLED; 476 1.1 christos bss->conf->ap_max_inactivity = wpa_s->conf->mesh_max_inactivity; 477 1.1.1.5 christos bss->conf->mesh_fwding = wpa_s->conf->mesh_fwding; 478 1.1.1.4 christos 479 1.1.1.4 christos if (ieee80211_is_dfs(ssid->frequency, wpa_s->hw.modes, 480 1.1.1.4 christos wpa_s->hw.num_modes) && wpa_s->conf->country[0]) { 481 1.1.1.4 christos conf->ieee80211h = 1; 482 1.1.1.4 christos conf->ieee80211d = 1; 483 1.1.1.4 christos conf->country[0] = wpa_s->conf->country[0]; 484 1.1.1.4 christos conf->country[1] = wpa_s->conf->country[1]; 485 1.1.1.4 christos conf->country[2] = ' '; 486 1.1.1.5 christos wpa_s->mesh_params->handle_dfs = true; 487 1.1.1.4 christos } 488 1.1.1.4 christos 489 1.1 christos bss->iconf = conf; 490 1.1 christos ifmsh->conf = conf; 491 1.1 christos 492 1.1 christos ifmsh->bss[0]->max_plinks = wpa_s->conf->max_peer_links; 493 1.1.1.2 christos ifmsh->bss[0]->dot11RSNASAERetransPeriod = 494 1.1.1.2 christos wpa_s->conf->dot11RSNASAERetransPeriod; 495 1.1 christos os_strlcpy(bss->conf->iface, wpa_s->ifname, sizeof(bss->conf->iface)); 496 1.1 christos 497 1.1.1.2 christos mconf = mesh_config_create(wpa_s, ssid); 498 1.1 christos if (!mconf) 499 1.1 christos goto out_free; 500 1.1 christos ifmsh->mconf = mconf; 501 1.1 christos 502 1.1 christos /* need conf->hw_mode for supported rates. */ 503 1.1.1.3 christos conf->hw_mode = ieee80211_freq_to_chan(frequency, &conf->channel); 504 1.1 christos if (conf->hw_mode == NUM_HOSTAPD_MODES) { 505 1.1 christos wpa_printf(MSG_ERROR, "Unsupported mesh mode frequency: %d MHz", 506 1.1.1.3 christos frequency); 507 1.1 christos goto out_free; 508 1.1 christos } 509 1.1 christos 510 1.1 christos if (ssid->mesh_basic_rates == NULL) { 511 1.1 christos /* 512 1.1 christos * XXX: Hack! This is so an MPM which correctly sets the ERP 513 1.1 christos * mandatory rates as BSSBasicRateSet doesn't reject us. We 514 1.1 christos * could add a new hw_mode HOSTAPD_MODE_IEEE80211G_ERP, but 515 1.1 christos * this is way easier. This also makes our BSSBasicRateSet 516 1.1 christos * advertised in beacons match the one in peering frames, sigh. 517 1.1 christos */ 518 1.1 christos if (conf->hw_mode == HOSTAPD_MODE_IEEE80211G) { 519 1.1.1.3 christos conf->basic_rates = os_memdup(basic_rates_erp, 520 1.1.1.3 christos sizeof(basic_rates_erp)); 521 1.1 christos if (!conf->basic_rates) 522 1.1 christos goto out_free; 523 1.1 christos } 524 1.1 christos } else { 525 1.1 christos rate_len = 0; 526 1.1 christos while (1) { 527 1.1 christos if (ssid->mesh_basic_rates[rate_len] < 1) 528 1.1 christos break; 529 1.1 christos rate_len++; 530 1.1 christos } 531 1.1 christos conf->basic_rates = os_calloc(rate_len + 1, sizeof(int)); 532 1.1 christos if (conf->basic_rates == NULL) 533 1.1 christos goto out_free; 534 1.1 christos os_memcpy(conf->basic_rates, ssid->mesh_basic_rates, 535 1.1 christos rate_len * sizeof(int)); 536 1.1 christos conf->basic_rates[rate_len] = -1; 537 1.1 christos } 538 1.1 christos 539 1.1.1.5 christos /* While it can enhance performance to switch the primary channel, which 540 1.1.1.5 christos * is also the secondary channel of another network at the same time), 541 1.1.1.5 christos * to the other primary channel, problems exist with this in mesh 542 1.1.1.5 christos * networks. 543 1.1.1.5 christos * 544 1.1.1.5 christos * Example with problems: 545 1.1.1.5 christos * - 3 mesh nodes M1-M3, freq (5200, 5180) 546 1.1.1.5 christos * - other node O1, e.g. AP mode, freq (5180, 5200), 547 1.1.1.5 christos * Locations: O1 M1 M2 M3 548 1.1.1.5 christos * 549 1.1.1.5 christos * M3 can only send frames to M1 over M2, no direct connection is 550 1.1.1.5 christos * possible 551 1.1.1.5 christos * Start O1, M1 and M3 first, M1 or O1 will switch channels to align 552 1.1.1.5 christos * with* each other. M3 does not swap, because M1 or O1 cannot be 553 1.1.1.5 christos * reached. M2 is started afterwards and can either connect to M3 or M1 554 1.1.1.5 christos * because of this primary secondary channel switch. 555 1.1.1.5 christos * 556 1.1.1.5 christos * Solutions: (1) central coordination -> not always possible 557 1.1.1.5 christos * (2) disable pri/sec channel switch in mesh networks 558 1.1.1.5 christos * 559 1.1.1.5 christos * In AP mode, when all nodes can work independently, this poses of 560 1.1.1.5 christos * course no problem, therefore disable it only in mesh mode. */ 561 1.1.1.5 christos conf->no_pri_sec_switch = 1; 562 1.1.1.5 christos wpa_supplicant_conf_ap_ht(wpa_s, ssid, conf); 563 1.1.1.5 christos 564 1.1 christos if (wpa_drv_init_mesh(wpa_s)) { 565 1.1 christos wpa_msg(wpa_s, MSG_ERROR, "Failed to init mesh in driver"); 566 1.1 christos return -1; 567 1.1 christos } 568 1.1 christos 569 1.1.1.4 christos if (hostapd_setup_interface(ifmsh)) { 570 1.1.1.4 christos wpa_printf(MSG_ERROR, 571 1.1.1.4 christos "Failed to initialize hostapd interface for mesh"); 572 1.1.1.4 christos return -1; 573 1.1 christos } 574 1.1 christos 575 1.1 christos return 0; 576 1.1 christos out_free: 577 1.1.1.5 christos wpa_supplicant_mesh_deinit(wpa_s, true); 578 1.1 christos return -ENOMEM; 579 1.1 christos } 580 1.1 christos 581 1.1 christos 582 1.1 christos void wpa_mesh_notify_peer(struct wpa_supplicant *wpa_s, const u8 *addr, 583 1.1 christos const u8 *ies, size_t ie_len) 584 1.1 christos { 585 1.1 christos struct ieee802_11_elems elems; 586 1.1 christos 587 1.1 christos wpa_msg(wpa_s, MSG_INFO, 588 1.1 christos "new peer notification for " MACSTR, MAC2STR(addr)); 589 1.1 christos 590 1.1 christos if (ieee802_11_parse_elems(ies, ie_len, &elems, 0) == ParseFailed) { 591 1.1 christos wpa_msg(wpa_s, MSG_INFO, "Could not parse beacon from " MACSTR, 592 1.1 christos MAC2STR(addr)); 593 1.1 christos return; 594 1.1 christos } 595 1.1 christos wpa_mesh_new_mesh_peer(wpa_s, addr, &elems); 596 1.1 christos } 597 1.1 christos 598 1.1 christos 599 1.1 christos void wpa_supplicant_mesh_add_scan_ie(struct wpa_supplicant *wpa_s, 600 1.1 christos struct wpabuf **extra_ie) 601 1.1 christos { 602 1.1 christos /* EID + 0-length (wildcard) mesh-id */ 603 1.1 christos size_t ielen = 2; 604 1.1 christos 605 1.1 christos if (wpabuf_resize(extra_ie, ielen) == 0) { 606 1.1 christos wpabuf_put_u8(*extra_ie, WLAN_EID_MESH_ID); 607 1.1 christos wpabuf_put_u8(*extra_ie, 0); 608 1.1 christos } 609 1.1 christos } 610 1.1 christos 611 1.1 christos 612 1.1 christos int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s, 613 1.1 christos struct wpa_ssid *ssid) 614 1.1 christos { 615 1.1.1.4 christos struct wpa_driver_mesh_join_params *params = os_zalloc(sizeof(*params)); 616 1.1 christos int ret = 0; 617 1.1 christos 618 1.1.1.4 christos if (!ssid || !ssid->ssid || !ssid->ssid_len || !ssid->frequency || 619 1.1.1.4 christos !params) { 620 1.1 christos ret = -ENOENT; 621 1.1.1.4 christos os_free(params); 622 1.1 christos goto out; 623 1.1 christos } 624 1.1 christos 625 1.1.1.5 christos wpa_supplicant_mesh_deinit(wpa_s, true); 626 1.1 christos 627 1.1.1.2 christos wpa_s->pairwise_cipher = WPA_CIPHER_NONE; 628 1.1.1.2 christos wpa_s->group_cipher = WPA_CIPHER_NONE; 629 1.1.1.2 christos wpa_s->mgmt_group_cipher = 0; 630 1.1.1.2 christos 631 1.1.1.4 christos params->meshid = ssid->ssid; 632 1.1.1.4 christos params->meshid_len = ssid->ssid_len; 633 1.1.1.4 christos ibss_mesh_setup_freq(wpa_s, ssid, ¶ms->freq); 634 1.1.1.4 christos wpa_s->mesh_ht_enabled = !!params->freq.ht_enabled; 635 1.1.1.4 christos wpa_s->mesh_vht_enabled = !!params->freq.vht_enabled; 636 1.1.1.4 christos wpa_s->mesh_he_enabled = !!params->freq.he_enabled; 637 1.1.1.5 christos wpa_s->mesh_eht_enabled = !!params->freq.eht_enabled; 638 1.1.1.4 christos if (params->freq.ht_enabled && params->freq.sec_channel_offset) 639 1.1.1.4 christos ssid->ht40 = params->freq.sec_channel_offset; 640 1.1.1.4 christos 641 1.1.1.2 christos if (wpa_s->mesh_vht_enabled) { 642 1.1.1.2 christos ssid->vht = 1; 643 1.1.1.4 christos ssid->vht_center_freq1 = params->freq.center_freq1; 644 1.1.1.4 christos switch (params->freq.bandwidth) { 645 1.1.1.2 christos case 80: 646 1.1.1.4 christos if (params->freq.center_freq2) { 647 1.1.1.5 christos ssid->max_oper_chwidth = 648 1.1.1.5 christos CONF_OPER_CHWIDTH_80P80MHZ; 649 1.1.1.2 christos ssid->vht_center_freq2 = 650 1.1.1.4 christos params->freq.center_freq2; 651 1.1.1.2 christos } else { 652 1.1.1.5 christos ssid->max_oper_chwidth = 653 1.1.1.5 christos CONF_OPER_CHWIDTH_80MHZ; 654 1.1.1.2 christos } 655 1.1.1.2 christos break; 656 1.1.1.2 christos case 160: 657 1.1.1.5 christos ssid->max_oper_chwidth = CONF_OPER_CHWIDTH_160MHZ; 658 1.1.1.2 christos break; 659 1.1.1.2 christos default: 660 1.1.1.5 christos ssid->max_oper_chwidth = CONF_OPER_CHWIDTH_USE_HT; 661 1.1.1.2 christos break; 662 1.1.1.2 christos } 663 1.1.1.2 christos } 664 1.1.1.4 christos if (wpa_s->mesh_he_enabled) 665 1.1.1.4 christos ssid->he = 1; 666 1.1.1.5 christos if (wpa_s->mesh_eht_enabled) 667 1.1.1.5 christos ssid->eht = 1; 668 1.1 christos if (ssid->beacon_int > 0) 669 1.1.1.4 christos params->beacon_int = ssid->beacon_int; 670 1.1 christos else if (wpa_s->conf->beacon_int > 0) 671 1.1.1.4 christos params->beacon_int = wpa_s->conf->beacon_int; 672 1.1.1.2 christos if (ssid->dtim_period > 0) 673 1.1.1.4 christos params->dtim_period = ssid->dtim_period; 674 1.1.1.2 christos else if (wpa_s->conf->dtim_period > 0) 675 1.1.1.4 christos params->dtim_period = wpa_s->conf->dtim_period; 676 1.1.1.4 christos params->conf.max_peer_links = wpa_s->conf->max_peer_links; 677 1.1.1.3 christos if (ssid->mesh_rssi_threshold < DEFAULT_MESH_RSSI_THRESHOLD) { 678 1.1.1.4 christos params->conf.rssi_threshold = ssid->mesh_rssi_threshold; 679 1.1.1.4 christos params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_RSSI_THRESHOLD; 680 1.1.1.3 christos } 681 1.1 christos 682 1.1 christos if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) { 683 1.1.1.4 christos params->flags |= WPA_DRIVER_MESH_FLAG_SAE_AUTH; 684 1.1.1.4 christos params->flags |= WPA_DRIVER_MESH_FLAG_AMPE; 685 1.1 christos wpa_s->conf->user_mpm = 1; 686 1.1 christos } 687 1.1 christos 688 1.1 christos if (wpa_s->conf->user_mpm) { 689 1.1.1.4 christos params->flags |= WPA_DRIVER_MESH_FLAG_USER_MPM; 690 1.1.1.4 christos params->conf.auto_plinks = 0; 691 1.1 christos } else { 692 1.1.1.4 christos params->flags |= WPA_DRIVER_MESH_FLAG_DRIVER_MPM; 693 1.1.1.4 christos params->conf.auto_plinks = 1; 694 1.1 christos } 695 1.1.1.4 christos params->conf.peer_link_timeout = wpa_s->conf->mesh_max_inactivity; 696 1.1 christos 697 1.1.1.5 christos /* Always explicitely set forwarding to on or off for now */ 698 1.1.1.5 christos params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_FORWARDING; 699 1.1.1.5 christos params->conf.forwarding = ssid->mesh_fwding; 700 1.1.1.5 christos 701 1.1.1.4 christos os_free(wpa_s->mesh_params); 702 1.1.1.4 christos wpa_s->mesh_params = params; 703 1.1.1.4 christos if (wpa_supplicant_mesh_init(wpa_s, ssid, ¶ms->freq)) { 704 1.1 christos wpa_msg(wpa_s, MSG_ERROR, "Failed to init mesh"); 705 1.1.1.5 christos wpa_supplicant_leave_mesh(wpa_s, true); 706 1.1 christos ret = -1; 707 1.1 christos goto out; 708 1.1 christos } 709 1.1 christos 710 1.1 christos out: 711 1.1 christos return ret; 712 1.1 christos } 713 1.1 christos 714 1.1 christos 715 1.1.1.5 christos int wpa_supplicant_leave_mesh(struct wpa_supplicant *wpa_s, bool need_deinit) 716 1.1 christos { 717 1.1 christos int ret = 0; 718 1.1 christos 719 1.1 christos wpa_msg(wpa_s, MSG_INFO, "leaving mesh"); 720 1.1 christos 721 1.1 christos /* Need to send peering close messages first */ 722 1.1.1.5 christos if (need_deinit) 723 1.1.1.5 christos wpa_supplicant_mesh_deinit(wpa_s, true); 724 1.1 christos 725 1.1 christos ret = wpa_drv_leave_mesh(wpa_s); 726 1.1 christos if (ret) 727 1.1 christos wpa_msg(wpa_s, MSG_ERROR, "mesh leave error=%d", ret); 728 1.1 christos 729 1.1 christos wpa_drv_set_operstate(wpa_s, 1); 730 1.1 christos 731 1.1 christos return ret; 732 1.1 christos } 733 1.1 christos 734 1.1 christos 735 1.1 christos static int mesh_attr_text(const u8 *ies, size_t ies_len, char *buf, char *end) 736 1.1 christos { 737 1.1 christos struct ieee802_11_elems elems; 738 1.1 christos char *mesh_id, *pos = buf; 739 1.1 christos u8 *bss_basic_rate_set; 740 1.1 christos int bss_basic_rate_set_len, ret, i; 741 1.1 christos 742 1.1 christos if (ieee802_11_parse_elems(ies, ies_len, &elems, 0) == ParseFailed) 743 1.1 christos return -1; 744 1.1 christos 745 1.1 christos if (elems.mesh_id_len < 1) 746 1.1 christos return 0; 747 1.1 christos 748 1.1 christos mesh_id = os_malloc(elems.mesh_id_len + 1); 749 1.1 christos if (mesh_id == NULL) 750 1.1 christos return -1; 751 1.1 christos 752 1.1 christos os_memcpy(mesh_id, elems.mesh_id, elems.mesh_id_len); 753 1.1 christos mesh_id[elems.mesh_id_len] = '\0'; 754 1.1 christos ret = os_snprintf(pos, end - pos, "mesh_id=%s\n", mesh_id); 755 1.1 christos os_free(mesh_id); 756 1.1 christos if (os_snprintf_error(end - pos, ret)) 757 1.1 christos return pos - buf; 758 1.1 christos pos += ret; 759 1.1 christos 760 1.1 christos if (elems.mesh_config_len > 6) { 761 1.1 christos ret = os_snprintf(pos, end - pos, 762 1.1 christos "active_path_selection_protocol_id=0x%02x\n" 763 1.1 christos "active_path_selection_metric_id=0x%02x\n" 764 1.1 christos "congestion_control_mode_id=0x%02x\n" 765 1.1 christos "synchronization_method_id=0x%02x\n" 766 1.1 christos "authentication_protocol_id=0x%02x\n" 767 1.1 christos "mesh_formation_info=0x%02x\n" 768 1.1 christos "mesh_capability=0x%02x\n", 769 1.1 christos elems.mesh_config[0], elems.mesh_config[1], 770 1.1 christos elems.mesh_config[2], elems.mesh_config[3], 771 1.1 christos elems.mesh_config[4], elems.mesh_config[5], 772 1.1 christos elems.mesh_config[6]); 773 1.1 christos if (os_snprintf_error(end - pos, ret)) 774 1.1 christos return pos - buf; 775 1.1 christos pos += ret; 776 1.1 christos } 777 1.1 christos 778 1.1 christos bss_basic_rate_set = os_malloc(elems.supp_rates_len + 779 1.1 christos elems.ext_supp_rates_len); 780 1.1 christos if (bss_basic_rate_set == NULL) 781 1.1 christos return -1; 782 1.1 christos 783 1.1 christos bss_basic_rate_set_len = 0; 784 1.1 christos for (i = 0; i < elems.supp_rates_len; i++) { 785 1.1 christos if (elems.supp_rates[i] & 0x80) { 786 1.1 christos bss_basic_rate_set[bss_basic_rate_set_len++] = 787 1.1 christos (elems.supp_rates[i] & 0x7f) * 5; 788 1.1 christos } 789 1.1 christos } 790 1.1 christos for (i = 0; i < elems.ext_supp_rates_len; i++) { 791 1.1 christos if (elems.ext_supp_rates[i] & 0x80) { 792 1.1 christos bss_basic_rate_set[bss_basic_rate_set_len++] = 793 1.1 christos (elems.ext_supp_rates[i] & 0x7f) * 5; 794 1.1 christos } 795 1.1 christos } 796 1.1 christos if (bss_basic_rate_set_len > 0) { 797 1.1 christos ret = os_snprintf(pos, end - pos, "bss_basic_rate_set=%d", 798 1.1 christos bss_basic_rate_set[0]); 799 1.1 christos if (os_snprintf_error(end - pos, ret)) 800 1.1.1.2 christos goto fail; 801 1.1 christos pos += ret; 802 1.1 christos 803 1.1 christos for (i = 1; i < bss_basic_rate_set_len; i++) { 804 1.1 christos ret = os_snprintf(pos, end - pos, " %d", 805 1.1 christos bss_basic_rate_set[i]); 806 1.1 christos if (os_snprintf_error(end - pos, ret)) 807 1.1.1.2 christos goto fail; 808 1.1 christos pos += ret; 809 1.1 christos } 810 1.1 christos 811 1.1 christos ret = os_snprintf(pos, end - pos, "\n"); 812 1.1 christos if (os_snprintf_error(end - pos, ret)) 813 1.1.1.2 christos goto fail; 814 1.1 christos pos += ret; 815 1.1 christos } 816 1.1.1.2 christos fail: 817 1.1 christos os_free(bss_basic_rate_set); 818 1.1 christos 819 1.1 christos return pos - buf; 820 1.1 christos } 821 1.1 christos 822 1.1 christos 823 1.1 christos int wpas_mesh_scan_result_text(const u8 *ies, size_t ies_len, char *buf, 824 1.1 christos char *end) 825 1.1 christos { 826 1.1 christos return mesh_attr_text(ies, ies_len, buf, end); 827 1.1 christos } 828 1.1 christos 829 1.1 christos 830 1.1 christos static int wpas_mesh_get_ifname(struct wpa_supplicant *wpa_s, char *ifname, 831 1.1 christos size_t len) 832 1.1 christos { 833 1.1 christos char *ifname_ptr = wpa_s->ifname; 834 1.1 christos int res; 835 1.1 christos 836 1.1 christos res = os_snprintf(ifname, len, "mesh-%s-%d", ifname_ptr, 837 1.1 christos wpa_s->mesh_if_idx); 838 1.1 christos if (os_snprintf_error(len, res) || 839 1.1 christos (os_strlen(ifname) >= IFNAMSIZ && 840 1.1 christos os_strlen(wpa_s->ifname) < IFNAMSIZ)) { 841 1.1 christos /* Try to avoid going over the IFNAMSIZ length limit */ 842 1.1 christos res = os_snprintf(ifname, len, "mesh-%d", wpa_s->mesh_if_idx); 843 1.1 christos if (os_snprintf_error(len, res)) 844 1.1 christos return -1; 845 1.1 christos } 846 1.1 christos wpa_s->mesh_if_idx++; 847 1.1 christos return 0; 848 1.1 christos } 849 1.1 christos 850 1.1 christos 851 1.1 christos int wpas_mesh_add_interface(struct wpa_supplicant *wpa_s, char *ifname, 852 1.1 christos size_t len) 853 1.1 christos { 854 1.1 christos struct wpa_interface iface; 855 1.1 christos struct wpa_supplicant *mesh_wpa_s; 856 1.1 christos u8 addr[ETH_ALEN]; 857 1.1 christos 858 1.1 christos if (ifname[0] == '\0' && wpas_mesh_get_ifname(wpa_s, ifname, len) < 0) 859 1.1 christos return -1; 860 1.1 christos 861 1.1 christos if (wpa_drv_if_add(wpa_s, WPA_IF_MESH, ifname, NULL, NULL, NULL, addr, 862 1.1 christos NULL) < 0) { 863 1.1 christos wpa_printf(MSG_ERROR, 864 1.1 christos "mesh: Failed to create new mesh interface"); 865 1.1 christos return -1; 866 1.1 christos } 867 1.1 christos wpa_printf(MSG_INFO, "mesh: Created virtual interface %s addr " 868 1.1 christos MACSTR, ifname, MAC2STR(addr)); 869 1.1 christos 870 1.1 christos os_memset(&iface, 0, sizeof(iface)); 871 1.1 christos iface.ifname = ifname; 872 1.1 christos iface.driver = wpa_s->driver->name; 873 1.1 christos iface.driver_param = wpa_s->conf->driver_param; 874 1.1 christos iface.ctrl_interface = wpa_s->conf->ctrl_interface; 875 1.1 christos 876 1.1 christos mesh_wpa_s = wpa_supplicant_add_iface(wpa_s->global, &iface, wpa_s); 877 1.1 christos if (!mesh_wpa_s) { 878 1.1 christos wpa_printf(MSG_ERROR, 879 1.1 christos "mesh: Failed to create new wpa_supplicant interface"); 880 1.1.1.2 christos wpa_drv_if_remove(wpa_s, WPA_IF_MESH, ifname); 881 1.1 christos return -1; 882 1.1 christos } 883 1.1 christos mesh_wpa_s->mesh_if_created = 1; 884 1.1 christos return 0; 885 1.1 christos } 886 1.1.1.2 christos 887 1.1.1.2 christos 888 1.1.1.2 christos int wpas_mesh_peer_remove(struct wpa_supplicant *wpa_s, const u8 *addr) 889 1.1.1.2 christos { 890 1.1.1.2 christos return mesh_mpm_close_peer(wpa_s, addr); 891 1.1.1.2 christos } 892 1.1.1.2 christos 893 1.1.1.2 christos 894 1.1.1.2 christos int wpas_mesh_peer_add(struct wpa_supplicant *wpa_s, const u8 *addr, 895 1.1.1.2 christos int duration) 896 1.1.1.2 christos { 897 1.1.1.2 christos return mesh_mpm_connect_peer(wpa_s, addr, duration); 898 1.1.1.2 christos } 899