1/* 2 * Broadcom Home Gateway Reference Design 3 * Web Page Configuration Support Routines 4 * 5 * Copyright 2004, Broadcom Corporation 6 * All Rights Reserved. 7 * 8 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY 9 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM 10 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS 11 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. 12 * $Id: broadcom.c,v 1.1.1.1 2008/10/15 03:31:22 james26_jang Exp $ 13 */ 14 15#ifdef WEBS 16#include <webs.h> 17#include <uemf.h> 18#include <ej.h> 19#else /* !WEBS */ 20#include <stdio.h> 21#include <stdlib.h> 22#include <string.h> 23#include <ctype.h> 24#include <errno.h> 25#include <unistd.h> 26#include <limits.h> 27#include <sys/types.h> 28#include <sys/stat.h> 29#include <sys/socket.h> 30#include <netinet/in.h> 31#include <arpa/inet.h> 32#include <assert.h> 33#include <httpd.h> 34#endif /* WEBS */ 35 36 37#include <typedefs.h> 38#include <proto/ethernet.h> 39#include <bcmnvram.h> 40#include <bcmutils.h> 41#include <shutils.h> 42#include <netconf.h> 43#include <nvparse.h> 44#include <wlutils.h> 45#include <bcmcvar.h> 46#include <ezc.h> 47#include <bcmconfig.h> 48 49static char * rfctime(const time_t *timep); 50static char * reltime(unsigned int seconds); 51static bool find_ethaddr_in_list (void *ethaddr, struct maclist *list); 52 53#define wan_prefix(unit, prefix) snprintf(prefix, sizeof(prefix), "wan%d_", unit) 54 55/* 56 * Country names and abbreviations from ISO 3166 57 */ 58typedef struct { 59 char *name; /* Long name */ 60 char *abbrev; /* Abbreviation */ 61} country_name_t; 62country_name_t country_names[]; /* At end of this file */ 63 64struct variable variables[]; 65extern struct nvram_tuple router_defaults[]; 66 67enum { 68 NOTHING, 69 REBOOT, 70 RESTART, 71}; 72 73static const char * const apply_header = 74"<head>" 75"<title>Broadcom Home Gateway Reference Design: Apply</title>" 76"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">" 77"<style type=\"text/css\">" 78"body { background: white; color: black; font-family: arial, sans-serif; font-size: 9pt }" 79".title { font-family: arial, sans-serif; font-size: 13pt; font-weight: bold }" 80".subtitle { font-family: arial, sans-serif; font-size: 11pt }" 81".label { color: #306498; font-family: arial, sans-serif; font-size: 7pt }" 82"</style>" 83"</head>" 84"<body>" 85"<p>" 86"<span class=\"title\">APPLY</span><br>" 87"<span class=\"subtitle\">This screen notifies you of any errors " 88"that were detected while changing the router's settings.</span>" 89"<form method=\"get\" action=\"apply.cgi\">" 90"<p>" 91; 92 93static const char * const apply_footer = 94"<p>" 95"<input type=\"button\" name=\"action\" value=\"Continue\" OnClick=\"document.location.href='%s';\">" 96"</form>" 97"<p class=\"label\">©2001-2004 Broadcom Corporation. All rights reserved.</p>" 98"</body>" 99; 100 101 102#if defined(linux) 103 104#include <fcntl.h> 105#include <signal.h> 106#include <time.h> 107#include <sys/klog.h> 108#include <sys/wait.h> 109#include <sys/ioctl.h> 110#include <net/if.h> 111 112typedef u_int64_t u64; 113typedef u_int32_t u32; 114typedef u_int16_t u16; 115typedef u_int8_t u8; 116#include <linux/ethtool.h> 117#include <linux/sockios.h> 118#include <net/if_arp.h> 119 120#define sys_restart() kill(1, SIGHUP) 121#define sys_reboot() kill(1, SIGTERM) 122#define sys_stats(url) eval("stats", (url)) 123 124#ifndef WEBS 125 126#define MIN_BUF_SIZE 4096 127 128/* Upgrade from remote server or socket stream */ 129static int 130sys_upgrade(char *url, FILE *stream, int *total) 131{ 132 char upload_fifo[] = "/tmp/uploadXXXXXX"; 133 FILE *fifo = NULL; 134 char *write_argv[] = { "write", upload_fifo, "linux", NULL }; 135 pid_t pid; 136 char *buf = NULL; 137 int count, ret = 0; 138 long flags = -1; 139 int size = BUFSIZ; 140 141 if (url) 142 return eval("write", url, "linux"); 143 144 /* Feed write from a temporary FIFO */ 145 if (!mktemp(upload_fifo) || 146 mkfifo(upload_fifo, S_IRWXU) < 0|| 147 (ret = _eval(write_argv, NULL, 0, &pid)) || 148 !(fifo = fopen(upload_fifo, "w"))) { 149 if (!ret) 150 ret = errno; 151 goto err; 152 } 153 154 /* Set nonblock on the socket so we can timeout */ 155 if ((flags = fcntl(fileno(stream), F_GETFL)) < 0 || 156 fcntl(fileno(stream), F_SETFL, flags | O_NONBLOCK) < 0) { 157 ret = errno; 158 goto err; 159 } 160 161 /* 162 * The buffer must be at least as big as what the stream file is 163 * using so that it can read all the data that has been buffered 164 * in the stream file. Otherwise it would be out of sync with fn 165 * select specially at the end of the data stream in which case 166 * the select tells there is no more data available but there in 167 * fact is data buffered in the stream file's buffer. Since no 168 * one has changed the default stream file's buffer size, let's 169 * use the constant BUFSIZ until someone changes it. 170 */ 171 if (size < MIN_BUF_SIZE) 172 size = MIN_BUF_SIZE; 173 if ((buf = malloc(size)) == NULL) { 174 ret = ENOMEM; 175 goto err; 176 } 177 178 /* Pipe the rest to the FIFO */ 179 cprintf("Upgrading"); 180 while (total && *total) { 181 if (waitfor(fileno(stream), 5) <= 0) 182 break; 183 count = safe_fread(buf, 1, size, stream); 184 if (!count && (ferror(stream) || feof(stream))) 185 break; 186 *total -= count; 187 safe_fwrite(buf, 1, count, fifo); 188 cprintf("."); 189 } 190 fclose(fifo); 191 fifo = NULL; 192 193 /* Wait for write to terminate */ 194 waitpid(pid, &ret, 0); 195 cprintf("done\n"); 196 197 /* Reset nonblock on the socket */ 198 if (fcntl(fileno(stream), F_SETFL, flags) < 0) { 199 ret = errno; 200 goto err; 201 } 202 203 err: 204 if (buf) 205 free(buf); 206 if (fifo) 207 fclose(fifo); 208 unlink(upload_fifo); 209 return ret; 210} 211 212#endif /* WEBS */ 213 214/* Dump firewall log */ 215static int 216ej_dumplog(int eid, webs_t wp, int argc, char_t **argv) 217{ 218 char buf[4096], *line, *next, *s; 219 int len, ret = 0; 220 221 time_t tm; 222 char *verdict, *src, *dst, *proto, *spt, *dpt; 223 224 if (klogctl(3, buf, 4096) < 0) { 225 websError(wp, 400, "Insufficient memory\n"); 226 return -1; 227 } 228 229 for (next = buf; (line = strsep(&next, "\n"));) { 230 if (!strncmp(line, "<4>DROP", 7)) 231 verdict = "denied"; 232 else if (!strncmp(line, "<4>ACCEPT", 9)) 233 verdict = "accepted"; 234 else 235 continue; 236 237 /* Parse into tokens */ 238 s = line; 239 len = strlen(s); 240 while (strsep(&s, " ")); 241 242 /* Initialize token values */ 243 time(&tm); 244 src = dst = proto = spt = dpt = "n/a"; 245 246 /* Set token values */ 247 for (s = line; s < &line[len] && *s; s += strlen(s) + 1) { 248 if (!strncmp(s, "TIME=", 5)) 249 tm = strtoul(&s[5], NULL, 10); 250 else if (!strncmp(s, "SRC=", 4)) 251 src = &s[4]; 252 else if (!strncmp(s, "DST=", 4)) 253 dst = &s[4]; 254 else if (!strncmp(s, "PROTO=", 6)) 255 proto = &s[6]; 256 else if (!strncmp(s, "SPT=", 4)) 257 spt = &s[4]; 258 else if (!strncmp(s, "DPT=", 4)) 259 dpt = &s[4]; 260 } 261 262 ret += websWrite(wp, "%s %s connection %s to %s:%s from %s:%s\n", 263 rfctime(&tm), proto, verdict, dst, dpt, src, spt); 264 ret += websWrite(wp, "<br>"); 265 } 266 267 return ret; 268} 269 270static int 271ej_syslog(int eid, webs_t wp, int argc, char_t **argv) 272{ 273 FILE *fp; 274 char buf[256] = "/sbin/logread > "; 275 char tmp[] = "/tmp/log.XXXXXX"; 276 int ret; 277 278 if (!nvram_match("log_ram_enable", "1")) { 279 websError(wp, 400, "\"Syslog in RAM\" is not enabled.\n"); 280 return (-1); 281 } 282 283 mktemp(tmp); 284 strcat(buf, tmp); 285 system(buf); 286 287 fp = fopen(tmp, "r"); 288 289 unlink(tmp); 290 291 if (fp == NULL) { 292 websError(wp, 400, "logread error\n"); 293 return (-1); 294 } 295 296 websWrite(wp, "<pre>"); 297 298 ret = 0; 299 while(fgets(buf, sizeof(buf), fp)) 300 ret += websWrite(wp, buf); 301 302 ret += websWrite(wp, "</pre>"); 303 304 fclose(fp); 305 306 return (ret); 307} 308 309struct lease_t { 310 unsigned char chaddr[16]; 311 u_int32_t yiaddr; 312 u_int32_t expires; 313 char hostname[64]; 314}; 315 316/* Dump leases in <tr><td>hostname</td><td>MAC</td><td>IP</td><td>expires</td></tr> format */ 317static int 318ej_lan_leases(int eid, webs_t wp, int argc, char_t **argv) 319{ 320 FILE *fp = NULL; 321 struct lease_t lease; 322 int i; 323 struct in_addr addr; 324 unsigned long expires = 0; 325 char sigusr1[] = "-XX"; 326 int ret = 0; 327 328 /* Write out leases file */ 329 sprintf(sigusr1, "-%d", SIGUSR1); 330 eval("killall", sigusr1, "udhcpd"); 331 332 if (!(fp = fopen("/tmp/udhcpd.leases", "r"))) 333 return 0; 334 335 while (fread(&lease, sizeof(lease), 1, fp)) { 336 /* Do not display reserved leases */ 337 if (ETHER_ISNULLADDR(lease.chaddr)) 338 continue; 339 ret += websWrite(wp, "<tr><td>%s</td><td>", lease.hostname); 340 for (i = 0; i < 6; i++) { 341 ret += websWrite(wp, "%02X", lease.chaddr[i]); 342 if (i != 5) ret += websWrite(wp, ":"); 343 } 344 addr.s_addr = lease.yiaddr; 345 ret += websWrite(wp, "</td><td>%s</td><td>", inet_ntoa(addr)); 346 expires = ntohl(lease.expires); 347 if (!expires) 348 ret += websWrite(wp, "Expired"); 349 else 350 ret += websWrite(wp, "%s", reltime(expires)); 351 ret += websWrite(wp, "</td></tr>"); 352 } 353 354 fclose(fp); 355 356 return ret; 357} 358 359/* Renew lease */ 360static int 361sys_renew(void) 362{ 363 int unit; 364 char tmp[NVRAM_BUFSIZE]; 365 char *str; 366 int pid; 367 368 if ((unit = atoi(nvram_safe_get("wan_unit"))) < 0) 369 unit = 0; 370 371 snprintf(tmp, sizeof(tmp), "/var/run/udhcpc%d.pid", unit); 372 if ((str = file2str(tmp))) { 373 pid = atoi(str); 374 free(str); 375 return kill(pid, SIGUSR1); 376 } 377 378 return -1; 379} 380 381/* Release lease */ 382static int 383sys_release(void) 384{ 385 int unit; 386 char tmp[NVRAM_BUFSIZE]; 387 char *str; 388 int pid; 389 390 if ((unit = atoi(nvram_safe_get("wan_unit"))) < 0) 391 unit = 0; 392 393 snprintf(tmp, sizeof(tmp), "/var/run/udhcpc%d.pid", unit); 394 if ((str = file2str(tmp))) { 395 pid = atoi(str); 396 free(str); 397 return kill(pid, SIGUSR2); 398 } 399 400 return -1; 401} 402 403#ifdef __CONFIG_NAT__ 404#define sin_addr(s) (((struct sockaddr_in *)(s))->sin_addr) 405 406/* Return WAN link state */ 407static int 408ej_wan_link(int eid, webs_t wp, int argc, char_t **argv) 409{ 410 char *wan_ifname; 411 int s; 412 struct ifreq ifr; 413 struct ethtool_cmd ecmd; 414 FILE *fp; 415 int unit; 416 char tmp[NVRAM_BUFSIZE], prefix[] = "wanXXXXXXXXXX_"; 417 418 if ((unit = atoi(nvram_safe_get("wan_unit"))) < 0) 419 unit = 0; 420 wan_prefix(unit, prefix); 421 422 /* non-exist and disabled */ 423 if (nvram_match(strcat_r(prefix, "proto", tmp), "") || 424 nvram_match(strcat_r(prefix, "proto", tmp), "disabled")) { 425 return websWrite(wp, "N/A"); 426 } 427 /* PPPoE connection status */ 428 else if (nvram_match(strcat_r(prefix, "proto", tmp), "pppoe")) { 429 wan_ifname = nvram_safe_get(strcat_r(prefix, "pppoe_ifname", tmp)); 430 if ((fp = fopen(strcat_r("/tmp/ppp/link.", wan_ifname, tmp), "r"))) { 431 fclose(fp); 432 return websWrite(wp, "Connected"); 433 } else 434 return websWrite(wp, "Disconnected"); 435 } 436 /* Get real interface name */ 437 else 438 wan_ifname = nvram_safe_get(strcat_r(prefix, "ifname", tmp)); 439 440 /* Open socket to kernel */ 441 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 442 return websWrite(wp, "N/A"); 443 444 /* Check for hardware link */ 445 strncpy(ifr.ifr_name, wan_ifname, IFNAMSIZ); 446 ifr.ifr_data = (void *) &ecmd; 447 ecmd.cmd = ETHTOOL_GSET; 448 if (ioctl(s, SIOCETHTOOL, &ifr) < 0) { 449 close(s); 450 return websWrite(wp, "Unknown"); 451 } 452 if (!ecmd.speed) { 453 close(s); 454 return websWrite(wp, "Disconnected"); 455 } 456 457 /* Check for valid IP address */ 458 strncpy(ifr.ifr_name, wan_ifname, IFNAMSIZ); 459 if (ioctl(s, SIOCGIFADDR, &ifr) < 0) { 460 close(s); 461 return websWrite(wp, "Connecting"); 462 } 463 464 /* Otherwise we are probably configured */ 465 close(s); 466 return websWrite(wp, "Connected"); 467} 468 469/* Display IP Address lease */ 470static int 471ej_wan_lease(int eid, webs_t wp, int argc, char_t **argv) 472{ 473 unsigned long expires = 0; 474 int ret = 0; 475 int unit; 476 char tmp[NVRAM_BUFSIZE], prefix[] = "wanXXXXXXXXXX_"; 477 478 if ((unit = atoi(nvram_safe_get("wan_unit"))) < 0) 479 unit = 0; 480 wan_prefix(unit, prefix); 481 482 if (nvram_match(strcat_r(prefix, "proto", tmp), "dhcp")) { 483 char *str; 484 time_t now; 485 486 snprintf(tmp, sizeof(tmp), "/tmp/udhcpc%d.expires", unit); 487 if ((str = file2str(tmp))) { 488 expires = atoi(str); 489 free(str); 490 } 491 time(&now); 492 if (expires <= now) 493 ret += websWrite(wp, "Expired"); 494 else 495 ret += websWrite(wp, "%s", reltime(expires - now)); 496 } else 497 ret += websWrite(wp, "N/A"); 498 499 return ret; 500} 501#endif /* __CONFIG_NAT__ */ 502 503/* Report sys up time */ 504static int 505ej_sysuptime(int eid, webs_t wp, int argc, char_t **argv) 506{ 507 char *str = file2str("/proc/uptime"); 508 if (str) { 509 unsigned int up = atoi(str); 510 free(str); 511 return websWrite(wp, reltime(up)); 512 } 513 return websWrite(wp, "N/A"); 514} 515 516#ifdef __CONFIG_NAT__ 517/* Return a list of wan interfaces (eth0/eth1/eth2/eth3) */ 518static int 519ej_wan_iflist(int eid, webs_t wp, int argc, char_t **argv) 520{ 521 char name[IFNAMSIZ], *next; 522 int ret = 0; 523 int unit; 524 char tmp[NVRAM_BUFSIZE], prefix[] = "wanXXXXXXXXXX_"; 525 char ea[64]; 526 int s; 527 struct ifreq ifr; 528 529 /* current unit # */ 530 if ((unit = atoi(nvram_safe_get("wan_unit"))) < 0) 531 unit = 0; 532 wan_prefix(unit, prefix); 533 534 if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) 535 return errno; 536 537 /* build wan interface name list */ 538 foreach(name, nvram_safe_get("wan_ifnames"), next) { 539 strncpy(ifr.ifr_name, name, IFNAMSIZ); 540 if (ioctl(s, SIOCGIFHWADDR, &ifr)) 541 continue; 542 ret += websWrite(wp, "<option value=\"%s\" %s>%s (%s)</option>", name, 543 nvram_match(strcat_r(prefix, "ifname", tmp), name) ? "selected" : "", 544 name, ether_etoa(ifr.ifr_hwaddr.sa_data, ea)); 545 } 546 547 close(s); 548 549 return ret; 550} 551#endif /* __CONFIG_NAT__ */ 552 553 554#endif /* vxworks */ 555 556static int 557ej_asp_list(int eid, webs_t wp, int argc, char_t **argv) 558{ 559 websWrite(wp, 560 "<tr>\n" 561 " <td><a href=\"index.asp\"><img border=\"0\" src=\"basic.gif\" alt=\"Basic\"></a></td>\n" 562 " <td><a href=\"lan.asp\"><img border=\"0\" src=\"lan.gif\" alt=\"LAN\"></a></td>\n"); 563#ifdef __CONFIG_NAT__ 564 websWrite(wp, 565 " <td><a href=\"wan.asp\"><img border=\"0\" src=\"wan.gif\" alt=\"WAN\"></a></td>\n"); 566#endif 567 websWrite(wp, 568 " <td><a href=\"status.asp\"><img border=\"0\" src=\"status.gif\" alt=\"Status\"></a></td>\n"); 569#ifdef __CONFIG_NAT__ 570 websWrite(wp, 571 " <td><a href=\"filter.asp\"><img border=\"0\" src=\"filter.gif\" alt=\"Filters\"></a></td>\n" 572 " <td><a href=\"forward.asp\"><img border=\"0\" src=\"forward.gif\" alt=\"Routing\"></a></td>\n"); 573#endif 574 websWrite(wp, 575 " <td><a href=\"wireless.asp\"><img border=\"0\" src=\"wireless.gif\" alt=\"Wireless\"></a></td>\n" 576 " <td><a href=\"security.asp\"><img border=\"0\" src=\"security.gif\" alt=\"Security\"></a></td>\n" 577 " <td><a href=\"firmware.asp\"><img border=\"0\" src=\"firmware.gif\" alt=\"Firmware\"></a></td>\n"); 578 websWrite(wp, 579 " <td width=\"100%%\"></td>\n" 580 "</tr>\n"); 581 return 0; 582} 583 584static char * 585rfctime(const time_t *timep) 586{ 587 static char s[201]; 588 struct tm tm; 589 590#if defined(linux) 591 setenv("TZ", nvram_safe_get("time_zone"), 1); 592#endif 593 memcpy(&tm, localtime(timep), sizeof(struct tm)); 594 strftime(s, 200, "%a, %d %b %Y %H:%M:%S %z", &tm); 595 return s; 596} 597 598static char * 599reltime(unsigned int seconds) 600{ 601 static char s[] = "XXXXX days, XX hours, XX minutes, XX seconds"; 602 char *c = s; 603 604 if (seconds > 60*60*24) { 605 c += sprintf(c, "%d days, ", seconds / (60*60*24)); 606 seconds %= 60*60*24; 607 } 608 if (seconds > 60*60) { 609 c += sprintf(c, "%d hours, ", seconds / (60*60)); 610 seconds %= 60*60; 611 } 612 if (seconds > 60) { 613 c += sprintf(c, "%d minutes, ", seconds / 60); 614 seconds %= 60; 615 } 616 c += sprintf(c, "%d seconds", seconds); 617 618 return s; 619} 620 621/* Report time in RFC-822 format */ 622static int 623ej_localtime(int eid, webs_t wp, int argc, char_t **argv) 624{ 625 time_t tm; 626 627 time(&tm); 628 return websWrite(wp, rfctime(&tm)); 629} 630 631static int 632ej_wl_mode_list(int eid, webs_t wp, int argc, char_t **argv) 633{ 634 int unit; 635 char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_"; 636 char *name, *next; 637 int ap = 0, sta = 0, wet = 0, wds = 0; 638 char cap[WLC_IOCTL_SMLEN]; 639 char caps[WLC_IOCTL_SMLEN]; 640 641 if ((unit = atoi(nvram_safe_get("wl_unit"))) < 0) 642 return -1; 643 644 snprintf(prefix, sizeof(prefix), "wl%d_", unit); 645 name = nvram_safe_get(strcat_r(prefix, "ifname", tmp)); 646 647 if (wl_get_val(name, "cap", (void *)caps, WLC_IOCTL_SMLEN)) 648 return -1; 649 650 foreach(cap, caps, next) { 651 if (!strcmp(cap, "ap")) 652 ap = wds = 1; 653 else if (!strcmp(cap, "sta")) 654 sta = 1; 655 else if (!strcmp(cap, "wet")) 656 wet = 1; 657 } 658 659 if (ap) 660 websWrite(wp, "<option value=\"ap\" %s>Access Point</option>\n", 661 nvram_match("wl_mode", "ap" ) ? "selected" : ""); 662 if (wds) 663 websWrite(wp, "<option value=\"wds\" %s>Wireless Bridge</option>\n", 664 nvram_match("wl_mode", "wds" ) ? "selected" : ""); 665 if (wet) 666 websWrite(wp, "<option value=\"wet\" %s>Wireless Ethernet</option>\n", 667 nvram_match("wl_mode", "wet" ) ? "selected" : ""); 668 669 return 0; 670 671} 672 673static int 674ej_wl_inlist(int eid, webs_t wp, int argc, char_t **argv) 675{ 676 int unit; 677 char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_"; 678 char *name, *next; 679 char cap[WLC_IOCTL_SMLEN]; 680 char caps[WLC_IOCTL_SMLEN]; 681 char *var, *item; 682 683 if (ejArgs(argc, argv, "%s %s", &var, &item) < 2) { 684 websError(wp, 400, "Insufficient args\n"); 685 return -1; 686 } 687 688 if ((unit = atoi(nvram_safe_get("wl_unit"))) < 0) 689 return -1; 690 691 snprintf(prefix, sizeof(prefix), "wl%d_", unit); 692 name = nvram_safe_get(strcat_r(prefix, "ifname", tmp)); 693 694 if (wl_get_val(name, var, (void *)caps, WLC_IOCTL_SMLEN)) 695 return -1; 696 697 foreach(cap, caps, next) { 698 if (!strcmp(cap, item)) 699 return websWrite(wp, "1"); 700 } 701 702 return websWrite(wp, "0"); 703} 704 705static int 706ej_wl_wds_status(int eid, webs_t wp, int argc, char_t **argv) 707{ 708 int unit; 709 char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_"; 710 char *macs, *next, *name; 711 char mac[100]; 712 int i, len; 713 sta_info_t *sta; 714 char buf[300]; 715 716 if (ejArgs(argc, argv, "%d", &i) < 1) { 717 websError(wp, 400, "Insufficient args\n"); 718 return -1; 719 } 720 721 if ((unit = atoi(nvram_safe_get("wl_unit"))) < 0) 722 return -1; 723 724 snprintf(prefix, sizeof(prefix), "wl%d_", unit); 725 name = nvram_safe_get(strcat_r(prefix, "ifname", tmp)); 726 macs = nvram_safe_get(strcat_r(prefix, "wds", tmp)); 727 728 foreach(mac, macs, next) { 729 if (i-- == 0) { 730 len = sprintf(buf, "sta_info"); 731 ether_atoe(mac, (unsigned char *)&buf[len + 1]); 732 if (atoi(nvram_safe_get(strcat_r(prefix, "wds_timeout", tmp))) && 733 !wl_ioctl(name, WLC_GET_VAR, buf, sizeof(buf))) { 734 sta = (sta_info_t *)buf; 735 return websWrite(wp, "%s", (sta->flags & WL_WDS_LINKUP) ? "up" : "down"); 736 } 737 else 738 return websWrite(wp, "%s", "unknown"); 739 } 740 } 741 742 return 0; 743} 744 745static int 746ej_ses_button_display(int eid, webs_t wp, int argc, char_t **argv) 747{ 748#ifdef __CONFIG_SES__ 749 if (atoi(nvram_safe_get("ses_enable")) == 0) { 750 return 1; 751 } 752 753 websWrite(wp, "<tr><th width=\"310\"> SES Button: </th>"); 754 websWrite(wp, "<td> </td>"); 755 websWrite(wp, "<td><input type=\"submit\" name=\"action\" value=\"NewSesNW\" ></td></tr>"); 756 websWrite(wp, "<tr><th width=\"310\"> SES Button: </th>"); 757 websWrite(wp, "<td> </td>"); 758 websWrite(wp, "<td><input type=\"submit\" name=\"action\" value=\"OpenWindow\" ></td></tr>"); 759 websWrite(wp, "<tr><th width=\"310\"> SES Button: </th>"); 760 websWrite(wp, "<td> </td>"); 761 websWrite(wp, "<td><input type=\"submit\" name=\"action\" value=\"NewSesNWAndOW\" ></td></tr>"); 762 websWrite(wp, "<tr><th width=\"310\"> SES Button: </th>"); 763 websWrite(wp, "<td> </td>"); 764 websWrite(wp, "<td><input type=\"submit\" name=\"action\" value=\"ResetNWToDefault\" ></td></tr>"); 765 766#endif /* __CONFIG_SES__ */ 767 768 return 1; 769} 770 771static int 772ej_wl_radio_roam_option(int eid, webs_t wp, int argc, char_t **argv) 773{ 774 int unit; 775 char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_"; 776 char *name; 777 int radio_status = 0; 778 779 if ((unit = atoi(nvram_safe_get("wl_unit"))) < 0) { 780 websError(wp, 400, "unit number variable doesn't exist\n"); 781 return -1; 782 } 783 snprintf(prefix, sizeof(prefix), "wl%d_", unit); 784 name = nvram_safe_get(strcat_r(prefix, "ifname", tmp)); 785 wl_ioctl(name, WLC_GET_RADIO, &radio_status, sizeof (radio_status)); 786 if (!radio_status) /* Radio on*/ 787 websWrite(wp, "<input type=\"submit\" name=\"action\" value=\"RadioOff\" >"); 788 else /* Radio Off */ 789 websWrite(wp, "<input type=\"submit\" name=\"action\" value=\"RadioOn\" >"); 790 791 return 1; 792 793 794} 795static int 796wl_radio_onoff(webs_t wp, int disable) 797{ 798 int unit; 799 char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_"; 800 char *name; 801 char *interface_status; 802 803 804 if ((unit = atoi(nvram_safe_get("wl_unit"))) < 0) { 805 websError(wp, 400, "unit number variable doesn't exist\n"); 806 return -1; 807 } 808 809 snprintf(prefix, sizeof(prefix), "wl%d_", unit); 810 interface_status = nvram_safe_get(strcat_r(prefix, "radio", tmp)); 811 812 if (interface_status != NULL) { 813 if (!strcmp(interface_status, "1")) { 814 snprintf(prefix, sizeof(prefix), "wl%d_", unit); 815 name = nvram_safe_get(strcat_r(prefix, "ifname", tmp)); 816 wl_ioctl(name, WLC_SET_RADIO, &disable, sizeof (disable)); 817 } 818 else { 819 websWrite(wp, "Interface is not Enabled..."); 820 return 0; 821 } 822 } 823 else { 824 websWrite(wp, "Interface status UnKnown..."); 825 return 0; 826 } 827 828 829 return 0; 830 831} 832 833/* 834 * Example: 835 * lan_ipaddr=192.168.1.1 836 * <% nvram_get("lan_ipaddr"); %> produces "192.168.1.1" 837 * <% nvram_get("undefined"); %> produces "" 838 */ 839static int 840ej_nvram_get(int eid, webs_t wp, int argc, char_t **argv) 841{ 842 char *name, *c; 843 int ret = 0; 844 845 if (ejArgs(argc, argv, "%s", &name) < 1) { 846 websError(wp, 400, "Insufficient args\n"); 847 return -1; 848 } 849 850 for (c = nvram_safe_get(name); *c; c++) { 851 if (isprint((int) *c) && 852 *c != '"' && *c != '&' && *c != '<' && *c != '>') 853 ret += websWrite(wp, "%c", *c); 854 else 855 ret += websWrite(wp, "&#%d", *c); 856 } 857 858 return ret; 859} 860 861/* 862 * Example: 863 * wan_proto=dhcp 864 * <% nvram_match("wan_proto", "dhcp", "selected"); %> produces "selected" 865 * <% nvram_match("wan_proto", "static", "selected"); %> does not produce 866 */ 867static int 868ej_nvram_match(int eid, webs_t wp, int argc, char_t **argv) 869{ 870 char *name, *match, *output; 871 872 if (ejArgs(argc, argv, "%s %s %s", &name, &match, &output) < 3) { 873 websError(wp, 400, "Insufficient args\n"); 874 return -1; 875 } 876 877 if (nvram_match(name, match)) 878 return websWrite(wp, output); 879 880 return 0; 881} 882 883static int 884ej_wme_match_op(int eid, webs_t wp, int argc, char_t **argv) 885{ 886 char *name, *match, *output; 887 char word[256], *next; 888 889 if (ejArgs(argc, argv, "%s %s %s", &name, &match, &output) < 3) { 890 websError(wp, 400, "Insufficient args\n"); 891 return -1; 892 } 893 894 foreach(word, nvram_safe_get(name), next) { 895 if (!strcmp(word, match)) 896 return websWrite(wp, output); 897 } 898 899 return 0; 900} 901 902static int 903wl_print_channel_list(webs_t wp, char *name, char *phytype, char *abbrev) 904{ 905 int j, status = 0; 906 wl_channels_in_country_t *cic = (wl_channels_in_country_t *)malloc(WLC_IOCTL_MAXLEN); 907 908 if (!cic) { 909 status = -1; 910 goto exit; 911 } 912 913 cic->buflen = WLC_IOCTL_MAXLEN; 914 strcpy(cic->country_abbrev, abbrev); 915 if (!strcmp(phytype, "a")) 916 cic->band = WLC_BAND_A; 917 else if ((!strcmp(phytype, "b")) || (!strcmp(phytype, "g"))) 918 cic->band = WLC_BAND_B; 919 else { 920 status = -1; 921 goto exit; 922 } 923 924 if (wl_ioctl(name, WLC_GET_CHANNELS_IN_COUNTRY, cic, cic->buflen) == 0) { 925 if (cic->count == 0) { 926 status = 0; 927 goto exit; 928 } 929 websWrite(wp, "\t\tif (country == \"%s\")\n\t\t\tchannels = new Array(0", 930 abbrev); 931 for(j = 0; j < cic->count; j++) 932 websWrite(wp, ", %d", cic->channel[j]); 933 websWrite(wp,");\n"); 934 } 935 936exit: 937 if (cic) 938 free((void *)cic); 939 return status; 940} 941 942static int 943ej_wl_country_list(int eid, webs_t wp, int argc, char_t **argv) 944{ 945 int unit, i, status = 0; 946 char *name; 947 char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_"; 948 char *phytype = NULL; 949 wl_country_list_t *cl = (wl_country_list_t *)malloc(WLC_IOCTL_MAXLEN); 950 country_name_t *cntry; 951 char *abbrev; 952 953 if (!cl) { 954 status = -1; 955 goto exit; 956 } 957 958 if (ejArgs(argc, argv, "%s", &phytype) < 1) { 959 websError(wp, 400, "Insufficient args\n"); 960 status = -1; 961 goto exit; 962 } 963 964 if ((unit = atoi(nvram_safe_get("wl_unit"))) < 0) { 965 status = -1; 966 goto exit; 967 } 968 969 snprintf(prefix, sizeof(prefix), "wl%d_", unit); 970 name = nvram_safe_get(strcat_r(prefix, "ifname", tmp)); 971 972 cl->buflen = WLC_IOCTL_MAXLEN; 973 cl->band_set = TRUE; 974 975 if (!strcmp(phytype, "a")) 976 cl->band = WLC_BAND_A; 977 else if ((!strcmp(phytype, "b")) || (!strcmp(phytype, "g"))) 978 cl->band = WLC_BAND_B; 979 else { 980 status = -1; 981 goto exit; 982 } 983 984 if (wl_ioctl(name, WLC_GET_COUNTRY_LIST, cl, cl->buflen) == 0) { 985 websWrite(wp, "\t\tvar countries = new Array("); 986 for(i = 0; i < cl->count; i++) { 987 abbrev = &cl->country_abbrev[i*WLC_CNTRY_BUF_SZ]; 988 websWrite(wp, "\"%s\"", abbrev); 989 if (i != (cl->count - 1)) 990 websWrite(wp, ", "); 991 } 992 websWrite(wp, ");\n"); 993 for(i = 0; i < cl->count; i++) { 994 abbrev = &cl->country_abbrev[i*WLC_CNTRY_BUF_SZ]; 995 for(cntry = country_names; 996 cntry->name && strcmp(abbrev, cntry->abbrev); 997 cntry++); 998 websWrite(wp, "\t\tdocument.forms[0].wl_country_code[%d] = new Option(\"%s\", \"%s\");\n", 999 i, cntry->name ? cntry->name : abbrev, abbrev); 1000 } 1001 } 1002 1003exit: 1004 if (cl) 1005 free((void *)cl); 1006 return status; 1007} 1008 1009static int 1010ej_wl_channel_list(int eid, webs_t wp, int argc, char_t **argv) 1011{ 1012 int unit, i, status = 0; 1013 char *name; 1014 char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_"; 1015 char *phytype = NULL; 1016 wl_country_list_t *cl = (wl_country_list_t *)malloc(WLC_IOCTL_MAXLEN); 1017 char *abbrev; 1018 1019 if (!cl) { 1020 status = -1; 1021 goto exit; 1022 } 1023 1024 if (ejArgs(argc, argv, "%s", &phytype) < 1) { 1025 websError(wp, 400, "Insufficient args\n"); 1026 status = -1; 1027 goto exit; 1028 } 1029 1030 if ((unit = atoi(nvram_safe_get("wl_unit"))) < 0) { 1031 status = -1; 1032 goto exit; 1033 } 1034 1035 snprintf(prefix, sizeof(prefix), "wl%d_", unit); 1036 name = nvram_safe_get(strcat_r(prefix, "ifname", tmp)); 1037 1038 cl->buflen = WLC_IOCTL_MAXLEN; 1039 cl->band_set = TRUE; 1040 1041 if (!strcmp(phytype, "a")) 1042 cl->band = WLC_BAND_A; 1043 else if ((!strcmp(phytype, "b")) || (!strcmp(phytype, "g"))) 1044 cl->band = WLC_BAND_B; 1045 else { 1046 status = -1; 1047 goto exit; 1048 } 1049 1050 if (wl_ioctl(name, WLC_GET_COUNTRY_LIST, cl, cl->buflen) == 0) { 1051 for(i = 0; i < cl->count; i++) { 1052 abbrev = &cl->country_abbrev[i*WLC_CNTRY_BUF_SZ]; 1053 wl_print_channel_list(wp, name, phytype, abbrev); 1054 } 1055 } 1056 1057 1058exit: 1059 if (cl) 1060 free((void *)cl); 1061 return status; 1062} 1063 1064static bool find_ethaddr_in_list (void *ethaddr, struct maclist *list) 1065{ 1066 int i; 1067 for (i = 0; i < list->count; i ++) { 1068 if (!bcmp(ethaddr, (void *)&list->ea[i], ETHER_ADDR_LEN)) { 1069 return TRUE; 1070 } 1071 } 1072 1073 return FALSE; 1074} 1075 1076static int 1077ej_wl_auth_list(int eid, webs_t wp, int argc, char_t **argv) 1078{ 1079 int unit; 1080 char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_"; 1081 char *name; 1082 struct maclist *auth, *assoc, *authorized, *wme; 1083 int max_sta_count, maclist_size; 1084 int i; 1085 1086 if ((unit = atoi(nvram_safe_get("wl_unit"))) < 0) 1087 return -1; 1088 1089 snprintf(prefix, sizeof(prefix), "wl%d_", unit); 1090 name = nvram_safe_get(strcat_r(prefix, "ifname", tmp)); 1091 1092 /* buffers and length */ 1093 max_sta_count = MAX_STA_COUNT; 1094 maclist_size = sizeof(auth->count) + max_sta_count * sizeof(struct ether_addr); 1095 1096 auth = malloc(maclist_size); 1097 assoc = malloc(maclist_size); 1098 authorized = malloc(maclist_size); 1099 wme = malloc(maclist_size); 1100 1101 if (!auth || !assoc || !authorized || !wme) 1102 goto exit; 1103 1104 /* query wl for authenticated sta list */ 1105 strcpy((char*)auth, "authe_sta_list"); 1106 if (wl_ioctl(name, WLC_GET_VAR, auth, maclist_size)) 1107 goto exit; 1108 1109 /* query wl for associated sta list */ 1110 assoc->count = max_sta_count; 1111 if (wl_ioctl(name, WLC_GET_ASSOCLIST, assoc, maclist_size)) 1112 goto exit; 1113 1114 /* query wl for authorized sta list */ 1115 strcpy((char*)authorized, "autho_sta_list"); 1116 if (wl_ioctl(name, WLC_GET_VAR, authorized, maclist_size)) 1117 goto exit; 1118 1119 /* query wl for WME sta list */ 1120 strcpy((char*)wme, "wme_sta_list"); 1121 if (wl_ioctl(name, WLC_GET_VAR, wme, maclist_size)) 1122 goto exit; 1123 1124 /* build authenticated/associated/authorized sta list */ 1125 for (i = 0; i < auth->count; i ++) { 1126 char ea[ETHER_ADDR_STR_LEN]; 1127 char *value; 1128 websWrite(wp, "<tr><td>%s</td>", ether_etoa((void *)&auth->ea[i], ea)); 1129 1130 value = (find_ethaddr_in_list ((void *)&auth->ea[i], assoc))? "Yes" : "No"; 1131 websWrite(wp, "<td>%s</td>", value); 1132 1133 value = (find_ethaddr_in_list ((void *)&auth->ea[i], authorized))? "Yes" : "No"; 1134 websWrite(wp, "<td>%s</td>", value); 1135 1136 value = (find_ethaddr_in_list ((void *)&auth->ea[i], wme))? "Yes" : "No"; 1137 websWrite(wp, "<td>%s</td>", value); 1138 1139 websWrite(wp, "</tr>"); 1140 } 1141 1142 /* error/exit */ 1143exit: 1144 if (auth) free(auth); 1145 if (assoc) free(assoc); 1146 if (authorized) free(authorized); 1147 if (wme) free(wme); 1148 1149 return 0; 1150} 1151 1152/* 1153 * Example: 1154 * wan_proto=dhcp 1155 * <% nvram_invmatch("wan_proto", "dhcp", "disabled"); %> does not produce 1156 * <% nvram_invmatch("wan_proto", "static", "disabled"); %> produces "disabled" 1157 */ 1158static int 1159ej_nvram_invmatch(int eid, webs_t wp, int argc, char_t **argv) 1160{ 1161 char *name, *invmatch, *output; 1162 1163 if (ejArgs(argc, argv, "%s %s %s", &name, &invmatch, &output) < 3) { 1164 websError(wp, 400, "Insufficient args\n"); 1165 return -1; 1166 } 1167 1168 if (nvram_invmatch(name, invmatch)) 1169 return websWrite(wp, output); 1170 1171 return 0; 1172} 1173 1174/* 1175 * Example: 1176 * filter_maclist=00:12:34:56:78:00 00:87:65:43:21:00 1177 * <% nvram_list("filter_maclist", 1); %> produces "00:87:65:43:21:00" 1178 * <% nvram_list("filter_maclist", 100); %> produces "" 1179 */ 1180static int 1181ej_nvram_list(int eid, webs_t wp, int argc, char_t **argv) 1182{ 1183 char *name; 1184 int which; 1185 char word[256], *next; 1186 1187 if (ejArgs(argc, argv, "%s %d", &name, &which) < 2) { 1188 websError(wp, 400, "Insufficient args\n"); 1189 return -1; 1190 } 1191 1192 foreach(word, nvram_safe_get(name), next) { 1193 if (which-- == 0) 1194 return websWrite(wp, word); 1195 } 1196 1197 return 0; 1198} 1199 1200static int 1201ej_nvram_inlist(int eid, webs_t wp, int argc, char_t **argv) 1202{ 1203 char *name, *item, *output; 1204 char word[256], *next; 1205 1206 if (ejArgs(argc, argv, "%s %s %s", &name, &item, &output) < 3) { 1207 websError(wp, 400, "Insufficient args\n"); 1208 return -1; 1209 } 1210 1211 foreach(word, nvram_safe_get(name), next) { 1212 if (!strcmp(word, item)) 1213 return websWrite(wp, output); 1214 } 1215 1216 return 0; 1217} 1218 1219static int 1220ej_nvram_invinlist(int eid, webs_t wp, int argc, char_t **argv) 1221{ 1222 char *name, *item, *output; 1223 char word[256], *next; 1224 1225 if (ejArgs(argc, argv, "%s %s %s", &name, &item, &output) < 3) { 1226 websError(wp, 400, "Insufficient args\n"); 1227 return -1; 1228 } 1229 1230 foreach(word, nvram_safe_get(name), next) { 1231 if (!strcmp(word, item)) 1232 return 0; 1233 } 1234 1235 return websWrite(wp, output); 1236} 1237 1238#ifdef __CONFIG_NAT__ 1239/* 1240 * Example: 1241 * <% filter_client(1, 10); %> produces a table of the first 10 client filter entries 1242 */ 1243static int 1244ej_filter_client(int eid, webs_t wp, int argc, char_t **argv) 1245{ 1246 int i, n, j, ret = 0; 1247 netconf_filter_t start, end; 1248 bool valid; 1249 char port[] = "XXXXX"; 1250 char *days[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; 1251 char *hours[] = { 1252 "12:00 AM", "1:00 AM", "2:00 AM", "3:00 AM", "4:00 AM", "5:00 AM", 1253 "6:00 AM", "7:00 AM", "8:00 AM", "9:00 AM", "10:00 AM", "11:00 AM", 1254 "12:00 PM", "1:00 PM", "2:00 PM", "3:00 PM", "4:00 PM", "5:00 PM", 1255 "6:00 PM", "7:00 PM", "8:00 PM", "9:00 PM", "10:00 PM", "11:00 PM" 1256 }; 1257 1258 if (ejArgs(argc, argv, "%d %d", &i, &n) < 2) { 1259 websError(wp, 400, "Insufficient args\n"); 1260 return -1; 1261 } 1262 1263 for (; i <= n; i++) { 1264 valid = get_filter_client(i, &start, &end); 1265 1266 ret += websWrite(wp, "<tr>"); 1267 ret += websWrite(wp, "<td></td>"); 1268 1269 /* Print address range */ 1270 ret += websWrite(wp, "<td><input name=\"filter_client_from_start%d\" value=\"%s\" size=\"15\" maxlength=\"15\"></td>", 1271 i, valid ? inet_ntoa(start.match.src.ipaddr) : ""); 1272 ret += websWrite(wp, "<td>-</td>"); 1273 ret += websWrite(wp, "<td><input name=\"filter_client_from_end%d\" value=\"%s\" size=\"15\" maxlength=\"15\"></td>", 1274 i, valid ? inet_ntoa(end.match.src.ipaddr) : ""); 1275 ret += websWrite(wp, "<td></td>"); 1276 1277 /* Print protocol */ 1278 ret += websWrite(wp, "<td>"); 1279 ret += websWrite(wp, "<select name=\"filter_client_proto%d\">", i); 1280 ret += websWrite(wp, "<option value=\"tcp\" %s>TCP</option>", 1281 valid && start.match.ipproto == IPPROTO_TCP ? "selected" : ""); 1282 ret += websWrite(wp, "<option value=\"udp\" %s>UDP</option>", 1283 valid && start.match.ipproto == IPPROTO_UDP ? "selected" : ""); 1284 ret += websWrite(wp, "</select>"); 1285 ret += websWrite(wp, "</td>"); 1286 ret += websWrite(wp, "<td></td>"); 1287 1288 /* Print port range */ 1289 if (valid) 1290 snprintf(port, sizeof(port), "%d", ntohs(start.match.dst.ports[0])); 1291 else 1292 *port = '\0'; 1293 ret += websWrite(wp, "<td><input name=\"filter_client_to_start%d\" value=\"%s\" size=\"5\" maxlength=\"5\"></td>", 1294 i, port); 1295 ret += websWrite(wp, "<td>-</td>"); 1296 if (valid) 1297 snprintf(port, sizeof(port), "%d", ntohs(start.match.dst.ports[1])); 1298 else 1299 *port = '\0'; 1300 ret += websWrite(wp, "<td><input name=\"filter_client_to_end%d\" value=\"%s\" size=\"5\" maxlength=\"5\"></td>", 1301 i, port); 1302 ret += websWrite(wp, "<td></td>"); 1303 1304 /* Print day range */ 1305 ret += websWrite(wp, "<td>"); 1306 ret += websWrite(wp, "<select name=\"filter_client_from_day%d\">", i); 1307 for (j = 0; j < ARRAYSIZE(days); j++) 1308 ret += websWrite(wp, "<option value=\"%d\" %s>%s</option>", 1309 j, valid && start.match.days[0] == j ? "selected" : "", days[j]); 1310 ret += websWrite(wp, "</select>"); 1311 ret += websWrite(wp, "</td>"); 1312 ret += websWrite(wp, "<td>-</td>"); 1313 ret += websWrite(wp, "<td>"); 1314 ret += websWrite(wp, "<select name=\"filter_client_to_day%d\">", i); 1315 for (j = 0; j < ARRAYSIZE(days); j++) 1316 ret += websWrite(wp, "<option value=\"%d\" %s>%s</option>", 1317 j, valid && start.match.days[1] == j ? "selected" : "", days[j]); 1318 ret += websWrite(wp, "</select>"); 1319 ret += websWrite(wp, "</td>"); 1320 ret += websWrite(wp, "<td></td>"); 1321 1322 /* Print time range */ 1323 ret += websWrite(wp, "<td>"); 1324 ret += websWrite(wp, "<select name=\"filter_client_from_sec%d\">", i); 1325 for (j = 0; j < ARRAYSIZE(hours); j++) 1326 ret += websWrite(wp, "<option value=\"%d\" %s>%s</option>", 1327 j * 3600, valid && start.match.secs[0] == (j * 3600) ? "selected" : "", hours[j]); 1328 ret += websWrite(wp, "</select>"); 1329 ret += websWrite(wp, "</td>"); 1330 ret += websWrite(wp, "<td>-</td>"); 1331 1332 ret += websWrite(wp, "<td>"); 1333 ret += websWrite(wp, "<select name=\"filter_client_to_sec%d\">", i); 1334 for (j = 0; j < ARRAYSIZE(hours); j++) 1335 ret += websWrite(wp, "<option value=\"%d\" %s>%s</option>", 1336 j * 3600, valid && start.match.secs[1] == (j * 3600) ? "selected" : "", hours[j]); 1337 /* Special case for 11:59:59 PM */ 1338 ret += websWrite(wp, "<option value=\"%d\" %s>12:00 AM</option>", 1339 24 * 3600 - 1, valid && start.match.secs[1] == (24 * 3600 - 1) ? "selected" : ""); 1340 ret += websWrite(wp, "</select>"); 1341 ret += websWrite(wp, "</td>"); 1342 ret += websWrite(wp, "<td></td>"); 1343 1344 /* Print enable */ 1345 ret += websWrite(wp, "<td><input type=\"checkbox\" name=\"filter_client_enable%d\" %s></td>", 1346 i, valid && !(start.match.flags & NETCONF_DISABLED) ? "checked" : ""); 1347 1348 ret += websWrite(wp, "</tr>"); 1349 } 1350 1351 return ret; 1352} 1353 1354/* 1355 * Example: 1356 * <% forward_port(1, 10); %> produces a table of the first 10 port forward entries 1357 */ 1358static int 1359ej_forward_port(int eid, webs_t wp, int argc, char_t **argv) 1360{ 1361 int i, n, ret = 0; 1362 netconf_nat_t nat; 1363 bool valid; 1364 char port[] = "XXXXX"; 1365 1366 if (ejArgs(argc, argv, "%d %d", &i, &n) < 2) { 1367 websError(wp, 400, "Insufficient args\n"); 1368 return -1; 1369 } 1370 1371 for (; i <= n; i++) { 1372 valid = get_forward_port(i, &nat); 1373 1374 ret += websWrite(wp, "<tr>"); 1375 ret += websWrite(wp, "<td></td>"); 1376 1377 /* Print protocol */ 1378 ret += websWrite(wp, "<td>"); 1379 ret += websWrite(wp, "<select name=\"forward_port_proto%d\">", i); 1380 ret += websWrite(wp, "<option value=\"tcp\" %s>TCP</option>", 1381 valid && nat.match.ipproto == IPPROTO_TCP ? "selected" : ""); 1382 ret += websWrite(wp, "<option value=\"udp\" %s>UDP</option>", 1383 valid && nat.match.ipproto == IPPROTO_UDP ? "selected" : ""); 1384 ret += websWrite(wp, "</select>"); 1385 ret += websWrite(wp, "</td>"); 1386 ret += websWrite(wp, "<td></td>"); 1387 1388 /* Print WAN destination port range */ 1389 if (valid) 1390 snprintf(port, sizeof(port), "%d", ntohs(nat.match.dst.ports[0])); 1391 else 1392 *port = '\0'; 1393 ret += websWrite(wp, "<td><input name=\"forward_port_from_start%d\" value=\"%s\" size=\"5\" maxlength=\"5\"></td>", 1394 i, port); 1395 ret += websWrite(wp, "<td>-</td>"); 1396 if (valid) 1397 snprintf(port, sizeof(port), "%d", ntohs(nat.match.dst.ports[1])); 1398 else 1399 *port = '\0'; 1400 ret += websWrite(wp, "<td><input name=\"forward_port_from_end%d\" value=\"%s\" size=\"5\" maxlength=\"5\"></td>", 1401 i, port); 1402 ret += websWrite(wp, "<td>></td>"); 1403 1404 /* Print address range */ 1405 ret += websWrite(wp, "<td><input name=\"forward_port_to_ip%d\" value=\"%s\" size=\"15\" maxlength=\"15\"></td>", 1406 i, valid ? inet_ntoa(nat.ipaddr) : ""); 1407 ret += websWrite(wp, "<td>:</td>"); 1408 1409 /* Print LAN destination port range */ 1410 if (valid) 1411 snprintf(port, sizeof(port), "%d", ntohs(nat.ports[0])); 1412 else 1413 *port = '\0'; 1414 ret += websWrite(wp, "<td><input name=\"forward_port_to_start%d\" value=\"%s\" size=\"5\" maxlength=\"5\"></td>", 1415 i, port); 1416 ret += websWrite(wp, "<td>-</td>"); 1417 if (valid) 1418 snprintf(port, sizeof(port), "%d", ntohs(nat.ports[1])); 1419 else 1420 *port = '\0'; 1421 ret += websWrite(wp, "<td><input name=\"forward_port_to_end%d\" value=\"%s\" size=\"5\" maxlength=\"5\"></td>", 1422 i, port); 1423 ret += websWrite(wp, "<td></td>"); 1424 1425 /* Print enable */ 1426 ret += websWrite(wp, "<td><input type=\"checkbox\" name=\"forward_port_enable%d\" %s></td>", 1427 i, valid && !(nat.match.flags & NETCONF_DISABLED) ? "checked" : ""); 1428 1429 ret += websWrite(wp, "</tr>"); 1430 } 1431 1432 return ret; 1433} 1434 1435static int 1436ej_autofw_port(int eid, webs_t wp, int argc, char_t **argv) 1437{ 1438 int i, n, ret = 0; 1439 netconf_app_t app; 1440 bool valid; 1441 char port[] = "XXXXX"; 1442 1443 if (ejArgs(argc, argv, "%d %d", &i, &n) < 2) { 1444 websError(wp, 400, "Insufficient args\n"); 1445 return -1; 1446 } 1447 1448 for (; i <= n; i++) { 1449 valid = get_autofw_port(i, &app); 1450 1451 /* Parse out_proto:out_port,in_proto:in_start-in_end>to_start-to_end,enable,desc */ 1452 ret += websWrite(wp, "<tr>"); 1453 ret += websWrite(wp, "<td></td>"); 1454 1455 /* Print outbound protocol */ 1456 ret += websWrite(wp, "<td>"); 1457 ret += websWrite(wp, "<select name=\"autofw_port_out_proto%d\">", i); 1458 ret += websWrite(wp, "<option value=\"tcp\" %s>TCP</option>", 1459 valid && app.match.ipproto == IPPROTO_TCP ? "selected" : ""); 1460 ret += websWrite(wp, "<option value=\"udp\" %s>UDP</option>", 1461 valid && app.match.ipproto == IPPROTO_UDP ? "selected" : ""); 1462 ret += websWrite(wp, "</select>"); 1463 ret += websWrite(wp, "</td>"); 1464 ret += websWrite(wp, "<td></td>"); 1465 1466 /* Print outbound port */ 1467 if (valid) 1468 snprintf(port, sizeof(port), "%d", ntohs(app.match.dst.ports[0])); 1469 else 1470 *port = '\0'; 1471 ret += websWrite(wp, "<td><input name=\"autofw_port_out_start%d\" value=\"%s\" size=\"5\" maxlength=\"5\"></td>", 1472 i, port); 1473 ret += websWrite(wp, "<td>-</td>"); 1474 if (valid) 1475 snprintf(port, sizeof(port), "%d", ntohs(app.match.dst.ports[1])); 1476 else 1477 *port = '\0'; 1478 ret += websWrite(wp, "<td><input name=\"autofw_port_out_end%d\" value=\"%s\" size=\"5\" maxlength=\"5\"></td>", 1479 i, port); 1480 ret += websWrite(wp, "<td></td>"); 1481 1482 /* Print related protocol */ 1483 ret += websWrite(wp, "<td>"); 1484 ret += websWrite(wp, "<select name=\"autofw_port_in_proto%d\">", i); 1485 ret += websWrite(wp, "<option value=\"tcp\" %s>TCP</option>", 1486 valid && app.proto == IPPROTO_TCP ? "selected" : ""); 1487 ret += websWrite(wp, "<option value=\"udp\" %s>UDP</option>", 1488 valid && app.proto == IPPROTO_UDP ? "selected" : ""); 1489 ret += websWrite(wp, "</select>"); 1490 ret += websWrite(wp, "</td>"); 1491 ret += websWrite(wp, "<td></td>"); 1492 1493 /* Print related destination port range */ 1494 if (valid) 1495 snprintf(port, sizeof(port), "%d", ntohs(app.dport[0])); 1496 else 1497 *port = '\0'; 1498 ret += websWrite(wp, "<td><input name=\"autofw_port_in_start%d\" value=\"%s\" size=\"5\" maxlength=\"5\"></td>", 1499 i, port); 1500 ret += websWrite(wp, "<td>-</td>"); 1501 if (valid) 1502 snprintf(port, sizeof(port), "%d", ntohs(app.dport[1])); 1503 else 1504 *port = '\0'; 1505 ret += websWrite(wp, "<td><input name=\"autofw_port_in_end%d\" value=\"%s\" size=\"5\" maxlength=\"5\"></td>", 1506 i, port); 1507 ret += websWrite(wp, "<td></td>"); 1508 1509 /* Print mapped destination port range */ 1510 if (valid) 1511 snprintf(port, sizeof(port), "%d", ntohs(app.to[0])); 1512 else 1513 *port = '\0'; 1514 ret += websWrite(wp, "<td><input name=\"autofw_port_to_start%d\" value=\"%s\" size=\"5\" maxlength=\"5\"></td>", 1515 i, port); 1516 ret += websWrite(wp, "<td>-</td>"); 1517 if (valid) 1518 snprintf(port, sizeof(port), "%d", ntohs(app.to[1])); 1519 else 1520 *port = '\0'; 1521 ret += websWrite(wp, "<td><input name=\"autofw_port_to_end%d\" value=\"%s\" size=\"5\" maxlength=\"5\"></td>", 1522 i, port); 1523 ret += websWrite(wp, "<td></td>"); 1524 1525 /* Print enable */ 1526 ret += websWrite(wp, "<td><input type=\"checkbox\" name=\"autofw_port_enable%d\" %s></td>", 1527 i, valid && !(app.match.flags & NETCONF_DISABLED) ? "checked" : ""); 1528 1529 ret += websWrite(wp, "</tr>"); 1530 } 1531 1532 return ret; 1533} 1534#endif /* __CONFIG_NAT__ */ 1535 1536/* 1537 * Example: 1538 * lan_route=192.168.2.0:255.255.255.0:192.168.2.1:1 1539 * <% lan_route("ipaddr", 0); %> produces "192.168.2.0" 1540 */ 1541static int 1542ej_lan_route(int eid, webs_t wp, int argc, char_t **argv) 1543{ 1544 char *arg; 1545 int which; 1546 char word[256], *next; 1547 char *ipaddr, *netmask, *gateway, *metric; 1548 1549 if (ejArgs(argc, argv, "%s %d", &arg, &which) < 2) { 1550 websError(wp, 400, "Insufficient args\n"); 1551 return -1; 1552 } 1553 1554 foreach(word, nvram_safe_get("lan_route"), next) { 1555 if (which-- == 0) { 1556 netmask = word; 1557 ipaddr = strsep(&netmask, ":"); 1558 if (!ipaddr || !netmask) 1559 continue; 1560 gateway = netmask; 1561 netmask = strsep(&gateway, ":"); 1562 if (!netmask || !gateway) 1563 continue; 1564 metric = gateway; 1565 gateway = strsep(&metric, ":"); 1566 if (!gateway || !metric) 1567 continue; 1568 if (!strcmp(arg, "ipaddr")) 1569 return websWrite(wp, ipaddr); 1570 else if (!strcmp(arg, "netmask")) 1571 return websWrite(wp, netmask); 1572 else if (!strcmp(arg, "gateway")) 1573 return websWrite(wp, gateway); 1574 else if (!strcmp(arg, "metric")) 1575 return websWrite(wp, metric); 1576 } 1577 } 1578 1579 return 0; 1580} 1581 1582#ifdef __CONFIG_NAT__ 1583/* 1584 * Example: 1585 * wan_route=192.168.10.0:255.255.255.0:192.168.10.1:1 1586 * <% wan_route("ipaddr", 0); %> produces "192.168.10.0" 1587 */ 1588static int 1589ej_wan_route(int eid, webs_t wp, int argc, char_t **argv) 1590{ 1591 char *arg; 1592 int which; 1593 char word[256], *next; 1594 char *ipaddr, *netmask, *gateway, *metric; 1595 int unit; 1596 char tmp[NVRAM_BUFSIZE], prefix[] = "wanXXXXXXXXXX_"; 1597 1598 1599 if (ejArgs(argc, argv, "%s %d", &arg, &which) < 2) { 1600 websError(wp, 400, "Insufficient args\n"); 1601 return -1; 1602 } 1603 1604 if ((unit = atoi(nvram_safe_get("wan_unit"))) < 0) 1605 unit = 0; 1606 wan_prefix(unit, prefix); 1607 1608 foreach(word, nvram_safe_get(strcat_r(prefix, "route", tmp)), next) { 1609 if (which-- == 0) { 1610 netmask = word; 1611 ipaddr = strsep(&netmask, ":"); 1612 if (!ipaddr || !netmask) 1613 continue; 1614 gateway = netmask; 1615 netmask = strsep(&gateway, ":"); 1616 if (!netmask || !gateway) 1617 continue; 1618 metric = gateway; 1619 gateway = strsep(&metric, ":"); 1620 if (!gateway || !metric) 1621 continue; 1622 if (!strcmp(arg, "ipaddr")) 1623 return websWrite(wp, ipaddr); 1624 else if (!strcmp(arg, "netmask")) 1625 return websWrite(wp, netmask); 1626 else if (!strcmp(arg, "gateway")) 1627 return websWrite(wp, gateway); 1628 else if (!strcmp(arg, "metric")) 1629 return websWrite(wp, metric); 1630 } 1631 } 1632 1633 return 0; 1634} 1635#endif /* __CONFIG_NAT__ */ 1636 1637/* Return a list of the currently present wireless interfaces */ 1638static int 1639ej_wl_list(int eid, webs_t wp, int argc, char_t **argv) 1640{ 1641 char name[IFNAMSIZ], *next; 1642 int unit, ret = 0; 1643 char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_"; 1644 char *hwaddr, *ssid; 1645 char ifnames[256]; 1646 1647 snprintf(ifnames, sizeof(ifnames), "%s %s", 1648 nvram_safe_get("lan_ifnames"), 1649 nvram_safe_get("wan_ifnames")); 1650 foreach(name, ifnames, next) { 1651 /* Probe for wl interfaces */ 1652 if (wl_probe(name) || 1653 wl_ioctl(name, WLC_GET_INSTANCE, &unit, sizeof(unit))) 1654 continue; 1655 1656 /* Get configured SSID */ 1657 snprintf(prefix, sizeof(prefix), "wl%d_", unit); 1658 hwaddr = nvram_get(strcat_r(prefix, "hwaddr", tmp)); 1659 ssid = nvram_get(strcat_r(prefix, "ssid", tmp)); 1660 if (!hwaddr || !*hwaddr || !ssid || !*ssid) 1661 continue; 1662 1663 ret += websWrite(wp, "<option value=\"%d\" %s>%s (%s)</option>", unit, 1664 unit == atoi(nvram_safe_get("wl_unit")) ? "selected" : "", 1665 ssid, hwaddr); 1666 } 1667 1668 if (!ret) 1669 ret += websWrite(wp, "<option value=\"-1\" selected>None</option>"); 1670 1671 return ret; 1672} 1673 1674/* Return a list of the supported bands on the currently selected wireless interface */ 1675static int 1676ej_wl_phytypes(int eid, webs_t wp, int argc, char_t **argv) 1677{ 1678 int unit, ret = 0; 1679 char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_"; 1680 char *phytype; 1681 char *phylist; 1682 int i; 1683 1684 if ((unit = atoi(nvram_safe_get("wl_unit"))) < 0) 1685 return websWrite(wp, "None"); 1686 1687 /* Get available phy types of the currently selected wireless interface */ 1688 snprintf(prefix, sizeof(prefix), "wl%d_", unit); 1689 phylist = nvram_safe_get(strcat_r(prefix, "phytypes", tmp)); 1690 1691 /* Get configured phy type */ 1692 phytype = nvram_safe_get("wl_phytype"); 1693 1694 for (i = 0; i < strlen(phylist); i++) { 1695 ret += websWrite(wp, "<option value=\"%c\" %s>802.11%c (%s GHz)</option>", 1696 phylist[i], phylist[i] == *phytype ? "selected" : "", phylist[i], 1697 phylist[i] == 'a' ? "5" : "2.4"); 1698 } 1699 1700 return ret; 1701} 1702 1703/* Return a radio ID given a phy type */ 1704static int 1705ej_wl_radioid(int eid, webs_t wp, int argc, char_t **argv) 1706{ 1707 char *phytype, var[NVRAM_BUFSIZE], *next; 1708 int unit; 1709 char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_"; 1710 int which; 1711 1712 if (ejArgs(argc, argv, "%s", &phytype) < 1) { 1713 websError(wp, 400, "Insufficient args\n"); 1714 return -1; 1715 } 1716 1717 if ((unit = atoi(nvram_safe_get("wl_unit"))) < 0) 1718 return websWrite(wp, "None"); 1719 snprintf(prefix, sizeof(prefix), "wl%d_", unit); 1720 1721 which = strcspn(nvram_safe_get(strcat_r(prefix, "phytypes", tmp)), phytype); 1722 foreach(var, nvram_safe_get(strcat_r(prefix, "radioids", tmp)), next) { 1723 if (which == 0) 1724 return websWrite(wp, var); 1725 which--; 1726 } 1727 1728 return websWrite(wp, "None"); 1729} 1730 1731/* Return current core revision */ 1732static int 1733ej_wl_corerev(int eid, webs_t wp, int argc, char_t **argv) 1734{ 1735 int unit; 1736 char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_"; 1737 1738 if ((unit = atoi(nvram_safe_get("wl_unit"))) < 0) 1739 return websWrite(wp, "None"); 1740 snprintf(prefix, sizeof(prefix), "wl%d_", unit); 1741 1742 return websWrite(wp, nvram_safe_get(strcat_r(prefix, "corerev", tmp))); 1743} 1744 1745/* Return current wireless channel */ 1746static int 1747ej_wl_cur_channel(int eid, webs_t wp, int argc, char_t **argv) 1748{ 1749 int unit; 1750 char *name; 1751 char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_"; 1752 channel_info_t ci; 1753 1754 if ((unit = atoi(nvram_safe_get("wl_unit"))) < 0) 1755 return -1; 1756 1757 snprintf(prefix, sizeof(prefix), "wl%d_", unit); 1758 name = nvram_safe_get(strcat_r(prefix, "ifname", tmp)); 1759 1760 wl_ioctl(name, WLC_GET_CHANNEL, &ci, sizeof(ci)); 1761 return websWrite(wp, "Current: %d", ci.target_channel); 1762} 1763 1764/* Return current country */ 1765static int 1766ej_wl_cur_country(int eid, webs_t wp, int argc, char_t **argv) 1767{ 1768 int unit; 1769 char *name; 1770 char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_"; 1771 char buf[WLC_CNTRY_BUF_SZ]; 1772 1773 if ((unit = atoi(nvram_safe_get("wl_unit"))) < 0) 1774 return -1; 1775 1776 snprintf(prefix, sizeof(prefix), "wl%d_", unit); 1777 name = nvram_safe_get(strcat_r(prefix, "ifname", tmp)); 1778 1779 wl_ioctl(name, WLC_GET_COUNTRY, buf, sizeof(buf)); 1780 return websWrite(wp, "%s", buf); 1781} 1782 1783/* hardware-defined phy types (from d11.h) */ 1784#define PHY_TYPE_A 0 1785#define PHY_TYPE_B 1 1786#define PHY_TYPE_G 2 1787#define PHY_TYPE_NULL 0xf 1788 1789/* Return current phytype */ 1790static int 1791ej_wl_cur_phytype(int eid, webs_t wp, int argc, char_t **argv) 1792{ 1793 int unit; 1794 char *name; 1795 char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_"; 1796 int phytype; 1797 1798 if ((unit = atoi(nvram_safe_get("wl_unit"))) < 0) 1799 return -1; 1800 1801 snprintf(prefix, sizeof(prefix), "wl%d_", unit); 1802 name = nvram_safe_get(strcat_r(prefix, "ifname", tmp)); 1803 1804 /* Get configured phy type */ 1805 wl_ioctl(name, WLC_GET_PHYTYPE, &phytype, sizeof(phytype)); 1806 1807 return websWrite(wp, "Current: 802.11%s", phytype == PHY_TYPE_A ? "a" : 1808 phytype == PHY_TYPE_B ? "b" : "g"); 1809} 1810 1811#ifdef __CONFIG_NAT__ 1812static char * 1813wan_name(int unit, char *prefix, char *name, int len) 1814{ 1815 char tmp[NVRAM_BUFSIZE], *desc; 1816 desc = nvram_safe_get(strcat_r(prefix, "desc", tmp)); 1817 snprintf(tmp, sizeof(tmp), "Connection %d", unit + 1); 1818 snprintf(name, len, "%s", !strcmp(desc, "") ? tmp : desc); 1819 return name; 1820} 1821 1822/* Return a list of wan connections (Connection <N>/<Connection Name>) */ 1823static int 1824ej_wan_list(int eid, webs_t wp, int argc, char_t **argv) 1825{ 1826 char tmp[NVRAM_BUFSIZE], prefix[] = "wanXXXXXXXXXX_"; 1827 int unit, ret = 0; 1828 1829 /* build wan connection name list */ 1830 for (unit = 0; unit < MAX_NVPARSE; unit ++) { 1831 wan_prefix(unit, prefix); 1832 if (!nvram_get(strcat_r(prefix, "unit", tmp))) 1833 continue; 1834 ret += websWrite(wp, "<option value=\"%d\" %s>%s</option>", unit, 1835 unit == atoi(nvram_safe_get("wan_unit")) ? "selected" : "", 1836 wan_name(unit, prefix, tmp, sizeof(tmp))); 1837 } 1838 1839 return ret; 1840} 1841#endif /* __CONFIG_NAT__ */ 1842 1843char *webs_buf=NULL; 1844int webs_buf_offset=0; 1845 1846static void 1847validate_list(webs_t wp, char *value, struct variable *v, 1848 int (*valid)(webs_t, char *, struct variable *)) 1849{ 1850 int n, i; 1851 char name[100]; 1852 char buf[1000] = "", *cur = buf; 1853 1854 n = atoi(value); 1855 1856 for (i = 0; i < n; i++) { 1857 snprintf(name, sizeof(name), "%s%d", v->name, i); 1858 if (!(value = websGetVar(wp, name, NULL))) 1859 return; 1860 if (!*value && v->nullok) 1861 continue; 1862 if (!valid(wp, value, v)) 1863 continue; 1864 cur += snprintf(cur, buf + sizeof(buf) - cur, "%s%s", 1865 cur == buf ? "" : " ", value); 1866 } 1867 1868 nvram_set(v->name, buf); 1869} 1870 1871static int 1872valid_ipaddr(webs_t wp, char *value, struct variable *v) 1873{ 1874 unsigned int buf[4]; 1875 struct in_addr ipaddr, netaddr, broadaddr, netmask; 1876 1877 if (sscanf(value, "%d.%d.%d.%d", &buf[0], &buf[1], &buf[2], &buf[3]) != 4) { 1878 websBufferWrite(wp, "Invalid <b>%s</b> %s: not an IP address<br>", 1879 v->longname, value); 1880 return FALSE; 1881 } 1882 1883 ipaddr.s_addr = htonl((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]); 1884 1885 if (v->argv) { 1886 (void) inet_aton(nvram_safe_get(v->argv[0]), &netaddr); 1887 (void) inet_aton(nvram_safe_get(v->argv[1]), &netmask); 1888 netaddr.s_addr &= netmask.s_addr; 1889 broadaddr.s_addr = netaddr.s_addr | ~netmask.s_addr; 1890 if (netaddr.s_addr != (ipaddr.s_addr & netmask.s_addr)) { 1891 websBufferWrite(wp, "Invalid <b>%s</b> %s: not in the %s/", 1892 v->longname, value, inet_ntoa(netaddr)); 1893 websBufferWrite(wp, "%s network<br>", inet_ntoa(netmask)); 1894 return FALSE; 1895 } 1896 if (ipaddr.s_addr == netaddr.s_addr) { 1897 websBufferWrite(wp, "Invalid <b>%s</b> %s: cannot be the network address<br>", 1898 v->longname, value); 1899 return FALSE; 1900 } 1901 if (ipaddr.s_addr == broadaddr.s_addr) { 1902 websBufferWrite(wp, "Invalid <b>%s</b> %s: cannot be the broadcast address<br>", 1903 v->longname, value); 1904 return FALSE; 1905 } 1906 } 1907 1908 return TRUE; 1909} 1910 1911static void 1912validate_ipaddr(webs_t wp, char *value, struct variable *v) 1913{ 1914 if (valid_ipaddr(wp, value, v)) 1915 nvram_set(v->name, value); 1916} 1917 1918static void 1919validate_ipaddrs(webs_t wp, char *value, struct variable *v) 1920{ 1921 validate_list(wp, value, v, valid_ipaddr); 1922} 1923 1924static int 1925valid_choice(webs_t wp, char *value, struct variable *v) 1926{ 1927 char **choice; 1928 1929 for (choice = v->argv; *choice; choice++) { 1930 if (!strcmp(value, *choice)) 1931 return TRUE; 1932 } 1933 1934 websBufferWrite(wp, "Invalid <b>%s</b> %s: not one of ", v->longname, value); 1935 for (choice = v->argv; *choice; choice++) 1936 websBufferWrite(wp, "%s%s", choice == v->argv ? "" : "/", *choice); 1937 websBufferWrite(wp, "<br>"); 1938 return FALSE; 1939} 1940 1941static void 1942validate_choice(webs_t wp, char *value, struct variable *v) 1943{ 1944 if (valid_choice(wp, value, v)) 1945 nvram_set(v->name, value); 1946} 1947 1948static int 1949valid_range(webs_t wp, char *value, struct variable *v) 1950{ 1951 int n, start, end; 1952 1953 n = atoi(value); 1954 start = atoi(v->argv[0]); 1955 end = atoi(v->argv[1]); 1956 1957 if (n < start || n > end) { 1958 websBufferWrite(wp, "Invalid <b>%s</b> %s: out of range %d-%d<br>", 1959 v->longname, value, start, end); 1960 return FALSE; 1961 } 1962 1963 return TRUE; 1964} 1965 1966static void 1967validate_range(webs_t wp, char *value, struct variable *v) 1968{ 1969 if (valid_range(wp, value, v)) 1970 nvram_set(v->name, value); 1971} 1972 1973static int 1974valid_name(webs_t wp, char *value, struct variable *v) 1975{ 1976 int n, min, max; 1977 1978 n = strlen(value); 1979 min = atoi(v->argv[0]); 1980 max = atoi(v->argv[1]); 1981 1982 if (n > max) { 1983 websBufferWrite(wp, "Invalid <b>%s</b> %s: longer than %d characters<br>", 1984 v->longname, value, max); 1985 return FALSE; 1986 } 1987 else if (n < min) { 1988 websBufferWrite(wp, "Invalid <b>%s</b> %s: shorter than %d characters<br>", 1989 v->longname, value, min); 1990 return FALSE; 1991 } 1992 1993 return TRUE; 1994} 1995 1996static void 1997validate_name(webs_t wp, char *value, struct variable *v) 1998{ 1999 if (valid_name(wp, value, v)) 2000 nvram_set(v->name, value); 2001} 2002 2003static int 2004valid_hwaddr(webs_t wp, char *value, struct variable *v) 2005{ 2006 unsigned char hwaddr[6]; 2007 2008 /* Make exception for "NOT IMPLELEMENTED" string */ 2009 if (!strcmp(value,"NOT_IMPLEMENTED")) 2010 return(TRUE); 2011 2012 /* Check for bad, multicast, broadcast, or null address */ 2013 if (!ether_atoe(value, hwaddr) || 2014 (hwaddr[0] & 1) || 2015 (hwaddr[0] & hwaddr[1] & hwaddr[2] & hwaddr[3] & hwaddr[4] & hwaddr[5]) == 0xff || 2016 (hwaddr[0] | hwaddr[1] | hwaddr[2] | hwaddr[3] | hwaddr[4] | hwaddr[5]) == 0x00) { 2017 websBufferWrite(wp, "Invalid <b>%s</b> %s: not a MAC address<br>", 2018 v->longname, value); 2019 return FALSE; 2020 } 2021 2022 return TRUE; 2023} 2024 2025#ifdef __CONFIG_NAT__ 2026static void 2027validate_hwaddr(webs_t wp, char *value, struct variable *v) 2028{ 2029 if (valid_hwaddr(wp, value, v)) 2030 nvram_set(v->name, value); 2031} 2032#endif /* __CONFIG_NAT__ */ 2033 2034static void 2035validate_hwaddrs(webs_t wp, char *value, struct variable *v) 2036{ 2037 validate_list(wp, value, v, valid_hwaddr); 2038} 2039 2040static void 2041validate_country(webs_t wp, char *value, struct variable *v) 2042{ 2043 country_name_t *country; 2044 for(country = country_names; country->name; country++) 2045 if (!strcmp(value, country->abbrev)) 2046 nvram_set(v->name, value); 2047} 2048 2049static void 2050validate_dhcp(webs_t wp, char *value, struct variable *v) 2051{ 2052 struct variable dhcp_variables[] = { 2053 { longname: "DHCP Server Starting LAN IP Address", argv: ARGV("lan_ipaddr", "lan_netmask") }, 2054 { longname: "DHCP Server Ending LAN IP Address", argv: ARGV("lan_ipaddr", "lan_netmask") }, 2055 }; 2056 char *start, *end; 2057 2058 if (!(start = websGetVar(wp, "dhcp_start", NULL)) || 2059 !(end = websGetVar(wp, "dhcp_end", NULL))) 2060 return; 2061 if (!*start) start = end; 2062 if (!*end) end = start; 2063 if (!*start && !*end && !strcmp(nvram_safe_get("lan_proto"), "dhcp")) { 2064 websBufferWrite(wp, "Invalid <b>%s</b>: must specify a range<br>", v->longname); 2065 return; 2066 } 2067 if (!valid_ipaddr(wp, start, &dhcp_variables[0]) || 2068 !valid_ipaddr(wp, end, &dhcp_variables[1])) 2069 return; 2070 if (ntohl(inet_addr(start)) > ntohl(inet_addr(end))) { 2071 websBufferWrite(wp, "Invalid <b>%s</b> %s: greater than <b>%s</b> %s<br>", 2072 dhcp_variables[0].longname, start, dhcp_variables[1].longname, end); 2073 return; 2074 } 2075 2076 nvram_set("dhcp_start", start); 2077 nvram_set("dhcp_end", end); 2078} 2079 2080static void 2081validate_lan_ipaddr(webs_t wp, char *value, struct variable *v) 2082{ 2083 struct variable fields[] = { 2084 { name: "lan_ipaddr", longname: "LAN IP Address" }, 2085 { name: "lan_netmask", longname: "LAN Subnet Mask" }, 2086 }; 2087 char *lan_ipaddr, *lan_netmask; 2088 struct in_addr ipaddr, netmask, netaddr, broadaddr; 2089 char *lan_ipaddrs[] = { "dhcp_start", "dhcp_end", "dmz_ipaddr" }; 2090#ifdef __CONFIG_NAT__ 2091 netconf_filter_t start, end; 2092 netconf_nat_t nat; 2093 bool valid; 2094#endif /* __CONFIG_NAT__ */ 2095 int i; 2096 2097 /* Basic validation */ 2098 if (!(lan_ipaddr = websGetVar(wp, fields[0].name, NULL)) || 2099 !(lan_netmask = websGetVar(wp, fields[1].name, NULL)) || 2100 !valid_ipaddr(wp, lan_ipaddr, &fields[0]) || 2101 !valid_ipaddr(wp, lan_netmask, &fields[1])) 2102 return; 2103 2104 /* Check for broadcast or network address */ 2105 (void) inet_aton(lan_ipaddr, &ipaddr); 2106 (void) inet_aton(lan_netmask, &netmask); 2107 netaddr.s_addr = ipaddr.s_addr & netmask.s_addr; 2108 broadaddr.s_addr = netaddr.s_addr | ~netmask.s_addr; 2109 if (ipaddr.s_addr == netaddr.s_addr) { 2110 websBufferWrite(wp, "Invalid <b>%s</b> %s: cannot be the network address<br>", 2111 fields[0].longname, lan_ipaddr); 2112 return; 2113 } 2114 if (ipaddr.s_addr == broadaddr.s_addr) { 2115 websBufferWrite(wp, "Invalid <b>%s</b> %s: cannot be the broadcast address<br>", 2116 fields[0].longname, lan_ipaddr); 2117 return; 2118 } 2119 2120 nvram_set("lan_ipaddr", lan_ipaddr); 2121 nvram_set("lan_netmask", lan_netmask); 2122 2123 /* Fix up LAN IP addresses */ 2124 for (i = 0; i < ARRAYSIZE(lan_ipaddrs); i++) { 2125 value = nvram_get(lan_ipaddrs[i]); 2126 if (value && *value) { 2127 (void) inet_aton(value, &ipaddr); 2128 ipaddr.s_addr &= ~netmask.s_addr; 2129 ipaddr.s_addr |= netaddr.s_addr; 2130 nvram_set(lan_ipaddrs[i], inet_ntoa(ipaddr)); 2131 } 2132 } 2133 2134#ifdef __CONFIG_NAT__ 2135 /* Fix up client filters and port forwards */ 2136 for (i = 0; i < MAX_NVPARSE; i++) { 2137 if (get_filter_client(i, &start, &end)) { 2138 start.match.src.ipaddr.s_addr &= ~netmask.s_addr; 2139 start.match.src.ipaddr.s_addr |= netaddr.s_addr; 2140 end.match.src.ipaddr.s_addr &= ~netmask.s_addr; 2141 end.match.src.ipaddr.s_addr |= netaddr.s_addr; 2142 valid = set_filter_client(i, &start, &end); 2143 a_assert(valid); 2144 } 2145 if (get_forward_port(i, &nat)) { 2146 nat.ipaddr.s_addr &= ~netmask.s_addr; 2147 nat.ipaddr.s_addr |= netaddr.s_addr; 2148 valid = set_forward_port(i, &nat); 2149 a_assert(valid); 2150 } 2151 } 2152#endif /* __CONFIG_NAT__ */ 2153} 2154 2155#ifdef __CONFIG_NAT__ 2156static void 2157validate_filter_client(webs_t wp, char *value, struct variable *v) 2158{ 2159 int n, i, j; 2160 bool valid; 2161 struct variable fields[] = { 2162 { name: "filter_client_from_start%d", longname: "LAN Client Filter Starting IP Address", argv: ARGV("lan_ipaddr", "lan_netmask") }, 2163 { name: "filter_client_from_end%d", longname: "LAN Client Filter Ending IP Address", argv: ARGV("lan_ipaddr", "lan_netmask") }, 2164 { name: "filter_client_proto%d", longname: "LAN Client Filter Protocol", argv: ARGV("tcp", "udp") }, 2165 { name: "filter_client_to_start%d", longname: "LAN Client Filter Starting Destination Port", argv: ARGV("0", "65535") }, 2166 { name: "filter_client_to_end%d", longname: "LAN Client Filter Ending Destination Port", argv: ARGV("0", "65535") }, 2167 { name: "filter_client_from_day%d", longname: "LAN Client Filter Starting Day", argv: ARGV("0", "6") }, 2168 { name: "filter_client_to_day%d", longname: "LAN Client Filter Ending Day", argv: ARGV("0", "6") }, 2169 { name: "filter_client_from_sec%d", longname: "LAN Client Filter Starting Second", argv: ARGV("0", "86400") }, 2170 { name: "filter_client_to_sec%d", longname: "LAN Client Filter Ending Second", argv: ARGV("0", "86400") }, 2171 }; 2172 char *from_start, *from_end, *proto, *to_start, *to_end, *from_day, *to_day, *from_sec, *to_sec, *enable; 2173 char **locals[] = { &from_start, &from_end, &proto, &to_start, &to_end, &from_day, &to_day, &from_sec, &to_sec }; 2174 char name[1000]; 2175 netconf_filter_t start, end; 2176 2177 /* filter_client indicates how many to expect */ 2178 if (!valid_range(wp, value, v)) 2179 return; 2180 n = atoi(value); 2181 2182 for (i = 0; i <= n; i++) { 2183 /* Set up field names */ 2184 for (j = 0; j < ARRAYSIZE(fields); j++) { 2185 snprintf(name, sizeof(name), fields[j].name, i); 2186 if (!(*locals[j] = websGetVar(wp, name, NULL))) 2187 break; 2188 } 2189 /* Incomplete web page */ 2190 if (j < ARRAYSIZE(fields)) 2191 continue; 2192 /* Enable is a checkbox */ 2193 snprintf(name, sizeof(name), "filter_client_enable%d", i); 2194 if (websGetVar(wp, name, NULL)) 2195 enable = "on"; 2196 else 2197 enable = "off"; 2198 /* Delete entry if all fields are blank */ 2199 if (!*from_start && !*from_end && !*to_start && !*to_end) { 2200 del_filter_client(i); 2201 continue; 2202 } 2203 /* Fill in empty fields with default values */ 2204 if (!*from_start) from_start = from_end; 2205 if (!*from_end) from_end = from_start; 2206 if (!*to_start) to_start = to_end; 2207 if (!*to_end) to_end = to_start; 2208 if (!*from_start || !*from_end) { 2209 websBufferWrite(wp, "Invalid <b>%s</b>: must specify a LAN IP Address Range<br>", v->longname); 2210 continue; 2211 } 2212 if (!*to_start || !*to_end) { 2213 websBufferWrite(wp, "Invalid <b>%s</b>: must specify a Destination Port Range<br>", v->longname); 2214 continue; 2215 } 2216 /* Check individual fields */ 2217 if (!valid_ipaddr(wp, from_start, &fields[0]) || 2218 !valid_ipaddr(wp, from_end, &fields[1]) || 2219 !valid_choice(wp, proto, &fields[2]) || 2220 !valid_range(wp, to_start, &fields[3]) || 2221 !valid_range(wp, to_end, &fields[4]) || 2222 !valid_range(wp, from_day, &fields[5]) || 2223 !valid_range(wp, to_day, &fields[6]) || 2224 !valid_range(wp, from_sec, &fields[7]) || 2225 !valid_range(wp, to_sec, &fields[8])) 2226 continue; 2227 /* Check dependencies between fields */ 2228 if (ntohl(inet_addr(from_start)) > ntohl(inet_addr(from_end))) { 2229 websBufferWrite(wp, "Invalid <b>%s</b> %s: greater than <b>%s</b> %s<br>", 2230 fields[0].longname, from_start, fields[1].longname, from_end); 2231 continue; 2232 } 2233 if (atoi(to_start) > atoi(to_end)) { 2234 websBufferWrite(wp, "Invalid <b>%s</b> %s: greater than <b>%s</b> %s<br>", 2235 fields[3].longname, to_start, fields[4].longname, to_end); 2236 continue; 2237 } 2238 2239 /* Set up parameters */ 2240 memset(&start, 0, sizeof(netconf_filter_t)); 2241 if (!strcmp(proto, "tcp")) 2242 start.match.ipproto = IPPROTO_TCP; 2243 else if (!strcmp(proto, "udp")) 2244 start.match.ipproto = IPPROTO_UDP; 2245 (void) inet_aton(from_start, &start.match.src.ipaddr); 2246 start.match.src.netmask.s_addr = htonl(0xffffffff); 2247 start.match.dst.ports[0] = htons(atoi(to_start)); 2248 start.match.dst.ports[1] = htons(atoi(to_end)); 2249 start.match.days[0] = atoi(from_day); 2250 start.match.days[1] = atoi(to_day); 2251 start.match.secs[0] = atoi(from_sec); 2252 start.match.secs[1] = atoi(to_sec); 2253 if (!strcmp(enable, "off")) 2254 start.match.flags |= NETCONF_DISABLED; 2255 memcpy(&end, &start, sizeof(netconf_filter_t)); 2256 (void) inet_aton(from_end, &end.match.src.ipaddr); 2257 2258 /* Do it */ 2259 valid = set_filter_client(i, &start, &end); 2260 a_assert(valid); 2261 } 2262} 2263 2264static void 2265validate_forward_port(webs_t wp, char *value, struct variable *v) 2266{ 2267 int n, i, j; 2268 bool valid; 2269 struct variable fields[] = { 2270 { name: "forward_port_proto%d", longname: "Port Forward Protocol", argv: ARGV("tcp", "udp") }, 2271 { name: "forward_port_from_start%d", longname: "Port Forward Starting WAN Port", argv: ARGV("0", "65535") }, 2272 { name: "forward_port_from_end%d", longname: "Port Forward Ending WAN Port", argv: ARGV("0", "65535") }, 2273 { name: "forward_port_to_ip%d", longname: "Port Forward LAN IP Address", argv: ARGV("lan_ipaddr", "lan_netmask") }, 2274 { name: "forward_port_to_start%d", longname: "Port Forward Starting LAN Port", argv: ARGV("0", "65535") }, 2275 { name: "forward_port_to_end%d", longname: "Port Forward Ending LAN Port", argv: ARGV("0", "65535") }, 2276 }; 2277 char *proto, *from_start, *from_end, *to_ip, *to_start, *to_end, *enable; 2278 char **locals[] = { &proto, &from_start, &from_end, &to_ip, &to_start, &to_end }; 2279 char name[1000]; 2280 netconf_nat_t nat; 2281 2282 /* forward_port indicates how many to expect */ 2283 if (!valid_range(wp, value, v)) 2284 return; 2285 n = atoi(value); 2286 2287 for (i = 0; i <= n; i++) { 2288 /* Set up field names */ 2289 for (j = 0; j < ARRAYSIZE(fields); j++) { 2290 snprintf(name, sizeof(name), fields[j].name, i); 2291 if (!(*locals[j] = websGetVar(wp, name, NULL))) 2292 break; 2293 } 2294 /* Incomplete web page */ 2295 if (j < ARRAYSIZE(fields)) 2296 continue; 2297 /* Enable is a checkbox */ 2298 snprintf(name, sizeof(name), "forward_port_enable%d", i); 2299 if (websGetVar(wp, name, NULL)) 2300 enable = "on"; 2301 else 2302 enable = "off"; 2303 /* Delete entry if all fields are blank */ 2304 if (!*from_start && !*from_end && !*to_ip && !*to_start && !*to_end) { 2305 del_forward_port(i); 2306 continue; 2307 } 2308 /* Fill in empty fields with default values */ 2309 if (!*from_start) from_start = from_end; 2310 if (!*from_end) from_end = from_start; 2311 if (!*to_start && !*to_end) 2312 to_start = from_start; 2313 if (!*to_start) to_start = to_end; 2314 if (!*to_end) to_end = to_start; 2315 if (!*from_start || !*from_end) { 2316 websBufferWrite(wp, "Invalid <b>%s</b>: must specify a LAN IP Address Range<br>", v->longname); 2317 continue; 2318 } 2319 if (!*to_ip) { 2320 websBufferWrite(wp, "Invalid <b>%s</b>: must specify a LAN IP Address<br>", v->longname); 2321 continue; 2322 } 2323 if (!*to_start || !*to_end) { 2324 websBufferWrite(wp, "Invalid <b>%s</b>: must specify a Destination Port Range<br>", v->longname); 2325 continue; 2326 } 2327 /* Check individual fields */ 2328 if (!valid_choice(wp, proto, &fields[0]) || 2329 !valid_range(wp, from_start, &fields[1]) || 2330 !valid_range(wp, from_end, &fields[2]) || 2331 !valid_ipaddr(wp, to_ip, &fields[3]) || 2332 !valid_range(wp, to_start, &fields[4]) || 2333 !valid_range(wp, to_end, &fields[5])) 2334 continue; 2335 if (atoi(from_start) > atoi(from_end)) { 2336 websBufferWrite(wp, "Invalid <b>%s</b> %s: greater than <b>%s</b> %s<br>", 2337 fields[1].longname, from_start, fields[2].longname, from_end); 2338 continue; 2339 } 2340 if (atoi(to_start) > atoi(to_end)) { 2341 websBufferWrite(wp, "Invalid <b>%s</b> %s: greater than <b>%s</b> %s<br>", 2342 fields[4].longname, to_start, fields[5].longname, to_end); 2343 continue; 2344 } 2345 if ((atoi(from_end) - atoi(from_start)) != (atoi(to_end) - atoi(to_start))) { 2346 websBufferWrite(wp, "Invalid <b>%s</b>: WAN Port Range and LAN Port Range must be the same size<br>", v->longname); 2347 continue; 2348 } 2349 2350 /* Set up parameters */ 2351 memset(&nat, 0, sizeof(netconf_nat_t)); 2352 if (!strcmp(proto, "tcp")) 2353 nat.match.ipproto = IPPROTO_TCP; 2354 else if (!strcmp(proto, "udp")) 2355 nat.match.ipproto = IPPROTO_UDP; 2356 nat.match.dst.ports[0] = htons(atoi(from_start)); 2357 nat.match.dst.ports[1] = htons(atoi(from_end)); 2358 (void) inet_aton(to_ip, &nat.ipaddr); 2359 nat.ports[0] = htons(atoi(to_start)); 2360 nat.ports[1] = htons(atoi(to_end)); 2361 if (!strcmp(enable, "off")) 2362 nat.match.flags |= NETCONF_DISABLED; 2363 2364 /* Do it */ 2365 valid = set_forward_port(i, &nat); 2366 a_assert(valid); 2367 } 2368} 2369 2370static void 2371validate_autofw_port(webs_t wp, char *value, struct variable *v) 2372{ 2373 int n, i, j; 2374 bool valid; 2375 struct variable fields[] = { 2376 { name: "autofw_port_out_proto%d", longname: "Outbound Protocol", argv: ARGV("tcp", "udp") }, 2377 { name: "autofw_port_out_start%d", longname: "Outbound Port Start", argv: ARGV("0", "65535") }, 2378 { name: "autofw_port_out_end%d", longname: "Outbound Port End", argv: ARGV("0", "65535") }, 2379 { name: "autofw_port_in_proto%d", longname: "Inbound Protocol", argv: ARGV("tcp", "udp") }, 2380 { name: "autofw_port_in_start%d", longname: "Inbound Port Start", argv: ARGV("0", "65535") }, 2381 { name: "autofw_port_in_end%d", longname: "Inbound Port End", argv: ARGV("0", "65535") }, 2382 { name: "autofw_port_to_start%d", longname: "To Port Start", argv: ARGV("0", "65535") }, 2383 { name: "autofw_port_to_end%d", longname: "To Port End", argv: ARGV("0", "65535") }, 2384 }; 2385 char *out_proto, *out_start, *out_end, *in_proto, *in_start, *in_end, *to_start, *to_end, *enable; 2386 char **locals[] = { &out_proto, &out_start, &out_end, &in_proto, &in_start, &in_end, &to_start, &to_end }; 2387 char name[1000]; 2388 netconf_app_t app; 2389 2390 /* autofw_port indicates how many to expect */ 2391 if (!valid_range(wp, value, v)) 2392 return; 2393 n = atoi(value); 2394 2395 for (i = 0; i <= n; i++) { 2396 /* Set up field names */ 2397 for (j = 0; j < ARRAYSIZE(fields); j++) { 2398 snprintf(name, sizeof(name), fields[j].name, i); 2399 if (!(*locals[j] = websGetVar(wp, name, NULL))) 2400 break; 2401 } 2402 /* Incomplete web page */ 2403 if (j < ARRAYSIZE(fields)) 2404 continue; 2405 /* Enable is a checkbox */ 2406 snprintf(name, sizeof(name), "autofw_port_enable%d", i); 2407 if (websGetVar(wp, name, NULL)) 2408 enable = "on"; 2409 else 2410 enable = "off"; 2411 /* Delete entry if all fields are blank */ 2412 if (!*out_start && !*out_end && !*in_start && !*in_end && !*to_start && !*to_end) { 2413 del_autofw_port(i); 2414 continue; 2415 } 2416 /* Fill in empty fields with default values */ 2417 if (!*out_start) out_start = out_end; 2418 if (!*out_end) out_end = out_start; 2419 if (!*in_start) in_start = in_end; 2420 if (!*in_end) in_end = in_start; 2421 if (!*to_start && !*to_end) 2422 to_start = in_start; 2423 if (!*to_start) to_start = to_end; 2424 if (!*to_end) to_end = to_start; 2425 if (!*out_start || !*out_end) { 2426 websBufferWrite(wp, "Invalid <b>%s</b>: must specify an Outbound Port Range<br>", v->longname); 2427 continue; 2428 } 2429 if (!*in_start || !*in_end) { 2430 websBufferWrite(wp, "Invalid <b>%s</b>: must specify an Inbound Port Range<br>", v->longname); 2431 continue; 2432 } 2433 if (!*to_start || !*to_end) { 2434 websBufferWrite(wp, "Invalid <b>%s</b>: must specify a To Port Range<br>", v->longname); 2435 continue; 2436 } 2437 /* Check individual fields */ 2438 if (!valid_choice(wp, out_proto, &fields[0]) || 2439 !valid_range(wp, out_start, &fields[1]) || 2440 !valid_range(wp, out_end, &fields[2]) || 2441 !valid_choice(wp, in_proto, &fields[3]) || 2442 !valid_range(wp, in_start, &fields[4]) || 2443 !valid_range(wp, in_end, &fields[5]) || 2444 !valid_range(wp, to_start, &fields[6]) || 2445 !valid_range(wp, to_end, &fields[7])) 2446 continue; 2447 /* Check dependencies between fields */ 2448 if (atoi(out_start) > atoi(out_end)) { 2449 websBufferWrite(wp, "Invalid <b>%s</b> %s: greater than <b>%s</b> %s<br>", 2450 fields[1].longname, out_start, fields[2].longname, out_end); 2451 continue; 2452 } 2453 if (atoi(in_start) > atoi(in_end)) { 2454 websBufferWrite(wp, "Invalid <b>%s</b> %s: greater than <b>%s</b> %s<br>", 2455 fields[4].longname, in_start, fields[5].longname, in_end); 2456 continue; 2457 } 2458 if (atoi(to_start) > atoi(to_end)) { 2459 websBufferWrite(wp, "Invalid <b>%s</b> %s: greater than <b>%s</b> %s<br>", 2460 fields[6].longname, in_start, fields[7].longname, in_end); 2461 continue; 2462 } 2463 if ((atoi(in_end) - atoi(in_start)) != (atoi(to_end) - atoi(to_start))) { 2464 websBufferWrite(wp, "Invalid <b>%s</b>: Inbound Port Range and To Port Range must be the same size<br>", v->longname); 2465 continue; 2466 } 2467#ifdef NEW_PORT_TRIG 2468 if ((atoi(in_end) - atoi(in_start)) > 100) { 2469 websBufferWrite(wp, "Invalid <b>%s</b>: Inbound Port Range must be less than 100<br>", v->longname); 2470 continue; 2471 } 2472#endif 2473 2474 /* Set up parameters */ 2475 memset(&app, 0, sizeof(netconf_app_t)); 2476 if (!strcmp(out_proto, "tcp")) 2477 app.match.ipproto = IPPROTO_TCP; 2478 else if (!strcmp(out_proto, "udp")) 2479 app.match.ipproto = IPPROTO_UDP; 2480 app.match.dst.ports[0] = htons(atoi(out_start)); 2481 app.match.dst.ports[1] = htons(atoi(out_end)); 2482 if (!strcmp(in_proto, "tcp")) 2483 app.proto = IPPROTO_TCP; 2484 else if (!strcmp(in_proto, "udp")) 2485 app.proto = IPPROTO_UDP; 2486 app.dport[0] = htons(atoi(in_start)); 2487 app.dport[1] = htons(atoi(in_end)); 2488 app.to[0] = htons(atoi(to_start)); 2489 app.to[1] = htons(atoi(to_end)); 2490 if (!strcmp(enable, "off")) 2491 app.match.flags |= NETCONF_DISABLED; 2492 2493 /* Do it */ 2494 valid = set_autofw_port(i, &app); 2495 a_assert(valid); 2496 } 2497} 2498#endif /* __CONFIG_NAT__ */ 2499 2500static void 2501validate_lan_route(webs_t wp, char *value, struct variable *v) 2502{ 2503 int n, i; 2504 char buf[1000] = "", *cur = buf; 2505 struct variable lan_route_variables[] = { 2506 { longname: "Route IP Address", argv: NULL }, 2507 { longname: "Route Subnet Mask", argv: NULL }, 2508 { longname: "Route Gateway", argv: NULL }, 2509 { longname: "Route Metric", argv: ARGV("0", "15") }, 2510 }; 2511 2512 n = atoi(value); 2513 2514 for (i = 0; i < n; i++) { 2515 char lan_route_ipaddr[] = "lan_route_ipaddrXXX"; 2516 char lan_route_netmask[] = "lan_route_netmaskXXX"; 2517 char lan_route_gateway[] = "lan_route_gatewayXXX"; 2518 char lan_route_metric[] = "lan_route_metricXXX"; 2519 char *ipaddr, *netmask, *gateway, *metric; 2520 2521 snprintf(lan_route_ipaddr, sizeof(lan_route_ipaddr), "%s_ipaddr%d", v->name, i); 2522 snprintf(lan_route_netmask, sizeof(lan_route_netmask), "%s_netmask%d", v->name, i); 2523 snprintf(lan_route_gateway, sizeof(lan_route_gateway), "%s_gateway%d", v->name, i); 2524 snprintf(lan_route_metric, sizeof(lan_route_metric), "%s_metric%d", v->name, i); 2525 if (!(ipaddr = websGetVar(wp, lan_route_ipaddr, NULL)) || 2526 !(netmask = websGetVar(wp, lan_route_netmask, NULL)) || 2527 !(gateway = websGetVar(wp, lan_route_gateway, NULL)) || 2528 !(metric = websGetVar(wp, lan_route_metric, NULL))) 2529 return; 2530 if (!*ipaddr && !*netmask && !*gateway && !*metric) 2531 continue; 2532 if (!*ipaddr && !*netmask && *gateway) { 2533 ipaddr = "0.0.0.0"; 2534 netmask = "0.0.0.0"; 2535 } 2536 if (!*gateway) 2537 gateway = "0.0.0.0"; 2538 if (!*metric) 2539 metric = "0"; 2540 if (!*ipaddr) { 2541 websBufferWrite(wp, "Invalid <b>%s</b>: must specify an IP Address<br>", v->longname); 2542 continue; 2543 } 2544 if (!*netmask) { 2545 websBufferWrite(wp, "Invalid <b>%s</b>: must specify a Subnet Mask<br>", v->longname); 2546 continue; 2547 } 2548 lan_route_variables[2].argv = ARGV("lan_ipaddr", "lan_netmask"); 2549 if (!valid_ipaddr(wp, ipaddr, &lan_route_variables[0]) || 2550 !valid_ipaddr(wp, netmask, &lan_route_variables[1]) || 2551 !valid_ipaddr(wp, gateway, &lan_route_variables[2]) || 2552 !valid_range(wp, metric, &lan_route_variables[3])) 2553 continue; 2554 cur += snprintf(cur, buf + sizeof(buf) - cur, "%s%s:%s:%s:%s", 2555 cur == buf ? "" : " ", ipaddr, netmask, gateway, metric); 2556 } 2557 2558 nvram_set(v->name, buf); 2559} 2560 2561#ifdef __CONFIG_NAT__ 2562static void 2563validate_wan_route(webs_t wp, char *value, struct variable *v) 2564{ 2565 int n, i; 2566 char buf[1000] = "", *cur = buf; 2567 struct variable wan_route_variables[] = { 2568 { longname: "Route IP Address", argv: NULL }, 2569 { longname: "Route Subnet Mask", argv: NULL }, 2570 { longname: "Route Gateway", argv: NULL }, 2571 { longname: "Route Metric", argv: ARGV("0", "15") }, 2572 }; 2573 2574 n = atoi(value); 2575 2576 for (i = 0; i < n; i++) { 2577 char wan_route_ipaddr[] = "wan_route_ipaddrXXX"; 2578 char wan_route_netmask[] = "wan_route_netmaskXXX"; 2579 char wan_route_gateway[] = "wan_route_gatewayXXX"; 2580 char wan_route_metric[] = "wan_route_metricXXX"; 2581 char *ipaddr, *netmask, *gateway, *metric; 2582 2583 snprintf(wan_route_ipaddr, sizeof(wan_route_ipaddr), "%s_ipaddr%d", v->name, i); 2584 snprintf(wan_route_netmask, sizeof(wan_route_netmask), "%s_netmask%d", v->name, i); 2585 snprintf(wan_route_gateway, sizeof(wan_route_gateway), "%s_gateway%d", v->name, i); 2586 snprintf(wan_route_metric, sizeof(wan_route_metric), "%s_metric%d", v->name, i); 2587 if (!(ipaddr = websGetVar(wp, wan_route_ipaddr, NULL)) || 2588 !(netmask = websGetVar(wp, wan_route_netmask, NULL)) || 2589 !(gateway = websGetVar(wp, wan_route_gateway, NULL)) || 2590 !(metric = websGetVar(wp, wan_route_metric, NULL))) 2591 continue; 2592 if (!*ipaddr && !*netmask && !*gateway && !*metric) 2593 continue; 2594 if (!*ipaddr && !*netmask && *gateway) { 2595 ipaddr = "0.0.0.0"; 2596 netmask = "0.0.0.0"; 2597 } 2598 if (!*gateway) 2599 gateway = "0.0.0.0"; 2600 if (!*metric) 2601 metric = "0"; 2602 if (!*ipaddr) { 2603 websBufferWrite(wp, "Invalid <b>%s</b>: must specify an IP Address<br>", v->longname); 2604 continue; 2605 } 2606 if (!*netmask) { 2607 websBufferWrite(wp, "Invalid <b>%s</b>: must specify a Subnet Mask<br>", v->longname); 2608 continue; 2609 } 2610 if (!valid_ipaddr(wp, ipaddr, &wan_route_variables[0]) || 2611 !valid_ipaddr(wp, netmask, &wan_route_variables[1]) || 2612 !valid_ipaddr(wp, gateway, &wan_route_variables[2]) || 2613 !valid_range(wp, metric, &wan_route_variables[3])) 2614 continue; 2615 cur += snprintf(cur, buf + sizeof(buf) - cur, "%s%s:%s:%s:%s", 2616 cur == buf ? "" : " ", ipaddr, netmask, gateway, metric); 2617 } 2618 2619 nvram_set(v->name, buf); 2620} 2621#endif /* __CONFIG_NAT__ */ 2622 2623static void 2624validate_wl_auth(webs_t wp, char *value, struct variable *v) 2625{ 2626 if (!valid_choice(wp, value, v)) 2627 return; 2628 2629 if (!strcmp(value, "1")) { 2630 char *wep = websGetVar(wp, "wl_wep", ""); 2631 if (!wep || strcmp(wep, "enabled")) { 2632 websBufferWrite(wp, "Invalid <b>WEP Encryption</b>: must be <b>Enabled</b> when <b>802.11 Authentication</b> is <b>%s</b><br>", value); 2633 return; 2634 } 2635 } 2636 2637 nvram_set(v->name, value); 2638} 2639 2640static void 2641validate_wl_preauth(webs_t wp, char *value, struct variable *v) 2642{ 2643 if (!strcmp(value, "disabled")) 2644 nvram_set(v->name, "0"); 2645 else 2646 nvram_set(v->name, "1"); 2647 return; 2648} 2649 2650static void 2651validate_wl_auth_mode(webs_t wp, char *value, struct variable *v) 2652{ 2653 if (!valid_choice(wp, value, v)) 2654 return; 2655 2656 if (!strcmp(value, "radius")) { 2657 char *wep = websGetVar(wp, "wl_wep", ""); 2658 char *ipaddr = websGetVar(wp, "wl_radius_ipaddr", ""); 2659 if (!wep || strcmp(wep, "enabled")) { 2660 websBufferWrite(wp, "Invalid <b>WEP Encryption</b>: must be <b>Enabled</b> when <b>Network Authentication</b> is <b>%s</b><br>", value); 2661 return; 2662 } 2663 if (!ipaddr || !strcmp(ipaddr, "")) { 2664 websBufferWrite(wp, "Invalid <b>%s</b>: must first specify a valid <b>RADIUS Server</b><br>", v->longname); 2665 return; 2666 } 2667 } 2668 2669 nvram_set(v->name, value); 2670} 2671 2672static void 2673validate_wl_akm(webs_t wp, char *value, struct variable *v) 2674{ 2675 char akms[WLC_IOCTL_SMLEN] = ""; 2676 char *wpa, *psk; 2677 char *wpa2, *psk2; 2678 2679 wpa = websGetVar(wp, "wl_akm_wpa", NULL); 2680 psk = websGetVar(wp, "wl_akm_psk", NULL); 2681 wpa2 = websGetVar(wp, "wl_akm_wpa2", NULL); 2682 psk2 = websGetVar(wp, "wl_akm_psk2", NULL); 2683 if (!wpa || !psk 2684 || !wpa2 || !psk2 2685 ) { 2686 return; 2687 } 2688 2689 if (!strcmp(wpa, "enabled") 2690 || !strcmp(wpa2, "enabled") 2691 ) { 2692 char *ipaddr = websGetVar(wp, "wl_radius_ipaddr", ""); 2693 if (!ipaddr || !strcmp(ipaddr, "")) { 2694 websBufferWrite(wp, "Invalid <b>%s</b>: must first specify a valid <b>RADIUS Server</b><br>", v->longname); 2695 return; 2696 } 2697 } 2698 2699 if (!strcmp(psk, "enabled") 2700 || !strcmp(psk2, "enabled") 2701 ) { 2702 char *key = websGetVar(wp, "wl_wpa_psk", ""); 2703 if (!key || !strcmp(key, "")) { 2704 websBufferWrite(wp, "Invalid <b>%s</b>: must first specify a valid <b>WPA Pre-Shared Key</b><br>", v->longname); 2705 return; 2706 } 2707 } 2708 2709 if (!strcmp(wpa, "enabled") || !strcmp(psk, "enabled") 2710 || !strcmp(wpa2, "enabled") || !strcmp(psk2, "enabled") 2711 ) { 2712 char *crypto = websGetVar(wp, "wl_crypto", ""); 2713 if (!crypto || (strcmp(crypto, "tkip") && strcmp(crypto, "aes") && 2714 strcmp(crypto, "tkip+aes"))) { 2715 websBufferWrite(wp, "Invalid <b>%s</b>: <b>Crypto Algorithm</b> mode must be TKIP or AES or TKIP+AES<br>", v->longname); 2716 return; 2717 } 2718 } 2719 2720 if (!strcmp(wpa, "enabled")) 2721 strcat(akms, "wpa "); 2722 if (!strcmp(psk, "enabled")) 2723 strcat(akms, "psk "); 2724 if (!strcmp(wpa2, "enabled")) 2725 strcat(akms, "wpa2 "); 2726 if (!strcmp(psk2, "enabled")) 2727 strcat(akms, "psk2 "); 2728 2729 nvram_set("wl_akm", akms); 2730} 2731 2732static void 2733validate_wl_wpa_psk(webs_t wp, char *value, struct variable *v) 2734{ 2735 int len = strlen(value); 2736 char *c; 2737 2738 if (len == 64) { 2739 for (c = value; *c; c++) { 2740 if (!isxdigit((int) *c)) { 2741 websBufferWrite(wp, "Invalid <b>%s</b>: character %c is not a hexadecimal digit<br>", v->longname, *c); 2742 return; 2743 } 2744 } 2745 } else if (len < 8 || len > 63) { 2746 websBufferWrite(wp, "Invalid <b>%s</b>: must be between 8 and 63 ASCII characters or 64 hexadecimal digits<br>", v->longname); 2747 return; 2748 } 2749 2750 nvram_set(v->name, value); 2751} 2752 2753static void 2754validate_wl_key(webs_t wp, char *value, struct variable *v) 2755{ 2756 char *c; 2757 2758 switch (strlen(value)) { 2759 case 5: 2760 case 13: 2761 break; 2762 case 10: 2763 case 26: 2764 for (c = value; *c; c++) { 2765 if (!isxdigit((int) *c)) { 2766 websBufferWrite(wp, "Invalid <b>%s</b>: character %c is not a hexadecimal digit<br>", v->longname, *c); 2767 return; 2768 } 2769 } 2770 break; 2771 default: 2772 websBufferWrite(wp, "Invalid <b>%s</b>: must be 5 or 13 ASCII characters or 10 or 26 hexadecimal digits<br>", v->longname); 2773 return; 2774 } 2775 2776 nvram_set(v->name, value); 2777} 2778 2779static void 2780validate_wl_wep(webs_t wp, char *value, struct variable *v) 2781{ 2782 char *auth_mode, *auth; 2783 2784 if (!valid_choice(wp, value, v)) 2785 return; 2786 2787 auth = websGetVar(wp, "wl_auth", NULL); 2788 auth_mode = websGetVar(wp, "wl_auth_mode", NULL); 2789 if (!strcmp(value, "enabled")) { 2790 if (!auth_mode || strcmp(auth_mode, "radius")) { 2791 char wl_key[] = "wl_keyXXX"; 2792 2793 snprintf(wl_key, sizeof(wl_key), "wl_key%s", nvram_safe_get("wl_key")); 2794 if (!strlen(nvram_safe_get(wl_key))) { 2795 websBufferWrite(wp, "Invalid <b>%s</b>: must first specify a valid <b>Network Key %s</b><br>", v->longname, nvram_safe_get("wl_key")); 2796 if (nvram_match(v->name, "enabled")) { 2797 websBufferWrite(wp, "<b>%s</b> is <b>Disabled</b><br>", v->longname); 2798 nvram_set(v->name, "disabled"); 2799 } 2800 return; 2801 } 2802 } 2803 } 2804 else { 2805 if (!auth || !strcmp(auth, "shared") || !auth_mode || !strcmp(auth_mode, "radius")) { 2806 websBufferWrite(wp, "Invalid <b>WEP Encryption</b>: must be <b>Enabled</b> when <b>Network Authentication</b> is <b>%s</b><br>", auth_mode); 2807 return; 2808 } 2809 } 2810 nvram_set(v->name, value); 2811} 2812 2813static void 2814validate_wl_crypto(webs_t wp, char *value, struct variable *v) 2815{ 2816 if (!valid_choice(wp, value, v)) 2817 return; 2818 2819 nvram_set(v->name, value); 2820} 2821 2822#ifdef __CONFIG_NAT__ 2823static void 2824validate_wan_ifname(webs_t wp, char *value, struct variable *v) 2825{ 2826 char ifname[64], *next; 2827 foreach (ifname, nvram_safe_get("wan_ifnames"), next) 2828 if (!strcmp(ifname, value)) { 2829 nvram_set(v->name, value); 2830 return; 2831 } 2832 websBufferWrite(wp, "Invalid <b>%s</b>: must be one of <b>%s</b><br>", v->longname, nvram_safe_get("wan_ifnames")); 2833} 2834#endif /* __CONFIG_NAT__ */ 2835 2836static void 2837validate_wl_afterburner(webs_t wp, char *value, struct variable *v) 2838{ 2839 if (!valid_choice(wp, value, v)) 2840 return; 2841 2842 /* force certain wireless variables to fixed values */ 2843 if (!strcmp(value, "auto")) { 2844 if ( 2845 nvram_invmatch("wl_mode", "ap") || 2846 nvram_invmatch("wl_lazywds", "0") || 2847 nvram_invmatch("wl_wds", "")) { 2848 /* notify the user */ 2849 websBufferWrite(wp, "Invalid <b>%s</b>: AfterBurner mode requires:" 2850 "<br><b>Mode</b> set to <b>Access Point</b>" 2851 "<br><b>Bridge Restrict</b> set to <b>Enabled</b>" 2852 "<br><b>Remote Bridges</b> set to <b>empty</b>" 2853 "<br><b>Fragmentation value</b> set to <b>2346(disable fragmentation)</b>" 2854 "<br><b>AfterBurner mode is disabled!</b>" 2855 "<br>", v->longname); 2856 return; 2857 } 2858 } 2859 2860 nvram_set(v->name, value); 2861} 2862 2863static void 2864validate_wl_lazywds(webs_t wp, char *value, struct variable *v) 2865{ 2866 char *afterburner; 2867 if (strcmp(value, "0") && 2868 (afterburner = websGetVar(wp, "wl_afterburner", NULL)) && (!strcmp(afterburner, "auto"))) { 2869 websBufferWrite(wp, "Invalid <b>%s</b>: must be set to <b>Enabled</b> when AfterBurner is enabled.<br>", v->longname); 2870 return; 2871 } 2872 validate_choice(wp, value, v); 2873} 2874 2875static void 2876validate_wl_wds_hwaddrs(webs_t wp, char *value, struct variable *v) 2877{ 2878 char *afterburner; 2879 if ((afterburner = websGetVar(wp, "wl_afterburner", NULL)) && (!strcmp(afterburner, "auto"))) { 2880 int n, i; 2881 char name[100], *mac; 2882 2883 n = atoi(value); 2884 2885 for (i = 0; i < n; i++) { 2886 snprintf(name, sizeof(name), "%s%d", v->name, i); 2887 if (!(mac = websGetVar(wp, name, NULL)) || strlen(mac) == 0) 2888 continue; 2889 websBufferWrite(wp, "Invalid <b>%s</b>: must be empty when AfterBurner is enabled.<br>", v->longname); 2890 return; 2891 } 2892 } 2893 validate_list(wp, value, v, valid_hwaddr); 2894} 2895 2896static void 2897validate_wl_mode(webs_t wp, char *value, struct variable *v) 2898{ 2899 char *afterburner; 2900 if (strcmp(value, "ap") && 2901 (afterburner = websGetVar(wp, "wl_afterburner", NULL)) && (!strcmp(afterburner, "auto"))) { 2902 websBufferWrite(wp, "Invalid <b>%s</b>: must be set to <b>Access Point</b> when AfterBurner is enabled.<br>", v->longname); 2903 return; 2904 } 2905 validate_choice(wp, value, v); 2906} 2907 2908static void 2909validate_noack(webs_t wp, char *value, struct variable *v) 2910{ 2911 char *wme; 2912 2913 /* return if wme is not enabled */ 2914 if (!(wme = websGetVar(wp, "wl_wme", NULL))) 2915 return; 2916 else if (strcmp(wme, "on")) 2917 return; 2918 2919 validate_choice(wp, value, v); 2920} 2921 2922static void 2923validate_wl_wme_params(webs_t wp, char *value, struct variable *v) 2924{ 2925 int n, i; 2926 int cwmin = 0, cwmax = 0; 2927 char *wme, *afterburner; 2928 char name[100]; 2929 char buf[1000] = "", *cur = buf; 2930 struct { 2931 char *name; 2932 int range; 2933 char *arg1; 2934 char *arg2; 2935 } field_attrib[] = { 2936 { "WME AC CWmin", 1, "0", "32767" }, 2937 { "WME AC CWmax", 1, "0", "32767" }, 2938 { "WME AC AIFSN", 1, "1", "15" }, 2939 { "WME AC TXOP(b)", 1, "0", "65504" }, 2940 { "WME AC TXOP(a/g)", 1, "0", "65504" }, 2941 { "WME AC Admin Forced", 0, "on", "off" } 2942 }; 2943 2944 /* return if wme is not enabled */ 2945 if (!(wme = websGetVar(wp, "wl_wme", NULL))) 2946 return; 2947 else if (strcmp(wme, "on")) 2948 return; 2949 2950 /* return if afterburner enabled */ 2951 if ((afterburner = websGetVar(wp, "wl_afterburner", NULL)) && (!strcmp(afterburner, "auto"))) 2952 return; 2953 2954 n = atoi(value) + 1; 2955 2956 for (i = 0; i < n; i++) { 2957 snprintf(name, sizeof(name), "%s%d", v->name, i); 2958 if (!(value = websGetVar(wp, name, NULL))) 2959 return; 2960 if (!*value && v->nullok) 2961 continue; 2962 2963 if (i == 0) 2964 cwmin = atoi(value); 2965 else if (i == 1) { 2966 cwmax = atoi(value); 2967 if (cwmax < cwmin) { 2968 websBufferWrite(wp, "Invalid <b>%s</b> %d: greater than <b>%s</b> %d<br>", 2969 field_attrib[0].name, cwmin, field_attrib[i].name, cwmax); 2970 return; 2971 } 2972 } 2973 if (field_attrib[i].range) { 2974 if (atoi(value) < atoi(field_attrib[i].arg1) || atoi(value) > atoi(field_attrib[i].arg2)) { 2975 websBufferWrite(wp, "Invalid <b>%s</b> %d: should be in range %s to %s<br>", 2976 field_attrib[i].name, atoi(value), field_attrib[i].arg1, field_attrib[i].arg2); 2977 return; 2978 } 2979 } else { 2980 if (strcmp(value, field_attrib[i].arg1) && strcmp(value, field_attrib[i].arg2)) { 2981 websBufferWrite(wp, "Invalid <b>%s</b> %s: should be %s or %s<br>", 2982 field_attrib[i].name, value, field_attrib[i].arg1, field_attrib[i].arg2); 2983 } 2984 } 2985 2986 cur += snprintf(cur, buf + sizeof(buf) - cur, "%s%s", 2987 cur == buf ? "" : " ", value); 2988 } 2989 2990 nvram_set(v->name, buf); 2991} 2992 2993/* Hook to write wl_* default set through to wl%d_* variable set */ 2994static void 2995wl_unit(webs_t wp, char *value, struct variable *v) 2996{ 2997 char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_"; 2998 2999 /* Do not write through if no interfaces are present */ 3000 if (atoi(value) < 0) 3001 return; 3002 3003 /* Set prefix */ 3004 snprintf(prefix, sizeof(prefix), "wl%d_", atoi(value)); 3005 3006 /* Write through to selected variable set */ 3007 for (; v >= variables && !strncmp(v->name, "wl_", 3); v--) 3008 nvram_set(strcat_r(prefix, &v->name[3], tmp), nvram_safe_get(v->name)); 3009} 3010 3011#ifdef __CONFIG_NAT__ 3012static void 3013wan_primary(webs_t wp) 3014{ 3015 char tmp[NVRAM_BUFSIZE], prefix[] = "wanXXXXXXXXXX_"; 3016 int i; 3017 for (i = 0; i < MAX_NVPARSE; i ++) { 3018 /* skip non-exist and disabled connection */ 3019 wan_prefix(i, prefix); 3020 if (!nvram_get(strcat_r(prefix, "unit", tmp))|| 3021 nvram_match(strcat_r(prefix, "proto", tmp), "disabled")) 3022 continue; 3023 /* make connection <i> primary */ 3024 nvram_set(strcat_r(prefix, "primary", tmp), "1"); 3025 /* notify the user */ 3026 websBufferWrite(wp, "<br><b>%s</b> is set to primary.", 3027 wan_name(i, prefix, tmp, sizeof(tmp))); 3028 break; 3029 } 3030} 3031 3032/* Hook to write wan_* default set through to wan%d_* variable set */ 3033static void 3034wan_unit(webs_t wp, char *value, struct variable *v) 3035{ 3036 char tmp[NVRAM_BUFSIZE], prefix[] = "wanXXXXXXXXXX_"; 3037 char pppx[] = "pppXXXXXXXXXXX"; 3038 int unit, i; 3039 char *wan_ifname; 3040 int wan_disabled = 0; 3041 int wan_prim = 0; 3042 int wan_wildcard = 0; 3043 char *wan_pppoe_service; 3044 char *wan_pppoe_ac; 3045 char wan_tmp[NVRAM_BUFSIZE]; 3046 int wildcard; 3047 char *pppoe_service; 3048 char *pppoe_ac; 3049 char ea[ETHER_ADDR_LEN], wan_ea[ETHER_ADDR_LEN]; 3050 3051 /* Do not write through if no connections are present */ 3052 if ((unit = atoi(value)) < 0) 3053 return; 3054 3055 /* override wan_pppoe_ifname */ 3056 if (nvram_match("wan_proto", "pppoe")) { 3057 snprintf(pppx, sizeof(pppx), "ppp%d", unit); 3058 nvram_set("wan_pppoe_ifname", pppx); 3059 } 3060 3061 /* 3062 * Need to make sure this connection can co-exist with others. 3063 * Disable others if it can't (assuming this is the wanted one). 3064 * Disabled connection is for sure no problem to co-exist with 3065 * other connections. 3066 */ 3067 if (nvram_match("wan_proto", "disabled")) { 3068 /* Non primary always go with disabled connection. */ 3069 nvram_set("wan_primary", "0"); 3070 wan_disabled = 1; 3071 } 3072 /* 3073 * PPPoE connection is for sure no problem to co-exist with 3074 * other PPPoE connections even when they share the same 3075 * ethernet interface, but we need to make sure certain 3076 * PPPoE parameters are reasonablely different from eatch other 3077 * if they share the same ethernet interface. 3078 */ 3079 else if (nvram_match("wan_proto", "pppoe")) { 3080 /* must disable others if this connection is wildcard (any service any ac) */ 3081 wan_pppoe_service = nvram_get("wan_pppoe_service"); 3082 wan_pppoe_ac = nvram_get("wan_pppoe_ac"); 3083 wan_wildcard = (wan_pppoe_service == NULL || *wan_pppoe_service == 0) && 3084 (wan_pppoe_ac == NULL || *wan_pppoe_ac == 0); 3085 wan_ifname = nvram_safe_get("wan_ifname"); 3086 wan_name(unit, "wan_", wan_tmp, sizeof(wan_tmp)); 3087 /* check all PPPoE connections that share the same interface */ 3088 for (i = 0; i < MAX_NVPARSE; i ++) { 3089 /* skip the current connection */ 3090 if (i == unit) 3091 continue; 3092 /* skip non-exist and connection that does not share the same i/f */ 3093 wan_prefix(i, prefix); 3094 if (!nvram_get(strcat_r(prefix, "unit", tmp)) || 3095 nvram_match(strcat_r(prefix, "proto", tmp), "disabled") || 3096 nvram_invmatch(strcat_r(prefix, "ifname", tmp), wan_ifname)) 3097 continue; 3098 /* PPPoE can share the same i/f, but none can be wildcard */ 3099 if (nvram_match(strcat_r(prefix, "proto", tmp), "pppoe")) { 3100 if (wan_wildcard) { 3101 /* disable connection <i> */ 3102 nvram_set(strcat_r(prefix, "proto", tmp), "disabled"); 3103 nvram_set(strcat_r(prefix, "primary", tmp), "0"); 3104 /* notify the user */ 3105 websBufferWrite(wp, "<br><b>%s</b> is <b>disabled</b> because both " 3106 "<b>PPPoE Service Name</b> and <b>PPPoE Access Concentrator</b> " 3107 "in <b>%s</b> are empty.", 3108 wan_name(i, prefix, tmp, sizeof(tmp)), wan_tmp); 3109 } 3110 else { 3111 pppoe_service = nvram_get(strcat_r(prefix, "pppoe_service", tmp)); 3112 pppoe_ac = nvram_get(strcat_r(prefix, "pppoe_ac", tmp)); 3113 wildcard = (pppoe_service == NULL || *pppoe_service == 0) && 3114 (pppoe_ac == NULL || *pppoe_ac == 0); 3115 /* allow connection <i> if certain pppoe parameters are not all same */ 3116 if (!wildcard && 3117 (nvram_invmatch(strcat_r(prefix, "pppoe_service", tmp), nvram_safe_get("wan_pppoe_service")) || 3118 nvram_invmatch(strcat_r(prefix, "pppoe_ac", tmp), nvram_safe_get("wan_pppoe_ac")))) 3119 continue; 3120 /* disable connection <i> */ 3121 nvram_set(strcat_r(prefix, "proto", tmp), "disabled"); 3122 nvram_set(strcat_r(prefix, "primary", tmp), "0"); 3123 /* notify the user */ 3124 websBufferWrite(wp, "<br><b>%s</b> is <b>disabled</b> because both its " 3125 "<b>PPPoE Service Name</b> and <b>PPPoE Access Concentrator</b> " 3126 "are empty.", 3127 wan_name(i, prefix, tmp, sizeof(tmp))); 3128 } 3129 } 3130 /* other types can't (?) share the same i/f with PPPoE */ 3131 else { 3132 /* disable connection <i> */ 3133 nvram_set(strcat_r(prefix, "proto", tmp), "disabled"); 3134 nvram_set(strcat_r(prefix, "primary", tmp), "0"); 3135 /* notify the user */ 3136 websBufferWrite(wp, "<br><b>%s</b> is <b>disabled</b> because it can't " 3137 "share the same interface with <b>%s</b>.", 3138 wan_name(i, prefix, tmp, sizeof(tmp)), wan_tmp); 3139 } 3140 } 3141 } 3142 /* 3143 * All other types (now DHCP, Static) can't co-exist with 3144 * other connections if they use the same ethernet i/f. 3145 */ 3146 else { 3147 wan_ifname = nvram_safe_get("wan_ifname"); 3148 wan_name(unit, "wan_", wan_tmp, sizeof(wan_tmp)); 3149 /* check all connections that share the same interface */ 3150 for (i = 0; i < MAX_NVPARSE; i ++) { 3151 /* skip the current connection */ 3152 if (i == unit) 3153 continue; 3154 /* check if connection <i> exists and share the same i/f*/ 3155 wan_prefix(i, prefix); 3156 if (!nvram_get(strcat_r(prefix, "unit", tmp)) || 3157 nvram_match(strcat_r(prefix, "proto", tmp), "disabled") || 3158 nvram_invmatch(strcat_r(prefix, "ifname", tmp), wan_ifname)) 3159 continue; 3160 /* disable connection <i> */ 3161 nvram_set(strcat_r(prefix, "proto", tmp), "disabled"); 3162 nvram_set(strcat_r(prefix, "primary", tmp), "0"); 3163 /* notify the user */ 3164 websBufferWrite(wp, "<br><b>%s</b> is disabled because it can't share " 3165 "the ethernet interface with <b>%s</b>.", 3166 wan_name(i, prefix, tmp, sizeof(tmp)), wan_tmp); 3167 } 3168 } 3169 3170 /* 3171 * Check if MAC address has been changed. Need to sync it to all connections 3172 * that share the same i/f if it is changed. 3173 */ 3174 wan_prefix(unit, prefix); 3175 ether_atoe(nvram_safe_get("wan_hwaddr"), wan_ea); 3176 ether_atoe(nvram_safe_get(strcat_r(prefix, "hwaddr", tmp)), ea); 3177 if (memcmp(ea, wan_ea, ETHER_ADDR_LEN)) { 3178 wan_ifname = nvram_safe_get("wan_ifname"); 3179 wan_name(unit, "wan_", wan_tmp, sizeof(wan_tmp)); 3180 /* sync all connections that share the same interface */ 3181 for (i = 0; i < MAX_NVPARSE; i ++) { 3182 /* skip the current connection */ 3183 if (i == unit) 3184 continue; 3185 /* check if connection <i> exists and share the same i/f*/ 3186 wan_prefix(i, prefix); 3187 if (!nvram_get(strcat_r(prefix, "unit", tmp)) || 3188 nvram_invmatch(strcat_r(prefix, "ifname", tmp), wan_ifname)) 3189 continue; 3190 /* check if connection <i>'s hardware address is different */ 3191 if (ether_atoe(nvram_safe_get(strcat_r(prefix, "hwaddr", tmp)), ea) && 3192 !memcmp(ea, wan_ea, ETHER_ADDR_LEN)) 3193 continue; 3194 /* change connection <i>'s hardware address */ 3195 nvram_set(strcat_r(prefix, "hwaddr", tmp), nvram_safe_get("wan_hwaddr")); 3196 /* notify the user */ 3197 websBufferWrite(wp, "<br><b>MAC Address</b> in <b>%s</b> is changed to " 3198 "<b>%s</b> because it shares the ethernet interface with <b>%s</b>.", 3199 wan_name(i, prefix, tmp, sizeof(tmp)), nvram_safe_get("wan_hwaddr"), 3200 wan_tmp); 3201 } 3202 } 3203 3204 /* Set prefix */ 3205 wan_prefix(unit, prefix); 3206 3207 /* Write through to selected variable set */ 3208 for (; v >= variables && !strncmp(v->name, "wan_", 4); v--) 3209 nvram_set(strcat_r(prefix, &v->name[4], tmp), nvram_safe_get(v->name)); 3210 3211 /* 3212 * There must be one and only one primary connection among all 3213 * enabled connections so that traffic can be routed by default 3214 * through the primary connection unless they are targetted to 3215 * a specific connection by means of static routes. (Primary ~= 3216 * Default Gateway). 3217 */ 3218 /* the current connection is primary, set others to non-primary */ 3219 if (!wan_disabled && nvram_match(strcat_r(prefix, "primary", tmp), "1")) { 3220 /* set other connections to non-primary */ 3221 for (i = 0; i < MAX_NVPARSE; i ++) { 3222 /* skip the current connection */ 3223 if (i == unit) 3224 continue; 3225 /* skip non-exist and disabled connection */ 3226 wan_prefix(i, prefix); 3227 if (!nvram_get(strcat_r(prefix, "unit", tmp)) || 3228 nvram_match(strcat_r(prefix, "proto", tmp), "disabled")) 3229 continue; 3230 /* skip non-primary connection */ 3231 if (nvram_invmatch(strcat_r(prefix, "primary", tmp), "1")) 3232 continue; 3233 /* force primary to non-primary */ 3234 nvram_set(strcat_r(prefix, "primary", tmp), "0"); 3235 /* notify the user */ 3236 websBufferWrite(wp, "<br><b>%s</b> is set to non-primary.", 3237 wan_name(i, prefix, tmp, sizeof(tmp))); 3238 } 3239 wan_prim = 1; 3240 } 3241 /* the current connection is not parimary, check if there is any primary */ 3242 else { 3243 /* check other connections to see if there is any primary */ 3244 for (i = 0; i < MAX_NVPARSE; i ++) { 3245 /* skip the current connection */ 3246 if (i == unit) 3247 continue; 3248 /* primary connection exists, honor it */ 3249 wan_prefix(i, prefix); 3250 if (nvram_match(strcat_r(prefix, "primary", tmp), "1")) { 3251 wan_prim = 1; 3252 break; 3253 } 3254 } 3255 } 3256 /* no one is primary, pick the first enabled one as primary */ 3257 if (!wan_prim) 3258 wan_primary(wp); 3259} 3260#endif /* __CONFIG_NAT__ */ 3261 3262/* 3263 * Variables are set in order (put dependent variables later). Set 3264 * nullok to TRUE to ignore zero-length values of the variable itself. 3265 * For more complicated validation that cannot be done in one pass or 3266 * depends on additional form components or can throw an error in a 3267 * unique painful way, write your own validation routine and assign it 3268 * to a hidden variable (e.g. filter_ip). 3269 * 3270 * EZC_FLAGS_READ : implies the variable will be returned for ezconfig read request 3271 * EZC_FLAGS_WRITE : allows the variable to be modified by the ezconfig tool 3272 * 3273 * The variables marked with EZConfig have to maintain backward compatibility. 3274 * If they cannot then the ezc_version has to be bumped up 3275 * 3276 */ 3277struct variable variables[] = { 3278 /* basic settings */ 3279 { "http_username", "Router Username", validate_name, ARGV("0", "63"), TRUE, EZC_FLAGS_READ | EZC_FLAGS_WRITE }, 3280 { "http_passwd", "Router Password", validate_name, ARGV("0", "63"), TRUE, EZC_FLAGS_WRITE }, 3281 { "http_wanport", "Router WAN Port", validate_range, ARGV("0", "65535"), TRUE, 0 }, 3282 { "router_disable", "Router Mode", validate_choice, ARGV("0", "1"), FALSE, 0 }, 3283 { "fw_disable", "Firewall", validate_choice, ARGV("0", "1"), FALSE, EZC_FLAGS_READ | EZC_FLAGS_WRITE }, 3284 { "time_zone", "Time Zone", validate_choice, ARGV("PST8PDT", "MST7MDT", "CST6CDT", "EST5EDT"), FALSE }, 3285 { "upnp_enable", "UPnP", validate_choice, ARGV("0", "1"), FALSE, 0 }, 3286 { "ezc_enable", "EZConfig", validate_choice, ARGV("0", "1"), FALSE, EZC_FLAGS_READ | EZC_FLAGS_WRITE}, 3287 { "ntp_server", "NTP Servers", validate_ipaddrs, NULL, TRUE, 0 }, 3288 { "log_level", "Connection Logging", validate_range, ARGV("0", "3"), FALSE, 0 }, 3289 { "log_ipaddr", "Log LAN IP Address", validate_ipaddr, ARGV("lan_ipaddr", "lan_netmask"), TRUE, 0 }, 3290 { "log_ram_enable", "Syslog in RAM", validate_choice, ARGV("0", "1"), FALSE, 0 }, 3291 /* SES Settings */ 3292 { "ses_enable", "SES", validate_choice, ARGV("0", "1"), FALSE, 0 }, 3293 { "ses_event", "SES Event", validate_choice, ARGV("0", "3", "4", "6", "7"), FALSE, 0 }, 3294 /* LAN settings */ 3295 { "lan_dhcp", "DHCP Client", validate_choice, ARGV("1", "0"), FALSE, 0 }, 3296 { "lan_ipaddr", "IP Address", validate_lan_ipaddr, NULL, FALSE, EZC_FLAGS_READ | EZC_FLAGS_WRITE }, 3297 { "lan_netmask", "Subnet Mask", validate_ipaddr, NULL, TRUE, 0 }, 3298 { "lan_gateway", "Gateway Address", validate_ipaddr, NULL, TRUE, 0 }, 3299 { "lan_proto", "DHCP Server", validate_choice, ARGV("dhcp", "static"), FALSE, EZC_FLAGS_READ | EZC_FLAGS_WRITE }, 3300 { "dhcp_start", "DHCP Server LAN IP Address Range", validate_dhcp, NULL, FALSE, EZC_FLAGS_READ | EZC_FLAGS_WRITE }, 3301 { "lan_lease", "DHCP Server Lease Time", validate_range, ARGV("1", "604800"), FALSE, EZC_FLAGS_READ | EZC_FLAGS_WRITE }, 3302 { "lan_stp", "Spanning Tree Protocol", validate_choice, ARGV("0", "1"), FALSE, EZC_FLAGS_READ | EZC_FLAGS_WRITE }, 3303 { "lan_route", "Static Routes", validate_lan_route, NULL, FALSE, 0 }, 3304#ifdef __CONFIG_NAT__ 3305 /* ALL wan_XXXX variables below till wan_uint variable are per-interface */ 3306 { "wan_desc", "Description", validate_name, ARGV("0", "255"), TRUE, EZC_FLAGS_READ | EZC_FLAGS_WRITE }, 3307 { "wan_proto", "Protocol", validate_choice, ARGV("dhcp", "static", "pppoe", "disabled"), FALSE, EZC_FLAGS_READ | EZC_FLAGS_WRITE }, 3308 { "wan_hostname", "Host Name", validate_name, ARGV("0", "255"), TRUE, EZC_FLAGS_READ | EZC_FLAGS_WRITE }, 3309 { "wan_domain", "Domain Name", validate_name, ARGV("0", "255"), TRUE, EZC_FLAGS_READ | EZC_FLAGS_WRITE }, 3310 { "wan_ifname", "Interface Name", validate_wan_ifname, NULL, TRUE, 0 }, 3311 { "wan_hwaddr", "MAC Address", validate_hwaddr, NULL, TRUE, EZC_FLAGS_READ | EZC_FLAGS_WRITE }, 3312 { "wan_ipaddr", "IP Address", validate_ipaddr, NULL, FALSE, EZC_FLAGS_READ | EZC_FLAGS_WRITE }, 3313 { "wan_netmask", "Subnet Mask", validate_ipaddr, NULL, FALSE, EZC_FLAGS_READ | EZC_FLAGS_WRITE }, 3314 { "wan_gateway", "Default Gateway", validate_ipaddr, NULL, TRUE, EZC_FLAGS_READ | EZC_FLAGS_WRITE }, 3315 { "wan_dns", "DNS Servers", validate_ipaddrs, NULL, TRUE, EZC_FLAGS_READ | EZC_FLAGS_WRITE }, 3316 { "wan_wins", "WINS Servers", validate_ipaddrs, NULL, TRUE, EZC_FLAGS_READ | EZC_FLAGS_WRITE }, 3317 { "wan_pppoe_ifname", "PPPoE Interface Name", NULL, NULL, TRUE, 0 }, 3318 { "wan_pppoe_username", "PPPoE Username", validate_name, ARGV("0", "255"), TRUE, EZC_FLAGS_READ | EZC_FLAGS_WRITE }, 3319 { "wan_pppoe_passwd", "PPPoE Password", validate_name, ARGV("0", "255"), TRUE, EZC_FLAGS_WRITE }, 3320 { "wan_pppoe_service", "PPPoE Service Name", validate_name, ARGV("0", "255"), TRUE, EZC_FLAGS_READ | EZC_FLAGS_WRITE }, 3321 { "wan_pppoe_ac", "PPPoE Access Concentrator", validate_name, ARGV("0", "255"), TRUE, EZC_FLAGS_READ | EZC_FLAGS_WRITE }, 3322 { "wan_pppoe_keepalive", "PPPoE Keep Alive", validate_choice, ARGV("0", "1"), FALSE, EZC_FLAGS_READ | EZC_FLAGS_WRITE }, 3323 { "wan_pppoe_demand", "PPPoE Connect on Demand", validate_choice, ARGV("0", "1"), FALSE, EZC_FLAGS_READ | EZC_FLAGS_WRITE }, 3324 { "wan_pppoe_idletime", "PPPoE Max Idle Time", validate_range, ARGV("1", "3600"), TRUE, EZC_FLAGS_READ | EZC_FLAGS_WRITE }, 3325 { "wan_pppoe_mru", "PPPoE MRU", validate_range, ARGV("128", "16384"), FALSE, EZC_FLAGS_READ | EZC_FLAGS_WRITE }, 3326 { "wan_pppoe_mtu", "PPPoE MTU", validate_range, ARGV("128", "16384"), FALSE, EZC_FLAGS_READ | EZC_FLAGS_WRITE }, 3327 { "wan_primary", "Primary Interface", validate_choice, ARGV("0", "1"), FALSE, 0 }, 3328 { "wan_route", "Static Routes", validate_wan_route, NULL, FALSE, 0 }, 3329 /* MUST leave this entry here after all wl_XXXX per-interface variables */ 3330 { "wan_unit", "WAN Instance", wan_unit, NULL, TRUE, 0 }, 3331 /* filter settings */ 3332 { "filter_macmode", "MAC Filter Mode", validate_choice, ARGV("disabled", "allow", "deny"), FALSE, 0 }, 3333 { "filter_maclist", "MAC Filter", validate_hwaddrs, NULL, TRUE, 0 }, 3334 { "filter_client", "LAN Client Filter", validate_filter_client, ARGV("0", XSTR(MAX_NVPARSE - 1)), FALSE, 0 }, 3335 /* routing settings */ 3336 { "forward_port", "Port Forward", validate_forward_port, ARGV("0", XSTR(MAX_NVPARSE - 1)), FALSE, 0 }, 3337 { "autofw_port", "Application Specific Port Forward", validate_autofw_port, ARGV("0", XSTR(MAX_NVPARSE - 1)), FALSE, 0 }, 3338 { "dmz_ipaddr", "DMZ LAN IP Address", validate_ipaddr, ARGV("lan_ipaddr", "lan_netmask"), TRUE, 0 }, 3339#endif /* __CONFIG_NAT__ */ 3340 /* ALL wl_XXXX variables are per-interface */ 3341 { "wl_ssid", "Network Name (SSID)", validate_name, ARGV("1", "32"), FALSE, EZC_FLAGS_READ | EZC_FLAGS_WRITE }, 3342 { "wl_closed", "Network Type", validate_choice, ARGV("0", "1"), FALSE, EZC_FLAGS_READ | EZC_FLAGS_WRITE }, 3343 { "wl_ap_isolate", "AP Isolate", validate_choice, ARGV("0", "1"), FALSE, 0 }, 3344 { "wl_country_code", "Country Code", validate_country, NULL, FALSE, EZC_FLAGS_READ | EZC_FLAGS_WRITE }, 3345 { "wl_mode", "Mode", validate_wl_mode, ARGV("ap", "wds", "sta", "wet"), FALSE, 0 }, 3346 { "wl_infra", "Network", validate_choice, ARGV("0", "1"), FALSE, 0 }, 3347 { "wl_lazywds", "Bridge Restrict", validate_wl_lazywds, ARGV("0", "1"), FALSE, 0 }, 3348 { "wl_wds", "Bridges", validate_wl_wds_hwaddrs, NULL, TRUE, 0 }, 3349 { "wl_wds_timeout", "Link Timeout Interval", NULL, NULL, TRUE, 0 }, 3350 { "wl_macmode", "MAC Restrict Mode", validate_choice, ARGV("disabled", "allow", "deny"), FALSE, 0 }, 3351 { "wl_maclist", "Allowed MAC Address", validate_hwaddrs, NULL, TRUE, 0 }, 3352 { "wl_radio", "Radio Enable", validate_choice, ARGV("0", "1"), FALSE, 0 }, 3353 { "wl_phytype", "Radio Band", validate_choice, ARGV("a", "b", "g"), TRUE, 0 }, 3354 { "wl_antdiv", "Antenna Diversity", validate_choice, ARGV("-1", "0", "1", "3"), FALSE, 0 }, 3355 /* Channel and rate are fixed in wlconf() if incorrect */ 3356 { "wl_channel", "Channel", validate_range, ARGV("0", "216"), FALSE, EZC_FLAGS_READ | EZC_FLAGS_WRITE }, 3357 { "wl_rate", "Rate", validate_range, ARGV("0", "54000000"), FALSE, 0 }, 3358 { "wl_rateset", "Supported Rates", validate_choice, ARGV("all", "default", "12"), FALSE, 0 }, 3359 { "wl_mrate", "Multicast Rate", validate_range, ARGV("0", "54000000"), FALSE, 0 }, 3360 { "wl_frag", "Fragmentation Threshold", validate_range, ARGV("256", "2346"), FALSE, 0 }, 3361 { "wl_rts", "RTS Threshold", validate_range, ARGV("0", "2347"), FALSE, 0 }, 3362 { "wl_dtim", "DTIM Period", validate_range, ARGV("1", "255"), FALSE, 0 }, 3363 { "wl_bcn", "Beacon Interval", validate_range, ARGV("1", "65535"), FALSE, 0 }, 3364 { "wl_plcphdr", "Preamble Type", validate_choice, ARGV("long", "short"), FALSE, 0 }, 3365 { "wl_maxassoc", "Max Assocation Limit", validate_range, ARGV("1", "256"), FALSE, 0 }, 3366 { "wl_gmode", "54g Mode", validate_choice, ARGV(XSTR(GMODE_AUTO), XSTR(GMODE_ONLY), XSTR(GMODE_PERFORMANCE), XSTR(GMODE_LRS), XSTR(GMODE_LEGACY_B)), FALSE, 0 }, 3367 { "wl_gmode_protection", "54g Protection", validate_choice, ARGV("off", "auto"), FALSE, 0 }, 3368 { "wl_frameburst", "XPress Technology", validate_choice, ARGV("off", "on"), FALSE, EZC_FLAGS_READ | EZC_FLAGS_WRITE }, 3369 { "wl_afterburner", "AfterBurner Technology", validate_wl_afterburner, ARGV("off", "auto"), FALSE, EZC_FLAGS_READ | EZC_FLAGS_WRITE }, 3370 { "wl_wme", "WME Support", validate_choice, ARGV("off", "on"), FALSE, EZC_FLAGS_READ | EZC_FLAGS_WRITE }, 3371 { "wl_wme_no_ack", "No-Acknowledgement", validate_noack, ARGV("off", "on"), FALSE, EZC_FLAGS_READ | EZC_FLAGS_WRITE }, 3372 { "wl_wme_ap_bk", "WME AP BK", validate_wl_wme_params, NULL, TRUE, 0 }, 3373 { "wl_wme_ap_be", "WME AP BE", validate_wl_wme_params, NULL, TRUE, 0 }, 3374 { "wl_wme_ap_vi", "WME AP VI", validate_wl_wme_params, NULL, TRUE, 0 }, 3375 { "wl_wme_ap_vo", "WME AP VO", validate_wl_wme_params, NULL, TRUE, 0 }, 3376 { "wl_wme_sta_bk", "WME STA BK", validate_wl_wme_params, NULL, TRUE, 0 }, 3377 { "wl_wme_sta_be", "WME STA BE", validate_wl_wme_params, NULL, TRUE, 0 }, 3378 { "wl_wme_sta_vi", "WME STA VI", validate_wl_wme_params, NULL, TRUE, 0 }, 3379 { "wl_wme_sta_vo", "WME STA VO", validate_wl_wme_params, NULL, TRUE, 0 }, 3380 /* security parameters */ 3381 { "wl_key", "Network Key Index", validate_range, ARGV("1", "4"), FALSE, EZC_FLAGS_WRITE }, 3382 { "wl_key1", "Network Key 1", validate_wl_key, NULL, TRUE, EZC_FLAGS_WRITE}, 3383 { "wl_key2", "Network Key 2", validate_wl_key, NULL, TRUE, EZC_FLAGS_WRITE}, 3384 { "wl_key3", "Network Key 3", validate_wl_key, NULL, TRUE, EZC_FLAGS_WRITE}, 3385 { "wl_key4", "Network Key 4", validate_wl_key, NULL, TRUE, EZC_FLAGS_WRITE}, 3386 { "wl_auth", "802.11 Authentication", validate_wl_auth, ARGV("0", "1"), FALSE, 0}, 3387 { "wl_auth_mode", "Network Authentication", validate_wl_auth_mode, ARGV("radius", "none"), FALSE, EZC_FLAGS_READ | EZC_FLAGS_WRITE }, 3388 { "wl_akm", "Authenticated Key Management", validate_wl_akm, NULL, FALSE, EZC_FLAGS_READ | EZC_FLAGS_WRITE }, 3389 { "wl_wep", "WEP Encryption", validate_wl_wep, ARGV("disabled", "enabled"), FALSE, EZC_FLAGS_READ | EZC_FLAGS_WRITE }, 3390 { "wl_crypto", "WPA Encryption", validate_wl_crypto, ARGV("tkip", "aes", "tkip+aes"), FALSE, EZC_FLAGS_READ | EZC_FLAGS_WRITE }, 3391 { "wl_net_reauth", "Network Re-auth Interval", NULL, NULL, TRUE, 0 }, 3392 { "wl_preauth", "Network Preauthentication Support", validate_wl_preauth, ARGV("disabled", "enabled"), FALSE, 0 }, 3393 { "wl_radius_ipaddr", "RADIUS Server", validate_ipaddr, NULL, TRUE, EZC_FLAGS_READ | EZC_FLAGS_WRITE }, 3394 { "wl_radius_port", "RADIUS Port", validate_range, ARGV("0", "65535"), FALSE, EZC_FLAGS_READ | EZC_FLAGS_WRITE }, 3395 { "wl_radius_key", "RADIUS Shared Secret", validate_name, ARGV("0", "255"), TRUE, EZC_FLAGS_WRITE}, 3396 { "wl_wpa_psk", "WPA Pre-Shared Key", validate_wl_wpa_psk, ARGV("64"), TRUE, EZC_FLAGS_WRITE}, 3397 { "wl_wpa_gtk_rekey", "Network Key Rotation Interval", NULL, NULL, TRUE, EZC_FLAGS_READ | EZC_FLAGS_WRITE }, 3398 /* MUST leave this entry here after all wl_XXXX variables */ 3399 { "wl_unit", "802.11 Instance", wl_unit, NULL, TRUE, 0 }, 3400 /* Internal variables */ 3401 { "os_server", "OS Server", NULL, NULL, TRUE, 0 }, 3402 { "stats_server", "Stats Server", NULL, NULL, TRUE, 0 }, 3403 { "timer_interval", "Timer Interval", NULL, NULL, TRUE, 0 }, 3404}; 3405 3406int 3407variables_arraysize(void) 3408{ 3409 return ARRAYSIZE(variables); 3410} 3411 3412static void 3413validate_cgi(webs_t wp) 3414{ 3415 struct variable *v; 3416 char *value; 3417 3418 websBufferInit(wp); 3419 if (!webs_buf) { 3420 websWrite(wp, "out of memory\n"); 3421 websDone(wp, 0); 3422 return; 3423 } 3424 3425 3426 /* Validate and set variables in table order */ 3427 for (v = variables; v < &variables[ARRAYSIZE(variables)]; v++) { 3428 if (!(value = websGetVar(wp, v->name, NULL))) 3429 continue; 3430 if ((!*value && v->nullok) || !v->validate) 3431 nvram_set(v->name, value); 3432 else 3433 v->validate(wp, value, v); 3434 } 3435 3436 websBufferFlush(wp); 3437} 3438 3439static int 3440apply_cgi(webs_t wp, char_t *urlPrefix, char_t *webDir, int arg, 3441 char_t *url, char_t *path, char_t *query) 3442{ 3443 int action = NOTHING; 3444 char *value; 3445 3446 websHeader(wp); 3447 websWrite(wp, (char_t *) apply_header); 3448 3449 value = websGetVar(wp, "action", ""); 3450 3451 /* Apply values */ 3452 if (!strcmp(value, "Apply")) { 3453 websWrite(wp, "Validating values..."); 3454 validate_cgi(wp); 3455 websWrite(wp, "done<br>"); 3456 websWrite(wp, "Committing values..."); 3457 nvram_set("is_modified", "1"); 3458 nvram_set("is_default", "0"); 3459 nvram_commit(); 3460 websWrite(wp, "done<br>"); 3461 action = RESTART; 3462 } 3463 3464 /* Restore defaults */ 3465 else if (!strncmp(value, "Restore", 7)) { 3466 websWrite(wp, "Restoring defaults..."); 3467 nvram_set("sdram_ncdl", "0"); 3468 nvram_set("restore_defaults", "1"); 3469 nvram_commit(); 3470 websWrite(wp, "done<br>"); 3471 action = REBOOT; 3472 } 3473 3474 /* Release lease */ 3475 else if (!strcmp(value, "Release")) { 3476 websWrite(wp, "Releasing lease..."); 3477 if (sys_release()) 3478 websWrite(wp, "error<br>"); 3479 else 3480 websWrite(wp, "done<br>"); 3481 action = NOTHING; 3482 } 3483 3484 /* Renew lease */ 3485 else if (!strcmp(value, "Renew")) { 3486 websWrite(wp, "Renewing lease..."); 3487 if (sys_renew()) 3488 websWrite(wp, "error<br>"); 3489 else 3490 websWrite(wp, "done<br>"); 3491 action = NOTHING; 3492 } 3493 3494 /* Reboot router */ 3495 else if (!strcmp(value, "Reboot")) { 3496 websWrite(wp, "Rebooting..."); 3497 action = REBOOT; 3498 } 3499 3500 /* Upgrade image */ 3501 else if (!strcmp(value, "Upgrade")) { 3502 char *os_name = nvram_safe_get("os_name"); 3503 char *os_server = websGetVar(wp, "os_server", nvram_safe_get("os_server")); 3504 char *os_version = websGetVar(wp, "os_version", "current"); 3505 char url[PATH_MAX]; 3506 if (!*os_version) 3507 os_version = "current"; 3508 snprintf(url, sizeof(url), "%s/%s/%s/%s.trx", 3509 os_server, os_name, os_version, os_name); 3510 websWrite(wp, "Retrieving %s...", url); 3511 if (sys_upgrade(url, NULL, NULL)) { 3512 websWrite(wp, "error<br>"); 3513 goto footer; 3514 } else { 3515 websWrite(wp, "done<br>"); 3516 action = REBOOT; 3517 } 3518 } 3519 3520 /* Report stats */ 3521 else if (!strcmp(value, "Stats")) { 3522 char *server = websGetVar(wp, "stats_server", nvram_safe_get("stats_server")); 3523 websWrite(wp, "Contacting %s...", server); 3524 if (sys_stats(server)) { 3525 websWrite(wp, "error<br>"); 3526 goto footer; 3527 } else { 3528 websWrite(wp, "done<br>"); 3529 nvram_set("stats_server", server); 3530 } 3531 } 3532 /* Radio On Off */ 3533 else if (!strcmp(value, "RadioOff")) { 3534 websWrite(wp, "Turing Off Radio..."); 3535 wl_radio_onoff(wp, 1); 3536 action = NOTHING; 3537 } 3538 else if (!strcmp(value, "RadioOn")) { 3539 websWrite(wp, "Radio on..."); 3540 wl_radio_onoff(wp, 0); 3541 action = NOTHING; 3542 } 3543#ifdef __CONFIG_SES__ 3544 /* SES events */ 3545 else if (!strcmp(value, "NewSesNW")) { 3546 websWrite(wp, "Creating SES Network"); 3547 nvram_set("ses_event", "3"); 3548 action = NOTHING; 3549 } 3550 else if (!strcmp(value, "OpenWindow")) { 3551 websWrite(wp, "Opening SES Window"); 3552 nvram_set("ses_event", "4"); 3553 action = NOTHING; 3554 } 3555 else if (!strcmp(value, "NewSesNWAndOW")) { 3556 websWrite(wp, "Creating SES Network and Opening SES Window"); 3557 nvram_set("ses_event", "6"); 3558 action = NOTHING; 3559 } 3560 else if (!strcmp(value, "ResetNWToDefault")) { 3561 websWrite(wp, "Restoring Network to Default"); 3562 nvram_set("ses_event", "7"); 3563 action = NOTHING; 3564 } 3565#endif /* __CONFIG_SES__ */ 3566#ifdef __CONFIG_NAT__ 3567 /* Delete connection */ 3568 else if (!strcmp(value, "Delete")) { 3569 int unit; 3570 if (!(value = websGetVar(wp, "wan_unit", NULL)) || 3571 (unit = atoi(value)) < 0 || unit >= MAX_NVPARSE) { 3572 websWrite(wp, "Unable to delete connection, index error."); 3573 action = NOTHING; 3574 } 3575 else { 3576 struct nvram_tuple *t; 3577 char tmp[NVRAM_BUFSIZE], prefix[] = "wanXXXXXXXXXX_"; 3578 int unit2, units = 0; 3579 /* 3580 * We cann't delete the last connection since we can't differentiate 3581 * the cases where user does not want any connection (user deletes 3582 * the last one) vs. the router is booted the first time when there 3583 * is no connection at all (where a default one is created anyway). 3584 */ 3585 for (unit2 = 0; unit2 < MAX_NVPARSE; unit2 ++) { 3586 wan_prefix(unit2, prefix); 3587 if (nvram_get(strcat_r(prefix, "unit", tmp)) && units++ > 0) 3588 break; 3589 } 3590 if (units < 2) { 3591 websWrite(wp, "Can not delete the last connection."); 3592 action = NOTHING; 3593 } 3594 else { 3595 /* set prefix */ 3596 wan_prefix(unit, prefix); 3597 /* remove selected wan%d_ set */ 3598 websWrite(wp, "Deleting connection..."); 3599 for (t = router_defaults; t->name; t ++) { 3600 if (!strncmp(t->name, "wan_", 4)) 3601 nvram_unset(strcat_r(prefix, &t->name[4], tmp)); 3602 } 3603 /* fix unit number */ 3604 unit2 = unit; 3605 for (; unit < MAX_NVPARSE; unit ++) { 3606 wan_prefix(unit, prefix); 3607 if (nvram_get(strcat_r(prefix, "unit", tmp))) 3608 break; 3609 } 3610 if (unit >= MAX_NVPARSE) { 3611 unit = unit2 - 1; 3612 for (; unit >= 0; unit --) { 3613 wan_prefix(unit, prefix); 3614 if (nvram_get(strcat_r(prefix, "unit", tmp))) 3615 break; 3616 } 3617 } 3618 snprintf(tmp, sizeof(tmp), "%d", unit); 3619 nvram_set("wan_unit", tmp); 3620 /* check if there is any primary connection - see comment in wan_unit() */ 3621 for (unit = 0; unit < MAX_NVPARSE; unit ++) { 3622 wan_prefix(unit, prefix); 3623 if (!nvram_get(strcat_r(prefix, "unit", tmp))) 3624 continue; 3625 if (nvram_invmatch(strcat_r(prefix, "proto", tmp), "disabled") && 3626 nvram_match(strcat_r(prefix, "primary", tmp), "1")) 3627 break; 3628 } 3629 /* no one is primary, pick the first enabled one as primary */ 3630 if (unit >= MAX_NVPARSE) 3631 wan_primary(wp); 3632 /* save the change */ 3633 nvram_set("is_modified", "1"); 3634 nvram_set("is_default", "0"); 3635 nvram_commit(); 3636 websWrite(wp, "done<br>"); 3637 action = RESTART; 3638 } 3639 } 3640 } 3641#endif /* __CONFIG_NAT__ */ 3642 3643 /* Invalid action */ 3644 else 3645 websWrite(wp, "Invalid action %s<br>", value); 3646 3647 footer: 3648 websWrite(wp, (char_t *) apply_footer, websGetVar(wp, "page", "")); 3649 websFooter(wp); 3650 websDone(wp, 200); 3651 3652 if (action == RESTART) 3653 sys_restart(); 3654 else if (action == REBOOT) 3655 sys_reboot(); 3656 3657 return 1; 3658} 3659 3660static int 3661wireless_asp(webs_t wp, char_t *urlPrefix, char_t *webDir, int arg, 3662 char_t *url, char_t *path, char_t *query) 3663{ 3664 struct variable *v; 3665 char *value; 3666 char name[IFNAMSIZ], *next; 3667 int unit = 0; 3668 char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_"; 3669 3670 /* Can enter this function through GET or POST */ 3671 if ((value = websGetVar(wp, "action", NULL))) { 3672 if (strcmp(value, "Select")) 3673 return apply_cgi(wp, urlPrefix, webDir, arg, url, path, query); 3674 } 3675 3676 /* copy wl%d_XXXXXXXX to wl_XXXXXXXX */ 3677 if ((value = websGetVar(wp, "wl_unit", NULL))) { 3678 unit = atoi(value); 3679 } else { 3680 char ifnames[256]; 3681 snprintf(ifnames, sizeof(ifnames), "%s %s", 3682 nvram_safe_get("lan_ifnames"), 3683 nvram_safe_get("wan_ifnames")); 3684 /* Probe for first wl interface */ 3685 foreach(name, ifnames, next) { 3686 if (wl_probe(name) == 0 && 3687 wl_ioctl(name, WLC_GET_INSTANCE, &unit, sizeof(unit)) == 0) 3688 break; 3689 } 3690 if (!*name) 3691 unit = -1; 3692 } 3693 if (unit >= 0) { 3694 snprintf(prefix, sizeof(prefix), "wl%d_", unit); 3695 for (v = variables; v < &variables[ARRAYSIZE(variables)]; v++) { 3696 if (!strncmp(v->name, "wl_", 3)) 3697 nvram_set(v->name, nvram_safe_get(strcat_r(prefix, &v->name[3], tmp))); 3698 if (!strncmp(v->name, "wl_unit", 7)) 3699 break; 3700 } 3701 } 3702 3703 /* Set currently selected unit */ 3704 snprintf(tmp, sizeof(tmp), "%d", unit); 3705 nvram_set("wl_unit", tmp); 3706 3707 /* Display the page */ 3708 return websDefaultHandler(wp, urlPrefix, webDir, arg, url, path, query); 3709} 3710 3711static int 3712internal_asp(webs_t wp, char_t *urlPrefix, char_t *webDir, int arg, 3713 char_t *url, char_t *path, char_t *query) 3714{ 3715 struct variable *v; 3716 char *value; 3717 char name[IFNAMSIZ], *next; 3718 int unit = 0; 3719 char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_"; 3720 3721 /* Can enter this function through GET or POST */ 3722 if ((value = websGetVar(wp, "action", NULL))) { 3723 if (strcmp(value, "Select")) 3724 return apply_cgi(wp, urlPrefix, webDir, arg, url, path, query); 3725 } 3726 3727 /* copy wl%d_XXXXXXXX to wl_XXXXXXXX */ 3728 if ((value = websGetVar(wp, "wl_unit", NULL))) { 3729 unit = atoi(value); 3730 } else { 3731 char ifnames[256]; 3732 snprintf(ifnames, sizeof(ifnames), "%s %s", 3733 nvram_safe_get("lan_ifnames"), 3734 nvram_safe_get("wan_ifnames")); 3735 /* Probe for first wl interface */ 3736 foreach(name, ifnames, next) { 3737 if (wl_probe(name) == 0 && 3738 wl_ioctl(name, WLC_GET_INSTANCE, &unit, sizeof(unit)) == 0) 3739 break; 3740 } 3741 if (!*name) 3742 unit = -1; 3743 } 3744 if (unit >= 0) { 3745 snprintf(prefix, sizeof(prefix), "wl%d_", unit); 3746 for (v = variables; v < &variables[ARRAYSIZE(variables)]; v++) { 3747 if (!strncmp(v->name, "wl_", 3)) 3748 nvram_set(v->name, nvram_safe_get(strcat_r(prefix, &v->name[3], tmp))); 3749 if (!strncmp(v->name, "wl_unit", 7)) 3750 break; 3751 } 3752 } 3753 3754 /* Set currently selected unit */ 3755 snprintf(tmp, sizeof(tmp), "%d", unit); 3756 nvram_set("wl_unit", tmp); 3757 3758 /* Display the page */ 3759 return (websDefaultHandler(wp, urlPrefix, webDir, arg, url, path, query)); 3760} 3761 3762static int 3763security_asp(webs_t wp, char_t *urlPrefix, char_t *webDir, int arg, 3764 char_t *url, char_t *path, char_t *query) 3765{ 3766 struct variable *v; 3767 char *value; 3768 char name[IFNAMSIZ], *next; 3769 int unit = 0; 3770 char tmp[NVRAM_BUFSIZE], prefix[] = "wlXXXXXXXXXX_"; 3771 3772 /* Can enter this function through GET or POST */ 3773 if ((value = websGetVar(wp, "action", NULL))) { 3774 if (strcmp(value, "Select")) 3775 return apply_cgi(wp, urlPrefix, webDir, arg, url, path, query); 3776 } 3777 3778 /* copy wl%d_XXXXXXXX to wl_XXXXXXXX */ 3779 if ((value = websGetVar(wp, "wl_unit", NULL))) { 3780 unit = atoi(value); 3781 } else { 3782 char ifnames[256]; 3783 snprintf(ifnames, sizeof(ifnames), "%s %s", 3784 nvram_safe_get("lan_ifnames"), 3785 nvram_safe_get("wan_ifnames")); 3786 /* Probe for first wl interface */ 3787 foreach(name, ifnames, next) { 3788 if (wl_probe(name) == 0 && 3789 wl_ioctl(name, WLC_GET_INSTANCE, &unit, sizeof(unit)) == 0) 3790 break; 3791 } 3792 if (!*name) 3793 unit = -1; 3794 } 3795 if (unit >= 0) { 3796 snprintf(prefix, sizeof(prefix), "wl%d_", unit); 3797 for (v = variables; v < &variables[ARRAYSIZE(variables)]; v++) { 3798 if (!strncmp(v->name, "wl_", 3)) 3799 nvram_set(v->name, nvram_safe_get(strcat_r(prefix, &v->name[3], tmp))); 3800 if (!strncmp(v->name, "wl_unit", 7)) 3801 break; 3802 } 3803 } 3804 3805 /* Set currently selected unit */ 3806 snprintf(tmp, sizeof(tmp), "%d", unit); 3807 nvram_set("wl_unit", tmp); 3808 3809 /* Display the page */ 3810 return websDefaultHandler(wp, urlPrefix, webDir, arg, url, path, query); 3811} 3812 3813#ifdef __CONFIG_NAT__ 3814static int 3815wan_asp(webs_t wp, char_t *urlPrefix, char_t *webDir, int arg, 3816 char_t *url, char_t *path, char_t *query) 3817{ 3818 struct variable *v; 3819 char *value; 3820 int unit = 0; 3821 char tmp[NVRAM_BUFSIZE], prefix[] = "wanXXXXXXXXXX_"; 3822 char ustr[16]; 3823 struct nvram_tuple *t; 3824 3825 /* Can enter this function through GET or POST */ 3826 if ((value = websGetVar(wp, "action", NULL))) { 3827 if (!strcmp(value, "New")) { 3828 /* pick one that 'does not' exist */ 3829 for (unit = 0; unit < MAX_NVPARSE; unit ++) { 3830 wan_prefix(unit, prefix); 3831 if (!nvram_get(strcat_r(prefix, "unit", tmp))) 3832 break; 3833 } 3834 if (unit >= MAX_NVPARSE) { 3835 websHeader(wp); 3836 websWrite(wp, (char_t *) apply_header); 3837 websWrite(wp, "Unable to create new connection. Maximum %d.", MAX_NVPARSE); 3838 websWrite(wp, (char_t *) apply_footer, websGetVar(wp, "page", "")); 3839 websFooter(wp); 3840 websDone(wp, 200); 3841 return 1; 3842 } 3843 /* copy default to newly created wan%d_ set */ 3844 for (t = router_defaults; t->name; t ++) { 3845 if (!strncmp(t->name, "wan_", 4)) 3846 nvram_set(strcat_r(prefix, &t->name[4], tmp), t->value); 3847 } 3848 /* the following variables must be overwritten */ 3849 snprintf(ustr, sizeof(ustr), "%d", unit); 3850 nvram_set(strcat_r(prefix, "unit", tmp), ustr); 3851 nvram_set(strcat_r(prefix, "proto", tmp), "disabled"); 3852 nvram_set(strcat_r(prefix, "ifname", tmp), nvram_safe_get("wan_ifname")); 3853 nvram_set(strcat_r(prefix, "hwaddr", tmp), nvram_safe_get("wan_hwaddr")); 3854 nvram_set(strcat_r(prefix, "ifnames", tmp), nvram_safe_get("wan_ifnames")); 3855 /* commit change */ 3856 nvram_set("is_modified", "1"); 3857 nvram_set("is_default", "0"); 3858 nvram_commit(); 3859 } 3860 else if (!strcmp(value, "Select")) { 3861 if ((value = websGetVar(wp, "wan_unit", NULL))) 3862 unit = atoi(value); 3863 else 3864 unit = -1; 3865 } 3866 else 3867 return apply_cgi(wp, urlPrefix, webDir, arg, url, path, query); 3868 } 3869 else if ((value = websGetVar(wp, "wan_unit", NULL))) 3870 unit = atoi(value); 3871 else 3872 unit = atoi(nvram_safe_get("wan_unit")); 3873 if (unit < 0 || unit >= MAX_NVPARSE) 3874 unit = 0; 3875 3876 /* Set prefix */ 3877 wan_prefix(unit, prefix); 3878 3879 /* copy wan%d_ set to wan_ set */ 3880 for (v = variables; v < &variables[ARRAYSIZE(variables)]; v++) { 3881 if (strncmp(v->name, "wan_", 4)) 3882 continue; 3883 value = nvram_get(strcat_r(prefix, &v->name[4], tmp)); 3884 if (value) 3885 nvram_set(v->name, value); 3886 if (!strncmp(v->name, "wan_unit", 8)) 3887 break; 3888 } 3889 3890 /* Set currently selected unit */ 3891 snprintf(tmp, sizeof(tmp), "%d", unit); 3892 nvram_set("wan_unit", tmp); 3893 3894 /* Display the page */ 3895 return websDefaultHandler(wp, urlPrefix, webDir, arg, url, path, query); 3896} 3897#endif /* __CONFIG_NAT__ */ 3898 3899#ifdef WEBS 3900 3901void 3902initHandlers(void) 3903{ 3904 websAspDefine("nvram_get", ej_nvram_get); 3905 websAspDefine("nvram_match", ej_nvram_match); 3906 websAspDefine("nvram_invmatch", ej_nvram_invmatch); 3907 websAspDefine("nvram_list", ej_nvram_list); 3908 websAspDefine("filter_client", ej_filter_client); 3909 websAspDefine("forward_port", ej_forward_port); 3910 websAspDefine("static_route", ej_static_route); 3911 websAspDefine("localtime", ej_localtime); 3912 websAspDefine("dumplog", ej_dumplog); 3913 websAspDefine("syslog", ej_syslog); 3914 websAspDefine("dumpleases", ej_dumpleases); 3915 websAspDefine("link", ej_link); 3916 websAspDefine("wme_match_op", ej_wme_match_op); 3917 3918 websUrlHandlerDefine("/apply.cgi", NULL, 0, apply_cgi, 0); 3919 websUrlHandlerDefine("/wireless.asp", NULL, 0, wireless_asp, 0); 3920 3921 websSetPassword(nvram_safe_get("http_passwd")); 3922 3923 websSetRealm("Broadcom Home Gateway Reference Design"); 3924} 3925 3926#else /* !WEBS */ 3927 3928static void 3929do_auth(char *userid, char *passwd, char *realm) 3930{ 3931 strncpy(userid, nvram_safe_get("http_username"), AUTH_MAX); 3932 strncpy(passwd, nvram_safe_get("http_passwd"), AUTH_MAX); 3933 strncpy(realm, "Broadcom Home Gateway Reference Design", AUTH_MAX); 3934} 3935 3936char post_buf[POST_BUF_SIZE]; 3937char ezc_version[128]; 3938char no_cache[] = 3939"Cache-Control: no-cache\r\n" 3940"Pragma: no-cache\r\n" 3941"Expires: 0" 3942; 3943 3944 3945static void 3946do_apply_post(char *url, FILE *stream, int len, char *boundary) 3947{ 3948 /* Get query */ 3949 if (!fgets(post_buf, MIN(len + 1, sizeof(post_buf)), stream)) 3950 return; 3951 len -= strlen(post_buf); 3952 3953 /* Initialize CGI */ 3954 init_cgi(post_buf); 3955 3956 /* Slurp anything remaining in the request */ 3957 while (len--) 3958 (void) fgetc(stream); 3959} 3960 3961static void 3962do_apply_cgi(char *url, FILE *stream) 3963{ 3964 char *path, *query; 3965 3966 /* Parse path */ 3967 query = url; 3968 path = strsep(&query, "?") ? : url; 3969 3970 apply_cgi(stream, NULL, NULL, 0, url, path, query); 3971 3972 /* Reset CGI */ 3973 init_cgi(NULL); 3974} 3975 3976static int upgrade_ret; 3977 3978static void 3979do_upgrade_post(char *url, FILE *stream, int len, char *boundary) 3980{ 3981 char buf[1024]; 3982 3983 upgrade_ret = EINVAL; 3984 3985 /* Look for our part */ 3986 while (len > 0) { 3987 if (!fgets(buf, MIN(len + 1, sizeof(buf)), stream)) 3988 return; 3989 len -= strlen(buf); 3990 if (!strncasecmp(buf, "Content-Disposition:", 20) && 3991 strstr(buf, "name=\"file\"")) 3992 break; 3993 } 3994 3995 /* Skip boundary and headers */ 3996 while (len > 0) { 3997 if (!fgets(buf, MIN(len + 1, sizeof(buf)), stream)) 3998 return; 3999 len -= strlen(buf); 4000 if (!strcmp(buf, "\n") || !strcmp(buf, "\r\n")) 4001 break; 4002 } 4003 4004 upgrade_ret = sys_upgrade(NULL, stream, &len); 4005 4006 /* Slurp anything remaining in the request */ 4007 while (len--) 4008 (void) fgetc(stream); 4009} 4010 4011static void 4012do_upgrade_cgi(char *url, FILE *stream) 4013{ 4014 websHeader(stream); 4015 websWrite(stream, (char_t *) apply_header); 4016 4017 /* We could probably be more informative here... */ 4018 if (upgrade_ret) 4019 websWrite(stream, "Error during upgrade<br>"); 4020 else 4021 websWrite(stream, "Upgrade complete. Rebooting...<br>"); 4022 4023 websWrite(stream, (char_t *) apply_footer, "firmware.asp"); 4024 websFooter(stream); 4025 websDone(stream, 200); 4026 4027 /* Reboot if successful */ 4028 if (upgrade_ret == 0) 4029 sys_reboot(); 4030} 4031 4032static void 4033do_wireless_asp(char *url, FILE *stream) 4034{ 4035 char *path, *query; 4036 4037 /* Parse path */ 4038 query = url; 4039 path = strsep(&query, "?") ? : url; 4040 4041 wireless_asp(stream, NULL, NULL, 0, url, path, query); 4042 4043 /* Reset CGI */ 4044 init_cgi(NULL); 4045} 4046 4047static void 4048do_security_asp(char *url, FILE *stream) 4049{ 4050 char *path, *query; 4051 4052 /* Parse path */ 4053 query = url; 4054 path = strsep(&query, "?") ? : url; 4055 4056 security_asp(stream, NULL, NULL, 0, url, path, query); 4057 4058 /* Reset CGI */ 4059 init_cgi(NULL); 4060} 4061 4062static void 4063do_internal_asp(char *url, FILE *stream) 4064{ 4065 char *path, *query; 4066 4067 /* Parse path */ 4068 query = url; 4069 path = strsep(&query, "?") ? : url; 4070 4071 internal_asp(stream, NULL, NULL, 0, url, path, query); 4072 4073 /* Reset CGI */ 4074 init_cgi(NULL); 4075} 4076 4077#ifdef __CONFIG_NAT__ 4078static void 4079do_wan_asp(char *url, FILE *stream) 4080{ 4081 char *path, *query; 4082 4083 /* Parse path */ 4084 query = url; 4085 path = strsep(&query, "?") ? : url; 4086 4087 wan_asp(stream, NULL, NULL, 0, url, path, query); 4088 4089 /* Reset CGI */ 4090 init_cgi(NULL); 4091} 4092#endif /* __CONFIG_NAT__ */ 4093 4094struct mime_handler mime_handlers[] = { 4095#ifdef __CONFIG_NAT__ 4096 { "wan.asp", "text/html", no_cache, do_apply_post, do_wan_asp, do_auth }, 4097#endif /* __CONFIG_NAT__ */ 4098 { "wireless.asp", "text/html", no_cache, do_apply_post, do_wireless_asp, do_auth }, 4099 { "security.asp", "text/html", no_cache, do_apply_post, do_security_asp, do_auth }, 4100 { "internal.asp", "text/html", no_cache, do_apply_post, do_internal_asp, do_auth }, 4101#ifdef __CONFIG_EZC__ 4102 { "ezconfig.asp", "text/html", ezc_version, do_apply_ezconfig_post, do_ezconfig_asp, do_auth }, 4103#endif /* __CONFIG_EZC__ */ 4104 { "**.asp", "text/html", no_cache, NULL, do_ej, do_auth }, 4105 { "**.css", "text/css", NULL, NULL, do_file, do_auth }, 4106 { "**.gif", "image/gif", NULL, NULL, do_file, do_auth }, 4107 { "**.jpg", "image/jpeg", NULL, NULL, do_file, do_auth }, 4108 { "**.js", "text/javascript", NULL, NULL, do_file, do_auth }, 4109 { "apply.cgi*", "text/html", no_cache, do_apply_post, do_apply_cgi, do_auth }, 4110 { "upgrade.cgi*", "text/html", no_cache, do_upgrade_post, do_upgrade_cgi, do_auth }, 4111 { NULL, NULL, NULL, NULL, NULL, NULL } 4112}; 4113 4114struct ej_handler ej_handlers[] = { 4115 { "nvram_get", ej_nvram_get }, 4116 { "nvram_match", ej_nvram_match }, 4117 { "nvram_invmatch", ej_nvram_invmatch }, 4118 { "nvram_list", ej_nvram_list }, 4119 { "nvram_inlist", ej_nvram_inlist }, 4120 { "nvram_invinlist", ej_nvram_invinlist }, 4121#ifdef __CONFIG_NAT__ 4122 { "wan_list", ej_wan_list }, 4123 { "wan_iflist", ej_wan_iflist }, 4124 { "wan_route", ej_wan_route }, 4125 { "wan_link", ej_wan_link }, 4126 { "wan_lease", ej_wan_lease }, 4127 { "filter_client", ej_filter_client }, 4128 { "forward_port", ej_forward_port }, 4129 { "autofw_port", ej_autofw_port }, 4130#endif /* __CONFIG_NAT__ */ 4131 { "localtime", ej_localtime }, 4132 { "sysuptime", ej_sysuptime }, 4133 { "dumplog", ej_dumplog }, 4134 { "syslog", ej_syslog }, 4135 { "wl_list", ej_wl_list }, 4136 { "wl_phytypes", ej_wl_phytypes }, 4137 { "wl_radioid", ej_wl_radioid }, 4138 { "wl_corerev", ej_wl_corerev }, 4139 { "wl_cur_channel", ej_wl_cur_channel }, 4140 { "wl_cur_phytype", ej_wl_cur_phytype }, 4141 { "wl_cur_country", ej_wl_cur_country }, 4142 { "wl_country_list", ej_wl_country_list }, 4143 { "wl_channel_list", ej_wl_channel_list }, 4144 { "wl_auth_list", ej_wl_auth_list }, 4145 { "wl_mode_list", ej_wl_mode_list }, 4146 { "wl_inlist", ej_wl_inlist }, 4147 { "wl_wds_status", ej_wl_wds_status }, 4148 { "wl_radio_roam_option", ej_wl_radio_roam_option}, 4149 { "ses_button_display", ej_ses_button_display}, 4150 { "lan_route", ej_lan_route }, 4151 { "lan_leases", ej_lan_leases }, 4152 { "asp_list", ej_asp_list }, 4153 { "wme_match_op", ej_wme_match_op }, 4154 { NULL, NULL } 4155}; 4156 4157#endif /* !WEBS */ 4158 4159/* 4160 * Country names and abbreviations from ISO 3166 4161 */ 4162country_name_t country_names[] = { 4163 4164{"AFGHANISTAN", "AF"}, 4165{"ALBANIA", "AL"}, 4166{"ALGERIA", "DZ"}, 4167{"AMERICAN SAMOA", "AS"}, 4168{"ANDORRA", "AD"}, 4169{"ANGOLA", "AO"}, 4170{"ANGUILLA", "AI"}, 4171{"ANTARCTICA", "AQ"}, 4172{"ANTIGUA AND BARBUDA", "AG"}, 4173{"ARGENTINA", "AR"}, 4174{"ARMENIA", "AM"}, 4175{"ARUBA", "AW"}, 4176{"AUSTRALIA", "AU"}, 4177{"AUSTRIA", "AT"}, 4178{"AZERBAIJAN", "AZ"}, 4179{"BAHAMAS", "BS"}, 4180{"BAHRAIN", "BH"}, 4181{"BANGLADESH", "BD"}, 4182{"BARBADOS", "BB"}, 4183{"BELARUS", "BY"}, 4184{"BELGIUM", "BE"}, 4185{"BELIZE", "BZ"}, 4186{"BENIN", "BJ"}, 4187{"BERMUDA", "BM"}, 4188{"BHUTAN", "BT"}, 4189{"BOLIVIA", "BO"}, 4190{"BOSNIA AND HERZEGOVINA","BA"}, 4191{"BOTSWANA", "BW"}, 4192{"BOUVET ISLAND", "BV"}, 4193{"BRAZIL", "BR"}, 4194{"BRITISH INDIAN OCEAN TERRITORY", "IO"}, 4195{"BRUNEI DARUSSALAM", "BN"}, 4196{"BULGARIA", "BG"}, 4197{"BURKINA FASO", "BF"}, 4198{"BURUNDI", "BI"}, 4199{"CAMBODIA", "KH"}, 4200{"CAMEROON", "CM"}, 4201{"CANADA", "CA"}, 4202{"CAPE VERDE", "CV"}, 4203{"CAYMAN ISLANDS", "KY"}, 4204{"CENTRAL AFRICAN REPUBLIC","CF"}, 4205{"CHAD", "TD"}, 4206{"CHILE", "CL"}, 4207{"CHINA", "CN"}, 4208{"CHRISTMAS ISLAND", "CX"}, 4209{"COCOS (KEELING) ISLANDS","CC"}, 4210{"COLOMBIA", "CO"}, 4211{"COMOROS", "KM"}, 4212{"CONGO", "CG"}, 4213{"CONGO, THE DEMOCRATIC REPUBLIC OF THE", "CD"}, 4214{"COOK ISLANDS", "CK"}, 4215{"COSTA RICA", "CR"}, 4216{"COTE D'IVOIRE", "CI"}, 4217{"CROATIA", "HR"}, 4218{"CUBA", "CU"}, 4219{"CYPRUS", "CY"}, 4220{"CZECH REPUBLIC", "CZ"}, 4221{"DENMARK", "DK"}, 4222{"DJIBOUTI", "DJ"}, 4223{"DOMINICA", "DM"}, 4224{"DOMINICAN REPUBLIC", "DO"}, 4225{"ECUADOR", "EC"}, 4226{"EGYPT", "EG"}, 4227{"EL SALVADOR", "SV"}, 4228{"EQUATORIAL GUINEA", "GQ"}, 4229{"ERITREA", "ER"}, 4230{"ESTONIA", "EE"}, 4231{"ETHIOPIA", "ET"}, 4232{"FALKLAND ISLANDS (MALVINAS)", "FK"}, 4233{"FAROE ISLANDS", "FO"}, 4234{"FIJI", "FJ"}, 4235{"FINLAND", "FI"}, 4236{"FRANCE", "FR"}, 4237{"FRENCH GUIANA", "GF"}, 4238{"FRENCH POLYNESIA", "PF"}, 4239{"FRENCH SOUTHERN TERRITORIES", "TF"}, 4240{"GABON", "GA"}, 4241{"GAMBIA", "GM"}, 4242{"GEORGIA", "GE"}, 4243{"GERMANY", "DE"}, 4244{"GHANA", "GH"}, 4245{"GIBRALTAR", "GI"}, 4246{"GREECE", "GR"}, 4247{"GREENLAND", "GL"}, 4248{"GRENADA", "GD"}, 4249{"GUADELOUPE", "GP"}, 4250{"GUAM", "GU"}, 4251{"GUATEMALA", "GT"}, 4252{"GUINEA", "GN"}, 4253{"GUINEA-BISSAU", "GW"}, 4254{"GUYANA", "GY"}, 4255{"HAITI", "HT"}, 4256{"HEARD ISLAND AND MCDONALD ISLANDS", "HM"}, 4257{"HOLY SEE (VATICAN CITY STATE)", "VA"}, 4258{"HONDURAS", "HN"}, 4259{"HONG KONG", "HK"}, 4260{"HUNGARY", "HU"}, 4261{"ICELAND", "IS"}, 4262{"INDIA", "IN"}, 4263{"INDONESIA", "ID"}, 4264{"IRAN, ISLAMIC REPUBLIC OF", "IR"}, 4265{"IRAQ", "IQ"}, 4266{"IRELAND", "IE"}, 4267{"ISRAEL", "IL"}, 4268{"ITALY", "IT"}, 4269{"JAMAICA", "JM"}, 4270{"JAPAN", "JP"}, 4271{"JORDAN", "JO"}, 4272{"KAZAKHSTAN", "KZ"}, 4273{"KENYA", "KE"}, 4274{"KIRIBATI", "KI"}, 4275{"KOREA, DEMOCRATIC PEOPLE'S REPUBLIC OF", "KP"}, 4276{"KOREA, REPUBLIC OF", "KR"}, 4277{"KUWAIT", "KW"}, 4278{"KYRGYZSTAN", "KG"}, 4279{"LAO PEOPLE'S DEMOCRATIC REPUBLIC", "LA"}, 4280{"LATVIA", "LV"}, 4281{"LEBANON", "LB"}, 4282{"LESOTHO", "LS"}, 4283{"LIBERIA", "LR"}, 4284{"LIBYAN ARAB JAMAHIRIYA","LY"}, 4285{"LIECHTENSTEIN", "LI"}, 4286{"LITHUANIA", "LT"}, 4287{"LUXEMBOURG", "LU"}, 4288{"MACAO", "MO"}, 4289{"MACEDONIA, THE FORMER YUGOSLAV REPUBLIC OF", "MK"}, 4290{"MADAGASCAR", "MG"}, 4291{"MALAWI", "MW"}, 4292{"MALAYSIA", "MY"}, 4293{"MALDIVES", "MV"}, 4294{"MALI", "ML"}, 4295{"MALTA", "MT"}, 4296{"MARSHALL ISLANDS", "MH"}, 4297{"MARTINIQUE", "MQ"}, 4298{"MAURITANIA", "MR"}, 4299{"MAURITIUS", "MU"}, 4300{"MAYOTTE", "YT"}, 4301{"MEXICO", "MX"}, 4302{"MICRONESIA, FEDERATED STATES OF", "FM"}, 4303{"MOLDOVA, REPUBLIC OF", "MD"}, 4304{"MONACO", "MC"}, 4305{"MONGOLIA", "MN"}, 4306{"MONTSERRAT", "MS"}, 4307{"MOROCCO", "MA"}, 4308{"MOZAMBIQUE", "MZ"}, 4309{"MYANMAR", "MM"}, 4310{"NAMIBIA", "NA"}, 4311{"NAURU", "NR"}, 4312{"NEPAL", "NP"}, 4313{"NETHERLANDS", "NL"}, 4314{"NETHERLANDS ANTILLES", "AN"}, 4315{"NEW CALEDONIA", "NC"}, 4316{"NEW ZEALAND", "NZ"}, 4317{"NICARAGUA", "NI"}, 4318{"NIGER", "NE"}, 4319{"NIGERIA", "NG"}, 4320{"NIUE", "NU"}, 4321{"NORFOLK ISLAND", "NF"}, 4322{"NORTHERN MARIANA ISLANDS","MP"}, 4323{"NORWAY", "NO"}, 4324{"OMAN", "OM"}, 4325{"PAKISTAN", "PK"}, 4326{"PALAU", "PW"}, 4327{"PALESTINIAN TERRITORY, OCCUPIED", "PS"}, 4328{"PANAMA", "PA"}, 4329{"PAPUA NEW GUINEA", "PG"}, 4330{"PARAGUAY", "PY"}, 4331{"PERU", "PE"}, 4332{"PHILIPPINES", "PH"}, 4333{"PITCAIRN", "PN"}, 4334{"POLAND", "PL"}, 4335{"PORTUGAL", "PT"}, 4336{"PUERTO RICO", "PR"}, 4337{"QATAR", "QA"}, 4338{"REUNION", "RE"}, 4339{"ROMANIA", "RO"}, 4340{"RUSSIAN FEDERATION", "RU"}, 4341{"RWANDA", "RW"}, 4342{"SAINT HELENA", "SH"}, 4343{"SAINT KITTS AND NEVIS","KN"}, 4344{"SAINT LUCIA", "LC"}, 4345{"SAINT PIERRE AND MIQUELON", "PM"}, 4346{"SAINT VINCENT AND THE GRENADINES", "VC"}, 4347{"SAMOA", "WS"}, 4348{"SAN MARINO", "SM"}, 4349{"SAO TOME AND PRINCIPE","ST"}, 4350{"SAUDI ARABIA", "SA"}, 4351{"SENEGAL", "SN"}, 4352{"SEYCHELLES", "SC"}, 4353{"SIERRA LEONE", "SL"}, 4354{"SINGAPORE", "SG"}, 4355{"SLOVAKIA", "SK"}, 4356{"SLOVENIA", "SI"}, 4357{"SOLOMON ISLANDS", "SB"}, 4358{"SOMALIA", "SO"}, 4359{"SOUTH AFRICA", "ZA"}, 4360{"SOUTH GEORGIA AND THE SOUTH SANDWICH ISLANDS", "GS"}, 4361{"SPAIN", "ES"}, 4362{"SRI LANKA", "LK"}, 4363{"SUDAN", "SD"}, 4364{"SURINAME", "SR"}, 4365{"SVALBARD AND JAN MAYEN","SJ"}, 4366{"SWAZILAND", "SZ"}, 4367{"SWEDEN", "SE"}, 4368{"SWITZERLAND", "CH"}, 4369{"SYRIAN ARAB REPUBLIC", "SY"}, 4370{"TAIWAN, PROVINCE OF CHINA", "TW"}, 4371{"TAJIKISTAN", "TJ"}, 4372{"TANZANIA, UNITED REPUBLIC OF", "TZ"}, 4373{"THAILAND", "TH"}, 4374{"TIMOR-LESTE", "TL"}, 4375{"TOGO", "TG"}, 4376{"TOKELAU", "TK"}, 4377{"TONGA", "TO"}, 4378{"TRINIDAD AND TOBAGO", "TT"}, 4379{"TUNISIA", "TN"}, 4380{"TURKEY", "TR"}, 4381{"TURKMENISTAN", "TM"}, 4382{"TURKS AND CAICOS ISLANDS", "TC"}, 4383{"TUVALU", "TV"}, 4384{"UGANDA", "UG"}, 4385{"UKRAINE", "UA"}, 4386{"UNITED ARAB EMIRATES", "AE"}, 4387{"UNITED KINGDOM", "GB"}, 4388{"UNITED STATES", "US"}, 4389{"UNITED STATES MINOR OUTLYING ISLANDS","UM"}, 4390{"URUGUAY", "UY"}, 4391{"UZBEKISTAN", "UZ"}, 4392{"VANUATU", "VU"}, 4393{"VENEZUELA", "VE"}, 4394{"VIET NAM", "VN"}, 4395{"VIRGIN ISLANDS, BRITISH", "VG"}, 4396{"VIRGIN ISLANDS, U.S.", "VI"}, 4397{"WALLIS AND FUTUNA", "WF"}, 4398{"WESTERN SAHARA", "EH"}, 4399{"YEMEN", "YE"}, 4400{"YUGOSLAVIA", "YU"}, 4401{"ZAMBIA", "ZM"}, 4402{"ZIMBABWE", "ZW"}, 4403{"ALL", "ALL"}, 4404{NULL, NULL} 4405}; 4406