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.
25 /*------------------------------------------------------------------*/
27 * Macro to handle errors when setting WE
28 * Print a nice error message and exit...
29 * We define them as macro so that "return" do the right thing.
30 * The "do {...} while(0)" is a standard trick
32 #define ERR_SET_EXT(rname, request) \
33 fprintf(stderr, "Error for wireless request \"%s\" (%X) :\n", \
36 #define ABORT_ARG_NUM(rname, request) \
38 ERR_SET_EXT(rname, request); \
39 fprintf(stderr, " too few arguments.\n"); \
42 #define ABORT_ARG_TYPE(rname, request, arg) \
44 ERR_SET_EXT(rname, request); \
45 fprintf(stderr, " invalid argument \"%s\".\n", arg); \
48 #define ABORT_ARG_SIZE(rname, request, max) \
50 ERR_SET_EXT(rname, request); \
51 fprintf(stderr, " argument too big (max %d)\n", max); \
54 /*------------------------------------------------------------------*/
56 * Wrapper to push some Wireless Parameter in the driver
57 * Use standard wrapper and add pretty error message if fail...
59 #define IW_SET_EXT_ERR(skfd, ifname, request, wrq, rname) \
61 if(iw_set_ext(skfd, ifname, request, wrq) < 0) { \
62 ERR_SET_EXT(rname, request); \
63 fprintf(stderr, " SET failed on device %-1.16s ; %s.\n", \
64 ifname, strerror(errno)); \
67 /*------------------------------------------------------------------*/
69 * Wrapper to extract some Wireless Parameter out of the driver
70 * Use standard wrapper and add pretty error message if fail...
72 #define IW_GET_EXT_ERR(skfd, ifname, request, wrq, rname) \
74 if(iw_get_ext(skfd, ifname, request, wrq) < 0) { \
75 ERR_SET_EXT(rname, request); \
76 fprintf(stderr, " GET failed on device %-1.16s ; %s.\n", \
77 ifname, strerror(errno)); \
80 static void set_wext_ssid(int skfd
, char *ifname
);
83 static char buffer
[128];
84 static int wpa_enc
= 0;
86 static char *wl_var(char *name
)
88 strcpy(buffer
, prefix
);
92 static int nvram_enabled(char *name
)
94 return (nvram_match(name
, "1") || nvram_match(name
, "on") || nvram_match(name
, "enabled") || nvram_match(name
, "true") || nvram_match(name
, "yes") ? 1 : 0);
97 static int nvram_disabled(char *name
)
99 return (nvram_match(name
, "0") || nvram_match(name
, "off") || nvram_match(name
, "disabled") || nvram_match(name
, "false") || nvram_match(name
, "no") ? 1 : 0);
103 static int bcom_ioctl(int skfd
, char *ifname
, int cmd
, void *buf
, int len
)
113 ifr
.ifr_data
= (caddr_t
) &ioc
;
114 strncpy(ifr
.ifr_name
, ifname
, IFNAMSIZ
);
116 ret
= ioctl(skfd
, SIOCDEVPRIVATE
, &ifr
);
121 static int bcom_set_val(int skfd
, char *ifname
, char *var
, void *val
, int len
)
126 if (strlen(var
) + 1 > sizeof(buf
) || len
> sizeof(buf
))
130 memcpy(&buf
[strlen(var
) + 1], val
, len
);
132 if ((ret
= bcom_ioctl(skfd
, ifname
, WLC_SET_VAR
, buf
, sizeof(buf
))))
138 static int bcom_set_int(int skfd
, char *ifname
, char *var
, int val
)
140 return bcom_set_val(skfd
, ifname
, var
, &val
, sizeof(val
));
143 static void stop_bcom(int skfd
, char *ifname
)
148 if (bcom_ioctl(skfd
, ifname
, WLC_GET_MAGIC
, &val
, sizeof(val
)) < 0)
153 bcom_ioctl(skfd
, ifname
, WLC_SET_SSID
, &ssid
, sizeof(ssid
));
154 bcom_ioctl(skfd
, ifname
, WLC_DOWN
, NULL
, 0);
158 static void start_bcom(int skfd
, char *ifname
)
162 if (bcom_ioctl(skfd
, ifname
, WLC_GET_MAGIC
, &val
, sizeof(val
)) < 0)
165 bcom_ioctl(skfd
, ifname
, WLC_UP
, &val
, sizeof(val
));
166 set_wext_ssid(skfd
, ifname
);
169 static int setup_bcom_wds(int skfd
, char *ifname
)
176 if (v
= nvram_get(wl_var("wds"))) {
177 struct maclist
*wdslist
= (struct maclist
*) buf
;
178 struct ether_addr
*addr
= wdslist
->ea
;
181 memset(buf
, 0, 8192);
182 foreach(wbuf
, v
, next
) {
183 if (ether_atoe(wbuf
, addr
->ether_addr_octet
)) {
189 bcom_ioctl(skfd
, ifname
, WLC_SET_WDSLIST
, buf
, sizeof(buf
));
194 void start_watchdog(int skfd
, char *ifname
)
197 unsigned char buf
[8192], buf2
[8192], wbuf
[80], *v
, *p
, *next
, *tmp
;
198 int wds
= 0, i
, restart_wds
;
203 system("kill $(cat /var/run/wifi.pid) 2>&- >&-");
204 f
= fopen("/var/run/wifi.pid", "w");
205 fprintf(f
, "%d\n", getpid());
208 v
= nvram_safe_get(wl_var("wds"));
209 memset(buf2
, 0, 8192);
211 foreach(wbuf
, v
, next
) {
212 if (ether_atoe(wbuf
, p
)) {
217 v
= nvram_safe_get(wl_var("ssid"));
221 if (bcom_ioctl(skfd
, ifname
, WLC_GET_BSSID
, buf
, 6) < 0)
222 bcom_ioctl(skfd
, ifname
, WLC_SET_SSID
, v
, strlen(v
));
225 for (i
= 0; i
< wds
; i
++) {
226 memset(buf
, 0, 8192);
227 strcpy(buf
, "sta_info");
228 memcpy(buf
+ strlen(buf
) + 1, p
, 6);
229 if (bcom_ioctl(skfd
, ifname
, WLC_GET_VAR
, buf
, 8192) < 0) {
231 sta_info_t
*sta
= (sta_info_t
*) (buf
+ 4);
232 if (!(sta
->flags
& 0x40)) {
241 setup_bcom_wds(skfd
, ifname
);
245 static void setup_bcom(int skfd
, char *ifname
)
253 if (bcom_ioctl(skfd
, ifname
, WLC_GET_MAGIC
, &val
, sizeof(val
)) < 0)
256 nvram_set(wl_var("ifname"), ifname
);
258 stop_bcom(skfd
, ifname
);
261 strncpy(buf
, nvram_safe_get(wl_var("country_code")), 4);
263 bcom_ioctl(skfd
, ifname
, WLC_SET_COUNTRY
, buf
, 4);
265 /* Set other options */
266 val
= nvram_enabled(wl_var("lazywds"));
268 bcom_ioctl(skfd
, ifname
, WLC_SET_LAZYWDS
, &val
, sizeof(val
));
270 if (v
= nvram_get(wl_var("frag"))) {
272 bcom_ioctl(skfd
, ifname
, WLC_SET_FRAG
, &val
, sizeof(val
));
274 if (v
= nvram_get(wl_var("dtim"))) {
276 bcom_ioctl(skfd
, ifname
, WLC_SET_DTIMPRD
, &val
, sizeof(val
));
278 if (v
= nvram_get(wl_var("bcn"))) {
280 bcom_ioctl(skfd
, ifname
, WLC_SET_BCNPRD
, &val
, sizeof(val
));
282 if (v
= nvram_get(wl_var("rts"))) {
284 bcom_ioctl(skfd
, ifname
, WLC_SET_RTS
, &val
, sizeof(val
));
286 if (v
= nvram_get(wl_var("antdiv"))) {
288 bcom_ioctl(skfd
, ifname
, WLC_SET_ANTDIV
, &val
, sizeof(val
));
290 if (v
= nvram_get(wl_var("txant"))) {
292 bcom_ioctl(skfd
, ifname
, WLC_SET_TXANT
, &val
, sizeof(val
));
295 val
= nvram_enabled(wl_var("closed"));
296 bcom_ioctl(skfd
, ifname
, WLC_SET_CLOSED
, &val
, sizeof(val
));
298 val
= nvram_enabled(wl_var("ap_isolate"));
299 bcom_set_int(skfd
, ifname
, "ap_isolate", val
);
301 val
= nvram_enabled(wl_var("frameburst"));
302 bcom_ioctl(skfd
, ifname
, WLC_SET_FAKEFRAG
, &val
, sizeof(val
));
304 /* Set up MAC list */
305 if (nvram_match(wl_var("macmode"), "allow"))
306 val
= WLC_MACMODE_ALLOW
;
307 else if (nvram_match(wl_var("macmode"), "deny"))
308 val
= WLC_MACMODE_DENY
;
310 val
= WLC_MACMODE_DISABLED
;
312 if ((val
!= WLC_MACMODE_DISABLED
) && (v
= nvram_get(wl_var("maclist")))) {
313 struct maclist
*mac_list
;
314 struct ether_addr
*addr
;
317 memset(buf
, 0, 8192);
318 mac_list
= (struct maclist
*) buf
;
321 foreach(wbuf
, v
, next
) {
322 if (ether_atoe(wbuf
, addr
->ether_addr_octet
)) {
327 bcom_ioctl(skfd
, ifname
, WLC_SET_MACLIST
, buf
, sizeof(buf
));
329 val
= WLC_MACMODE_DISABLED
;
331 bcom_ioctl(skfd
, ifname
, WLC_SET_MACMODE
, &val
, sizeof(val
));
333 if (ap
= !nvram_match(wl_var("mode"), "sta") && !nvram_match(wl_var("mode"), "wet"))
334 wds_enabled
= setup_bcom_wds(skfd
, ifname
);
336 if (!ap
|| wds_enabled
)
337 start_watchdog(skfd
, ifname
);
339 /* Set up afterburner, disabled it if WDS is enabled */
344 if (nvram_enabled(wl_var("afterburner")))
346 if (nvram_disabled(wl_var("afterburner")))
350 bcom_set_val(skfd
, ifname
, "afterburner_override", &val
, sizeof(val
));
353 bcom_ioctl(skfd
, ifname
, WLC_GET_PHYTYPE
, &val
, sizeof(val
));
355 int override
= WLC_G_PROTECTION_OFF
;
356 int control
= WLC_G_PROTECTION_CTL_OFF
;
358 if (v
= nvram_get(wl_var("gmode")))
366 bcom_ioctl(skfd
, ifname
, WLC_SET_GMODE
, &val
, sizeof(val
));
368 if (nvram_match(wl_var("gmode_protection"), "auto")) {
369 override
= WLC_G_PROTECTION_AUTO
;
370 control
= WLC_G_PROTECTION_CTL_OVERLAP
;
372 if (nvram_enabled(wl_var("gmode_protection"))) {
373 override
= WLC_G_PROTECTION_ON
;
374 control
= WLC_G_PROTECTION_CTL_OVERLAP
;
376 bcom_ioctl(skfd
, ifname
, WLC_SET_GMODE_PROTECTION_CONTROL
, &override
, sizeof(control
));
377 bcom_ioctl(skfd
, ifname
, WLC_SET_GMODE_PROTECTION_OVERRIDE
, &override
, sizeof(override
));
380 if (nvram_match(wl_var("plcphdr"), "long"))
383 val
= WLC_PLCP_SHORT
;
385 bcom_ioctl(skfd
, ifname
, WLC_SET_PLCPHDR
, &val
, sizeof(val
));
389 start_bcom(skfd
, ifname
);
391 if (!(v
= nvram_get(wl_var("akm"))))
392 v
= nvram_safe_get(wl_var("auth_mode"));
394 if (strstr(v
, "wpa") || strstr(v
, "psk")) {
398 if (nvram_match(wl_var("crypto"), "tkip"))
400 else if (nvram_match(wl_var("crypto"), "aes"))
402 else if (nvram_match(wl_var("crypto"), "tkip+aes") || nvram_match(wl_var("crypto"), "aes+tkip"))
403 val
= TKIP_ENABLED
| AES_ENABLED
;
406 bcom_ioctl(skfd
, ifname
, WLC_SET_WSEC
, &val
, sizeof(val
));
408 if (val
&& strstr(v
, "psk")) {
409 v
= nvram_safe_get(wl_var("wpa_psk"));
411 if ((strlen(v
) >= 8) && (strlen(v
) < 63)) {
413 bcom_ioctl(skfd
, ifname
, WLC_SET_WPA_AUTH
, &val
, sizeof(val
));
415 bcom_ioctl(skfd
, ifname
, WLC_GET_AP
, &val
, sizeof(val
));
417 /* Enable in-driver WPA supplicant */
420 pmk
.key_len
= (unsigned short) strlen(v
);
421 pmk
.flags
= WSEC_PASSPHRASE
;
423 bcom_ioctl(skfd
, ifname
, WLC_SET_WSEC_PMK
, &pmk
, sizeof(pmk
));
424 bcom_set_int(skfd
, ifname
, "sup_wpa", 1);
429 bcom_ioctl(skfd
, ifname
, WLC_SET_EAP_RESTRICT
, &val
, sizeof(val
));
434 bcom_ioctl(skfd
, ifname
, WLC_SET_WSEC
, &val
, sizeof(val
));
435 bcom_ioctl(skfd
, ifname
, WLC_SET_WPA_AUTH
, &val
, sizeof(val
));
436 bcom_ioctl(skfd
, ifname
, WLC_SET_EAP_RESTRICT
, &val
, sizeof(val
));
437 bcom_set_int(skfd
, ifname
, "sup_wpa", 0);
441 static void set_wext_ssid(int skfd
, char *ifname
)
444 char essid
[IW_ESSID_MAX_SIZE
+ 1];
447 buffer
= nvram_get(wl_var("ssid"));
449 if (!buffer
|| (strlen(buffer
) > IW_ESSID_MAX_SIZE
))
452 wrq
.u
.essid
.flags
= 1;
453 strcpy(essid
, buffer
);
454 wrq
.u
.essid
.pointer
= (caddr_t
) essid
;
455 wrq
.u
.essid
.length
= strlen(essid
) + 1;
456 IW_SET_EXT_ERR(skfd
, ifname
, SIOCSIWESSID
, &wrq
, "Set ESSID");
459 static void setup_wext_wep(int skfd
, char *ifname
)
465 unsigned char key
[IW_ENCODING_TOKEN_MAX
];
467 memset(&wrq
, 0, sizeof(wrq
));
468 strcpy(keystr
, "key1");
469 for (i
= 1; i
<= 4; i
++) {
470 if (keyval
= nvram_get(wl_var(keystr
))) {
471 keylen
= iw_in_key(keyval
, key
);
474 wrq
.u
.data
.length
= keylen
;
475 wrq
.u
.data
.pointer
= (caddr_t
) key
;
476 wrq
.u
.data
.flags
= i
;
477 IW_SET_EXT_ERR(skfd
, ifname
, SIOCSIWENCODE
, &wrq
, "Set Encode");
483 memset(&wrq
, 0, sizeof(wrq
));
484 i
= atoi(nvram_safe_get(wl_var("key")));
485 if (i
> 0 && i
< 4) {
486 wrq
.u
.data
.flags
= i
| IW_ENCODE_RESTRICTED
;
487 IW_SET_EXT_ERR(skfd
, ifname
, SIOCSIWENCODE
, &wrq
, "Set Encode");
491 static void set_wext_mode(skfd
, ifname
)
494 int ap
= 0, infra
= 0, wet
= 0;
496 /* Set operation mode */
497 ap
= !nvram_match(wl_var("mode"), "sta") && !nvram_match(wl_var("mode"), "wet");
498 infra
= !nvram_disabled(wl_var("infra"));
499 wet
= !ap
&& nvram_match(wl_var("mode"), "wet");
501 wrq
.u
.mode
= (!infra
? IW_MODE_ADHOC
: (ap
? IW_MODE_MASTER
: (wet
? IW_MODE_REPEAT
: IW_MODE_INFRA
)));
502 IW_SET_EXT_ERR(skfd
, ifname
, SIOCSIWMODE
, &wrq
, "Set Mode");
505 static void setup_wext(int skfd
, char *ifname
)
511 int channel
= atoi(nvram_safe_get(wl_var("channel")));
515 wrq
.u
.freq
.flags
= 0;
518 wrq
.u
.freq
.flags
= IW_FREQ_FIXED
;
519 wrq
.u
.freq
.m
= channel
;
520 IW_SET_EXT_ERR(skfd
, ifname
, SIOCSIWFREQ
, &wrq
, "Set Frequency");
524 /* Disable radio if wlX_radio is set and not enabled */
525 wrq
.u
.txpower
.disabled
= nvram_disabled(wl_var("radio"));
527 wrq
.u
.txpower
.value
= -1;
528 wrq
.u
.txpower
.fixed
= 1;
529 wrq
.u
.txpower
.flags
= IW_TXPOW_DBM
;
530 IW_SET_EXT_ERR(skfd
, ifname
, SIOCSIWTXPOW
, &wrq
, "Set Tx Power");
533 if (nvram_enabled(wl_var("wep")) && !wpa_enc
)
534 setup_wext_wep(skfd
, ifname
);
537 set_wext_ssid(skfd
, ifname
);
541 static int setup_interfaces(int skfd
, char *ifname
, char *args
[], int count
)
546 /* Avoid "Unused parameter" warning */
547 args
= args
; count
= count
;
549 if(iw_get_ext(skfd
, ifname
, SIOCGIWNAME
, &wrq
) < 0)
552 if (strncmp(ifname
, "ath", 3) == 0) {
553 set_wext_mode(skfd
, ifname
);
554 setup_wext(skfd
, ifname
);
556 stop_bcom(skfd
, ifname
);
557 set_wext_mode(skfd
, ifname
);
558 setup_bcom(skfd
, ifname
);
559 setup_wext(skfd
, ifname
);
565 int main(int argc
, char **argv
)
568 if((skfd
= iw_sockets_open()) < 0) {
573 prefix
= strdup("wl0_");
574 iw_enum_devices(skfd
, &setup_interfaces
, NULL
, 0);