Tomato 1.28
[tomato.git] / release / src / router / rc / network.c
blob1d707188dbd960a217c9564f9bb4e612d7623be3
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/sockios.h>
53 #include <linux/ethtool.h>
54 #include <sys/ioctl.h>
55 #include <net/if_arp.h>
57 #include <wlutils.h>
58 #include <bcmparams.h>
59 #include <wlioctl.h>
61 #ifndef WL_BSS_INFO_VERSION
62 #error WL_BSS_INFO_VERSION
63 #endif
64 #if WL_BSS_INFO_VERSION == 108
65 #include <etioctl.h>
66 #else
67 #include <etsockio.h>
68 #endif
70 #define IFUP (IFF_UP | IFF_RUNNING | IFF_BROADCAST | IFF_MULTICAST)
71 #define sin_addr(s) (((struct sockaddr_in *)(s))->sin_addr)
73 void set_host_domain_name(void)
75 const char *s;
77 s = nvram_safe_get("wan_hostname");
78 sethostname(s, strlen(s));
79 s = nvram_get("wan_domain");
80 if ((s == NULL) || (*s == 0)) s = nvram_safe_get("wan_get_domain");
81 setdomainname(s, strlen(s));
84 static int wlconf(char *ifname)
86 int r;
88 r = eval("wlconf", ifname, "up");
89 if (r == 0) {
90 // set_mac(ifname, "mac_wl", 2);
92 nvram_set("rrules_radio", "-1");
94 eval("wl", "antdiv", nvram_safe_get("wl_antdiv"));
95 eval("wl", "txant", nvram_safe_get("wl_txant"));
96 eval("wl", "txpwr1", "-o", "-m", nvram_safe_get("wl_txpwr"));
98 killall("wldist", SIGTERM);
99 eval("wldist");
101 if (wl_client()) {
102 if (nvram_match("wl_mode", "wet")) {
103 ifconfig(ifname, IFUP|IFF_ALLMULTI, NULL, NULL);
105 if (nvram_match("wl_radio", "1")) {
106 xstart("radio", "join");
110 return r;
113 static void check_afterburner(void)
115 char *p;
117 if (nvram_match("wl_afterburner", "off")) return;
118 if ((p = nvram_get("boardflags")) == NULL) return;
120 if (strcmp(p, "0x0118") == 0) { // G 2.2, 3.0, 3.1
121 p = "0x0318";
123 else if (strcmp(p, "0x0188") == 0) { // G 2.0
124 p = "0x0388";
126 else if (strcmp(p, "0x2558") == 0) { // G 4.0, GL 1.0, 1.1
127 p = "0x2758";
129 else {
130 return;
133 nvram_set("boardflags", p);
135 if (!nvram_match("debug_abrst", "0")) {
136 modprobe_r("wl");
137 modprobe("wl");
141 /* safe?
143 unsigned long bf;
144 char s[64];
146 bf = strtoul(p, &p, 0);
147 if ((*p == 0) && ((bf & BFL_AFTERBURNER) == 0)) {
148 sprintf(s, "0x%04lX", bf | BFL_AFTERBURNER);
149 nvram_set("boardflags", s);
155 void start_lan(void)
157 _dprintf("%s %d\n", __FUNCTION__, __LINE__);
159 char *lan_ifname;
160 struct ifreq ifr;
161 char *lan_ifnames, *ifname, *p;
162 int sfd;
164 set_mac(nvram_safe_get("wl_ifname"), "mac_wl", 2);
165 check_afterburner();
167 if ((sfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) return;
169 lan_ifname = strdup(nvram_safe_get("lan_ifname"));
170 if (strncmp(lan_ifname, "br", 2) == 0) {
171 eval("brctl", "addbr", lan_ifname);
172 eval("brctl", "setfd", lan_ifname, "0");
173 eval("brctl", "stp", lan_ifname, nvram_safe_get("lan_stp"));
175 if ((lan_ifnames = strdup(nvram_safe_get("lan_ifnames"))) != NULL) {
176 p = lan_ifnames;
177 while ((ifname = strsep(&p, " ")) != NULL) {
178 while (*ifname == ' ') ++ifname;
179 if (*ifname == 0) break;
181 // bring up interface
182 if (ifconfig(ifname, IFUP, NULL, NULL) != 0) continue;
184 // set the logical bridge address to that of the first interface
185 strlcpy(ifr.ifr_name, lan_ifname, IFNAMSIZ);
186 if ((ioctl(sfd, SIOCGIFHWADDR, &ifr) == 0) && (memcmp(ifr.ifr_hwaddr.sa_data, "\0\0\0\0\0\0", ETHER_ADDR_LEN) == 0)) {
187 strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
188 if (ioctl(sfd, SIOCGIFHWADDR, &ifr) == 0) {
189 strlcpy(ifr.ifr_name, lan_ifname, IFNAMSIZ);
190 ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
191 ioctl(sfd, SIOCSIFHWADDR, &ifr);
195 if (wlconf(ifname) == 0) {
196 const char *mode = nvram_get("wl0_mode");
197 if ((mode) && ((strcmp(mode, "ap") != 0) && (strcmp(mode, "wet") != 0))) continue;
199 eval("brctl", "addif", lan_ifname, ifname);
202 if ((nvram_get_int("wan_islan")) &&
203 ((get_wan_proto() == WP_DISABLED) || (nvram_match("wl_mode", "sta")))) {
204 ifname = nvram_get("wan_ifnameX");
205 if (ifconfig(ifname, IFUP, NULL, NULL) == 0)
206 eval("brctl", "addif", lan_ifname, ifname);
209 free(lan_ifnames);
212 // --- this shouldn't happen ---
213 else if (*lan_ifname) {
214 ifconfig(lan_ifname, IFUP, NULL, NULL);
215 wlconf(lan_ifname);
217 else {
218 close(sfd);
219 free(lan_ifname);
220 return;
224 // Get current LAN hardware address
225 char eabuf[32];
226 strlcpy(ifr.ifr_name, lan_ifname, IFNAMSIZ);
227 if (ioctl(sfd, SIOCGIFHWADDR, &ifr) == 0) nvram_set("lan_hwaddr", ether_etoa(ifr.ifr_hwaddr.sa_data, eabuf));
230 int i, qos;
231 caddr_t ifrdata;
232 struct ethtool_drvinfo info;
234 qos = (strcmp(nvram_safe_get("wl_wme"), "on")) ? 0 : 1;
235 for (i = 1; i <= DEV_NUMIFS; i++) {
236 ifr.ifr_ifindex = i;
237 if (ioctl(sfd, SIOCGIFNAME, &ifr)) continue;
238 if (ioctl(sfd, SIOCGIFHWADDR, &ifr)) continue;
239 if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) continue;
240 /* get flags */
241 if (ioctl(sfd, SIOCGIFFLAGS, &ifr)) continue;
242 /* if up(wan not up yet at this point) */
243 if (ifr.ifr_flags & IFF_UP) {
244 ifrdata = ifr.ifr_data;
245 memset(&info, 0, sizeof(info));
246 info.cmd = ETHTOOL_GDRVINFO;
247 ifr.ifr_data = (caddr_t)&info;
248 if (ioctl(sfd, SIOCETHTOOL, &ifr) >= 0) {
249 /* currently only need to set QoS to et devices */
250 if (!strncmp(info.driver, "et", 2)) {
251 ifr.ifr_data = (caddr_t)&qos;
252 ioctl(sfd, SIOCSETCQOS, &ifr);
255 ifr.ifr_data = ifrdata;
259 close(sfd);
261 // bring up and configure LAN interface
262 ifconfig(lan_ifname, IFUP, nvram_safe_get("lan_ipaddr"), nvram_safe_get("lan_netmask"));
264 config_loopback();
265 do_static_routes(1);
267 if (nvram_match("wan_proto", "disabled")) {
268 char *gateway = nvram_safe_get("lan_gateway") ;
269 if ((*gateway) && (strcmp(gateway, "0.0.0.0") != 0)) {
270 int tries = 5;
271 while ((route_add(lan_ifname, 0, "0.0.0.0", gateway, "0.0.0.0") != 0) && (tries-- > 0)) sleep(1);
272 _dprintf("%s: add gateway=%s tries=%d\n", __FUNCTION__, gateway, tries);
276 free(lan_ifname);
278 _dprintf("%s %d\n", __FUNCTION__, __LINE__);
281 void stop_lan(void)
283 _dprintf("%s %d\n", __FUNCTION__, __LINE__);
285 char *lan_ifname;
286 char *lan_ifnames, *p, *ifname;
288 lan_ifname = nvram_safe_get("lan_ifname");
289 ifconfig(lan_ifname, 0, NULL, NULL);
291 if (strncmp(lan_ifname, "br", 2) == 0) {
292 if ((lan_ifnames = strdup(nvram_safe_get("lan_ifnames"))) != NULL) {
293 p = lan_ifnames;
294 while ((ifname = strsep(&p, " ")) != NULL) {
295 while (*ifname == ' ') ++ifname;
296 if (*ifname == 0) break;
297 eval("wlconf", ifname, "down");
298 ifconfig(ifname, 0, NULL, NULL);
299 eval("brctl", "delif", lan_ifname, ifname);
301 free(lan_ifnames);
304 else if (*lan_ifname) {
305 eval("wlconf", lan_ifname, "down");
308 _dprintf("%s %d\n", __FUNCTION__, __LINE__);
312 void do_static_routes(int add)
314 char *buf;
315 char *p, *q;
316 char *dest, *mask, *gateway, *metric, *ifname;
317 int r;
319 if ((buf = strdup(nvram_safe_get(add ? "routes_static" : "routes_static_saved"))) == NULL) return;
320 if (add) nvram_set("routes_static_saved", buf);
321 else nvram_unset("routes_static_saved");
322 p = buf;
323 while ((q = strsep(&p, ">")) != NULL) {
324 if (vstrsep(q, "<", &dest, &gateway, &mask, &metric, &ifname) != 5) continue;
325 ifname = nvram_safe_get((*ifname == 'L') ? "lan_ifname" : "wan_ifname");
326 if (add) {
327 for (r = 3; r >= 0; --r) {
328 if (route_add(ifname, atoi(metric) + 1, dest, gateway, mask) == 0) break;
329 sleep(1);
332 else {
333 route_del(ifname, atoi(metric) + 1, dest, gateway, mask);
336 free(buf);
339 void hotplug_net(void)
341 char *interface, *action;
342 char *lan_ifname;
344 if (((interface = getenv("INTERFACE")) == NULL) || ((action = getenv("ACTION")) == NULL)) return;
346 _dprintf("hotplug net INTERFACE=%s ACTION=%s\n", interface, action);
348 if ((nvram_match("wds_enable", "1")) && (strncmp(interface, "wds", 3) == 0) && (strcmp(action, "register") == 0)) {
349 ifconfig(interface, IFUP, NULL, NULL);
350 lan_ifname = nvram_safe_get("lan_ifname");
351 if (strncmp(lan_ifname, "br", 2) == 0) {
352 eval("brctl", "addif", lan_ifname, interface);
353 notify_nas(interface);
358 int radio_main(int argc, char *argv[])
360 if (argc != 2) {
361 HELP:
362 usage_exit(argv[0], "on|off|toggle|join\n");
365 if (!nvram_match("wl_radio", "1")) {
366 return 1;
369 if (strcmp(argv[1], "toggle") == 0) {
370 argv[1] = get_radio() ? "off" : "on";
373 if (strcmp(argv[1], "off") == 0) {
374 set_radio(0);
375 led(LED_DIAG, 0);
376 return 0;
378 else if (strcmp(argv[1], "on") == 0) {
379 set_radio(1);
381 else if (strcmp(argv[1], "join") != 0) {
382 goto HELP;
386 if (wl_client()) {
387 int i;
388 wlc_ssid_t ssid;
389 char s[32];
391 if (f_read_string("/var/run/radio.pid", s, sizeof(s)) > 0) {
392 if ((i = atoi(s)) > 1) {
393 kill(i, SIGTERM);
394 sleep(1);
398 if (fork() == 0) {
399 sprintf(s, "%d", getpid());
400 f_write("/var/run/radio.pid", s, sizeof(s), 0, 0644);
402 while (1) {
403 if (!get_radio()) break;
405 eval("wl", "join", nvram_safe_get("wl_ssid"));
406 for (i = 6; i > 0; --i) {
407 sleep(1);
408 if ((wl_ioctl(nvram_safe_get("wl_ifname"), WLC_GET_SSID, &ssid, sizeof(ssid)) == 0) &&
409 (ssid.SSID_len > 0)) break;
411 if (i > 0) break;
412 sleep(5);
415 unlink("/var/run/radio.pid");
419 return 0;
423 int wdist_main(int argc, char *argv[])
425 int n;
426 rw_reg_t r;
427 int v;
429 if (argc != 2) {
430 r.byteoff = 0x684;
431 r.size = 2;
432 if (wl_ioctl(nvram_safe_get("wl_ifname"), 101, &r, sizeof(r)) == 0) {
433 v = r.val - 510;
434 if (v <= 9) v = 0;
435 else v = (v - (9 + 1)) * 150;
436 printf("Current: %d-%dm (0x%02x)\n\n", v + (v ? 1 : 0), v + 150, r.val);
438 usage_exit(argv[0], "<meters>");
440 if ((n = atoi(argv[1])) <= 0) setup_wldistance();
441 else set_wldistance(n);
442 return 0;
447 // ref: wificonf.c
448 int wldist_main(int argc, char *argv[])
450 rw_reg_t r;
451 uint32 s;
452 char *p;
453 int n;
455 if (fork() == 0) {
456 p = nvram_safe_get("wl_distance");
457 if ((*p == 0) || ((n = atoi(p)) < 0)) return 0;
458 n = 9 + (n / 150) + ((n % 150) ? 1 : 0);
460 while (1) {
461 s = 0x10 | (n << 16);
462 p = nvram_safe_get("wl_ifname");
463 wl_ioctl(p, 197, &s, sizeof(s));
465 r.byteoff = 0x684;
466 r.val = n + 510;
467 r.size = 2;
468 wl_ioctl(p, 102, &r, sizeof(r));
470 sleep(2);
474 return 0;