| 1 | /* |
|---|
| 2 | * Wireless Network Adapter Configuration Utility |
|---|
| 3 | * |
|---|
| 4 | * Copyright 2006, Broadcom Corporation |
|---|
| 5 | * All Rights Reserved. |
|---|
| 6 | * |
|---|
| 7 | * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; |
|---|
| 8 | * the contents of this file may not be disclosed to third parties, copied |
|---|
| 9 | * or duplicated in any form, in whole or in part, without the prior |
|---|
| 10 | * written permission of Broadcom Corporation. |
|---|
| 11 | * |
|---|
| 12 | * $Id$ |
|---|
| 13 | */ |
|---|
| 14 | |
|---|
| 15 | #include <typedefs.h> |
|---|
| 16 | #include <stdio.h> |
|---|
| 17 | #include <stdlib.h> |
|---|
| 18 | #include <string.h> |
|---|
| 19 | #include <assert.h> |
|---|
| 20 | #include <bcmnvram.h> |
|---|
| 21 | #include <bcmutils.h> |
|---|
| 22 | #include <bcmparams.h> |
|---|
| 23 | #include <shutils.h> |
|---|
| 24 | #include <wlutils.h> |
|---|
| 25 | |
|---|
| 26 | /* phy types */ |
|---|
| 27 | #define PHY_TYPE_A 0 |
|---|
| 28 | #define PHY_TYPE_B 1 |
|---|
| 29 | #define PHY_TYPE_G 2 |
|---|
| 30 | #define PHY_TYPE_N 4 |
|---|
| 31 | #define PHY_TYPE_LP 5 |
|---|
| 32 | #define PHY_TYPE_NULL 0xf |
|---|
| 33 | |
|---|
| 34 | /* how many times to attempt to bring up a virtual i/f when |
|---|
| 35 | * we are in APSTA mode and IOVAR set of "bss" "up" returns busy |
|---|
| 36 | */ |
|---|
| 37 | #define MAX_BSS_UP_RETRIES 5 |
|---|
| 38 | |
|---|
| 39 | /* notify the average dma xfer rate (in kbps) to the driver */ |
|---|
| 40 | #define AVG_DMA_XFER_RATE 120000 |
|---|
| 41 | |
|---|
| 42 | /* parts of an idcode: */ |
|---|
| 43 | #define IDCODE_MFG_MASK 0x00000fff |
|---|
| 44 | #define IDCODE_MFG_SHIFT 0 |
|---|
| 45 | #define IDCODE_ID_MASK 0x0ffff000 |
|---|
| 46 | #define IDCODE_ID_SHIFT 12 |
|---|
| 47 | #define IDCODE_REV_MASK 0xf0000000 |
|---|
| 48 | #define IDCODE_REV_SHIFT 28 |
|---|
| 49 | |
|---|
| 50 | /* |
|---|
| 51 | * Debugging Macros |
|---|
| 52 | */ |
|---|
| 53 | #define WLCONF_DBG(fmt, arg...) |
|---|
| 54 | #define WL_IOCTL(name, cmd, buf, len) (ret = wl_ioctl(name, cmd, buf, len)) |
|---|
| 55 | #define WL_SETINT(name, cmd, val) (ret = wlconf_setint(name, cmd, val)) |
|---|
| 56 | #define WL_GETINT(name, cmd, pval) (ret = wlconf_getint(name, cmd, pval)) |
|---|
| 57 | #define WL_IOVAR_SET(ifname, iovar, param, paramlen) (ret = wl_iovar_set(ifname, iovar, \ |
|---|
| 58 | param, paramlen)) |
|---|
| 59 | #define WL_IOVAR_SETINT(ifname, iovar, val) (ret = wl_iovar_setint(ifname, iovar, val)) |
|---|
| 60 | #define WL_IOVAR_GETINT(ifname, iovar, val) (ret = wl_iovar_getint(ifname, iovar, val)) |
|---|
| 61 | #define WL_BSSIOVAR_SETBUF(ifname, iovar, bssidx, param, paramlen, buf, buflen) \ |
|---|
| 62 | (ret = wl_bssiovar_setbuf(ifname, iovar, bssidx, param, paramlen, buf, buflen)) |
|---|
| 63 | #define WL_BSSIOVAR_SET(ifname, iovar, bssidx, param, paramlen) \ |
|---|
| 64 | (ret = wl_bssiovar_set(ifname, iovar, bssidx, param, paramlen)) |
|---|
| 65 | #define WL_BSSIOVAR_GET(ifname, iovar, bssidx, param, paramlen) \ |
|---|
| 66 | (ret = wl_bssiovar_get(ifname, iovar, bssidx, param, paramlen)) |
|---|
| 67 | #define WL_BSSIOVAR_SETINT(ifname, iovar, bssidx, val) (ret = wl_bssiovar_setint(ifname, iovar, \ |
|---|
| 68 | bssidx, val)) |
|---|
| 69 | |
|---|
| 70 | #ifdef BCMWPA2 |
|---|
| 71 | #define CHECK_PSK(mode) ((mode) & (WPA_AUTH_PSK | WPA2_AUTH_PSK)) |
|---|
| 72 | #else |
|---|
| 73 | #define CHECK_PSK(mode) ((mode) & WPA_AUTH_PSK) |
|---|
| 74 | #endif |
|---|
| 75 | |
|---|
| 76 | /* prototypes */ |
|---|
| 77 | struct bsscfg_list *wlconf_get_bsscfgs(char* ifname, char* prefix); |
|---|
| 78 | int wlconf(char *name); |
|---|
| 79 | int wlconf_down(char *name); |
|---|
| 80 | |
|---|
| 81 | static int |
|---|
| 82 | wlconf_getint(char* ifname, int cmd, int *pval) |
|---|
| 83 | { |
|---|
| 84 | return wl_ioctl(ifname, cmd, pval, sizeof(int)); |
|---|
| 85 | } |
|---|
| 86 | |
|---|
| 87 | static int |
|---|
| 88 | wlconf_setint(char* ifname, int cmd, int val) |
|---|
| 89 | { |
|---|
| 90 | return wl_ioctl(ifname, cmd, &val, sizeof(int)); |
|---|
| 91 | } |
|---|
| 92 | |
|---|
| 93 | /* set WEP key */ |
|---|
| 94 | static int |
|---|
| 95 | wlconf_set_wep_key(char *name, char *prefix, int bsscfg_idx, int i) |
|---|
| 96 | { |
|---|
| 97 | wl_wsec_key_t key; |
|---|
| 98 | char wl_key[] = "wlXXXXXXXXXX_keyXXXXXXXXXX"; |
|---|
| 99 | char *keystr, hex[] = "XX"; |
|---|
| 100 | unsigned char *data = key.data; |
|---|
| 101 | int ret = 0; |
|---|
| 102 | |
|---|
| 103 | memset(&key, 0, sizeof(key)); |
|---|
| 104 | key.index = i - 1; |
|---|
| 105 | sprintf(wl_key, "%skey%d", prefix, i); |
|---|
| 106 | keystr = nvram_safe_get(wl_key); |
|---|
| 107 | |
|---|
| 108 | switch (strlen(keystr)) { |
|---|
| 109 | case WEP1_KEY_SIZE: |
|---|
| 110 | case WEP128_KEY_SIZE: |
|---|
| 111 | key.len = strlen(keystr); |
|---|
| 112 | strcpy((char *)key.data, keystr); |
|---|
| 113 | break; |
|---|
| 114 | case WEP1_KEY_HEX_SIZE: |
|---|
| 115 | case WEP128_KEY_HEX_SIZE: |
|---|
| 116 | key.len = strlen(keystr) / 2; |
|---|
| 117 | while (*keystr) { |
|---|
| 118 | strncpy(hex, keystr, 2); |
|---|
| 119 | *data++ = (unsigned char) strtoul(hex, NULL, 16); |
|---|
| 120 | keystr += 2; |
|---|
| 121 | } |
|---|
| 122 | break; |
|---|
| 123 | default: |
|---|
| 124 | key.len = 0; |
|---|
| 125 | break; |
|---|
| 126 | } |
|---|
| 127 | |
|---|
| 128 | /* Set current WEP key */ |
|---|
| 129 | if (key.len && i == atoi(nvram_safe_get(strcat_r(prefix, "key", wl_key)))) |
|---|
| 130 | key.flags = WL_PRIMARY_KEY; |
|---|
| 131 | |
|---|
| 132 | WL_BSSIOVAR_SET(name, "wsec_key", bsscfg_idx, &key, sizeof(key)); |
|---|
| 133 | |
|---|
| 134 | return ret; |
|---|
| 135 | } |
|---|
| 136 | |
|---|
| 137 | extern struct nvram_tuple router_defaults[]; |
|---|
| 138 | |
|---|
| 139 | /* Keep this table in order */ |
|---|
| 140 | static struct { |
|---|
| 141 | int locale; |
|---|
| 142 | char **names; |
|---|
| 143 | char *abbr; |
|---|
| 144 | } countries[] = { |
|---|
| 145 | { WLC_WW, ((char *[]) { "Worldwide", "WW", NULL }), "AU" }, |
|---|
| 146 | { WLC_THA, ((char *[]) { "Thailand", "THA", NULL }), "TH" }, |
|---|
| 147 | { WLC_ISR, ((char *[]) { "Israel", "ISR", NULL }), "IL" }, |
|---|
| 148 | { WLC_JDN, ((char *[]) { "Jordan", "JDN", NULL }), "JO" }, |
|---|
| 149 | { WLC_PRC, ((char *[]) { "China", "P.R. China", "PRC", NULL }), "CN" }, |
|---|
| 150 | { WLC_JPN, ((char *[]) { "Japan", "JPN", NULL }), "JP" }, |
|---|
| 151 | { WLC_FCC, ((char *[]) { "USA", "Canada", "ANZ", "New Zealand", "FCC", NULL }), "US" }, |
|---|
| 152 | { WLC_EUR, ((char *[]) { "Europe", "EUR", NULL }), "DE" }, |
|---|
| 153 | { WLC_USL, ((char *[]) { "USA Low", "USALow", "USL", NULL }), "US" }, |
|---|
| 154 | { WLC_JPH, ((char *[]) { "Japan High", "JapanHigh", "JPH", NULL }), "JP" }, |
|---|
| 155 | { WLC_ALL, ((char *[]) { "All", "AllTheChannels", NULL }), "All" }, |
|---|
| 156 | }; |
|---|
| 157 | |
|---|
| 158 | /* validate/restore all per-interface related variables */ |
|---|
| 159 | static void |
|---|
| 160 | wlconf_validate_all(char *prefix, bool restore) |
|---|
| 161 | { |
|---|
| 162 | struct nvram_tuple *t; |
|---|
| 163 | char tmp[100]; |
|---|
| 164 | char *v; |
|---|
| 165 | for (t = router_defaults; t->name; t++) { |
|---|
| 166 | if (!strncmp(t->name, "wl_", 3)) { |
|---|
| 167 | strcat_r(prefix, &t->name[3], tmp); |
|---|
| 168 | if (!restore && nvram_get(tmp)) |
|---|
| 169 | continue; |
|---|
| 170 | v = nvram_get(t->name); |
|---|
| 171 | nvram_set(tmp, v ? v : t->value); |
|---|
| 172 | } |
|---|
| 173 | } |
|---|
| 174 | } |
|---|
| 175 | |
|---|
| 176 | /* restore specific per-interface variable */ |
|---|
| 177 | static void |
|---|
| 178 | wlconf_restore_var(char *prefix, char *name) |
|---|
| 179 | { |
|---|
| 180 | struct nvram_tuple *t; |
|---|
| 181 | char tmp[100]; |
|---|
| 182 | for (t = router_defaults; t->name; t++) { |
|---|
| 183 | if (!strncmp(t->name, "wl_", 3) && !strcmp(&t->name[3], name)) { |
|---|
| 184 | nvram_set(strcat_r(prefix, name, tmp), t->value); |
|---|
| 185 | break; |
|---|
| 186 | } |
|---|
| 187 | } |
|---|
| 188 | } |
|---|
| 189 | static int |
|---|
| 190 | wlconf_akm_options(char *prefix) |
|---|
| 191 | { |
|---|
| 192 | char comb[32]; |
|---|
| 193 | char *wl_akm; |
|---|
| 194 | int akm_ret_val = 0; |
|---|
| 195 | char akm[32]; |
|---|
| 196 | char *next; |
|---|
| 197 | |
|---|
| 198 | wl_akm = nvram_default_get(strcat_r(prefix, "akm", comb),"disabled"); |
|---|
| 199 | foreach(akm, wl_akm, next) { |
|---|
| 200 | if (!strcmp(akm, "wpa")) |
|---|
| 201 | akm_ret_val |= WPA_AUTH_UNSPECIFIED; |
|---|
| 202 | if (!strcmp(akm, "psk")) |
|---|
| 203 | akm_ret_val |= WPA_AUTH_PSK; |
|---|
| 204 | #ifdef BCMWPA2 |
|---|
| 205 | if (!strcmp(akm, "wpa2")) |
|---|
| 206 | akm_ret_val |= WPA2_AUTH_UNSPECIFIED; |
|---|
| 207 | if (!strcmp(akm, "psk2")) |
|---|
| 208 | akm_ret_val |= WPA2_AUTH_PSK; |
|---|
| 209 | #endif |
|---|
| 210 | } |
|---|
| 211 | return akm_ret_val; |
|---|
| 212 | } |
|---|
| 213 | |
|---|
| 214 | /* Set up wsec */ |
|---|
| 215 | static int |
|---|
| 216 | wlconf_set_wsec(char *ifname, char *prefix, int bsscfg_idx) |
|---|
| 217 | { |
|---|
| 218 | char tmp[100]; |
|---|
| 219 | int val = 0; |
|---|
| 220 | int akm_val; |
|---|
| 221 | int ret; |
|---|
| 222 | |
|---|
| 223 | nvram_default_get(strcat_r(prefix, "crypto", tmp),"off"); |
|---|
| 224 | /* Set wsec bitvec */ |
|---|
| 225 | akm_val = wlconf_akm_options(prefix); |
|---|
| 226 | if (akm_val != 0) { |
|---|
| 227 | if (nvram_match(strcat_r(prefix, "crypto", tmp), "tkip")) |
|---|
| 228 | val = TKIP_ENABLED; |
|---|
| 229 | else if (nvram_match(strcat_r(prefix, "crypto", tmp), "aes")) |
|---|
| 230 | val = AES_ENABLED; |
|---|
| 231 | else if (nvram_match(strcat_r(prefix, "crypto", tmp), "tkip+aes")) |
|---|
| 232 | val = TKIP_ENABLED | AES_ENABLED; |
|---|
| 233 | } |
|---|
| 234 | if (nvram_default_match(strcat_r(prefix, "wep", tmp), "enabled","disabled")) |
|---|
| 235 | val |= WEP_ENABLED; |
|---|
| 236 | WL_BSSIOVAR_SETINT(ifname, "wsec", bsscfg_idx, val); |
|---|
| 237 | /* Set wsec restrict if WSEC_ENABLED */ |
|---|
| 238 | WL_BSSIOVAR_SETINT(ifname, "wsec_restrict", bsscfg_idx, val ? 1 : 0); |
|---|
| 239 | |
|---|
| 240 | return 0; |
|---|
| 241 | } |
|---|
| 242 | |
|---|
| 243 | #ifdef BCMWPA2 |
|---|
| 244 | static int |
|---|
| 245 | wlconf_set_preauth(char *name, int bsscfg_idx, int preauth) |
|---|
| 246 | { |
|---|
| 247 | uint cap; |
|---|
| 248 | int ret; |
|---|
| 249 | |
|---|
| 250 | WL_BSSIOVAR_GET(name, "wpa_cap", bsscfg_idx, &cap, sizeof(uint)); |
|---|
| 251 | if (ret != 0) return -1; |
|---|
| 252 | |
|---|
| 253 | if (preauth) |
|---|
| 254 | cap |= WPA_CAP_WPA2_PREAUTH; |
|---|
| 255 | else |
|---|
| 256 | cap &= ~WPA_CAP_WPA2_PREAUTH; |
|---|
| 257 | |
|---|
| 258 | WL_BSSIOVAR_SETINT(name, "wpa_cap", bsscfg_idx, cap); |
|---|
| 259 | |
|---|
| 260 | return ret; |
|---|
| 261 | } |
|---|
| 262 | #endif /* BCMWPA2 */ |
|---|
| 263 | |
|---|
| 264 | /* Set up WME */ |
|---|
| 265 | static void |
|---|
| 266 | wlconf_set_wme(char *name, char *prefix) |
|---|
| 267 | { |
|---|
| 268 | int i, j, k; |
|---|
| 269 | int val, ret; |
|---|
| 270 | int phytype, gmode, no_ack, apsd, dp[2]; |
|---|
| 271 | edcf_acparam_t *acparams; |
|---|
| 272 | char buf[WLC_IOCTL_MAXLEN]; |
|---|
| 273 | char *v, *nv_value, nv[100]; |
|---|
| 274 | char nv_name[] = "%swme_%s_%s"; |
|---|
| 275 | char *ac[] = {"be", "bk", "vi", "vo"}; |
|---|
| 276 | char *cwmin, *cwmax, *aifsn, *txop_b, *txop_ag, *admin_forced, *oldest_first; |
|---|
| 277 | char **locals[] = { &cwmin, &cwmax, &aifsn, &txop_b, &txop_ag, &admin_forced, |
|---|
| 278 | &oldest_first }; |
|---|
| 279 | struct {char *req; char *str;} mode[] = {{"wme_ac_sta", "sta"}, {"wme_ac_ap", "ap"}}; |
|---|
| 280 | |
|---|
| 281 | /* query the phy type */ |
|---|
| 282 | WL_IOCTL(name, WLC_GET_PHYTYPE, &phytype, sizeof(phytype)); |
|---|
| 283 | /* get gmode */ |
|---|
| 284 | gmode = atoi(nvram_default_get(strcat_r(prefix, "gmode", nv),"1")); |
|---|
| 285 | |
|---|
| 286 | /* WME sta setting first */ |
|---|
| 287 | for (i = 0; i < 2; i++) { |
|---|
| 288 | /* build request block */ |
|---|
| 289 | memset(buf, 0, sizeof(buf)); |
|---|
| 290 | strcpy(buf, mode[i].req); |
|---|
| 291 | /* put push wmeac params after "wme-ac" in buf */ |
|---|
| 292 | acparams = (edcf_acparam_t *)(buf + strlen(buf) + 1); |
|---|
| 293 | dp[i] = 0; |
|---|
| 294 | for (j = 0; j < AC_COUNT; j++) { |
|---|
| 295 | /* get packed nvram parameter */ |
|---|
| 296 | snprintf(nv, sizeof(nv), nv_name, prefix, mode[i].str, ac[j]); |
|---|
| 297 | nv_value = nvram_safe_get(nv); |
|---|
| 298 | strcpy(nv, nv_value); |
|---|
| 299 | /* unpack it */ |
|---|
| 300 | v = nv; |
|---|
| 301 | for (k = 0; k < (sizeof(locals) / sizeof(locals[0])); k++) { |
|---|
| 302 | *locals[k] = v; |
|---|
| 303 | while (*v && *v != ' ') |
|---|
| 304 | v++; |
|---|
| 305 | if (*v) { |
|---|
| 306 | *v = 0; |
|---|
| 307 | v++; |
|---|
| 308 | } |
|---|
| 309 | } |
|---|
| 310 | |
|---|
| 311 | /* update CWmin */ |
|---|
| 312 | acparams->ECW &= ~EDCF_ECWMIN_MASK; |
|---|
| 313 | val = atoi(cwmin); |
|---|
| 314 | for (val++, k = 0; val; val >>= 1, k++); |
|---|
| 315 | acparams->ECW |= (k ? k - 1 : 0) & EDCF_ECWMIN_MASK; |
|---|
| 316 | /* update CWmax */ |
|---|
| 317 | acparams->ECW &= ~EDCF_ECWMAX_MASK; |
|---|
| 318 | val = atoi(cwmax); |
|---|
| 319 | for (val++, k = 0; val; val >>= 1, k++); |
|---|
| 320 | acparams->ECW |= ((k ? k - 1 : 0) << EDCF_ECWMAX_SHIFT) & EDCF_ECWMAX_MASK; |
|---|
| 321 | /* update AIFSN */ |
|---|
| 322 | acparams->ACI &= ~EDCF_AIFSN_MASK; |
|---|
| 323 | acparams->ACI |= atoi(aifsn) & EDCF_AIFSN_MASK; |
|---|
| 324 | /* update ac */ |
|---|
| 325 | acparams->ACI &= ~EDCF_ACI_MASK; |
|---|
| 326 | acparams->ACI |= j << EDCF_ACI_SHIFT; |
|---|
| 327 | /* update TXOP */ |
|---|
| 328 | if (phytype == PHY_TYPE_B || gmode == 0) |
|---|
| 329 | val = atoi(txop_b); |
|---|
| 330 | else |
|---|
| 331 | val = atoi(txop_ag); |
|---|
| 332 | acparams->TXOP = val / 32; |
|---|
| 333 | /* update acm */ |
|---|
| 334 | acparams->ACI &= ~EDCF_ACM_MASK; |
|---|
| 335 | val = strcmp(admin_forced, "on") ? 0 : 1; |
|---|
| 336 | acparams->ACI |= val << 4; |
|---|
| 337 | |
|---|
| 338 | /* configure driver */ |
|---|
| 339 | WL_IOCTL(name, WLC_SET_VAR, buf, sizeof(buf)); |
|---|
| 340 | } |
|---|
| 341 | } |
|---|
| 342 | |
|---|
| 343 | /* set no-ack */ |
|---|
| 344 | v = nvram_default_get(strcat_r(prefix, "wme_no_ack", nv),"off"); |
|---|
| 345 | no_ack = strcmp(v, "on") ? 0 : 1; |
|---|
| 346 | WL_IOVAR_SETINT(name, "wme_noack", no_ack); |
|---|
| 347 | |
|---|
| 348 | /* set APSD */ |
|---|
| 349 | v = nvram_default_get(strcat_r(prefix, "wme_apsd", nv),"on"); |
|---|
| 350 | apsd = strcmp(v, "on") ? 0 : 1; |
|---|
| 351 | WL_IOVAR_SETINT(name, "wme_apsd", apsd); |
|---|
| 352 | |
|---|
| 353 | /* set per-AC discard policy */ |
|---|
| 354 | strcpy(buf, "wme_dp"); |
|---|
| 355 | WL_IOVAR_SETINT(name, "wme_dp", dp[1]); |
|---|
| 356 | } |
|---|
| 357 | |
|---|
| 358 | #if defined(linux) |
|---|
| 359 | #include <unistd.h> |
|---|
| 360 | static void |
|---|
| 361 | sleep_ms(const unsigned int ms) |
|---|
| 362 | { |
|---|
| 363 | usleep(1000*ms); |
|---|
| 364 | } |
|---|
| 365 | #else |
|---|
| 366 | #error "sleep_ms() not defined for this OS!!!" |
|---|
| 367 | #endif /* defined(linux) */ |
|---|
| 368 | |
|---|
| 369 | /* |
|---|
| 370 | * The following condition(s) must be met when Auto Channel Selection |
|---|
| 371 | * is enabled. |
|---|
| 372 | * - the I/F is up (change radio channel requires it is up?) |
|---|
| 373 | * - the AP must not be associated (setting SSID to empty should |
|---|
| 374 | * make sure it for us) |
|---|
| 375 | */ |
|---|
| 376 | static uint8 |
|---|
| 377 | wlconf_auto_channel(char *name) |
|---|
| 378 | { |
|---|
| 379 | int chosen = 0; |
|---|
| 380 | wl_uint32_list_t request; |
|---|
| 381 | int phytype; |
|---|
| 382 | int ret; |
|---|
| 383 | int i; |
|---|
| 384 | |
|---|
| 385 | /* query the phy type */ |
|---|
| 386 | WL_GETINT(name, WLC_GET_PHYTYPE, &phytype); |
|---|
| 387 | |
|---|
| 388 | request.count = 0; /* let the ioctl decide */ |
|---|
| 389 | WL_IOCTL(name, WLC_START_CHANNEL_SEL, &request, sizeof(request)); |
|---|
| 390 | if (!ret) { |
|---|
| 391 | sleep_ms(phytype == PHY_TYPE_A ? 1000 : 750); |
|---|
| 392 | for (i = 0; i < 100; i++) { |
|---|
| 393 | WL_GETINT(name, WLC_GET_CHANNEL_SEL, &chosen); |
|---|
| 394 | if (!ret) |
|---|
| 395 | break; |
|---|
| 396 | sleep_ms(100); |
|---|
| 397 | } |
|---|
| 398 | } |
|---|
| 399 | WLCONF_DBG("interface %s: channel selected %d\n", name, chosen); |
|---|
| 400 | return chosen; |
|---|
| 401 | } |
|---|
| 402 | |
|---|
| 403 | static chanspec_t |
|---|
| 404 | wlconf_auto_chanspec(char *name,char *prefix) |
|---|
| 405 | { |
|---|
| 406 | chanspec_t chosen = 0; |
|---|
| 407 | wl_uint32_list_t request; |
|---|
| 408 | char tmp[100]; |
|---|
| 409 | int bandtype; |
|---|
| 410 | int ret; |
|---|
| 411 | int i; |
|---|
| 412 | int chanspec_asus = 0; |
|---|
| 413 | |
|---|
| 414 | /* query the band type */ |
|---|
| 415 | WL_GETINT(name, WLC_GET_BAND, &bandtype); |
|---|
| 416 | |
|---|
| 417 | request.count = 0; /* let the ioctl decide */ |
|---|
| 418 | WL_IOCTL(name, WLC_START_CHANNEL_SEL, &request, sizeof(request)); |
|---|
| 419 | if (!ret) { |
|---|
| 420 | sleep_ms(1000); |
|---|
| 421 | for (i = 0; i < 100; i++) { |
|---|
| 422 | WL_IOVAR_GETINT(name, "apcschspec", (void *)&chosen); |
|---|
| 423 | if (!ret) |
|---|
| 424 | break; |
|---|
| 425 | sleep_ms(100); |
|---|
| 426 | } |
|---|
| 427 | } |
|---|
| 428 | |
|---|
| 429 | WLCONF_DBG("interface %s: chanspec selected %04x\n", name, chosen); |
|---|
| 430 | return chosen; |
|---|
| 431 | } |
|---|
| 432 | |
|---|
| 433 | |
|---|
| 434 | /* PHY type/BAND conversion */ |
|---|
| 435 | #define WLCONF_PHYTYPE2BAND(phy) ((phy) == PHY_TYPE_A ? WLC_BAND_5G : WLC_BAND_2G) |
|---|
| 436 | /* PHY type conversion */ |
|---|
| 437 | #define WLCONF_PHYTYPE2STR(phy) ((phy) == PHY_TYPE_A ? "a" : \ |
|---|
| 438 | (phy) == PHY_TYPE_B ? "b" : \ |
|---|
| 439 | (phy) == PHY_TYPE_LP ? "l" : \ |
|---|
| 440 | (phy) == PHY_TYPE_G ? "g" : "n") |
|---|
| 441 | #define WLCONF_STR2PHYTYPE(phy) ((phy) && (phy)[0] == 'a' ? PHY_TYPE_A : \ |
|---|
| 442 | (phy) && (phy)[0] == 'b' ? PHY_TYPE_B : \ |
|---|
| 443 | (phy) && (phy)[0] == 'l' ? PHY_TYPE_LP : \ |
|---|
| 444 | (phy) && (phy)[0] == 'g' ? PHY_TYPE_G : PHY_TYPE_N) |
|---|
| 445 | |
|---|
| 446 | |
|---|
| 447 | #define PREFIX_LEN 32 /* buffer size for wlXXX_ prefix */ |
|---|
| 448 | |
|---|
| 449 | struct bsscfg_info { |
|---|
| 450 | int idx; /* bsscfg index */ |
|---|
| 451 | char ifname[PREFIX_LEN]; /* OS name of interface (debug only) */ |
|---|
| 452 | char prefix[PREFIX_LEN]; /* prefix for nvram params (eg. "wl0.1_") */ |
|---|
| 453 | }; |
|---|
| 454 | |
|---|
| 455 | struct bsscfg_list { |
|---|
| 456 | int count; |
|---|
| 457 | struct bsscfg_info bsscfgs[WL_MAXBSSCFG]; |
|---|
| 458 | }; |
|---|
| 459 | |
|---|
| 460 | struct bsscfg_list * |
|---|
| 461 | wlconf_get_bsscfgs(char* ifname, char* prefix) |
|---|
| 462 | { |
|---|
| 463 | char var[80]; |
|---|
| 464 | char tmp[100]; |
|---|
| 465 | char *next; |
|---|
| 466 | |
|---|
| 467 | struct bsscfg_list *bclist; |
|---|
| 468 | struct bsscfg_info *bsscfg; |
|---|
| 469 | |
|---|
| 470 | bclist = (struct bsscfg_list*)malloc(sizeof(struct bsscfg_list)); |
|---|
| 471 | if (bclist == NULL) |
|---|
| 472 | return NULL; |
|---|
| 473 | memset(bclist, 0, sizeof(struct bsscfg_list)); |
|---|
| 474 | |
|---|
| 475 | /* Set up Primary BSS Config information */ |
|---|
| 476 | bsscfg = &bclist->bsscfgs[0]; |
|---|
| 477 | bsscfg->idx = 0; |
|---|
| 478 | strncpy(bsscfg->ifname, ifname, PREFIX_LEN-1); |
|---|
| 479 | strcpy(bsscfg->prefix, prefix); |
|---|
| 480 | bclist->count = 1; |
|---|
| 481 | |
|---|
| 482 | /* additional virtual BSS Configs from wlX_vifs */ |
|---|
| 483 | if (nvram_default_match(strcat_r(prefix, "mode", tmp),"ap","ap") || nvram_match(strcat_r(prefix, "mode", tmp),"apsta") || nvram_match(strcat_r(prefix, "mode", tmp),"apstawet")) |
|---|
| 484 | { |
|---|
| 485 | foreach(var, nvram_safe_get(strcat_r(prefix, "vifs", tmp)), next) { |
|---|
| 486 | if (bclist->count == WL_MAXBSSCFG) { |
|---|
| 487 | WLCONF_DBG("wlconf(%s): exceeded max number of BSS Configs (%d)" |
|---|
| 488 | "in nvram %s\n" |
|---|
| 489 | "while configuring interface \"%s\"\n", |
|---|
| 490 | ifname, WL_MAXBSSCFG, strcat_r(prefix, "vifs", tmp), var); |
|---|
| 491 | continue; |
|---|
| 492 | } |
|---|
| 493 | bsscfg = &bclist->bsscfgs[bclist->count]; |
|---|
| 494 | if (get_ifname_unit(var, NULL, &bsscfg->idx) != 0) { |
|---|
| 495 | WLCONF_DBG("wlconfg(%s): unable to parse unit.subunit in interface " |
|---|
| 496 | "name \"%s\"\n", |
|---|
| 497 | ifname, var); |
|---|
| 498 | continue; |
|---|
| 499 | } |
|---|
| 500 | strncpy(bsscfg->ifname, var, PREFIX_LEN-1); |
|---|
| 501 | snprintf(bsscfg->prefix, PREFIX_LEN, "%s_", bsscfg->ifname); |
|---|
| 502 | bclist->count++; |
|---|
| 503 | } |
|---|
| 504 | } |
|---|
| 505 | |
|---|
| 506 | return bclist; |
|---|
| 507 | } |
|---|
| 508 | |
|---|
| 509 | static void |
|---|
| 510 | wlconf_security_options(char *name, char *prefix, int bsscfg_idx, bool wet) |
|---|
| 511 | { |
|---|
| 512 | int i; |
|---|
| 513 | int val; |
|---|
| 514 | int ret; |
|---|
| 515 | char tmp[100]; |
|---|
| 516 | |
|---|
| 517 | /* Set WSEC */ |
|---|
| 518 | /* |
|---|
| 519 | * Need to check errors (card may have changed) and change to |
|---|
| 520 | * defaults since the new chip may not support the requested |
|---|
| 521 | * encryptions after the card has been changed. |
|---|
| 522 | */ |
|---|
| 523 | if (wlconf_set_wsec(name, prefix, bsscfg_idx)) { |
|---|
| 524 | /* change nvram only, code below will pass them on */ |
|---|
| 525 | wlconf_restore_var(prefix, "auth_mode"); |
|---|
| 526 | wlconf_restore_var(prefix, "auth"); |
|---|
| 527 | /* reset wep to default */ |
|---|
| 528 | wlconf_restore_var(prefix, "crypto"); |
|---|
| 529 | wlconf_restore_var(prefix, "wep"); |
|---|
| 530 | wlconf_set_wsec(name, prefix, bsscfg_idx); |
|---|
| 531 | } |
|---|
| 532 | |
|---|
| 533 | val = wlconf_akm_options(prefix); |
|---|
| 534 | /* In wet mode enable in driver wpa supplicant */ |
|---|
| 535 | if (wet && (CHECK_PSK(val))) { |
|---|
| 536 | wsec_pmk_t psk; |
|---|
| 537 | char *key; |
|---|
| 538 | |
|---|
| 539 | if (((key = nvram_get(strcat_r(prefix, "wpa_psk", tmp))) != NULL) && |
|---|
| 540 | (strlen(key) < WSEC_MAX_PSK_LEN)) { |
|---|
| 541 | psk.key_len = (ushort) strlen(key); |
|---|
| 542 | psk.flags = WSEC_PASSPHRASE; |
|---|
| 543 | strcpy((char *)psk.key, key); |
|---|
| 544 | WL_IOCTL(name, WLC_SET_WSEC_PMK, &psk, sizeof(psk)); |
|---|
| 545 | } |
|---|
| 546 | wl_iovar_setint(name, "sup_wpa", 1); |
|---|
| 547 | } |
|---|
| 548 | WL_BSSIOVAR_SETINT(name, "wpa_auth", bsscfg_idx, val); |
|---|
| 549 | |
|---|
| 550 | /* EAP Restrict if we have an AKM or radius authentication */ |
|---|
| 551 | val = ((val != 0) || (nvram_default_match(strcat_r(prefix, "auth_mode", tmp), "radius","disabled"))); |
|---|
| 552 | WL_BSSIOVAR_SETINT(name, "eap_restrict", bsscfg_idx, val); |
|---|
| 553 | |
|---|
| 554 | /* Set WEP keys */ |
|---|
| 555 | if (nvram_default_match(strcat_r(prefix, "wep", tmp), "enabled","disabled")) { |
|---|
| 556 | for (i = 1; i <= DOT11_MAX_DEFAULT_KEYS; i++) |
|---|
| 557 | wlconf_set_wep_key(name, prefix, bsscfg_idx, i); |
|---|
| 558 | } |
|---|
| 559 | |
|---|
| 560 | /* Set 802.11 authentication mode - open/shared */ |
|---|
| 561 | val = atoi(nvram_default_get(strcat_r(prefix, "auth", tmp),"0")); |
|---|
| 562 | WL_BSSIOVAR_SETINT(name, "auth", bsscfg_idx, val); |
|---|
| 563 | } |
|---|
| 564 | |
|---|
| 565 | /* configure the specified wireless interface */ |
|---|
| 566 | int |
|---|
| 567 | wlconf(char *name) |
|---|
| 568 | { |
|---|
| 569 | int restore_defaults, val, unit, phytype, bandtype, gmode = 0, ret = 0; |
|---|
| 570 | int buflen; |
|---|
| 571 | uint32 *val_ptr; /* required for iovars */ |
|---|
| 572 | int bcmerr; |
|---|
| 573 | int error_bg, error_a; |
|---|
| 574 | struct bsscfg_list *bclist = NULL; |
|---|
| 575 | struct bsscfg_info *bsscfg; |
|---|
| 576 | char tmp[100], prefix[PREFIX_LEN]; |
|---|
| 577 | char var[80], *next, phy[] = "a", *str, *addr = NULL; |
|---|
| 578 | char buf[WLC_IOCTL_MAXLEN]; |
|---|
| 579 | char *country; |
|---|
| 580 | wlc_rev_info_t rev; |
|---|
| 581 | channel_info_t ci; |
|---|
| 582 | struct maclist *maclist; |
|---|
| 583 | struct ether_addr *ea; |
|---|
| 584 | wlc_ssid_t ssid; |
|---|
| 585 | wl_rateset_t rs; |
|---|
| 586 | unsigned int i; |
|---|
| 587 | char eaddr[32]; |
|---|
| 588 | int ap, apsta, wds, sta = 0, wet = 0, mac_spoof = 0; |
|---|
| 589 | char country_code[4]; |
|---|
| 590 | int nas_will_run = 0; |
|---|
| 591 | char *wme, *ba; |
|---|
| 592 | char vif_addr[WLC_IOCTL_SMLEN]; |
|---|
| 593 | #ifdef BCMWPA2 |
|---|
| 594 | char *preauth; |
|---|
| 595 | int set_preauth; |
|---|
| 596 | #endif |
|---|
| 597 | int ii; |
|---|
| 598 | int wlunit = -1; |
|---|
| 599 | int wlsubunit = -1; |
|---|
| 600 | int max_no_vifs = 0; |
|---|
| 601 | int mbsscap = 0; |
|---|
| 602 | int wl_ap_build = 0; /* wl compiled with AP capabilities */ |
|---|
| 603 | char cap[WLC_IOCTL_SMLEN]; |
|---|
| 604 | char caps[WLC_IOCTL_SMLEN]; |
|---|
| 605 | int btc_mode; |
|---|
| 606 | uint32 leddc; |
|---|
| 607 | bool ure_enab = FALSE; |
|---|
| 608 | |
|---|
| 609 | /* wlconf doesn't work for virtual i/f, so if we are given a |
|---|
| 610 | * virtual i/f return 0 if that interface is in it's parent's "vifs" |
|---|
| 611 | * list otherwise return -1 |
|---|
| 612 | */ |
|---|
| 613 | cprintf("get ifname unit\n"); |
|---|
| 614 | if (get_ifname_unit(name, &wlunit, &wlsubunit) == 0) |
|---|
| 615 | { |
|---|
| 616 | if (wlsubunit >= 0) |
|---|
| 617 | { |
|---|
| 618 | /* we have been given a virtual i/f, |
|---|
| 619 | * is it in it's parent i/f's virtual i/f list? |
|---|
| 620 | */ |
|---|
| 621 | sprintf(tmp, "wl%d_vifs", wlunit); |
|---|
| 622 | |
|---|
| 623 | if (strstr(nvram_safe_get(tmp), name) == NULL) |
|---|
| 624 | return -1; /* config error */ |
|---|
| 625 | else |
|---|
| 626 | return 0; /* okay */ |
|---|
| 627 | } |
|---|
| 628 | } |
|---|
| 629 | else |
|---|
| 630 | { |
|---|
| 631 | return -1; |
|---|
| 632 | } |
|---|
| 633 | |
|---|
| 634 | /* clean up tmp */ |
|---|
| 635 | memset(tmp, 0, sizeof(tmp)); |
|---|
| 636 | |
|---|
| 637 | /* because of ifdefs in wl driver, when we don't have AP capabilities we |
|---|
| 638 | * can't use the same iovars to configure the wl. |
|---|
| 639 | * so we use "wl_ap_build" to help us know how to configure the driver |
|---|
| 640 | */ |
|---|
| 641 | cprintf("get caps\n"); |
|---|
| 642 | if (wl_iovar_get(name, "cap", (void *)caps, WLC_IOCTL_SMLEN)) |
|---|
| 643 | return -1; |
|---|
| 644 | |
|---|
| 645 | |
|---|
| 646 | foreach(cap, caps, next) { |
|---|
| 647 | if (!strcmp(cap, "ap")) { |
|---|
| 648 | wl_ap_build = 1; |
|---|
| 649 | } |
|---|
| 650 | else if (!strcmp(cap, "mbss16")) |
|---|
| 651 | { |
|---|
| 652 | max_no_vifs = 16; |
|---|
| 653 | mbsscap = 1; |
|---|
| 654 | } |
|---|
| 655 | else if (!strcmp(cap, "mbss4")) |
|---|
| 656 | { |
|---|
| 657 | max_no_vifs = 4; |
|---|
| 658 | mbsscap = 1; |
|---|
| 659 | } |
|---|
| 660 | } |
|---|
| 661 | cprintf("wl probe\n"); |
|---|
| 662 | /* Check interface (fail silently for non-wl interfaces) */ |
|---|
| 663 | if ((ret = wl_probe(name))) |
|---|
| 664 | return ret; |
|---|
| 665 | |
|---|
| 666 | cprintf("get wl addr\n"); |
|---|
| 667 | /* Get MAC address */ |
|---|
| 668 | (void) wl_hwaddr(name, (uchar *)buf); |
|---|
| 669 | memcpy(vif_addr, buf, ETHER_ADDR_LEN); |
|---|
| 670 | /* Get instance */ |
|---|
| 671 | cprintf("get instance\n"); |
|---|
| 672 | WL_IOCTL(name, WLC_GET_INSTANCE, &unit, sizeof(unit)); |
|---|
| 673 | sprintf(tmp, "wl%d_mbss", unit); |
|---|
| 674 | if (mbsscap) |
|---|
| 675 | { |
|---|
| 676 | nvram_set(tmp,"1"); |
|---|
| 677 | }else |
|---|
| 678 | { |
|---|
| 679 | nvram_set(tmp,"0"); |
|---|
| 680 | } |
|---|
| 681 | /* clean up tmp */ |
|---|
| 682 | memset(tmp, 0, sizeof(tmp)); |
|---|
| 683 | |
|---|
| 684 | snprintf(prefix, sizeof(prefix), "wl%d_", unit); |
|---|
| 685 | |
|---|
| 686 | /* Restore defaults if per-interface parameters do not exist */ |
|---|
| 687 | restore_defaults = !nvram_get(strcat_r(prefix, "ifname", tmp)); |
|---|
| 688 | wlconf_validate_all(prefix, restore_defaults); |
|---|
| 689 | nvram_set(strcat_r(prefix, "ifname", tmp), name); |
|---|
| 690 | nvram_set(strcat_r(prefix, "hwaddr", tmp), ether_etoa((uchar *)buf, eaddr)); |
|---|
| 691 | snprintf(buf, sizeof(buf), "%d", unit); |
|---|
| 692 | nvram_set(strcat_r(prefix, "unit", tmp), buf); |
|---|
| 693 | |
|---|
| 694 | |
|---|
| 695 | cprintf("shut down %s\n",name); |
|---|
| 696 | /* Bring the interface down */ |
|---|
| 697 | WL_IOCTL(name, WLC_DOWN, NULL, sizeof(val)); |
|---|
| 698 | |
|---|
| 699 | cprintf("disable bss %s\n",name); |
|---|
| 700 | /* Disable all BSS Configs */ |
|---|
| 701 | for (i = 0; i < WL_MAXBSSCFG; i++) { |
|---|
| 702 | struct {int bsscfg_idx; int enable;} setbuf; |
|---|
| 703 | setbuf.bsscfg_idx = i; |
|---|
| 704 | setbuf.enable = 0; |
|---|
| 705 | |
|---|
| 706 | ret = wl_iovar_set(name, "bss", &setbuf, sizeof(setbuf)); |
|---|
| 707 | if (ret) { |
|---|
| 708 | wl_iovar_getint(name, "bcmerror", &bcmerr); |
|---|
| 709 | /* fail quietly on a range error since the driver may |
|---|
| 710 | * support fewer bsscfgs than we are prepared to configure |
|---|
| 711 | */ |
|---|
| 712 | if (bcmerr == BCME_RANGE) |
|---|
| 713 | break; |
|---|
| 714 | } |
|---|
| 715 | if (ret) |
|---|
| 716 | WLCONF_DBG("%d:(%s): setting bsscfg #%d iovar \"bss\" to 0" |
|---|
| 717 | " (down) failed, ret = %d, bcmerr = %d\n", |
|---|
| 718 | __LINE__, name, i, ret, bcmerr); |
|---|
| 719 | } |
|---|
| 720 | |
|---|
| 721 | /* Get the list of BSS Configs */ |
|---|
| 722 | bclist = wlconf_get_bsscfgs(name, prefix); |
|---|
| 723 | if (bclist == NULL) { |
|---|
| 724 | ret = -1; |
|---|
| 725 | goto exit; |
|---|
| 726 | } |
|---|
| 727 | |
|---|
| 728 | |
|---|
| 729 | /* create a wlX.Y_ifname nvram setting */ |
|---|
| 730 | for (i = 1; i < bclist->count; i++) { |
|---|
| 731 | bsscfg = &bclist->bsscfgs[i]; |
|---|
| 732 | #if defined(linux) |
|---|
| 733 | strcpy(var, bsscfg->ifname); |
|---|
| 734 | #endif |
|---|
| 735 | nvram_set(strcat_r(bsscfg->prefix, "ifname", tmp), var); |
|---|
| 736 | } |
|---|
| 737 | |
|---|
| 738 | /* wlX_mode settings: AP, STA, WET, BSS/IBSS, APSTA */ |
|---|
| 739 | str = nvram_default_get(strcat_r(prefix, "mode", tmp),"dd-wrt"); |
|---|
| 740 | ap = (!strcmp(str, "") || !strcmp(str, "ap") || !strcmp(str, "mssid")); |
|---|
| 741 | apsta = (!strcmp(str, "apsta") || !strcmp(str, "apstawet") || ((!strcmp(str, "sta") || !strcmp(str, "wet")) && bclist->count > 1)); |
|---|
| 742 | sta = (!strcmp(str, "sta") && bclist->count == 1); |
|---|
| 743 | wds = !strcmp(str, "wds"); |
|---|
| 744 | wet = !strcmp(str, "wet") || !strcmp(str, "apstawet"); |
|---|
| 745 | mac_spoof = !strcmp(str, "mac_spoof"); |
|---|
| 746 | |
|---|
| 747 | if (wet && apsta) { /* URE is enabled */ |
|---|
| 748 | ure_enab = TRUE; |
|---|
| 749 | } |
|---|
| 750 | cprintf("set mssid flags %s\n",name); |
|---|
| 751 | if (wl_ap_build) { |
|---|
| 752 | /* Enable MSSID mode if appropriate */ |
|---|
| 753 | WL_IOVAR_SETINT(name, "mssid", (bclist->count > 1)); |
|---|
| 754 | if (!ure_enab && mbsscap) { |
|---|
| 755 | WL_IOVAR_SETINT(name, "mbss", (bclist->count > 1)); //compatiblitiy with newer drivers |
|---|
| 756 | }else{ |
|---|
| 757 | WL_IOVAR_SETINT(name, "mbss", 0); //compatiblitiy with newer drivers |
|---|
| 758 | |
|---|
| 759 | } |
|---|
| 760 | /* |
|---|
| 761 | * Set SSID for each BSS Config |
|---|
| 762 | */ |
|---|
| 763 | for (i = 0; i < bclist->count; i++) { |
|---|
| 764 | bsscfg = &bclist->bsscfgs[i]; |
|---|
| 765 | strcat_r(bsscfg->prefix, "ssid", tmp); |
|---|
| 766 | ssid.SSID_len = strlen(nvram_default_get(tmp,"dd-wrt")); |
|---|
| 767 | if (ssid.SSID_len > sizeof(ssid.SSID)) |
|---|
| 768 | ssid.SSID_len = sizeof(ssid.SSID); |
|---|
| 769 | strncpy((char *)ssid.SSID, nvram_safe_get(tmp), ssid.SSID_len); |
|---|
| 770 | WLCONF_DBG("wlconfig(%s): configuring bsscfg #%d (%s) with SSID \"%s\"\n", |
|---|
| 771 | name, bsscfg->idx, bsscfg->ifname, nvram_safe_get(tmp)); |
|---|
| 772 | WL_BSSIOVAR_SET(name, "ssid", bsscfg->idx, &ssid, sizeof(ssid)); |
|---|
| 773 | } |
|---|
| 774 | } |
|---|
| 775 | #define MBSS_UC_IDX_MASK (4 - 1) |
|---|
| 776 | |
|---|
| 777 | cprintf("set local addr %s\n",name); |
|---|
| 778 | if (!ure_enab) { |
|---|
| 779 | /* set local bit for our MBSS vif base */ |
|---|
| 780 | if (mbsscap) |
|---|
| 781 | ETHER_SET_LOCALADDR(vif_addr); |
|---|
| 782 | char newmac[32]; |
|---|
| 783 | memcpy(newmac,vif_addr,sizeof(vif_addr)); |
|---|
| 784 | /* construct and set other wlX.Y_hwaddr */ |
|---|
| 785 | for (i = 1; i < 4; i++) { |
|---|
| 786 | snprintf(tmp, sizeof(tmp), "wl%d.%d_hwaddr", unit, i); |
|---|
| 787 | addr = nvram_safe_get(tmp); |
|---|
| 788 | if (mbsscap) |
|---|
| 789 | vif_addr[5] = (newmac[5] & ~MBSS_UC_IDX_MASK) | (MBSS_UC_IDX_MASK & (newmac[5]+i)); |
|---|
| 790 | |
|---|
| 791 | nvram_set(tmp, ether_etoa((uchar *)vif_addr, |
|---|
| 792 | eaddr)); |
|---|
| 793 | } |
|---|
| 794 | /* The addresses are available in NVRAM, so set them */ |
|---|
| 795 | for (i = 1; i < 4; i++) { |
|---|
| 796 | snprintf(tmp, sizeof(tmp), "wl%d.%d_hwaddr", |
|---|
| 797 | unit, i); |
|---|
| 798 | ether_atoe(nvram_safe_get(tmp), eaddr); |
|---|
| 799 | snprintf(tmp, sizeof(tmp), "wl%d.%d", |
|---|
| 800 | unit, i); |
|---|
| 801 | WL_BSSIOVAR_SET(tmp, "cur_etheraddr", i, |
|---|
| 802 | eaddr, ETHER_ADDR_LEN); |
|---|
| 803 | } |
|---|
| 804 | } else { /* URE is enabled */ |
|---|
| 805 | /* URE is on, so set wlX.1 hwaddr is same as that of primary interface */ |
|---|
| 806 | snprintf(tmp, sizeof(tmp), "wl%d.1_hwaddr", unit); |
|---|
| 807 | WL_BSSIOVAR_SET(name, "cur_etheraddr", 1, vif_addr, |
|---|
| 808 | ETHER_ADDR_LEN); |
|---|
| 809 | } |
|---|
| 810 | |
|---|
| 811 | |
|---|
| 812 | /* Set AP mode */ |
|---|
| 813 | val = (ap || apsta || wds) ? 1 : 0; |
|---|
| 814 | cprintf("set ap flag %s\n",name); |
|---|
| 815 | WL_IOCTL(name, WLC_SET_AP, &val, sizeof(val)); |
|---|
| 816 | |
|---|
| 817 | cprintf("set apsta flag %s\n",name); |
|---|
| 818 | WL_IOVAR_SETINT(name, "apsta", apsta); |
|---|
| 819 | |
|---|
| 820 | /* Set mode: WET */ |
|---|
| 821 | cprintf("set wet flag %s\n",name); |
|---|
| 822 | if (wet) |
|---|
| 823 | WL_IOCTL(name, WLC_SET_WET, &wet, sizeof(wet)); |
|---|
| 824 | |
|---|
| 825 | cprintf("set spoof flag %s\n",name); |
|---|
| 826 | if (mac_spoof) { |
|---|
| 827 | sta = 1; |
|---|
| 828 | WL_IOVAR_SETINT(name, "mac_spoof", 1); |
|---|
| 829 | } |
|---|
| 830 | |
|---|
| 831 | /* For STA configurations, configure association retry time. |
|---|
| 832 | * Use specified time (capped), or mode-specific defaults. |
|---|
| 833 | */ |
|---|
| 834 | cprintf("set sta retry time %s\n",name); |
|---|
| 835 | if (sta || wet || apsta) { |
|---|
| 836 | char *retry_time = nvram_default_get(strcat_r(prefix, "sta_retry_time", tmp),"5"); |
|---|
| 837 | val = atoi(retry_time); |
|---|
| 838 | WL_IOVAR_SETINT(name, "sta_retry_time", val); |
|---|
| 839 | } |
|---|
| 840 | |
|---|
| 841 | /* Retain remaining WET effects only if not APSTA */ |
|---|
| 842 | // wet &= !apsta; |
|---|
| 843 | |
|---|
| 844 | /* Set infra: BSS/IBSS (IBSS only for WET or STA modes) */ |
|---|
| 845 | val = 1; |
|---|
| 846 | if (wet || sta) |
|---|
| 847 | val = atoi(nvram_default_get(strcat_r(prefix, "infra", tmp),"1")); |
|---|
| 848 | cprintf("set infra flag %s\n",name); |
|---|
| 849 | WL_IOCTL(name, WLC_SET_INFRA, &val, sizeof(val)); |
|---|
| 850 | |
|---|
| 851 | cprintf("set maxassoc flag %s\n",name); |
|---|
| 852 | /* Set The AP MAX Associations Limit */ |
|---|
| 853 | if (ap | apsta) { |
|---|
| 854 | val = atoi(nvram_default_get(strcat_r(prefix, "maxassoc", tmp),"128")); |
|---|
| 855 | if (val > 0) |
|---|
| 856 | WL_IOVAR_SETINT(name, "maxassoc", val); |
|---|
| 857 | } |
|---|
| 858 | cprintf("set bsscfg %s\n",name); |
|---|
| 859 | |
|---|
| 860 | for (i = 0; i < bclist->count; i++) { |
|---|
| 861 | char *subprefix; |
|---|
| 862 | bsscfg = &bclist->bsscfgs[i]; |
|---|
| 863 | |
|---|
| 864 | #ifdef BCMWPA2 |
|---|
| 865 | /* XXXMSSID: The note about setting preauth now does not seem right. |
|---|
| 866 | * NAS brings the BSS up if it runs, so setting the preauth value |
|---|
| 867 | * will make it in the bcn/prb. If that is right, we can move this |
|---|
| 868 | * chunk out of wlconf. |
|---|
| 869 | */ |
|---|
| 870 | /* |
|---|
| 871 | * Set The WPA2 Pre auth cap. only reason we are doing it here is the driver is down |
|---|
| 872 | * if we do it in the NAS we need to bring down the interface and up to make |
|---|
| 873 | * it affect in the beacons |
|---|
| 874 | */ |
|---|
| 875 | if (ap || (apsta && bsscfg->idx != 0)) { |
|---|
| 876 | set_preauth = 1; |
|---|
| 877 | preauth = nvram_safe_get(strcat_r(bsscfg->prefix, "preauth", tmp)); |
|---|
| 878 | if (strlen (preauth) != 0) { |
|---|
| 879 | set_preauth = atoi(preauth); |
|---|
| 880 | } |
|---|
| 881 | wlconf_set_preauth(name, bsscfg->idx, set_preauth); |
|---|
| 882 | } |
|---|
| 883 | #endif /* BCMWPA2 */ |
|---|
| 884 | |
|---|
| 885 | subprefix = apsta ? prefix : bsscfg->prefix; |
|---|
| 886 | |
|---|
| 887 | /* Set network type */ |
|---|
| 888 | val = atoi(nvram_default_get(strcat_r(subprefix, "closed", tmp),"0")); |
|---|
| 889 | WL_BSSIOVAR_SETINT(name, "closednet", bsscfg->idx, val); |
|---|
| 890 | |
|---|
| 891 | /* Set the ap isolate mode */ |
|---|
| 892 | val = atoi(nvram_default_get(strcat_r(subprefix, "ap_isolate", tmp),"0")); |
|---|
| 893 | WL_BSSIOVAR_SETINT(name, "ap_isolate", bsscfg->idx, val); |
|---|
| 894 | } |
|---|
| 895 | |
|---|
| 896 | cprintf("get phy type %s\n",name); |
|---|
| 897 | /* Get current phy type */ |
|---|
| 898 | WL_IOCTL(name, WLC_GET_PHYTYPE, &phytype, sizeof(phytype)); |
|---|
| 899 | snprintf(buf, sizeof(buf), "%s", WLCONF_PHYTYPE2STR(phytype)); |
|---|
| 900 | nvram_set(strcat_r(prefix, "phytype", tmp), buf); |
|---|
| 901 | |
|---|
| 902 | /* Set up the country code */ |
|---|
| 903 | (void) strcat_r(prefix, "country_code", tmp); |
|---|
| 904 | |
|---|
| 905 | #ifdef HAVE_BUFFALO |
|---|
| 906 | country = BUFFALO_COUNTRY; |
|---|
| 907 | #else |
|---|
| 908 | if (nvram_match("wl0_phytype","a")) |
|---|
| 909 | country="US"; |
|---|
| 910 | else |
|---|
| 911 | country="JP"; |
|---|
| 912 | if (phytype == PHY_TYPE_N) |
|---|
| 913 | { |
|---|
| 914 | if (nvram_default_match(strcat_r(prefix, "net_mode", tmp),"n-only","mixed") || nvram_match(strcat_r(prefix, "net_mode", tmp),"mixed")) |
|---|
| 915 | country="DE"; |
|---|
| 916 | } |
|---|
| 917 | //country = nvram_get(tmp); |
|---|
| 918 | #endif |
|---|
| 919 | cprintf("set country %s\n",name); |
|---|
| 920 | if (country) { |
|---|
| 921 | strncpy(country_code, country, sizeof(country_code)); |
|---|
| 922 | WL_IOCTL(name, WLC_SET_COUNTRY, country_code, strlen(country_code)+1); |
|---|
| 923 | } |
|---|
| 924 | else { |
|---|
| 925 | /* If country_code doesn't exist, check for country to be backward compatible */ |
|---|
| 926 | (void) strcat_r(prefix, "country", tmp); |
|---|
| 927 | country = nvram_safe_get(tmp); |
|---|
| 928 | for (val = 0; val < ARRAYSIZE(countries); val++) { |
|---|
| 929 | char **synonym; |
|---|
| 930 | for (synonym = countries[val].names; *synonym; synonym++) |
|---|
| 931 | if (!strcmp(country, *synonym)) |
|---|
| 932 | break; |
|---|
| 933 | if (*synonym) |
|---|
| 934 | break; |
|---|
| 935 | } |
|---|
| 936 | |
|---|
| 937 | /* Get the default country code if undefined or invalid and set the NVRAM */ |
|---|
| 938 | if (val >= ARRAYSIZE(countries)) { |
|---|
| 939 | WL_IOCTL(name, WLC_GET_COUNTRY, country_code, sizeof(country_code)); |
|---|
| 940 | } |
|---|
| 941 | else { |
|---|
| 942 | strncpy(country_code, countries[val].abbr, sizeof(country_code)); |
|---|
| 943 | WL_IOCTL(name, WLC_SET_COUNTRY, country_code, strlen(country_code)+1); |
|---|
| 944 | } |
|---|
| 945 | |
|---|
| 946 | /* Add the new NVRAM variable */ |
|---|
| 947 | nvram_set("wl_country_code", country_code); |
|---|
| 948 | (void) strcat_r(prefix, "country_code", tmp); |
|---|
| 949 | nvram_set(tmp, country_code); |
|---|
| 950 | } |
|---|
| 951 | |
|---|
| 952 | cprintf("set reg mode %s\n",name); |
|---|
| 953 | /* Setup regulatory mode */ |
|---|
| 954 | strcat_r(prefix, "reg_mode", tmp); |
|---|
| 955 | if (nvram_default_match(tmp, "off","off")) { |
|---|
| 956 | val = 0; |
|---|
| 957 | WL_IOCTL(name, WLC_SET_REGULATORY, &val, sizeof(val)); |
|---|
| 958 | WL_IOCTL(name, WLC_SET_RADAR, &val, sizeof(val)); |
|---|
| 959 | WL_IOCTL(name, WLC_SET_SPECT_MANAGMENT, &val, sizeof(val)); |
|---|
| 960 | } else if (nvram_match(tmp, "h")) { |
|---|
| 961 | val = 0; |
|---|
| 962 | WL_IOCTL(name, WLC_SET_REGULATORY, &val, sizeof(val)); |
|---|
| 963 | val = 1; |
|---|
| 964 | WL_IOCTL(name, WLC_SET_RADAR, &val, sizeof(val)); |
|---|
| 965 | WL_IOCTL(name, WLC_SET_SPECT_MANAGMENT, &val, sizeof(val)); |
|---|
| 966 | |
|---|
| 967 | /* Set the CAC parameters */ |
|---|
| 968 | val = atoi(nvram_safe_get(strcat_r(prefix, "dfs_preism", tmp))); |
|---|
| 969 | wl_iovar_setint(name, "dfs_preism", val); |
|---|
| 970 | val = atoi(nvram_safe_get(strcat_r(prefix, "dfs_postism", tmp))); |
|---|
| 971 | wl_iovar_setint(name, "dfs_postism", val); |
|---|
| 972 | val = atoi(nvram_safe_get(strcat_r(prefix, "tpc_db", tmp))); |
|---|
| 973 | WL_IOCTL(name, WLC_SEND_PWR_CONSTRAINT, &val, sizeof(val)); |
|---|
| 974 | |
|---|
| 975 | } else if (nvram_match(tmp, "d")) { |
|---|
| 976 | val = 0; |
|---|
| 977 | WL_IOCTL(name, WLC_SET_RADAR, &val, sizeof(val)); |
|---|
| 978 | WL_IOCTL(name, WLC_SET_SPECT_MANAGMENT, &val, sizeof(val)); |
|---|
| 979 | val = 1; |
|---|
| 980 | WL_IOCTL(name, WLC_SET_REGULATORY, &val, sizeof(val)); |
|---|
| 981 | } |
|---|
| 982 | cprintf("set maclist %s\n",name); |
|---|
| 983 | |
|---|
| 984 | /* Set the MAC list */ |
|---|
| 985 | maclist = (struct maclist *) buf; |
|---|
| 986 | maclist->count = 0; |
|---|
| 987 | if (!nvram_default_match(strcat_r(prefix, "macmode", tmp), "disabled","disabled")) { |
|---|
| 988 | ea = maclist->ea; |
|---|
| 989 | foreach(var, nvram_safe_get(strcat_r(prefix, "maclist", tmp)), next) { |
|---|
| 990 | if (((char *)((&ea[1])->octet)) > ((char *)(&buf[sizeof(buf)]))) |
|---|
| 991 | break; |
|---|
| 992 | if (ether_atoe(var, ea->octet)) { |
|---|
| 993 | maclist->count++; |
|---|
| 994 | ea++; |
|---|
| 995 | } |
|---|
| 996 | } |
|---|
| 997 | } |
|---|
| 998 | WL_IOCTL(name, WLC_SET_MACLIST, buf, sizeof(buf)); |
|---|
| 999 | |
|---|
| 1000 | cprintf("set macmode %s\n",name); |
|---|
| 1001 | /* Set the MAC list mode */ |
|---|
| 1002 | (void) strcat_r(prefix, "macmode", tmp); |
|---|
| 1003 | if (nvram_default_match(tmp, "deny","disabled")) |
|---|
| 1004 | val = WLC_MACMODE_DENY; |
|---|
| 1005 | else if (nvram_match(tmp, "allow")) |
|---|
| 1006 | val = WLC_MACMODE_ALLOW; |
|---|
| 1007 | else |
|---|
| 1008 | val = WLC_MACMODE_DISABLED; |
|---|
| 1009 | WL_IOCTL(name, WLC_SET_MACMODE, &val, sizeof(val)); |
|---|
| 1010 | |
|---|
| 1011 | /* Change LED Duty Cycle */ |
|---|
| 1012 | leddc = (uint32)strtoul(nvram_default_get(strcat_r(prefix, "leddc", tmp),"0x640000"), NULL, 16); |
|---|
| 1013 | if (leddc) |
|---|
| 1014 | WL_IOVAR_SETINT(name, "leddc", leddc); |
|---|
| 1015 | |
|---|
| 1016 | /* Enable or disable the radio */ |
|---|
| 1017 | cprintf("set radio flag %s\n",name); |
|---|
| 1018 | val = nvram_default_match(strcat_r(prefix, "radio", tmp), "0","1"); |
|---|
| 1019 | val += WL_RADIO_SW_DISABLE << 16; |
|---|
| 1020 | WL_IOCTL(name, WLC_SET_RADIO, &val, sizeof(val)); |
|---|
| 1021 | |
|---|
| 1022 | cprintf("get phy flags %s\n",name); |
|---|
| 1023 | /* Get supported phy types */ |
|---|
| 1024 | WL_IOCTL(name, WLC_GET_PHYLIST, var, sizeof(var)); |
|---|
| 1025 | |
|---|
| 1026 | nvram_set(strcat_r(prefix, "phytypes", tmp), var); |
|---|
| 1027 | |
|---|
| 1028 | /* Get radio IDs */ |
|---|
| 1029 | *(next = buf) = '\0'; |
|---|
| 1030 | for (i = 0; i < strlen(var); i++) { |
|---|
| 1031 | /* Switch to band */ |
|---|
| 1032 | phy[0] = var[i]; |
|---|
| 1033 | val = WLCONF_STR2PHYTYPE(phy); |
|---|
| 1034 | if (val == PHY_TYPE_N) { |
|---|
| 1035 | WL_GETINT(name, WLC_GET_BAND, &val); |
|---|
| 1036 | } else |
|---|
| 1037 | val = WLCONF_PHYTYPE2BAND(val); |
|---|
| 1038 | WL_IOCTL(name, WLC_SET_BAND, &val, sizeof(val)); |
|---|
| 1039 | /* Get radio ID on this band */ |
|---|
| 1040 | WL_IOCTL(name, WLC_GET_REVINFO, &rev, sizeof(rev)); |
|---|
| 1041 | next += sprintf(next, "%sBCM%X", i ? " " : "", |
|---|
| 1042 | (rev.radiorev & IDCODE_ID_MASK) >> IDCODE_ID_SHIFT); |
|---|
| 1043 | } |
|---|
| 1044 | cprintf("set radio ids %s\n",name); |
|---|
| 1045 | nvram_set(strcat_r(prefix, "radioids", tmp), buf); |
|---|
| 1046 | |
|---|
| 1047 | /* Set band */ |
|---|
| 1048 | cprintf("set nband %s\n",name); |
|---|
| 1049 | str = nvram_get(strcat_r(prefix, "phytype", tmp)); |
|---|
| 1050 | val = WLCONF_STR2PHYTYPE(str); |
|---|
| 1051 | /* For NPHY use band value from NVRAM */ |
|---|
| 1052 | if (val == PHY_TYPE_N) { |
|---|
| 1053 | str = nvram_get(strcat_r(prefix, "nband", tmp)); |
|---|
| 1054 | if (str) |
|---|
| 1055 | val = atoi(str); |
|---|
| 1056 | else { |
|---|
| 1057 | WL_GETINT(name, WLC_GET_BAND, &val); |
|---|
| 1058 | } |
|---|
| 1059 | } else |
|---|
| 1060 | val = WLCONF_PHYTYPE2BAND(val); |
|---|
| 1061 | |
|---|
| 1062 | cprintf("set band %s\n",name); |
|---|
| 1063 | WL_SETINT(name, WLC_SET_BAND, val); |
|---|
| 1064 | |
|---|
| 1065 | /* Check errors (card may have changed) */ |
|---|
| 1066 | if (ret) { |
|---|
| 1067 | /* default band to the first band in band list */ |
|---|
| 1068 | phy[0] = var[0]; |
|---|
| 1069 | val = WLCONF_STR2PHYTYPE(phy); |
|---|
| 1070 | val = WLCONF_PHYTYPE2BAND(val); |
|---|
| 1071 | WL_SETINT(name, WLC_SET_BAND, val); |
|---|
| 1072 | } |
|---|
| 1073 | |
|---|
| 1074 | /* Store the resolved bandtype */ |
|---|
| 1075 | bandtype = val; |
|---|
| 1076 | |
|---|
| 1077 | /* Get current core revision */ |
|---|
| 1078 | cprintf("get core rev %s\n",name); |
|---|
| 1079 | WL_IOCTL(name, WLC_GET_REVINFO, &rev, sizeof(rev)); |
|---|
| 1080 | snprintf(buf, sizeof(buf), "%d", rev.corerev); |
|---|
| 1081 | nvram_set(strcat_r(prefix, "corerev", tmp), buf); |
|---|
| 1082 | |
|---|
| 1083 | |
|---|
| 1084 | /* Set channel before setting gmode or rateset */ |
|---|
| 1085 | /* Manual Channel Selection - when channel # is not 0 */ |
|---|
| 1086 | cprintf("set channel %s\n",name); |
|---|
| 1087 | val = atoi(nvram_default_get(strcat_r(prefix, "channel", tmp),"0")); |
|---|
| 1088 | if (val && phytype != PHY_TYPE_N) { |
|---|
| 1089 | WL_SETINT(name, WLC_SET_CHANNEL, val); |
|---|
| 1090 | if (ret) { |
|---|
| 1091 | /* Use current channel (card may have changed) */ |
|---|
| 1092 | WL_IOCTL(name, WLC_GET_CHANNEL, &ci, sizeof(ci)); |
|---|
| 1093 | snprintf(buf, sizeof(buf), "%d", ci.target_channel); |
|---|
| 1094 | nvram_set(strcat_r(prefix, "channel", tmp), buf); |
|---|
| 1095 | } |
|---|
| 1096 | } else if (val && phytype == PHY_TYPE_N) { |
|---|
| 1097 | chanspec_t chanspec = 0; |
|---|
| 1098 | uint channel; |
|---|
| 1099 | uint nbw; |
|---|
| 1100 | uint nctrlsb = WL_CHANSPEC_CTL_SB_NONE; |
|---|
| 1101 | |
|---|
| 1102 | channel = val; |
|---|
| 1103 | /* Get BW */ |
|---|
| 1104 | val = atoi(nvram_safe_get(strcat_r(prefix, "nbw", tmp))); |
|---|
| 1105 | if (nvram_match(strcat_r(prefix, "net_mode", tmp),"b-only") || nvram_match(strcat_r(prefix, "net_mode", tmp),"g-only") || nvram_match(strcat_r(prefix, "net_mode", tmp),"a-only") || nvram_match(strcat_r(prefix, "net_mode", tmp),"bg-mixed")); |
|---|
| 1106 | val = 20; |
|---|
| 1107 | |
|---|
| 1108 | fprintf(stderr,"channel %d, val %d\n",channel,val); |
|---|
| 1109 | switch (val) { |
|---|
| 1110 | case 40: |
|---|
| 1111 | val = WL_CHANSPEC_BW_40; |
|---|
| 1112 | break; |
|---|
| 1113 | case 20: |
|---|
| 1114 | val = WL_CHANSPEC_BW_20; |
|---|
| 1115 | break; |
|---|
| 1116 | case 10: |
|---|
| 1117 | val = WL_CHANSPEC_BW_10; |
|---|
| 1118 | break; |
|---|
| 1119 | default: |
|---|
| 1120 | val = WL_CHANSPEC_BW_20; |
|---|
| 1121 | nvram_set(strcat_r(prefix, "nbw", tmp), "20"); |
|---|
| 1122 | } |
|---|
| 1123 | nbw = val; |
|---|
| 1124 | |
|---|
| 1125 | /* Get Ctrl SB for 40MHz channel */ |
|---|
| 1126 | if (nbw == WL_CHANSPEC_BW_40) { |
|---|
| 1127 | str = nvram_safe_get(strcat_r(prefix, "nctrlsb", tmp)); |
|---|
| 1128 | |
|---|
| 1129 | /* Adjust the channel to be center channel */ |
|---|
| 1130 | if (!strcmp(str, "lower")) { |
|---|
| 1131 | nctrlsb = WL_CHANSPEC_CTL_SB_LOWER; |
|---|
| 1132 | channel = channel + 2; |
|---|
| 1133 | } else if (!strcmp(str, "upper")) { |
|---|
| 1134 | nctrlsb = WL_CHANSPEC_CTL_SB_UPPER; |
|---|
| 1135 | channel = channel - 2; |
|---|
| 1136 | } |
|---|
| 1137 | } |
|---|
| 1138 | |
|---|
| 1139 | /* band | BW | CTRL SB | Channel */ |
|---|
| 1140 | fprintf(stderr,"%X, %X, %X\n",nbw,nctrlsb,channel); |
|---|
| 1141 | chanspec |= ((bandtype << WL_CHANSPEC_BAND_SHIFT) | |
|---|
| 1142 | (nbw | nctrlsb | channel)); |
|---|
| 1143 | fprintf(stderr,"spec %X\n",chanspec); |
|---|
| 1144 | |
|---|
| 1145 | WL_IOVAR_SETINT(name, "chanspec", (uint32)chanspec); |
|---|
| 1146 | } |
|---|
| 1147 | |
|---|
| 1148 | cprintf("set rate set %s\n",name); |
|---|
| 1149 | /* Reset to hardware rateset (band may have changed) */ |
|---|
| 1150 | WL_IOCTL(name, WLC_GET_RATESET, &rs, sizeof(wl_rateset_t)); |
|---|
| 1151 | WL_IOCTL(name, WLC_SET_RATESET, &rs, sizeof(wl_rateset_t)); |
|---|
| 1152 | |
|---|
| 1153 | cprintf("set g mode %s\n",name); |
|---|
| 1154 | /* Set gmode */ |
|---|
| 1155 | if (bandtype == WLC_BAND_2G) { |
|---|
| 1156 | int override = WLC_G_PROTECTION_OFF; |
|---|
| 1157 | int control = WLC_G_PROTECTION_CTL_OFF; |
|---|
| 1158 | |
|---|
| 1159 | /* Set gmode */ |
|---|
| 1160 | gmode = atoi(nvram_default_get(strcat_r(prefix, "gmode", tmp),"1")); |
|---|
| 1161 | WL_IOCTL(name, WLC_SET_GMODE, &gmode, sizeof(gmode)); |
|---|
| 1162 | |
|---|
| 1163 | /* Set gmode protection override and control algorithm */ |
|---|
| 1164 | strcat_r(prefix, "gmode_protection", tmp); |
|---|
| 1165 | if (nvram_default_match(tmp, "auto","auto")) { |
|---|
| 1166 | override = WLC_G_PROTECTION_AUTO; |
|---|
| 1167 | control = WLC_G_PROTECTION_CTL_OVERLAP; |
|---|
| 1168 | } |
|---|
| 1169 | WL_IOCTL(name, WLC_SET_GMODE_PROTECTION_OVERRIDE, &override, sizeof(override)); |
|---|
| 1170 | WL_IOCTL(name, WLC_SET_GMODE_PROTECTION_CONTROL, &control, sizeof(control)); |
|---|
| 1171 | } |
|---|
| 1172 | |
|---|
| 1173 | cprintf("set n prot mode %s\n",name); |
|---|
| 1174 | /* Set nmode_protectoin */ |
|---|
| 1175 | if (phytype == PHY_TYPE_N) { |
|---|
| 1176 | int override = WLC_PROTECTION_OFF; |
|---|
| 1177 | int control = WLC_PROTECTION_CTL_OFF; |
|---|
| 1178 | int nmode = AUTO; |
|---|
| 1179 | |
|---|
| 1180 | /* Set n mode */ |
|---|
| 1181 | |
|---|
| 1182 | |
|---|
| 1183 | strcat_r(prefix, "nreqd", tmp); |
|---|
| 1184 | if (nvram_default_match(tmp, "0","0")) |
|---|
| 1185 | nmode = 0; |
|---|
| 1186 | if (nvram_match(tmp, "1")) |
|---|
| 1187 | nmode = 1; |
|---|
| 1188 | WL_IOVAR_SETINT(name, "nreqd", (uint32)nmode); |
|---|
| 1189 | |
|---|
| 1190 | strcat_r(prefix, "nmode", tmp); |
|---|
| 1191 | if (nvram_default_match(tmp, "0","-1")) |
|---|
| 1192 | nmode = OFF; |
|---|
| 1193 | if (nvram_match(tmp, "-1")) |
|---|
| 1194 | nmode = AUTO; |
|---|
| 1195 | if (nvram_match(tmp, "2")) |
|---|
| 1196 | nmode = WL_NMODE_NONLY; |
|---|
| 1197 | WL_IOVAR_SETINT(name, "nmode", (uint32)nmode); |
|---|
| 1198 | |
|---|
| 1199 | /* Set n protection override and control algorithm */ |
|---|
| 1200 | strcat_r(prefix, "nmode_protection", tmp); |
|---|
| 1201 | |
|---|
| 1202 | if (nvram_default_match(tmp, "auto","auto")) { |
|---|
| 1203 | override = WLC_PROTECTION_AUTO; |
|---|
| 1204 | control = WLC_PROTECTION_CTL_OVERLAP; |
|---|
| 1205 | } |
|---|
| 1206 | |
|---|
| 1207 | memset(buf, 0, WLC_IOCTL_MAXLEN); |
|---|
| 1208 | strcpy(buf, "nmode_protection_override"); |
|---|
| 1209 | buflen = strlen(buf) + 1; |
|---|
| 1210 | |
|---|
| 1211 | val_ptr = (uint32*)(buf + buflen); |
|---|
| 1212 | buflen += sizeof(override); |
|---|
| 1213 | memcpy(val_ptr, &override, sizeof(override)); |
|---|
| 1214 | WL_IOCTL(name, WLC_SET_VAR, buf, sizeof(buf)); |
|---|
| 1215 | WL_IOCTL(name, WLC_SET_PROTECTION_CONTROL, &control, sizeof(control)); |
|---|
| 1216 | } |
|---|
| 1217 | |
|---|
| 1218 | /* Set WME mode */ |
|---|
| 1219 | /* This needs to be done before afterburner as wme has precedence |
|---|
| 1220 | * -disable afterburner mode to allow any wme mode be configured |
|---|
| 1221 | * -set wme mode before set afterburner mode |
|---|
| 1222 | */ |
|---|
| 1223 | cprintf("set afterburner override %s\n",name); |
|---|
| 1224 | val = OFF; |
|---|
| 1225 | strcpy(var, "afterburner_override"); |
|---|
| 1226 | wl_iovar_setint(name, var, val); |
|---|
| 1227 | wme = nvram_default_get(strcat_r(prefix, "wme", tmp),"on"); |
|---|
| 1228 | val = strcmp(wme, "on") ? 0 : 1; |
|---|
| 1229 | cprintf("set wme %s\n",name); |
|---|
| 1230 | wl_iovar_set(name, "wme", &val, sizeof(val)); |
|---|
| 1231 | if (val) |
|---|
| 1232 | wlconf_set_wme(name, prefix); |
|---|
| 1233 | |
|---|
| 1234 | cprintf("set btc mode %s\n",name); |
|---|
| 1235 | /* Get bluetootch coexistance(BTC) mode */ |
|---|
| 1236 | btc_mode = atoi(nvram_default_get(strcat_r(prefix, "btc_mode", tmp),"0")); |
|---|
| 1237 | |
|---|
| 1238 | /* Set options based on capability */ |
|---|
| 1239 | cprintf("get caps %s\n",name); |
|---|
| 1240 | wl_iovar_get(name, "cap", (void *)tmp, 100); |
|---|
| 1241 | foreach(var, tmp, next) { |
|---|
| 1242 | bool valid_option = FALSE; |
|---|
| 1243 | char *nvram_str = nvram_get(strcat_r(prefix, var, buf)); |
|---|
| 1244 | |
|---|
| 1245 | if (!nvram_str) |
|---|
| 1246 | continue; |
|---|
| 1247 | |
|---|
| 1248 | if (!strcmp(nvram_str, "on")) |
|---|
| 1249 | val = ON; |
|---|
| 1250 | else if (!strcmp(nvram_str, "off")) |
|---|
| 1251 | val = OFF; |
|---|
| 1252 | else if (!strcmp(nvram_str, "auto")) |
|---|
| 1253 | val = AUTO; |
|---|
| 1254 | else |
|---|
| 1255 | continue; |
|---|
| 1256 | |
|---|
| 1257 | if (btc_mode != WL_BTC_PREMPT && strncmp(var, "afterburner", sizeof(var)) == 0) { |
|---|
| 1258 | if (val == ON || val == OFF || val == AUTO) |
|---|
| 1259 | valid_option = TRUE; |
|---|
| 1260 | strcpy(var, "afterburner_override"); |
|---|
| 1261 | } |
|---|
| 1262 | if ((strncmp(var, "amsdu", sizeof(var)) == 0) || |
|---|
| 1263 | (strncmp(var, "ampdu", sizeof(var)) == 0)) { |
|---|
| 1264 | if (val == ON || val == OFF || val == AUTO) |
|---|
| 1265 | valid_option = TRUE; |
|---|
| 1266 | } |
|---|
| 1267 | if (valid_option) |
|---|
| 1268 | wl_iovar_setint(name, var, val); |
|---|
| 1269 | } |
|---|
| 1270 | |
|---|
| 1271 | /* Get current rateset (gmode may have changed) */ |
|---|
| 1272 | WL_IOCTL(name, WLC_GET_CURR_RATESET, &rs, sizeof(wl_rateset_t)); |
|---|
| 1273 | |
|---|
| 1274 | strcat_r(prefix, "rateset", tmp); |
|---|
| 1275 | if (nvram_default_match(tmp, "all","default")) { |
|---|
| 1276 | /* Make all rates basic */ |
|---|
| 1277 | for (i = 0; i < rs.count; i++) |
|---|
| 1278 | rs.rates[i] |= 0x80; |
|---|
| 1279 | } else if (nvram_match(tmp, "12")) { |
|---|
| 1280 | /* Make 1 and 2 basic */ |
|---|
| 1281 | for (i = 0; i < rs.count; i++) { |
|---|
| 1282 | if ((rs.rates[i] & 0x7f) == 2 || (rs.rates[i] & 0x7f) == 4) |
|---|
| 1283 | rs.rates[i] |= 0x80; |
|---|
| 1284 | else |
|---|
| 1285 | rs.rates[i] &= ~0x80; |
|---|
| 1286 | } |
|---|
| 1287 | } |
|---|
| 1288 | cprintf("set btc mode %s\n",name); |
|---|
| 1289 | |
|---|
| 1290 | /* Set BTC mode */ |
|---|
| 1291 | if (!wl_iovar_setint(name, "btc_mode", btc_mode)) { |
|---|
| 1292 | if (btc_mode == WL_BTC_PREMPT) { |
|---|
| 1293 | wl_rateset_t rs_tmp = rs; |
|---|
| 1294 | /* remove 1Mbps and 2 Mbps from rateset */ |
|---|
| 1295 | for (i = 0, rs.count = 0; i < rs_tmp.count; i++) { |
|---|
| 1296 | if ((rs_tmp.rates[i] & 0x7f) == 2 || (rs_tmp.rates[i] & 0x7f) == 4) |
|---|
| 1297 | continue; |
|---|
| 1298 | rs.rates[rs.count++] = rs_tmp.rates[i]; |
|---|
| 1299 | } |
|---|
| 1300 | } |
|---|
| 1301 | } |
|---|
| 1302 | |
|---|
| 1303 | cprintf("set rate set %s\n",name); |
|---|
| 1304 | /* Set rateset */ |
|---|
| 1305 | WL_IOCTL(name, WLC_SET_RATESET, &rs, sizeof(wl_rateset_t)); |
|---|
| 1306 | |
|---|
| 1307 | cprintf("set plcphdr %s\n",name); |
|---|
| 1308 | /* Allow short preamble override for b cards */ |
|---|
| 1309 | if (phytype == PHY_TYPE_B || |
|---|
| 1310 | (phytype == PHY_TYPE_G && (gmode == GMODE_LEGACY_B || gmode == GMODE_AUTO))) { |
|---|
| 1311 | strcat_r(prefix, "plcphdr", tmp); |
|---|
| 1312 | if (nvram_default_match(tmp, "long","long")) |
|---|
| 1313 | val = WLC_PLCP_AUTO; |
|---|
| 1314 | else |
|---|
| 1315 | val = WLC_PLCP_SHORT; |
|---|
| 1316 | WL_IOCTL(name, WLC_SET_PLCPHDR, &val, sizeof(val)); |
|---|
| 1317 | } |
|---|
| 1318 | |
|---|
| 1319 | /* Set rate in 500 Kbps units */ |
|---|
| 1320 | val = atoi(nvram_default_get(strcat_r(prefix, "rate", tmp),"0")) / 500000; |
|---|
| 1321 | |
|---|
| 1322 | |
|---|
| 1323 | /* Convert Auto mcsidx to Auto rate */ |
|---|
| 1324 | if (phytype == PHY_TYPE_N) { |
|---|
| 1325 | int mcsidx = atoi(nvram_default_get(strcat_r(prefix, "nmcsidx", tmp),"-1")); |
|---|
| 1326 | /* -1 mcsidx used to designate AUTO rate */ |
|---|
| 1327 | if (mcsidx == -1) |
|---|
| 1328 | val = 0; |
|---|
| 1329 | } |
|---|
| 1330 | |
|---|
| 1331 | /* 1Mbps and 2 Mbps are not allowed in BTC pre-emptive mode */ |
|---|
| 1332 | if (btc_mode == WL_BTC_PREMPT && (val == 2 || val == 4)) |
|---|
| 1333 | /* Must b/g band. Set to 5.5Mbps */ |
|---|
| 1334 | val = 11; |
|---|
| 1335 | |
|---|
| 1336 | cprintf("set get rates %s\n",name); |
|---|
| 1337 | /* it is band-blind. try both band */ |
|---|
| 1338 | error_bg = wl_iovar_setint(name, "bg_rate", val); |
|---|
| 1339 | error_a = wl_iovar_setint(name, "a_rate", val); |
|---|
| 1340 | |
|---|
| 1341 | if (error_bg && error_a) { |
|---|
| 1342 | /* both failed. Try default rate (card may have changed) */ |
|---|
| 1343 | val = 0; |
|---|
| 1344 | |
|---|
| 1345 | error_bg = wl_iovar_setint(name, "bg_rate", val); |
|---|
| 1346 | error_a = wl_iovar_setint(name, "a_rate", val); |
|---|
| 1347 | |
|---|
| 1348 | snprintf(buf, sizeof(buf), "%d", val); |
|---|
| 1349 | nvram_set(strcat_r(prefix, "rate", tmp), buf); |
|---|
| 1350 | } |
|---|
| 1351 | |
|---|
| 1352 | /* For N-Phy, check if nrate needs to be applied */ |
|---|
| 1353 | if (phytype == PHY_TYPE_N) { |
|---|
| 1354 | uint32 nrate = 0; |
|---|
| 1355 | int mcsidx = atoi(nvram_safe_get(strcat_r(prefix, "nmcsidx", tmp))); |
|---|
| 1356 | bool ismcs = (mcsidx >= 0); |
|---|
| 1357 | uint nbw = atoi(nvram_safe_get(strcat_r(prefix, "nbw", tmp))); |
|---|
| 1358 | |
|---|
| 1359 | /* mcsidx of 32 is valid only for 40 Mhz */ |
|---|
| 1360 | if (mcsidx == 32 && nbw == 20) { |
|---|
| 1361 | mcsidx = -1; |
|---|
| 1362 | ismcs = FALSE; |
|---|
| 1363 | nvram_set(strcat_r(prefix, "nmcsidx", tmp), "-1"); |
|---|
| 1364 | } |
|---|
| 1365 | |
|---|
| 1366 | /* Use nrate iovar only for MCS rate. */ |
|---|
| 1367 | if (ismcs) { |
|---|
| 1368 | nrate |= NRATE_MCS_INUSE; |
|---|
| 1369 | nrate |= mcsidx & NRATE_RATE_MASK; |
|---|
| 1370 | |
|---|
| 1371 | memset(buf, 0, WLC_IOCTL_MAXLEN); |
|---|
| 1372 | strcpy(buf, "nrate"); |
|---|
| 1373 | buflen = strlen(buf) + 1; |
|---|
| 1374 | |
|---|
| 1375 | val_ptr = (uint32*)(buf + buflen); |
|---|
| 1376 | buflen += sizeof(nrate); |
|---|
| 1377 | memcpy(val_ptr, &nrate, sizeof(nrate)); |
|---|
| 1378 | WL_IOCTL(name, WLC_SET_VAR, buf, sizeof(buf)); |
|---|
| 1379 | } |
|---|
| 1380 | } |
|---|
| 1381 | |
|---|
| 1382 | cprintf("set mrates %s\n",name); |
|---|
| 1383 | /* Set multicast rate in 500 Kbps units */ |
|---|
| 1384 | val = atoi(nvram_default_get(strcat_r(prefix, "mrate", tmp),"0")) / 500000; |
|---|
| 1385 | /* 1Mbps and 2 Mbps are not allowed in BTC pre-emptive mode */ |
|---|
| 1386 | if (btc_mode == WL_BTC_PREMPT && (val == 2 || val == 4)) |
|---|
| 1387 | /* Must b/g band. Set to 5.5Mbps */ |
|---|
| 1388 | val = 11; |
|---|
| 1389 | |
|---|
| 1390 | /* it is band-blind. try both band */ |
|---|
| 1391 | error_bg = wl_iovar_setint(name, "bg_mrate", val); |
|---|
| 1392 | error_a = wl_iovar_setint(name, "a_mrate", val); |
|---|
| 1393 | |
|---|
| 1394 | if (error_bg && error_a) { |
|---|
| 1395 | /* Try default rate (card may have changed) */ |
|---|
| 1396 | val = 0; |
|---|
| 1397 | |
|---|
| 1398 | wl_iovar_setint(name, "bg_mrate", val); |
|---|
| 1399 | wl_iovar_setint(name, "a_mrate", val); |
|---|
| 1400 | |
|---|
| 1401 | snprintf(buf, sizeof(buf), "%d", val); |
|---|
| 1402 | nvram_set(strcat_r(prefix, "mrate", tmp), buf); |
|---|
| 1403 | } |
|---|
| 1404 | |
|---|
| 1405 | cprintf("set frag tres %s\n",name); |
|---|
| 1406 | /* Set fragmentation threshold */ |
|---|
| 1407 | val = atoi(nvram_default_get(strcat_r(prefix, "frag", tmp),"2346")); |
|---|
| 1408 | wl_iovar_setint(name, "fragthresh", val); |
|---|
| 1409 | |
|---|
| 1410 | /* Set RTS threshold */ |
|---|
| 1411 | val = atoi(nvram_default_get(strcat_r(prefix, "rts", tmp),"2347")); |
|---|
| 1412 | wl_iovar_setint(name, "rtsthresh", val); |
|---|
| 1413 | |
|---|
| 1414 | /* Set DTIM period */ |
|---|
| 1415 | val = atoi(nvram_default_get(strcat_r(prefix, "dtim", tmp),"1")); |
|---|
| 1416 | WL_IOCTL(name, WLC_SET_DTIMPRD, &val, sizeof(val)); |
|---|
| 1417 | |
|---|
| 1418 | /* Set beacon period */ |
|---|
| 1419 | val = atoi(nvram_default_get(strcat_r(prefix, "bcn", tmp),"100")); |
|---|
| 1420 | WL_IOCTL(name, WLC_SET_BCNPRD, &val, sizeof(val)); |
|---|
| 1421 | |
|---|
| 1422 | cprintf("set wds %s\n",name); |
|---|
| 1423 | /* AP only config */ |
|---|
| 1424 | if (ap || apsta || wds) { |
|---|
| 1425 | /* Set lazy WDS mode */ |
|---|
| 1426 | val = atoi(nvram_default_get(strcat_r(prefix, "lazywds", tmp),"0")); |
|---|
| 1427 | WL_IOCTL(name, WLC_SET_LAZYWDS, &val, sizeof(val)); |
|---|
| 1428 | |
|---|
| 1429 | /* Set the WDS list */ |
|---|
| 1430 | maclist = (struct maclist *) buf; |
|---|
| 1431 | maclist->count = 0; |
|---|
| 1432 | ea = maclist->ea; |
|---|
| 1433 | foreach(var, nvram_safe_get(strcat_r(prefix, "wds", tmp)), next) { |
|---|
| 1434 | if (((char *)(ea->octet)) > ((char *)(&buf[sizeof(buf)]))) |
|---|
| 1435 | break; |
|---|
| 1436 | ether_atoe(var, ea->octet); |
|---|
| 1437 | maclist->count++; |
|---|
| 1438 | ea++; |
|---|
| 1439 | } |
|---|
| 1440 | WL_IOCTL(name, WLC_SET_WDSLIST, buf, sizeof(buf)); |
|---|
| 1441 | |
|---|
| 1442 | /* Set WDS link detection timeout */ |
|---|
| 1443 | val = atoi(nvram_safe_get(strcat_r(prefix, "wds_timeout", tmp))); |
|---|
| 1444 | wl_iovar_setint(name, "wdstimeout", val); |
|---|
| 1445 | } |
|---|
| 1446 | |
|---|
| 1447 | cprintf("set wframeburst %s\n",name); |
|---|
| 1448 | /* Set framebursting mode */ |
|---|
| 1449 | if (btc_mode == WL_BTC_PREMPT) |
|---|
| 1450 | val = FALSE; |
|---|
| 1451 | else |
|---|
| 1452 | val = nvram_default_match(strcat_r(prefix, "frameburst", tmp), "on","off"); |
|---|
| 1453 | WL_IOCTL(name, WLC_SET_FAKEFRAG, &val, sizeof(val)); |
|---|
| 1454 | |
|---|
| 1455 | cprintf("set rifs mode %s\n",name); |
|---|
| 1456 | /* Set RIFS mode based on framebursting */ |
|---|
| 1457 | if (phytype == PHY_TYPE_N) { |
|---|
| 1458 | char *nvram_str = nvram_safe_get(strcat_r(prefix, "rifs", tmp)); |
|---|
| 1459 | if (!strcmp(nvram_str, "on")) |
|---|
| 1460 | wl_iovar_setint(name, "rifs", ON); |
|---|
| 1461 | else if (!strcmp(nvram_str, "off")) |
|---|
| 1462 | wl_iovar_setint(name, "rifs", OFF); |
|---|
| 1463 | } |
|---|
| 1464 | |
|---|
| 1465 | cprintf("set ba mode %s\n",name); |
|---|
| 1466 | /* Override BA mode only if set to on/off */ |
|---|
| 1467 | ba = nvram_safe_get(strcat_r(prefix, "ba", tmp)); |
|---|
| 1468 | if (!strcmp(ba, "on")) |
|---|
| 1469 | wl_iovar_setint(name, "ba", ON); |
|---|
| 1470 | else if (!strcmp(ba, "off")) |
|---|
| 1471 | wl_iovar_setint(name, "ba", OFF); |
|---|
| 1472 | |
|---|
| 1473 | cprintf("set up %s\n",name); |
|---|
| 1474 | /* Bring the interface back up */ |
|---|
| 1475 | WL_IOCTL(name, WLC_UP, NULL, 0); |
|---|
| 1476 | |
|---|
| 1477 | cprintf("set antdiv mode %s\n",name); |
|---|
| 1478 | /* Set antenna */ |
|---|
| 1479 | val = atoi(nvram_default_get(strcat_r(prefix, "antdiv", tmp),"3")); |
|---|
| 1480 | WL_IOCTL(name, WLC_SET_ANTDIV, &val, sizeof(val)); |
|---|
| 1481 | |
|---|
| 1482 | /* Auto Channel Selection - when channel # is 0 in AP mode |
|---|
| 1483 | * |
|---|
| 1484 | * The following condition(s) must be met in order for |
|---|
| 1485 | * Auto Channel Selection to work. |
|---|
| 1486 | * - the I/F must be up for the channel scan |
|---|
| 1487 | * - the AP must not be supporting a BSS (all BSS Configs must be disabled) |
|---|
| 1488 | */ |
|---|
| 1489 | if (ap || apsta) { |
|---|
| 1490 | if (!(val = atoi(nvram_default_get(strcat_r(prefix, "channel", tmp),"0")))) { |
|---|
| 1491 | if (phytype == PHY_TYPE_N) { |
|---|
| 1492 | chanspec_t chanspec = wlconf_auto_chanspec(name,prefix); |
|---|
| 1493 | if (chanspec != 0) |
|---|
| 1494 | { |
|---|
| 1495 | // fprintf(stderr,"auto chanspec %X\n",chanspec); |
|---|
| 1496 | WL_IOVAR_SETINT(name, "chanspec", chanspec); |
|---|
| 1497 | } |
|---|
| 1498 | } |
|---|
| 1499 | else { |
|---|
| 1500 | /* select a channel */ |
|---|
| 1501 | val = wlconf_auto_channel(name); |
|---|
| 1502 | /* switch to the selected channel */ |
|---|
| 1503 | if (val != 0) |
|---|
| 1504 | WL_IOCTL(name, WLC_SET_CHANNEL, &val, sizeof(val)); |
|---|
| 1505 | } |
|---|
| 1506 | /* set the auto channel scan timer in the driver when in auto mode */ |
|---|
| 1507 | val = 15; /* 15 minutes for now */ |
|---|
| 1508 | WL_IOCTL(name, WLC_SET_CS_SCAN_TIMER, &val, sizeof(val)); |
|---|
| 1509 | } |
|---|
| 1510 | else { |
|---|
| 1511 | /* reset the channel scan timer in the driver when not in auto mode */ |
|---|
| 1512 | val = 0; |
|---|
| 1513 | WL_IOCTL(name, WLC_SET_CS_SCAN_TIMER, &val, sizeof(val)); |
|---|
| 1514 | } |
|---|
| 1515 | } |
|---|
| 1516 | |
|---|
| 1517 | /* Security settings for each BSS Configuration */ |
|---|
| 1518 | for (i = 0; i < bclist->count; i++) { |
|---|
| 1519 | bsscfg = &bclist->bsscfgs[i]; |
|---|
| 1520 | wlconf_security_options(name, bsscfg->prefix, bsscfg->idx, wet); |
|---|
| 1521 | } |
|---|
| 1522 | |
|---|
| 1523 | /* |
|---|
| 1524 | * Finally enable BSS Configs or Join BSS |
|---|
| 1525 | * |
|---|
| 1526 | * AP: Enable BSS Config to bring AP up only when nas will not run |
|---|
| 1527 | * STA: Join the BSS regardless. |
|---|
| 1528 | */ |
|---|
| 1529 | for (i = 0; i < bclist->count; i++) { |
|---|
| 1530 | struct {int bsscfg_idx; int enable;} setbuf; |
|---|
| 1531 | |
|---|
| 1532 | setbuf.bsscfg_idx = bclist->bsscfgs[i].idx; |
|---|
| 1533 | setbuf.enable = 1; |
|---|
| 1534 | |
|---|
| 1535 | /* NAS runs if we have an AKM or radius authentication */ |
|---|
| 1536 | nas_will_run = wlconf_akm_options(bclist->bsscfgs[i].prefix) || |
|---|
| 1537 | nvram_default_match(strcat_r(bclist->bsscfgs[i].prefix, "auth_mode", tmp), |
|---|
| 1538 | "radius","disabled"); |
|---|
| 1539 | |
|---|
| 1540 | if (((ap || apsta) && !nas_will_run) || sta || wet) { |
|---|
| 1541 | for (ii = 0; ii < MAX_BSS_UP_RETRIES; ii++) { |
|---|
| 1542 | if (wl_ap_build) { |
|---|
| 1543 | WL_IOVAR_SET(name, "bss", &setbuf, sizeof(setbuf)); |
|---|
| 1544 | } |
|---|
| 1545 | else { |
|---|
| 1546 | strcat_r(prefix, "ssid", tmp); |
|---|
| 1547 | ssid.SSID_len = strlen(nvram_safe_get(tmp)); |
|---|
| 1548 | if (ssid.SSID_len > sizeof(ssid.SSID)) |
|---|
| 1549 | ssid.SSID_len = sizeof(ssid.SSID); |
|---|
| 1550 | strncpy((char *)ssid.SSID, nvram_safe_get(tmp), |
|---|
| 1551 | ssid.SSID_len); |
|---|
| 1552 | WL_IOCTL(name, WLC_SET_SSID, &ssid, sizeof(ssid)); |
|---|
| 1553 | } |
|---|
| 1554 | if (apsta && (ret != 0)) |
|---|
| 1555 | sleep_ms(1000); |
|---|
| 1556 | else |
|---|
| 1557 | break; |
|---|
| 1558 | } |
|---|
| 1559 | } |
|---|
| 1560 | } |
|---|
| 1561 | |
|---|
| 1562 | ret = 0; |
|---|
| 1563 | exit: |
|---|
| 1564 | if (bclist != NULL) |
|---|
| 1565 | free(bclist); |
|---|
| 1566 | |
|---|
| 1567 | return ret; |
|---|
| 1568 | } |
|---|
| 1569 | |
|---|
| 1570 | int |
|---|
| 1571 | wlconf_down(char *name) |
|---|
| 1572 | { |
|---|
| 1573 | int val, ret = 0; |
|---|
| 1574 | int i; |
|---|
| 1575 | int wlsubunit; |
|---|
| 1576 | int bcmerr; |
|---|
| 1577 | unsigned char buf[WLC_IOCTL_MAXLEN]; |
|---|
| 1578 | struct maclist *maclist; |
|---|
| 1579 | struct {int bsscfg_idx; int enable;} setbuf; |
|---|
| 1580 | int wl_ap_build = 0; /* 1 = wl compiled with AP capabilities */ |
|---|
| 1581 | char cap[WLC_IOCTL_SMLEN]; |
|---|
| 1582 | char caps[WLC_IOCTL_SMLEN]; |
|---|
| 1583 | char *next; |
|---|
| 1584 | wlc_ssid_t ssid; |
|---|
| 1585 | |
|---|
| 1586 | /* wlconf doesn't work for virtual i/f */ |
|---|
| 1587 | if (get_ifname_unit(name, NULL, &wlsubunit) == 0 && wlsubunit >= 0) { |
|---|
| 1588 | WLCONF_DBG("wlconf: skipping virtual interface \"%s\"\n", name); |
|---|
| 1589 | return 0; |
|---|
| 1590 | } |
|---|
| 1591 | |
|---|
| 1592 | /* Check interface (fail silently for non-wl interfaces) */ |
|---|
| 1593 | if ((ret = wl_probe(name))) |
|---|
| 1594 | return ret; |
|---|
| 1595 | |
|---|
| 1596 | /* because of ifdefs in wl driver, when we don't have AP capabilities we |
|---|
| 1597 | * can't use the same iovars to configure the wl. |
|---|
| 1598 | * so we use "wl_ap_build" to help us know how to configure the driver |
|---|
| 1599 | */ |
|---|
| 1600 | if (wl_iovar_get(name, "cap", (void *)caps, WLC_IOCTL_SMLEN)) |
|---|
| 1601 | return -1; |
|---|
| 1602 | |
|---|
| 1603 | foreach(cap, caps, next) { |
|---|
| 1604 | if (!strcmp(cap, "ap")) { |
|---|
| 1605 | wl_ap_build = 1; |
|---|
| 1606 | } |
|---|
| 1607 | } |
|---|
| 1608 | |
|---|
| 1609 | if (wl_ap_build) { |
|---|
| 1610 | /* Bring down the interface */ |
|---|
| 1611 | WL_IOCTL(name, WLC_DOWN, NULL, sizeof(val)); |
|---|
| 1612 | |
|---|
| 1613 | /* Disable all BSS Configs */ |
|---|
| 1614 | for (i = 0; i < WL_MAXBSSCFG; i++) { |
|---|
| 1615 | setbuf.bsscfg_idx = i; |
|---|
| 1616 | setbuf.enable = 0; |
|---|
| 1617 | |
|---|
| 1618 | ret = wl_iovar_set(name, "bss", &setbuf, sizeof(setbuf)); |
|---|
| 1619 | if (ret) { |
|---|
| 1620 | wl_iovar_getint(name, "bcmerror", &bcmerr); |
|---|
| 1621 | /* fail quietly on a range error since the driver may |
|---|
| 1622 | * support fewer bsscfgs than we are prepared to configure |
|---|
| 1623 | */ |
|---|
| 1624 | if (bcmerr == BCME_RANGE) |
|---|
| 1625 | break; |
|---|
| 1626 | } |
|---|
| 1627 | } |
|---|
| 1628 | } |
|---|
| 1629 | else { |
|---|
| 1630 | WL_IOCTL(name, WLC_GET_UP, &val, sizeof(val)); |
|---|
| 1631 | if (val) { |
|---|
| 1632 | /* Nuke SSID */ |
|---|
| 1633 | ssid.SSID_len = 0; |
|---|
| 1634 | ssid.SSID[0] = '\0'; |
|---|
| 1635 | WL_IOCTL(name, WLC_SET_SSID, &ssid, sizeof(ssid)); |
|---|
| 1636 | |
|---|
| 1637 | /* Bring down the interface */ |
|---|
| 1638 | WL_IOCTL(name, WLC_DOWN, NULL, sizeof(val)); |
|---|
| 1639 | } |
|---|
| 1640 | } |
|---|
| 1641 | |
|---|
| 1642 | /* Nuke the WDS list */ |
|---|
| 1643 | maclist = (struct maclist *) buf; |
|---|
| 1644 | maclist->count = 0; |
|---|
| 1645 | WL_IOCTL(name, WLC_SET_WDSLIST, buf, sizeof(buf)); |
|---|
| 1646 | |
|---|
| 1647 | return 0; |
|---|
| 1648 | } |
|---|
| 1649 | |
|---|
| 1650 | #if defined(linux) |
|---|
| 1651 | int |
|---|
| 1652 | main(int argc, char *argv[]) |
|---|
| 1653 | { |
|---|
| 1654 | /* Check parameters and branch based on action */ |
|---|
| 1655 | if (argc == 3 && !strcmp(argv[2], "up")) |
|---|
| 1656 | return wlconf(argv[1]); |
|---|
| 1657 | else if (argc == 3 && !strcmp(argv[2], "down")) |
|---|
| 1658 | return wlconf_down(argv[1]); |
|---|
| 1659 | else { |
|---|
| 1660 | fprintf(stderr, "Usage: wlconf <ifname> up|down\n"); |
|---|
| 1661 | return -1; |
|---|
| 1662 | } |
|---|
| 1663 | } |
|---|
| 1664 | #endif |
|---|