Allow to specify static routes for MAN interface
[tomato.git] / release / src / router / rc / network.c
blob016f22826a531794bc84bc57a94935fe9c7b369e
1 /*
3 Copyright 2003, CyberTAN Inc. All Rights Reserved
5 This is UNPUBLISHED PROPRIETARY SOURCE CODE of CyberTAN Inc.
6 the contents of this file may not be disclosed to third parties,
7 copied or duplicated in any form without the prior written
8 permission of CyberTAN Inc.
10 This software should be used as a reference only, and it not
11 intended for production use!
13 THIS SOFTWARE IS OFFERED "AS IS", AND CYBERTAN GRANTS NO WARRANTIES OF ANY
14 KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. CYBERTAN
15 SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
16 FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE
21 Copyright 2005, Broadcom Corporation
22 All Rights Reserved.
24 THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
25 KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
26 SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
27 FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
32 wificonf, OpenWRT
33 Copyright (C) 2005 Felix Fietkau <nbd@vd-s.ath.cx>
38 Modified for Tomato Firmware
39 Portions, Copyright (C) 2006-2009 Jonathan Zarate
43 #include <rc.h>
45 #ifndef UU_INT
46 typedef u_int64_t u64;
47 typedef u_int32_t u32;
48 typedef u_int16_t u16;
49 typedef u_int8_t u8;
50 #endif
52 #include <linux/types.h>
53 #include <linux/sockios.h>
54 #include <linux/ethtool.h>
55 #include <sys/ioctl.h>
56 #include <net/if_arp.h>
58 #include <wlutils.h>
59 #include <bcmparams.h>
60 #include <wlioctl.h>
62 #ifndef WL_BSS_INFO_VERSION
63 #error WL_BSS_INFO_VERSION
64 #endif
65 #if WL_BSS_INFO_VERSION == 108
66 #include <etioctl.h>
67 #else
68 #include <etsockio.h>
69 #endif
71 #define IFUP (IFF_UP | IFF_RUNNING | IFF_BROADCAST | IFF_MULTICAST)
72 #define sin_addr(s) (((struct sockaddr_in *)(s))->sin_addr)
74 #ifdef TCONFIG_SAMBASRV
75 //!!TB - hostname is required for Samba to work
76 void set_lan_hostname(const char *wan_hostname)
78 const char *s;
79 FILE *f;
81 nvram_set("lan_hostname", wan_hostname);
82 if ((wan_hostname == NULL) || (*wan_hostname == 0)) {
83 /* derive from et0 mac address */
84 s = nvram_get("et0macaddr");
85 if (s && strlen(s) >= 17) {
86 char hostname[16];
87 sprintf(hostname, "RT-%c%c%c%c%c%c%c%c%c%c%c%c",
88 s[0], s[1], s[3], s[4], s[6], s[7],
89 s[9], s[10], s[12], s[13], s[15], s[16]);
91 if ((f = fopen("/proc/sys/kernel/hostname", "w"))) {
92 fputs(hostname, f);
93 fclose(f);
95 nvram_set("lan_hostname", hostname);
99 if ((f = fopen("/etc/hosts", "w"))) {
100 fprintf(f, "127.0.0.1 localhost\n");
101 fprintf(f, "%s %s\n",
102 nvram_safe_get("lan_ipaddr"), nvram_safe_get("lan_hostname"));
103 fclose(f);
106 #endif
108 void set_host_domain_name(void)
110 const char *s;
112 s = nvram_safe_get("wan_hostname");
113 sethostname(s, strlen(s));
115 #ifdef TCONFIG_SAMBASRV
116 //!!TB - hostname is required for Samba to work
117 set_lan_hostname(s);
118 #endif
120 s = nvram_get("wan_domain");
121 if ((s == NULL) || (*s == 0)) s = nvram_safe_get("wan_get_domain");
122 setdomainname(s, strlen(s));
125 static int wlconf(char *ifname)
127 int r;
129 r = eval("wlconf", ifname, "up");
130 if (r == 0) {
131 // set_mac(ifname, "mac_wl", 2);
133 nvram_set("rrules_radio", "-1");
135 eval("wl", "antdiv", nvram_safe_get("wl_antdiv"));
136 eval("wl", "txant", nvram_safe_get("wl_txant"));
137 eval("wl", "txpwr1", "-o", "-m", nvram_get_int("wl_txpwr") ? nvram_safe_get("wl_txpwr") : "-1");
139 killall("wldist", SIGTERM);
140 eval("wldist");
142 if (wl_client()) {
143 if (nvram_match("wl_mode", "wet")) {
144 ifconfig(ifname, IFUP|IFF_ALLMULTI, NULL, NULL);
146 if (nvram_match("wl_radio", "1")) {
147 xstart("radio", "join");
151 return r;
155 /* Set initial QoS mode for all et interfaces that are up. */
156 void set_et_qos_mode(int sfd)
158 int i, qos;
159 caddr_t ifrdata;
160 struct ifreq ifr;
161 struct ethtool_drvinfo info;
163 qos = (strcmp(nvram_safe_get("wl_wme"), "off") != 0);
164 for (i = 1; i <= DEV_NUMIFS; i++) {
165 ifr.ifr_ifindex = i;
166 if (ioctl(sfd, SIOCGIFNAME, &ifr)) continue;
167 if (ioctl(sfd, SIOCGIFHWADDR, &ifr)) continue;
168 if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) continue;
169 /* get flags */
170 if (ioctl(sfd, SIOCGIFFLAGS, &ifr)) continue;
171 /* if up (wan may not be up yet at this point) */
172 if (ifr.ifr_flags & IFF_UP) {
173 ifrdata = ifr.ifr_data;
174 memset(&info, 0, sizeof(info));
175 info.cmd = ETHTOOL_GDRVINFO;
176 ifr.ifr_data = (caddr_t)&info;
177 if (ioctl(sfd, SIOCETHTOOL, &ifr) >= 0) {
178 /* Set QoS for et & bcm57xx devices */
179 if (!strncmp(info.driver, "et", 2) ||
180 !strncmp(info.driver, "bcm57", 5)) {
181 ifr.ifr_data = (caddr_t)&qos;
182 ioctl(sfd, SIOCSETCQOS, &ifr);
185 ifr.ifr_data = ifrdata;
190 static void check_afterburner(void)
192 char *p;
194 if (nvram_match("wl_afterburner", "off")) return;
195 if ((p = nvram_get("boardflags")) == NULL) return;
197 if (strcmp(p, "0x0118") == 0) { // G 2.2, 3.0, 3.1
198 p = "0x0318";
200 else if (strcmp(p, "0x0188") == 0) { // G 2.0
201 p = "0x0388";
203 else if (strcmp(p, "0x2558") == 0) { // G 4.0, GL 1.0, 1.1
204 p = "0x2758";
206 else {
207 return;
210 nvram_set("boardflags", p);
212 if (!nvram_match("debug_abrst", "0")) {
213 modprobe_r("wl");
214 modprobe("wl");
218 /* safe?
220 unsigned long bf;
221 char s[64];
223 bf = strtoul(p, &p, 0);
224 if ((*p == 0) && ((bf & BFL_AFTERBURNER) == 0)) {
225 sprintf(s, "0x%04lX", bf | BFL_AFTERBURNER);
226 nvram_set("boardflags", s);
231 #ifdef CONFIG_BCMWL5
232 void start_wl(void)
234 char *lan_ifname, *lan_ifnames, *ifname, *p;
236 lan_ifname = nvram_safe_get("lan_ifname");
237 if (strncmp(lan_ifname, "br", 2) == 0) {
238 if ((lan_ifnames = strdup(nvram_safe_get("lan_ifnames"))) != NULL) {
239 p = lan_ifnames;
240 while ((ifname = strsep(&p, " ")) != NULL) {
241 while (*ifname == ' ') ++ifname;
242 if (*ifname == 0) break;
243 #if 0
244 /* Ignore disabled wl vifs */
245 if (strncmp(ifname, "wl", 2) == 0) {
246 char nv[40];
247 snprintf(nv, sizeof(nv) - 1, "%s_bss_enabled", ifname);
248 if (!nvram_get_int(nv))
249 continue;
251 #endif
252 eval("wlconf", ifname, "start"); /* start wl iface */
254 free(lan_ifnames);
257 else if (strcmp(lan_ifname, "")) {
258 /* specific non-bridged lan iface */
259 eval("wlconf", lan_ifname, "start");
262 if (wl_client() && nvram_match("wl_radio", "1"))
263 xstart("radio", "join");
265 #endif // CONFIG_BCMWL5
267 void start_lan(void)
269 _dprintf("%s %d\n", __FUNCTION__, __LINE__);
271 char *lan_ifname;
272 struct ifreq ifr;
273 char *lan_ifnames, *ifname, *p;
274 int sfd;
276 set_mac(nvram_safe_get("wl_ifname"), "mac_wl", 2);
277 check_afterburner();
279 if ((sfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) return;
281 lan_ifname = strdup(nvram_safe_get("lan_ifname"));
282 if (strncmp(lan_ifname, "br", 2) == 0) {
283 eval("brctl", "addbr", lan_ifname);
284 eval("brctl", "setfd", lan_ifname, "0");
285 eval("brctl", "stp", lan_ifname, nvram_safe_get("lan_stp"));
287 if ((lan_ifnames = strdup(nvram_safe_get("lan_ifnames"))) != NULL) {
288 p = lan_ifnames;
289 while ((ifname = strsep(&p, " ")) != NULL) {
290 while (*ifname == ' ') ++ifname;
291 if (*ifname == 0) break;
293 // bring up interface
294 if (ifconfig(ifname, IFUP, NULL, NULL) != 0) continue;
296 // set the logical bridge address to that of the first interface
297 strlcpy(ifr.ifr_name, lan_ifname, IFNAMSIZ);
298 if ((ioctl(sfd, SIOCGIFHWADDR, &ifr) == 0) && (memcmp(ifr.ifr_hwaddr.sa_data, "\0\0\0\0\0\0", ETHER_ADDR_LEN) == 0)) {
299 strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
300 if (ioctl(sfd, SIOCGIFHWADDR, &ifr) == 0) {
301 strlcpy(ifr.ifr_name, lan_ifname, IFNAMSIZ);
302 ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
303 ioctl(sfd, SIOCSIFHWADDR, &ifr);
307 if (wlconf(ifname) == 0) {
308 const char *mode = nvram_get("wl0_mode");
309 if ((mode) && ((strcmp(mode, "ap") != 0) && (strcmp(mode, "wet") != 0))) continue;
311 eval("brctl", "addif", lan_ifname, ifname);
314 if ((nvram_get_int("wan_islan")) &&
315 ((get_wan_proto() == WP_DISABLED) || (nvram_match("wl_mode", "sta")))) {
316 ifname = nvram_get("wan_ifnameX");
317 if (ifconfig(ifname, IFUP, NULL, NULL) == 0)
318 eval("brctl", "addif", lan_ifname, ifname);
321 free(lan_ifnames);
324 // --- this shouldn't happen ---
325 else if (*lan_ifname) {
326 ifconfig(lan_ifname, IFUP, NULL, NULL);
327 wlconf(lan_ifname);
329 else {
330 close(sfd);
331 free(lan_ifname);
332 return;
336 // Get current LAN hardware address
337 char eabuf[32];
338 strlcpy(ifr.ifr_name, lan_ifname, IFNAMSIZ);
339 if (ioctl(sfd, SIOCGIFHWADDR, &ifr) == 0) nvram_set("lan_hwaddr", ether_etoa(ifr.ifr_hwaddr.sa_data, eabuf));
341 // Set initial QoS mode for LAN ports
342 set_et_qos_mode(sfd);
344 close(sfd);
346 // bring up and configure LAN interface
347 ifconfig(lan_ifname, IFUP, nvram_safe_get("lan_ipaddr"), nvram_safe_get("lan_netmask"));
349 config_loopback();
350 do_static_routes(1);
352 #ifdef TCONFIG_SAMBASRV
353 //!!TB - hostname is required for Samba to work
354 set_lan_hostname(nvram_safe_get("wan_hostname"));
355 #endif
357 if (nvram_match("wan_proto", "disabled")) {
358 char *gateway = nvram_safe_get("lan_gateway") ;
359 if ((*gateway) && (strcmp(gateway, "0.0.0.0") != 0)) {
360 int tries = 5;
361 while ((route_add(lan_ifname, 0, "0.0.0.0", gateway, "0.0.0.0") != 0) && (tries-- > 0)) sleep(1);
362 _dprintf("%s: add gateway=%s tries=%d\n", __FUNCTION__, gateway, tries);
366 free(lan_ifname);
368 _dprintf("%s %d\n", __FUNCTION__, __LINE__);
371 void stop_lan(void)
373 _dprintf("%s %d\n", __FUNCTION__, __LINE__);
375 char *lan_ifname;
376 char *lan_ifnames, *p, *ifname;
378 lan_ifname = nvram_safe_get("lan_ifname");
379 ifconfig(lan_ifname, 0, NULL, NULL);
381 if (strncmp(lan_ifname, "br", 2) == 0) {
382 if ((lan_ifnames = strdup(nvram_safe_get("lan_ifnames"))) != NULL) {
383 p = lan_ifnames;
384 while ((ifname = strsep(&p, " ")) != NULL) {
385 while (*ifname == ' ') ++ifname;
386 if (*ifname == 0) break;
387 eval("wlconf", ifname, "down");
388 ifconfig(ifname, 0, NULL, NULL);
389 eval("brctl", "delif", lan_ifname, ifname);
391 free(lan_ifnames);
393 eval("brctl", "delbr", lan_ifname);
395 else if (*lan_ifname) {
396 eval("wlconf", lan_ifname, "down");
399 _dprintf("%s %d\n", __FUNCTION__, __LINE__);
403 void do_static_routes(int add)
405 char *buf;
406 char *p, *q;
407 char *dest, *mask, *gateway, *metric, *ifname;
408 int r;
410 if ((buf = strdup(nvram_safe_get(add ? "routes_static" : "routes_static_saved"))) == NULL) return;
411 if (add) nvram_set("routes_static_saved", buf);
412 else nvram_unset("routes_static_saved");
413 p = buf;
414 while ((q = strsep(&p, ">")) != NULL) {
415 if (vstrsep(q, "<", &dest, &gateway, &mask, &metric, &ifname) != 5) continue;
416 ifname = nvram_safe_get((*ifname == 'L') ? "lan_ifname" :
417 ((*ifname == 'W') ? "wan_iface" : "wan_ifname"));
418 if (add) {
419 for (r = 3; r >= 0; --r) {
420 if (route_add(ifname, atoi(metric) + 1, dest, gateway, mask) == 0) break;
421 sleep(1);
424 else {
425 route_del(ifname, atoi(metric) + 1, dest, gateway, mask);
428 free(buf);
431 void hotplug_net(void)
433 char *interface, *action;
434 char *lan_ifname;
436 if (((interface = getenv("INTERFACE")) == NULL) || ((action = getenv("ACTION")) == NULL)) return;
438 _dprintf("hotplug net INTERFACE=%s ACTION=%s\n", interface, action);
440 if ((nvram_match("wds_enable", "1")) && (strncmp(interface, "wds", 3) == 0) &&
441 (strcmp(action, "register") == 0 || strcmp(action, "add") == 0)) {
442 ifconfig(interface, IFUP, NULL, NULL);
443 lan_ifname = nvram_safe_get("lan_ifname");
444 if (strncmp(lan_ifname, "br", 2) == 0) {
445 eval("brctl", "addif", lan_ifname, interface);
446 notify_nas(interface);
452 static int is_same_addr(struct ether_addr *addr1, struct ether_addr *addr2)
454 int i;
455 for (i = 0; i < 6; i++) {
456 if (addr1->octet[i] != addr2->octet[i])
457 return 0;
459 return 1;
462 #define WL_MAX_ASSOC 128
463 static int check_wl_client(char *ifname)
465 struct ether_addr bssid;
466 wl_bss_info_t *bi;
467 char buf[WLC_IOCTL_MAXLEN];
468 struct maclist *mlist;
469 int mlsize, i;
470 int associated, authorized;
472 *(uint32 *)buf = WLC_IOCTL_MAXLEN;
473 if (wl_ioctl(ifname, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN) < 0 ||
474 wl_ioctl(ifname, WLC_GET_BSS_INFO, buf, WLC_IOCTL_MAXLEN) < 0)
475 return 0;
477 bi = (wl_bss_info_t *)(buf + 4);
478 if ((bi->SSID_len == 0) ||
479 (bi->BSSID.octet[0] + bi->BSSID.octet[1] + bi->BSSID.octet[2] +
480 bi->BSSID.octet[3] + bi->BSSID.octet[4] + bi->BSSID.octet[5] == 0))
481 return 0;
483 associated = 0;
484 authorized = strstr(nvram_safe_get("wl_akm"), "psk") == 0;
486 mlsize = sizeof(struct maclist) + (WL_MAX_ASSOC * sizeof(struct ether_addr));
487 if ((mlist = malloc(mlsize)) != NULL) {
488 mlist->count = WL_MAX_ASSOC;
489 if (wl_ioctl(ifname, WLC_GET_ASSOCLIST, mlist, mlsize) == 0) {
490 for (i = 0; i < mlist->count; ++i) {
491 if (is_same_addr(&mlist->ea[i], &bi->BSSID)) {
492 associated = 1;
493 break;
498 if (associated && !authorized) {
499 memset(mlist, 0, mlsize);
500 mlist->count = WL_MAX_ASSOC;
501 strcpy((char*)mlist, "autho_sta_list");
502 if (wl_ioctl(ifname, WLC_GET_VAR, mlist, mlsize) == 0) {
503 for (i = 0; i < mlist->count; ++i) {
504 if (is_same_addr(&mlist->ea[i], &bi->BSSID)) {
505 authorized = 1;
506 break;
511 free(mlist);
514 return (associated && authorized);
517 #define STACHECK_CONNECT 30
518 #define STACHECK_DISCONNECT 5
520 int radio_main(int argc, char *argv[])
522 if (argc != 2) {
523 HELP:
524 usage_exit(argv[0], "on|off|toggle|join\n");
527 if (!nvram_match("wl_radio", "1")) {
528 return 1;
531 if (strcmp(argv[1], "toggle") == 0) {
532 argv[1] = get_radio() ? "off" : "on";
535 if (strcmp(argv[1], "off") == 0) {
536 set_radio(0);
537 led(LED_DIAG, 0);
538 return 0;
540 else if (strcmp(argv[1], "on") == 0) {
541 set_radio(1);
543 else if (strcmp(argv[1], "join") != 0) {
544 goto HELP;
548 if (wl_client()) {
549 int i;
550 char s[32];
552 if (f_read_string("/var/run/radio.pid", s, sizeof(s)) > 0) {
553 if ((i = atoi(s)) > 1) {
554 kill(i, SIGTERM);
555 sleep(1);
559 if (fork() == 0) {
560 sprintf(s, "%d", getpid());
561 f_write("/var/run/radio.pid", s, sizeof(s), 0, 0644);
563 int stacheck_connect = nvram_get_int("sta_chkint");
564 if (stacheck_connect <= 0)
565 stacheck_connect = STACHECK_CONNECT;
566 int stacheck;
568 while (get_radio() && wl_client()) {
570 if (check_wl_client(nvram_safe_get("wl_ifname"))) {
571 stacheck = stacheck_connect;
573 else {
574 eval("wl", "disassoc");
575 #ifdef CONFIG_BCMWL5
576 char *amode, *sec = nvram_safe_get("security_mode2");
578 if (strstr(sec, "personal")) {
579 if (strstr(sec, "wpa2")) amode = "wpa2psk";
580 else amode = "wpapsk";
582 else if (strstr(sec, "wpa2")) amode = "wpa2";
583 else if (strstr(sec, "wpa")) amode = "wpa";
584 else if (nvram_get_int("wl_auth")) amode = "shared";
585 else amode = "open";
587 eval("wl", "join", nvram_safe_get("wl_ssid"),
588 "imode", "bss", "amode", amode);
589 #else
590 eval("wl", "join", nvram_safe_get("wl_ssid"));
591 #endif
592 stacheck = STACHECK_DISCONNECT;
595 sleep(stacheck);
598 unlink("/var/run/radio.pid");
602 return 0;
606 int wdist_main(int argc, char *argv[])
608 int n;
609 rw_reg_t r;
610 int v;
612 if (argc != 2) {
613 r.byteoff = 0x684;
614 r.size = 2;
615 if (wl_ioctl(nvram_safe_get("wl_ifname"), 101, &r, sizeof(r)) == 0) {
616 v = r.val - 510;
617 if (v <= 9) v = 0;
618 else v = (v - (9 + 1)) * 150;
619 printf("Current: %d-%dm (0x%02x)\n\n", v + (v ? 1 : 0), v + 150, r.val);
621 usage_exit(argv[0], "<meters>");
623 if ((n = atoi(argv[1])) <= 0) setup_wldistance();
624 else set_wldistance(n);
625 return 0;
630 // ref: wificonf.c
631 int wldist_main(int argc, char *argv[])
633 rw_reg_t r;
634 uint32 s;
635 char *p;
636 int n;
638 if (fork() == 0) {
639 p = nvram_safe_get("wl_distance");
640 if ((*p == 0) || ((n = atoi(p)) < 0)) return 0;
641 n = 9 + (n / 150) + ((n % 150) ? 1 : 0);
643 while (1) {
644 s = 0x10 | (n << 16);
645 p = nvram_safe_get("wl_ifname");
646 wl_ioctl(p, 197, &s, sizeof(s));
648 r.byteoff = 0x684;
649 r.val = n + 510;
650 r.size = 2;
651 wl_ioctl(p, 102, &r, sizeof(r));
653 sleep(2);
657 return 0;