1#include <stdio.h> 2#include <stdlib.h> 3#include <string.h> 4#include <unistd.h> 5#include <sys/types.h> 6#include <sys/stat.h> 7#include <fcntl.h> 8#include <bcmnvram.h> 9#include <bcmdevs.h> 10#include <sys/ioctl.h> 11#include <net/if.h> 12#include <sys/socket.h> 13#include <linux/sockios.h> 14#include <wlutils.h> 15#include <linux_gpio.h> 16#include <etioctl.h> 17#include "utils.h" 18#include "shutils.h" 19#include "shared.h" 20#include <trxhdr.h> 21#include <bcmutils.h> 22#include <bcmendian.h> 23 24#ifdef RTCONFIG_QTN 25#include "web-qtn.h" 26#endif 27 28uint32_t gpio_dir(uint32_t gpio, int dir) 29{ 30 /* FIXME 31 return bcmgpio_connect(gpio, dir); 32 */ 33 34 return 0; 35} 36 37#define swapportstatus(x) \ 38{ \ 39 unsigned int data = *(unsigned int*)&(x); \ 40 data = ((data & 0x000c0000) >> 18) | \ 41 ((data & 0x00030000) >> 14) | \ 42 ((data & 0x0000c000) >> 10) | \ 43 ((data & 0x00003000) >> 6) | \ 44 ((data & 0x00000c00) >> 2); \ 45 *(unsigned int*)&(x) = data; \ 46} 47 48extern uint32_t gpio_read(void); 49extern void gpio_write(uint32_t bitvalue, int en); 50 51uint32_t get_gpio(uint32_t gpio) 52{ 53 uint32_t bit_value; 54 uint32_t bit_mask; 55 56 bit_mask = 1 << gpio; 57 bit_value = gpio_read()&bit_mask; 58 59 return bit_value == 0 ? 0 : 1; 60} 61 62 63uint32_t set_gpio(uint32_t gpio, uint32_t value) 64{ 65/* 66 uint32_t bit; 67 bit = 1<< gpio; 68 69 _dprintf("set_gpio: %d %d\n", bit, value); 70 gpio_write(bit, value); 71*/ 72 //_dprintf("set_gpio: %d %d\n", gpio, value); 73 gpio_write(gpio, value); 74 75 return 0; 76} 77 78#ifdef RTCONFIG_BCMFA 79int get_fa_rev(void) 80{ 81 int fd, ret; 82 unsigned int rev; 83 struct ifreq ifr; 84 et_var_t var; 85 86 fd = socket(AF_INET, SOCK_DGRAM, 0); 87 if (fd < 0) goto skip; 88 89 rev = 0; 90 var.set = 0; 91 var.cmd = IOV_FA_REV; 92 var.buf = &rev; 93 var.len = sizeof(rev); 94 95 memset(&ifr, 0, sizeof(ifr)); 96 strcpy(ifr.ifr_name, "eth0"); 97 ifr.ifr_data = (caddr_t) &var; 98 99 ret = ioctl(fd, SIOCSETGETVAR, (caddr_t)&ifr); 100 close(fd); 101 if (ret < 0) 102 goto skip; 103 104 return rev; 105 106skip: 107 return 0; 108} 109 110int get_fa_dump(void) 111{ 112 int fd, rev, ret; 113 struct ifreq ifr; 114 et_var_t var; 115 116 fd = socket(AF_INET, SOCK_DGRAM, 0); 117 if (fd < 0) goto skip; 118 119 rev = 0; 120 var.set = 0; 121 var.cmd = IOV_FA_DUMP; 122 var.buf = &rev; 123 var.len = sizeof(rev); 124 125 memset(&ifr, 0, sizeof(ifr)); 126 strcpy(ifr.ifr_name, "eth0"); 127 ifr.ifr_data = (caddr_t) &var; 128 129 ret = ioctl(fd, SIOCSETGETVAR, (caddr_t)&ifr); 130 close(fd); 131 if (ret < 0) 132 goto skip; 133 134 return rev; 135 136skip: 137 return 0; 138} 139 140#endif 141 142int get_switch_model(void) 143{ 144 int fd, devid, ret; 145 struct ifreq ifr; 146 et_var_t var; 147 148 fd = socket(AF_INET, SOCK_DGRAM, 0); 149 if (fd < 0) goto skip; 150 151 devid = 0; 152 var.set = 0; 153 var.cmd = IOV_ET_ROBO_DEVID; 154 var.buf = &devid; 155 var.len = sizeof(devid); 156 157 memset(&ifr, 0, sizeof(ifr)); 158 strcpy(ifr.ifr_name, "eth0"); // is it always the same? 159 ifr.ifr_data = (caddr_t) &var; 160 161 ret = ioctl(fd, SIOCSETGETVAR, (caddr_t)&ifr); 162 close(fd); 163 if (ret < 0) 164 goto skip; 165 if (devid == 0x25) 166 return SWITCH_BCM5325; 167 else if (devid == 0x3115) 168 return SWITCH_BCM53115; 169 else if (devid == 0x3125) 170 return SWITCH_BCM53125; 171 else if ((devid & 0xfffffff0) == 0x53010) 172 return SWITCH_BCM5301x; 173 174skip: 175 return SWITCH_UNKNOWN; 176} 177 178int robo_ioctl(int fd, int write, int page, int reg, uint32_t *value) 179{ 180 static int __ioctl_args[2] = { SIOCGETCROBORD, SIOCSETCROBOWR }; 181 struct ifreq ifr; 182 int ret, vecarg[4]; 183 184 memset(&ifr, 0, sizeof(ifr)); 185 strcpy(ifr.ifr_name, "eth0"); // is it always the same? 186 ifr.ifr_data = (caddr_t) vecarg; 187 188 vecarg[0] = (page << 16) | reg; 189#if defined(BCM5301X) || defined(RTAC1200G) || defined(RTAC1200GP) 190 vecarg[1] = 0; 191 vecarg[2] = *value; 192#else 193 vecarg[1] = *value; 194#endif 195 ret = ioctl(fd, __ioctl_args[write], (caddr_t)&ifr); 196 197#if defined(BCM5301X) || defined(RTAC1200G) || defined(RTAC1200GP) 198 *value = vecarg[2]; 199#else 200 *value = vecarg[1]; 201#endif 202 203 return ret; 204} 205 206int phy_ioctl(int fd, int write, int phy, int reg, uint32_t *value) 207{ 208#ifndef BCM5301X 209 static int __ioctl_args[2] = { SIOCGETCPHYRD2, SIOCSETCPHYWR2 }; 210 struct ifreq ifr; 211 int ret, vecarg[2]; 212 213 memset(&ifr, 0, sizeof(ifr)); 214 strcpy(ifr.ifr_name, "eth0"); // is it always the same? 215 ifr.ifr_data = (caddr_t) vecarg; 216 217 vecarg[0] = (phy << 16) | reg; 218 vecarg[1] = *value; 219 ret = ioctl(fd, __ioctl_args[write], (caddr_t)&ifr); 220 221 *value = vecarg[1]; 222 223 return ret; 224#else 225 return robo_ioctl(fd, write, 0x10 + phy, reg, value); 226#endif 227} 228 229// !0: connected 230// 0: disconnected 231uint32_t get_phy_status(uint32_t portmask) 232{ 233 int fd, model; 234 uint32_t value, mask = 0; 235#ifndef BCM5301X 236 int i; 237#endif 238 239 model = get_switch(); 240 if (model == SWITCH_UNKNOWN) return 0; 241 242 fd = socket(AF_INET, SOCK_DGRAM, 0); 243 if (fd < 0) return 0; 244 245 switch (model) { 246#ifndef BCM5301X 247 case SWITCH_BCM53125: 248#ifdef RTCONFIG_LANWAN_LED 249 /* N15U can't read link status from phy sometimes */ 250 if (get_model() == MODEL_RTN15U) 251 goto case_SWITCH_ROBORD; 252 /* fall through */ 253#endif 254 case SWITCH_BCM53115: 255 case SWITCH_BCM5325: 256 for (i = 0; i < 5 && (portmask >> i); i++) { 257 if ((portmask & (1U << i)) == 0) 258 continue; 259 260 if (phy_ioctl(fd, 0, i, 0x01, &value) < 0) 261 continue; 262 /* link is down, but negotiation has started 263 * read register again, use previous value, if failed */ 264 if ((value & 0x22) == 0x20) 265 phy_ioctl(fd, 0, i, 0x01, &value); 266 267 if (value & (1U << 2)) 268 mask |= (1U << i); 269 } 270 break; 271#ifdef RTCONFIG_LANWAN_LED 272 case_SWITCH_ROBORD: 273 /* fall through */ 274#endif 275#endif 276 case SWITCH_BCM5301x: 277 if (robo_ioctl(fd, 0, 0x01, 0x00, &value) < 0) 278 _dprintf("et ioctl SIOCGETCROBORD failed!\n"); 279 mask = value & portmask & 0x1f; 280 break; 281 } 282 close(fd); 283 284 //_dprintf("# get_phy_status %x %x\n", mask, portmask); 285 286 return mask; 287} 288 289// 2bit per port (0-4(5)*2 shift) 290// 0: 10 Mbps 291// 1: 100 Mbps 292// 2: 1000 Mbps 293uint32_t get_phy_speed(uint32_t portmask) 294{ 295 int fd, model; 296 uint32_t value, mask = 0; 297 298 model = get_switch(); 299 if (model == SWITCH_UNKNOWN) return 0; 300 301 fd = socket(AF_INET, SOCK_DGRAM, 0); 302 if (fd < 0) return 0; 303 304 if (robo_ioctl(fd, 0, 0x01, 0x04, &value) < 0) 305 value = 0; 306 close(fd); 307 308 switch (model) { 309#ifndef BCM5301X 310 case SWITCH_BCM5325: 311 /* 5325E/535x, 1bit: 0=10 Mbps, 1=100Mbps */ 312 for (mask = 0; value & 0x1f; value >>= 1) { 313 mask |= (value & 0x01); 314 mask <<= 2; 315 } 316 swapportstatus(mask); 317 break; 318 case SWITCH_BCM53115: 319 case SWITCH_BCM53125: 320 /* fall through */ 321#endif 322 case SWITCH_BCM5301x: 323 /* 5301x/53115/53125, 2bit:00=10 Mbps,01=100Mbps,10=1000Mbps */ 324 mask = value & portmask & 0x3ff; 325 break; 326 } 327 328 //_dprintf("get_phy_speed %x %x\n", vecarg[1], portmask); 329 330 return mask; 331} 332 333uint32_t set_phy_ctrl(uint32_t portmask, int ctrl) 334{ 335 int fd, i, model; 336 uint32_t value; 337 338 model = get_switch(); 339 if (model == SWITCH_UNKNOWN) return 0; 340 341 fd = socket(AF_INET, SOCK_DGRAM, 0); 342 if (fd < 0) return 0; 343 344 for (i = 0; i < 5 && (portmask >> i); i++) { 345 if ((portmask & (1U << i)) == 0) 346 continue; 347 348 switch (model) { 349#ifndef BCM5301X 350 case SWITCH_BCM5325: 351 if (phy_ioctl(fd, 0, i, 0x1e, &value) < 0) 352 value = 0; 353 value &= 0x0007; 354 value |= ctrl ? 0 : 0x0008; 355 phy_ioctl(fd, 1, i, 0x1e, &value); 356 value = 0x3300; 357 break; 358 case SWITCH_BCM53115: 359 case SWITCH_BCM53125: 360 /* fall through */ 361#endif 362 case SWITCH_BCM5301x: 363 value = 0x1340; 364 value |= ctrl ? 0 : 0x0800; 365 break; 366 default: 367 continue; 368 } 369 370 /* issue write */ 371 phy_ioctl(fd, 1, i, 0, &value); 372 } 373 374 close(fd); 375 376 return 0; 377} 378 379#define IMAGE_HEADER "HDR0" 380#define MAX_VERSION_LEN 64 381#define MAX_PID_LEN 12 382#define MAX_HW_COUNT 4 383 384/* 385 * 0: illegal image 386 * 1: legal image 387 */ 388int 389check_crc(char *fname) 390{ 391 FILE *fp; 392 int ret = 1; 393 int first_read = 1; 394 unsigned int len, count; 395 396 struct trx_header trx; 397 uint32 crc; 398 static uint32 buf[16*1024]; 399 400 fp = fopen(fname, "r"); 401 if (fp == NULL) 402 { 403 _dprintf("Open trx fail!!!\n"); 404 return 0; 405 } 406 407 /* Read header */ 408 ret = fread((unsigned char *) &trx, 1, sizeof(struct trx_header), fp); 409 if (ret != sizeof(struct trx_header)) { 410 ret = 0; 411 _dprintf("read header error!!!\n"); 412 goto done; 413 } 414 415 /* Checksum over header */ 416 crc = hndcrc32((uint8 *) &trx.flag_version, 417 sizeof(struct trx_header) - OFFSETOF(struct trx_header, flag_version), 418 CRC32_INIT_VALUE); 419 420 for (len = ltoh32(trx.len) - sizeof(struct trx_header); len; len -= count) { 421 if (first_read) { 422 count = MIN(len, sizeof(buf) - sizeof(struct trx_header)); 423 first_read = 0; 424 } else 425 count = MIN(len, sizeof(buf)); 426 427 /* Read data */ 428 ret = fread((unsigned char *) &buf, 1, count, fp); 429 if (ret != count) { 430 ret = 0; 431 _dprintf("read error!\n"); 432 goto done; 433 } 434 435 /* Checksum over data */ 436 crc = hndcrc32((uint8 *) &buf, count, crc); 437 } 438 /* Verify checksum */ 439 //_dprintf("checksum: %u ? %u\n", ltoh32(trx.crc32), crc); 440 if (ltoh32(trx.crc32) != crc) { 441 ret = 0; 442 goto done; 443 } 444 445done: 446 fclose(fp); 447 448 return ret; 449} 450 451/* 452 * 0: illegal image 453 * 1: legal image 454 */ 455 456int check_imageheader(char *buf, long *filelen) 457{ 458 long aligned; 459 460 if (strncmp(buf, IMAGE_HEADER, sizeof(IMAGE_HEADER) - 1) == 0) 461 { 462 memcpy(&aligned, buf + sizeof(IMAGE_HEADER) - 1, sizeof(aligned)); 463 *filelen = aligned; 464#ifdef RTCONFIG_DSL_TCLINUX 465 *filelen+=0x790000; 466#endif 467 _dprintf("image len: %x\n", aligned); 468 return 1; 469 } 470 else return 0; 471} 472 473/* 474 * 0: illegal image 475 * 1: legal image 476 * 477 * check product id, crc .. 478 */ 479 480int check_imagefile(char *fname) 481{ 482 FILE *fp; 483 struct version_t { 484 uint8_t ver[4]; /* Firmware version */ 485 uint8_t pid[MAX_PID_LEN]; /* Product Id */ 486 uint8_t hw[MAX_HW_COUNT][4]; /* Compatible hw list lo maj.min, hi maj.min */ 487#ifdef RTCONFIG_BCMWL6A 488 uint16_t sn; 489 uint16_t en; 490#endif 491 uint8_t pad[0]; /* Padding up to MAX_VERSION_LEN */ 492 } version; 493 int i, model; 494 495 fp = fopen(fname, "r"); 496 if (fp == NULL) 497 return 0; 498 499 fseek(fp, -MAX_VERSION_LEN, SEEK_END); 500 fread(&version, 1, sizeof(version), fp); 501 fclose(fp); 502 503 _dprintf("productid field in image: %.12s\n", version.pid); 504 505 for (i = 0; i < sizeof(version); i++) 506 _dprintf("%02x ", ((uint8_t *)&version)[i]); 507 _dprintf("\n"); 508 509 /* safe strip trailing spaces */ 510 for (i = 0; i < MAX_PID_LEN && version.pid[i] != '\0'; i++); 511 for (i--; i >= 0 && version.pid[i] == '\x20'; i--) 512 version.pid[i] = '\0'; 513 514 if (!check_crc(fname)) { 515 _dprintf("check crc error!!!\n"); 516 return 0; 517 } 518 519#if defined(RTCONFIG_BCMWL6A) && !(defined(RTCONFIG_BCM7) || defined(RTCONFIG_BCM_7114)) 520 doSystem("nvram set cpurev=`cat /dev/mtd0 | grep cpurev | cut -d \"=\" -f 2`"); 521 if (nvram_match("cpurev", "c0") && 522 (!version.sn || 523 !version.en || 524 version.sn < 380 || 525 (version.sn == 380 && version.en < 738))) 526 { 527 dbg("version check fail!\n"); 528 return 0; 529 } 530#endif 531 532 model = get_model(); 533 534 /* compare up to the first \0 or MAX_PID_LEN 535 * nvram productid or hw model's original productid */ 536 if (strncmp(nvram_safe_get("productid"), (char *) version.pid, MAX_PID_LEN) == 0 || 537 strncmp(get_modelid(model), (char *) (char *) version.pid, MAX_PID_LEN) == 0) 538 { 539 return 1; 540 } 541 542 /* common RT-N12 productid FW image */ 543 if ((model == MODEL_RTN12B1 || model == MODEL_RTN12C1 || 544 model == MODEL_RTN12D1 || model == MODEL_RTN12VP || model == MODEL_RTN12HP || model == MODEL_RTN12HP_B1 ||model == MODEL_APN12HP) && 545 strncmp(get_modelid(MODEL_RTN12), (char *) version.pid, MAX_PID_LEN) == 0) 546 return 1; 547 548 return 0; 549} 550 551#ifdef RTCONFIG_QTN 552char *wl_vifname_qtn(int unit, int subunit) 553{ 554 static char tmp[128]; 555 556 if ((subunit > 0) && (subunit < 4)) 557 { 558 sprintf(tmp, "wifi%d", subunit); 559 return strdup(tmp); 560 } 561 else 562 return strdup(""); 563} 564#endif 565 566int get_radio(int unit, int subunit) 567{ 568 int n = 0; 569 570 //_dprintf("get radio %x %x %s\n", unit, subunit, nvram_safe_get(wl_nvname("ifname", unit, subunit))); 571 572#ifdef RTCONFIG_QTN 573 int ret; 574 char interface_status = 0; 575 576 if (unit) 577 { 578 if(!rpc_qtn_ready()) 579 return -1; 580 581 if (subunit > 0) 582 { 583 ret = qcsapi_interface_get_status(wl_vifname_qtn(unit, subunit), &interface_status); 584// if (ret < 0) 585// dbG("Qcsapi qcsapi_interface_get_status %s error, return: %d\n", wl_vifname_qtn(unit, subunit), ret); 586 587 return interface_status; 588 } 589 else 590 { 591 ret = qcsapi_wifi_rfstatus((qcsapi_unsigned_int *) &n); 592// if (ret < 0) 593// dbG("Qcsapi qcsapi_wifi_rfstatus %s error, return: %d\n", wl_vifname_qtn(unit, subunit), ret); 594 595 return n; 596 } 597 } 598 else 599#endif 600 601 return (wl_ioctl(nvram_safe_get(wl_nvname("ifname", unit, subunit)), WLC_GET_RADIO, &n, sizeof(n)) == 0) && 602 !(n & (WL_RADIO_SW_DISABLE | WL_RADIO_HW_DISABLE)); 603} 604 605void set_radio(int on, int unit, int subunit) 606{ 607 uint32 n; 608 char tmp[100], prefix[] = "wlXXXXXXXXXXXXXX"; 609 610#ifdef RTCONFIG_QTN 611 if (unit) { 612 if (!rpc_qtn_ready()) 613 return; 614 615 rpc_set_radio(unit, subunit, on); 616 617 return; 618 } 619#endif 620 //_dprintf("set radio %x %x %x %s\n", on, unit, subunit, nvram_safe_get(wl_nvname("ifname", unit, subunit))); 621 622 if (subunit > 0) 623 snprintf(prefix, sizeof(prefix), "wl%d.%d_", unit, subunit); 624 else 625 snprintf(prefix, sizeof(prefix), "wl%d_", unit); 626 627 //if (nvram_match(strcat_r(prefix, "radio", tmp), "0")) return; 628 629#if defined(RTAC66U) || defined(BCM4352) 630 if ((unit == 1) & (subunit < 1)) { 631 if (on) { 632#ifndef RTCONFIG_LED_BTN 633 if (!(nvram_get_int("sw_mode")==SW_MODE_AP && nvram_get_int("wlc_psta")==1 && nvram_get_int("wlc_band")==0)) { 634 nvram_set("led_5g", "1"); 635 led_control(LED_5G, LED_ON); 636 } 637#else 638 nvram_set("led_5g", "1"); 639 if (nvram_get_int("AllLED")) 640 led_control(LED_5G, LED_ON); 641#endif 642 } 643 else { 644 nvram_set("led_5g", "0"); 645 led_control(LED_5G, LED_OFF); 646 } 647 } 648#endif 649 650 if (subunit > 0) { 651 sprintf(tmp, "%d", subunit); 652 if (on) eval("wl", "-i", nvram_safe_get(wl_nvname("ifname", unit, 0)), "bss", "-C", tmp, "up"); 653 else eval("wl", "-i", nvram_safe_get(wl_nvname("ifname", unit, 0)), "bss", "-C", tmp, "down"); 654 655 return; 656 } 657 658#ifndef WL_BSS_INFO_VERSION 659#error WL_BSS_INFO_VERSION 660#endif 661 662#if WL_BSS_INFO_VERSION >= 108 663 n = on ? (WL_RADIO_SW_DISABLE << 16) : ((WL_RADIO_SW_DISABLE << 16) | 1); 664 wl_ioctl(nvram_safe_get(wl_nvname("ifname", unit, subunit)), WLC_SET_RADIO, &n, sizeof(n)); 665 if (!on) { 666 //led(LED_WLAN, 0); 667 //led(LED_DIAG, 0); 668 } 669#else 670 n = on ? 0 : WL_RADIO_SW_DISABLE; 671 wl_ioctl(nvram_safe_get(wl_nvname("ifname", unit, subunit)), WLC_SET_RADIO, &n, sizeof(n)); 672 if (!on) { 673 //led(LED_DIAG, 0); 674 } 675#endif 676} 677