2 * Wireless Network Adapter configuration utility
4 * Copyright (C) 2005 Felix Fietkau <nbd@vd-s.ath.cx>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
26 #define WD_AUTH_IDLE 20
27 #define WD_CLIENT_IDLE 20
29 /*------------------------------------------------------------------*/
31 * Macro to handle errors when setting WE
32 * Print a nice error message and exit...
33 * We define them as macro so that "return" do the right thing.
34 * The "do {...} while(0)" is a standard trick
36 #define ERR_SET_EXT(rname, request) \
37 fprintf(stderr, "Error for wireless request \"%s\" (%X) :\n", \
40 #define ABORT_ARG_NUM(rname, request) \
42 ERR_SET_EXT(rname, request); \
43 fprintf(stderr, " too few arguments.\n"); \
46 #define ABORT_ARG_TYPE(rname, request, arg) \
48 ERR_SET_EXT(rname, request); \
49 fprintf(stderr, " invalid argument \"%s\".\n", arg); \
52 #define ABORT_ARG_SIZE(rname, request, max) \
54 ERR_SET_EXT(rname, request); \
55 fprintf(stderr, " argument too big (max %d)\n", max); \
58 /*------------------------------------------------------------------*/
60 * Wrapper to push some Wireless Parameter in the driver
61 * Use standard wrapper and add pretty error message if fail...
63 #define IW_SET_EXT_ERR(skfd, ifname, request, wrq, rname) \
65 if(iw_set_ext(skfd, ifname, request, wrq) < 0) { \
66 ERR_SET_EXT(rname, request); \
67 fprintf(stderr, " SET failed on device %-1.16s ; %s.\n", \
68 ifname, strerror(errno)); \
71 /*------------------------------------------------------------------*/
73 * Wrapper to extract some Wireless Parameter out of the driver
74 * Use standard wrapper and add pretty error message if fail...
76 #define IW_GET_EXT_ERR(skfd, ifname, request, wrq, rname) \
78 if(iw_get_ext(skfd, ifname, request, wrq) < 0) { \
79 ERR_SET_EXT(rname, request); \
80 fprintf(stderr, " GET failed on device %-1.16s ; %s.\n", \
81 ifname, strerror(errno)); \
84 static void set_wext_ssid(int skfd
, char *ifname
);
87 static char buffer
[128];
88 static int wpa_enc
= 0;
90 static char *wl_var(char *name
)
92 strcpy(buffer
, prefix
);
97 static int nvram_enabled(char *name
)
99 return (nvram_match(name
, "1") || nvram_match(name
, "on") || nvram_match(name
, "enabled") || nvram_match(name
, "true") || nvram_match(name
, "yes") ? 1 : 0);
102 static int nvram_disabled(char *name
)
104 return (nvram_match(name
, "0") || nvram_match(name
, "off") || nvram_match(name
, "disabled") || nvram_match(name
, "false") || nvram_match(name
, "no") ? 1 : 0);
107 static int bcom_ioctl(int skfd
, char *ifname
, int cmd
, void *buf
, int len
)
117 ifr
.ifr_data
= (caddr_t
) &ioc
;
118 strncpy(ifr
.ifr_name
, ifname
, IFNAMSIZ
);
120 ret
= ioctl(skfd
, SIOCDEVPRIVATE
, &ifr
);
125 static int bcom_set_val(int skfd
, char *ifname
, char *var
, void *val
, int len
)
130 if (strlen(var
) + 1 > sizeof(buf
) || len
> sizeof(buf
))
134 memcpy(&buf
[strlen(var
) + 1], val
, len
);
136 if ((ret
= bcom_ioctl(skfd
, ifname
, WLC_SET_VAR
, buf
, sizeof(buf
))))
142 static int bcom_set_int(int skfd
, char *ifname
, char *var
, int val
)
144 return bcom_set_val(skfd
, ifname
, var
, &val
, sizeof(val
));
147 static void stop_bcom(int skfd
, char *ifname
)
152 if (bcom_ioctl(skfd
, ifname
, WLC_GET_MAGIC
, &val
, sizeof(val
)) < 0)
157 bcom_ioctl(skfd
, ifname
, WLC_SET_SSID
, &ssid
, sizeof(ssid
));
158 bcom_ioctl(skfd
, ifname
, WLC_DOWN
, NULL
, 0);
162 static inline void set_distance(int skfd
, char *ifname
)
169 if (v
= nvram_get(wl_var("distance"))) {
170 val
= strtol(v
,NULL
,0);
171 val
= 9+(val
/150)+((val
%150)?1:0);
175 bcom_ioctl(skfd
, ifname
, 197, &shm
, sizeof(shm
));
180 bcom_ioctl(skfd
, ifname
, 102, ®
, sizeof(reg
));
184 static void start_bcom(int skfd
, char *ifname
)
188 if (bcom_ioctl(skfd
, ifname
, WLC_GET_MAGIC
, &val
, sizeof(val
)) < 0)
191 bcom_ioctl(skfd
, ifname
, WLC_UP
, &val
, sizeof(val
));
192 set_wext_ssid(skfd
, ifname
);
193 set_distance(skfd
, ifname
);
196 static int setup_bcom_wds(int skfd
, char *ifname
)
203 memset(buf
, 0, 8192);
204 if (v
= nvram_get(wl_var("wds"))) {
205 struct maclist
*wdslist
= (struct maclist
*) buf
;
206 struct ether_addr
*addr
= wdslist
->ea
;
209 foreach(wbuf
, v
, next
) {
210 if (ether_atoe(wbuf
, addr
->ether_addr_octet
)) {
217 bcom_ioctl(skfd
, ifname
, WLC_SET_WDSLIST
, buf
, sizeof(buf
));
222 void start_watchdog(int skfd
, char *ifname
)
225 unsigned char buf
[8192], wdslist
[8192], wbuf
[80], *v
, *p
, *next
, *tmp
;
226 int i
, j
, wds
= 0, c
= 0, restart_wds
= 0, wdstimeout
= 0, infra
;
231 f
= fopen("/var/run/wifi.pid", "w");
232 fprintf(f
, "%d\n", getpid());
235 infra
= strtol(nvram_safe_get(wl_var("infra")), NULL
, 0);
237 v
= nvram_safe_get(wl_var("wds"));
238 memset(wdslist
, 0, 8192);
240 foreach(wbuf
, v
, next
) {
241 if (ether_atoe(wbuf
, p
)) {
250 /* refresh the distance setting - the driver might change it */
251 set_distance(skfd
, ifname
);
256 if ((c
++ < WD_INTERVAL
) || ((restart_wds
> 0) && (wdstimeout
> 0)))
264 if (nvram_match(wl_var("mode"), "sta") ||
265 nvram_match(wl_var("mode"), "wet")) {
267 if (bcom_ioctl(skfd
, ifname
, WLC_GET_BSSID
, buf
, 6) < 0)
269 if (memcmp(buf
, "\0\0\0\0\0\0", 6) == 0)
272 memset(buf
, 0, 8192);
273 strcpy(buf
, "sta_info");
274 bcom_ioctl(skfd
, ifname
, WLC_GET_BSSID
, buf
+ strlen(buf
) + 1, 6);
275 if (bcom_ioctl(skfd
, ifname
, WLC_GET_VAR
, buf
, 8192) < 0) {
278 sta_info_t
*sta
= (sta_info_t
*) (buf
+ 4);
279 if ((sta
->flags
& 0x18) != 0x18)
281 if (sta
->idle
> WD_CLIENT_IDLE
)
286 set_wext_ssid(skfd
, ifname
);
293 wdstimeout
= strtol(nvram_safe_get(wl_var("wdstimeout")),NULL
,0);
295 for (i
= 0; (i
< wds
) && !restart_wds
; i
++, p
+= 6) {
296 memset(buf
, 0, 8192);
297 strcpy(buf
, "sta_info");
298 memcpy(buf
+ strlen(buf
) + 1, p
, 6);
299 if (!(bcom_ioctl(skfd
, ifname
, WLC_GET_VAR
, buf
, 8192) < 0)) {
300 sta_info_t
*sta
= (sta_info_t
*) (buf
+ 4);
301 if ((sta
->flags
& 0x40) == 0x40) /* this is a wds link */ {
302 if (sta
->idle
> wdstimeout
)
305 /* if not authorized after WD_AUTH_IDLE seconds idletime */
306 if (((sta
->flags
& WL_STA_AUTHO
) != WL_STA_AUTHO
) && (sta
->idle
> WD_AUTH_IDLE
))
312 if (restart_wds
&& (wdstimeout
> 0)) {
313 setup_bcom_wds(skfd
, ifname
);
318 static void setup_bcom(int skfd
, char *ifname
)
326 if (bcom_ioctl(skfd
, ifname
, WLC_GET_MAGIC
, &val
, sizeof(val
)) < 0)
329 nvram_set(wl_var("ifname"), ifname
);
331 stop_bcom(skfd
, ifname
);
334 strncpy(buf
, nvram_safe_get(wl_var("country_code")), 4);
336 bcom_ioctl(skfd
, ifname
, WLC_SET_COUNTRY
, buf
, 4);
338 val
= strtol(nvram_safe_get(wl_var("txpwr")),NULL
,0);
340 val
= strtol(nvram_safe_get("pa0maxpwr"),NULL
,0);
343 bcom_set_int(skfd
, ifname
, "qtxpower", val
);
345 /* Set other options */
346 val
= nvram_enabled(wl_var("lazywds"));
348 bcom_ioctl(skfd
, ifname
, WLC_SET_LAZYWDS
, &val
, sizeof(val
));
350 if (v
= nvram_get(wl_var("frag"))) {
351 val
= strtol(v
,NULL
,0);
352 bcom_ioctl(skfd
, ifname
, WLC_SET_FRAG
, &val
, sizeof(val
));
354 if ((val
= strtol(nvram_safe_get(wl_var("rate")),NULL
,0)) > 0) {
356 bcom_ioctl(skfd
, ifname
, WLC_SET_RATE
, &val
, sizeof(val
));
358 if (v
= nvram_get(wl_var("dtim"))) {
359 val
= strtol(v
,NULL
,0);
360 bcom_ioctl(skfd
, ifname
, WLC_SET_DTIMPRD
, &val
, sizeof(val
));
362 if (v
= nvram_get(wl_var("bcn"))) {
363 val
= strtol(v
,NULL
,0);
364 bcom_ioctl(skfd
, ifname
, WLC_SET_BCNPRD
, &val
, sizeof(val
));
366 if (v
= nvram_get(wl_var("rts"))) {
367 val
= strtol(v
,NULL
,0);
368 bcom_ioctl(skfd
, ifname
, WLC_SET_RTS
, &val
, sizeof(val
));
370 if (v
= nvram_get(wl_var("antdiv"))) {
371 val
= strtol(v
,NULL
,0);
372 bcom_ioctl(skfd
, ifname
, WLC_SET_ANTDIV
, &val
, sizeof(val
));
374 if (v
= nvram_get(wl_var("txant"))) {
375 val
= strtol(v
,NULL
,0);
376 bcom_ioctl(skfd
, ifname
, WLC_SET_TXANT
, &val
, sizeof(val
));
379 val
= nvram_enabled(wl_var("closed"));
380 bcom_ioctl(skfd
, ifname
, WLC_SET_CLOSED
, &val
, sizeof(val
));
382 val
= nvram_enabled(wl_var("ap_isolate"));
383 bcom_set_int(skfd
, ifname
, "ap_isolate", val
);
385 val
= nvram_enabled(wl_var("frameburst"));
386 bcom_ioctl(skfd
, ifname
, WLC_SET_FAKEFRAG
, &val
, sizeof(val
));
388 /* Set up MAC list */
389 if (nvram_match(wl_var("macmode"), "allow"))
390 val
= WLC_MACMODE_ALLOW
;
391 else if (nvram_match(wl_var("macmode"), "deny"))
392 val
= WLC_MACMODE_DENY
;
394 val
= WLC_MACMODE_DISABLED
;
396 if ((val
!= WLC_MACMODE_DISABLED
) && (v
= nvram_get(wl_var("maclist")))) {
397 struct maclist
*mac_list
;
398 struct ether_addr
*addr
;
401 memset(buf
, 0, 8192);
402 mac_list
= (struct maclist
*) buf
;
405 foreach(wbuf
, v
, next
) {
406 if (ether_atoe(wbuf
, addr
->ether_addr_octet
)) {
411 bcom_ioctl(skfd
, ifname
, WLC_SET_MACLIST
, buf
, sizeof(buf
));
413 val
= WLC_MACMODE_DISABLED
;
415 bcom_ioctl(skfd
, ifname
, WLC_SET_MACMODE
, &val
, sizeof(val
));
417 if (ap
= !nvram_match(wl_var("mode"), "sta") && !nvram_match(wl_var("mode"), "wet"))
418 wds_enabled
= setup_bcom_wds(skfd
, ifname
);
420 start_watchdog(skfd
, ifname
);
422 /* Set up afterburner, disabled it if WDS is enabled */
427 if (nvram_enabled(wl_var("afterburner")))
429 if (nvram_disabled(wl_var("afterburner")))
433 bcom_set_val(skfd
, ifname
, "afterburner_override", &val
, sizeof(val
));
436 bcom_ioctl(skfd
, ifname
, WLC_GET_PHYTYPE
, &val
, sizeof(val
));
438 int override
= WLC_G_PROTECTION_OFF
;
439 int control
= WLC_G_PROTECTION_CTL_OFF
;
441 if (v
= nvram_get(wl_var("gmode")))
442 val
= strtol(v
,NULL
,0);
449 bcom_ioctl(skfd
, ifname
, WLC_SET_GMODE
, &val
, sizeof(val
));
451 if (nvram_match(wl_var("gmode_protection"), "auto")) {
452 override
= WLC_G_PROTECTION_AUTO
;
453 control
= WLC_G_PROTECTION_CTL_OVERLAP
;
455 if (nvram_enabled(wl_var("gmode_protection"))) {
456 override
= WLC_G_PROTECTION_ON
;
457 control
= WLC_G_PROTECTION_CTL_OVERLAP
;
459 bcom_ioctl(skfd
, ifname
, WLC_SET_GMODE_PROTECTION_CONTROL
, &override
, sizeof(control
));
460 bcom_ioctl(skfd
, ifname
, WLC_SET_GMODE_PROTECTION_OVERRIDE
, &override
, sizeof(override
));
463 if (nvram_match(wl_var("plcphdr"), "long"))
466 val
= WLC_PLCP_SHORT
;
468 bcom_ioctl(skfd
, ifname
, WLC_SET_PLCPHDR
, &val
, sizeof(val
));
472 bcom_ioctl(skfd
, ifname
, WLC_UP
, &val
, sizeof(val
));
474 if (!(v
= nvram_get(wl_var("akm"))))
475 v
= nvram_safe_get(wl_var("auth_mode"));
477 if (strstr(v
, "wpa") || strstr(v
, "psk")) {
481 if (nvram_match(wl_var("crypto"), "tkip"))
483 else if (nvram_match(wl_var("crypto"), "aes"))
485 else if (nvram_match(wl_var("crypto"), "tkip+aes") || nvram_match(wl_var("crypto"), "aes+tkip"))
486 val
= TKIP_ENABLED
| AES_ENABLED
;
489 bcom_ioctl(skfd
, ifname
, WLC_SET_WSEC
, &val
, sizeof(val
));
491 if (val
&& strstr(v
, "psk")) {
492 val
= (strstr(v
, "psk2") ? 0x84 : 0x4);
493 v
= nvram_safe_get(wl_var("wpa_psk"));
494 if ((strlen(v
) >= 8) && (strlen(v
) <= 63)) {
496 bcom_ioctl(skfd
, ifname
, WLC_SET_WPA_AUTH
, &val
, sizeof(val
));
498 if (nvram_match(wl_var("mode"), "wet")) {
499 /* Enable in-driver WPA supplicant */
502 pmk
.key_len
= (unsigned short) strlen(v
);
503 pmk
.flags
= WSEC_PASSPHRASE
;
505 bcom_ioctl(skfd
, ifname
, WLC_SET_WSEC_PMK
, &pmk
, sizeof(pmk
));
506 bcom_set_int(skfd
, ifname
, "sup_wpa", 1);
511 bcom_ioctl(skfd
, ifname
, WLC_SET_EAP_RESTRICT
, &val
, sizeof(val
));
516 bcom_ioctl(skfd
, ifname
, WLC_SET_WSEC
, &val
, sizeof(val
));
517 bcom_ioctl(skfd
, ifname
, WLC_SET_WPA_AUTH
, &val
, sizeof(val
));
518 bcom_ioctl(skfd
, ifname
, WLC_SET_EAP_RESTRICT
, &val
, sizeof(val
));
519 bcom_set_int(skfd
, ifname
, "sup_wpa", 0);
522 if (v
= nvram_get(wl_var("auth"))) {
523 val
= strtol(v
,NULL
,0);
524 bcom_ioctl(skfd
, ifname
, WLC_SET_AUTH
, &val
, sizeof(val
));
528 static void set_wext_ssid(int skfd
, char *ifname
)
531 char essid
[IW_ESSID_MAX_SIZE
+ 1];
534 buffer
= nvram_get(wl_var("ssid"));
536 if (!buffer
|| (strlen(buffer
) > IW_ESSID_MAX_SIZE
))
539 wrq
.u
.essid
.flags
= 1;
540 strcpy(essid
, buffer
);
541 wrq
.u
.essid
.pointer
= (caddr_t
) essid
;
542 wrq
.u
.essid
.length
= strlen(essid
) + 1;
543 IW_SET_EXT_ERR(skfd
, ifname
, SIOCSIWESSID
, &wrq
, "Set ESSID");
546 static void setup_wext_wep(int skfd
, char *ifname
)
552 unsigned char key
[IW_ENCODING_TOKEN_MAX
];
554 memset(&wrq
, 0, sizeof(wrq
));
555 strcpy(keystr
, "key1");
556 for (i
= 1; i
<= 4; i
++) {
557 if (keyval
= nvram_get(wl_var(keystr
))) {
558 keylen
= iw_in_key(keyval
, key
);
561 wrq
.u
.data
.length
= keylen
;
562 wrq
.u
.data
.pointer
= (caddr_t
) key
;
563 wrq
.u
.data
.flags
= i
;
564 IW_SET_EXT_ERR(skfd
, ifname
, SIOCSIWENCODE
, &wrq
, "Set Encode");
570 memset(&wrq
, 0, sizeof(wrq
));
571 i
= strtol(nvram_safe_get(wl_var("key")),NULL
,0);
572 if (i
> 0 && i
< 4) {
573 wrq
.u
.data
.flags
= i
| IW_ENCODE_RESTRICTED
;
574 IW_SET_EXT_ERR(skfd
, ifname
, SIOCSIWENCODE
, &wrq
, "Set Encode");
578 static void set_wext_mode(int skfd
, char *ifname
)
581 int ap
= 0, infra
= 0, wet
= 0;
583 /* Set operation mode */
584 ap
= !nvram_match(wl_var("mode"), "sta") && !nvram_match(wl_var("mode"), "wet");
585 infra
= !nvram_disabled(wl_var("infra"));
586 wet
= !ap
&& nvram_match(wl_var("mode"), "wet");
588 wrq
.u
.mode
= (!infra
? IW_MODE_ADHOC
: (ap
? IW_MODE_MASTER
: (wet
? IW_MODE_REPEAT
: IW_MODE_INFRA
)));
589 IW_SET_EXT_ERR(skfd
, ifname
, SIOCSIWMODE
, &wrq
, "Set Mode");
592 static void setup_wext(int skfd
, char *ifname
)
598 int channel
= strtol(nvram_safe_get(wl_var("channel")),NULL
,0);
602 wrq
.u
.freq
.flags
= 0;
605 wrq
.u
.freq
.flags
= IW_FREQ_FIXED
;
606 wrq
.u
.freq
.m
= channel
;
607 IW_SET_EXT_ERR(skfd
, ifname
, SIOCSIWFREQ
, &wrq
, "Set Frequency");
611 /* Disable radio if wlX_radio is set and not enabled */
612 wrq
.u
.txpower
.disabled
= nvram_disabled(wl_var("radio"));
614 wrq
.u
.txpower
.value
= -1;
615 wrq
.u
.txpower
.fixed
= 1;
616 wrq
.u
.txpower
.flags
= IW_TXPOW_DBM
;
617 IW_SET_EXT_ERR(skfd
, ifname
, SIOCSIWTXPOW
, &wrq
, "Set Tx Power");
620 if (nvram_enabled(wl_var("wep")) && !wpa_enc
)
621 setup_wext_wep(skfd
, ifname
);
624 set_wext_ssid(skfd
, ifname
);
628 static int setup_interfaces(int skfd
, char *ifname
, char *args
[], int count
)
633 /* Avoid "Unused parameter" warning */
634 args
= args
; count
= count
;
636 if(iw_get_ext(skfd
, ifname
, SIOCGIWNAME
, &wrq
) < 0)
639 if (strncmp(ifname
, "ath", 3) == 0) {
640 set_wext_mode(skfd
, ifname
);
641 setup_wext(skfd
, ifname
);
643 stop_bcom(skfd
, ifname
);
644 set_wext_mode(skfd
, ifname
);
645 setup_bcom(skfd
, ifname
);
646 setup_wext(skfd
, ifname
);
647 start_bcom(skfd
, ifname
);
653 int main(int argc
, char **argv
)
656 if((skfd
= iw_sockets_open()) < 0) {
661 system("kill $(cat /var/run/wifi.pid 2>&-) 2>&- >&-");
663 prefix
= strdup("wl0_");
664 iw_enum_devices(skfd
, &setup_interfaces
, NULL
, 0);