1#include <stdio.h> 2#include <stdlib.h> 3#include <unistd.h> 4#include <fcntl.h> 5#include <sys/stat.h> 6#include <sys/mman.h> 7 8#include <bcmnvram.h> 9 10#include <rtconfig.h> 11#include <flash_mtd.h> 12#include <shutils.h> 13#include <shared.h> 14#include <plc_utils.h> 15 16#ifdef RTCONFIG_QCA 17#include <qca.h> 18#endif 19 20/* 21 * Convert PLC Key (e.g. NMK, DAK) string representation to binary data 22 * @param a string in xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx notation 23 * @param e binary data 24 * @return TRUE if conversion was successful and FALSE otherwise 25 */ 26int 27key_atoe(const char *a, unsigned char *e) 28{ 29 char *c = (char *) a; 30 int i = 0; 31 32 memset(e, 0, PLC_KEY_LEN); 33 for (;;) { 34 e[i++] = (unsigned char) strtoul(c, &c, 16); 35 if (!*c++ || i == PLC_KEY_LEN) 36 break; 37 } 38 return (i == PLC_KEY_LEN); 39} 40 41/* 42 * Convert PLC Key binary data to string representation 43 * @param e binary data 44 * @param a string in xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx notation 45 * @return a 46 */ 47char * 48key_etoa(const unsigned char *e, char *a) 49{ 50 char *c = a; 51 int i; 52 53 for (i = 0; i < PLC_KEY_LEN; i++) { 54 if (i) 55 *c++ = ':'; 56 c += sprintf(c, "%02X", e[i] & 0xff); 57 } 58 return a; 59} 60 61/* 62 * increase n to mac last 24 bits and handle a carry problem 63 */ 64static void inc_mac(unsigned char n, unsigned char *mac) 65{ 66 int c = 0; 67 68 //dbg("MAC + %u\n", n); 69 70 if (mac[5] >= (0xff - n + 1)) 71 c = 1; 72 else 73 c = 0; 74 mac[5] += n; 75 76 if (c == 1) { 77 if (mac[4] >= 0xff) 78 c = 1; 79 else 80 c = 0; 81 mac[4] += 1; 82 83 if (c == 1) 84 mac[3] += 1; 85 } 86} 87 88/* 89 * check PLC MAC/Key 90 * reference isValidMacAddr() in rc/ate.c 91 */ 92int isValidPara(const char* str, int len) 93{ 94 #define MULTICAST_BIT 0x0001 95 #define UNIQUE_OUI_BIT 0x0002 96 int sec_byte; 97 int i = 0, s = 0; 98 99 if (strlen(str) != ((len * 2) + len - 1)) 100 return 0; 101 102 while (*str && i < (len * 2)) { 103 if (isxdigit(*str)) { 104 if (i == 1 && len == ETHER_ADDR_LEN) { 105 sec_byte = strtol(str, NULL, 16); 106 if ((sec_byte & MULTICAST_BIT) || (sec_byte & UNIQUE_OUI_BIT)) 107 break; 108 } 109 i++; 110 } 111 else if (*str == ':') { 112 if (i == 0 || i/2-1 != s) 113 break; 114 ++s; 115 } 116 ++str; 117 } 118 return (i == (len * 2) && s == (len - 1)); 119} 120 121static int __getPLC_para(char *ebuf, int addr) 122{ 123 int len; 124 125 if (addr == OFFSET_PLC_MAC) 126 len = ETHER_ADDR_LEN; 127 else if (addr == OFFSET_PLC_NMK) 128 len = PLC_KEY_LEN; 129 else 130 return 0; 131 132 memset(ebuf, 0, sizeof(ebuf)); 133 134 if (FRead(ebuf, addr, len) < 0) { 135 dbg("READ PLC parameter: Out of scope\n"); 136 return 0; 137 } 138 139 return 1; 140} 141 142/* 143 * get PLC MAC from factory partition 144 */ 145int getPLC_MAC(char *abuf) 146{ 147 unsigned char ebuf[ETHER_ADDR_LEN]; 148 149 if (__getPLC_para(ebuf, OFFSET_PLC_MAC)) { 150 memset(abuf, 0, sizeof(abuf)); 151 if (ether_etoa(ebuf, abuf)) 152 return 1; 153 } 154 155 return 0; 156} 157 158/* 159 * get PLC NMK from factory partition 160 */ 161int getPLC_NMK(char *abuf) 162{ 163 unsigned char ebuf[PLC_KEY_LEN]; 164 165 if (__getPLC_para(ebuf, OFFSET_PLC_NMK)) { 166 memset(abuf, 0, sizeof(abuf)); 167 if (key_etoa(ebuf, abuf)) 168 return 1; 169 } 170 171 return 0; 172} 173 174/* 175 * ATE get PLC password from MAC 176 */ 177static int __getPLC_PWD(unsigned char *emac, char *pwd) 178{ 179 FILE *fp; 180 int len; 181 char cmd[64], buf[32]; 182 183 inc_mac(2, emac); 184 sprintf(cmd, "/usr/local/bin/mac2pw -q %02x%02x%02x%02x%02x%02x", emac[0], emac[1], emac[2], emac[3], emac[4], emac[5]); 185 fp = popen(cmd, "r"); 186 if (fp) { 187 len = fread(buf, 1, sizeof(buf), fp); 188 pclose(fp); 189 if (len > 1) { 190 buf[len - 1] = '\0'; 191 strcpy(pwd, buf); 192 } 193 else 194 return 0; 195 } 196 else 197 return 0; 198 199 return 1; 200} 201 202int getPLC_PWD(void) 203{ 204 unsigned char ebuf[ETHER_ADDR_LEN]; 205 char pwd[32]; 206 207 if (__getPLC_para(ebuf, OFFSET_PLC_MAC)) { 208 memset(pwd, 0, sizeof(pwd)); 209 if (!__getPLC_PWD(ebuf, pwd)) 210 return 0; 211 212 puts(pwd); 213 } 214 else 215 return 0; 216 217 return 1; 218} 219 220/* 221 * ATE get/set PLC parameter from/to factory partition, e.g. MAC, NMK 222 */ 223int getPLC_para(int addr) 224{ 225 char abuf[64], ebuf[16]; 226 227 228 if (__getPLC_para(ebuf, addr)) { 229 memset(abuf, 0, sizeof(abuf)); 230 if (addr == OFFSET_PLC_MAC) 231 ether_etoa(ebuf, abuf); 232 else 233 key_etoa(ebuf, abuf); 234 puts(abuf); 235 } 236 else 237 return 0; 238 239 return 1; 240} 241 242int setPLC_para(const char *abuf, int addr) 243{ 244 unsigned char ebuf[32]; 245 int len, ret; 246 247 if (abuf == NULL) 248 return 0; 249 250 memset(ebuf, 0, sizeof(ebuf)); 251 252 if (addr == OFFSET_PLC_MAC) { 253 len = ETHER_ADDR_LEN; 254 if (!isValidPara(abuf, len)) 255 return 0; 256 257 ret = ether_atoe(abuf, ebuf); 258 } else if (addr == OFFSET_PLC_NMK) { 259 len = PLC_KEY_LEN; 260 if (!isValidPara(abuf, len)) 261 return 0; 262 263 ret = key_atoe(abuf, ebuf); 264 } else 265 return 0; 266 267 if (ret) { 268 FWrite(ebuf, addr, len); 269 getPLC_para(addr); 270 return 1; 271 } 272 else 273 return 0; 274} 275 276/* 277 * modify the value of specific offset 278 */ 279static int modify_pib_byte(unsigned int offset, unsigned int value) 280{ 281 return doSystem("/usr/local/bin/setpib -x %s 0x%x data %02x", BOOT_PIB_PATH, offset, value); 282} 283 284/* 285 * disable all LED event of PLC except Power event 286 */ 287void ate_ctl_plc_led(void) 288{ 289 int i = 0; 290 291 for (i = 0; i < 18; i++) { 292#if defined(RTCONFIG_AR7420) 293 if (i == 7) /* Power event */ 294 continue; 295 modify_pib_byte((0x1B13 + (8 * i)), 0x1); 296#elif defined(RTCONFIG_QCA7500) 297 if (i == 11) /* Power event */ 298 continue; 299 modify_pib_byte((0x21A7 + (8 * i)), 0x1); 300#endif 301 } 302} 303 304/* 305 * ATE turn on/off all LED of PLC 306 */ 307int set_plc_all_led_onoff(int on) 308{ 309 if (on) { 310#if defined(RTCONFIG_AR7420) 311 modify_pib_byte(0x1B49, 0x61); /* GPIO 0, 5, 6 */ 312#elif defined(RTCONFIG_QCA7500) 313 modify_pib_byte(0x21FD, 0xC0); /* GPIO 6, 7 */ 314 modify_pib_byte(0x21FE, 0x0); 315#endif 316 } 317 else { 318#if defined(RTCONFIG_AR7420) 319 modify_pib_byte(0x1B49, 0x0); 320#elif defined(RTCONFIG_QCA7500) 321 modify_pib_byte(0x21FD, 0x0); 322 modify_pib_byte(0x21FE, 0x02); /* GPIO 9 */ 323#endif 324 } 325 326 system("/usr/local/bin/plctool -i br0 -R -e > /dev/null"); 327 328 return 0; 329} 330 331 332/* 333 * backup user's .nvm and .pib mechanism 334 */ 335#define PLC_MAGIC 0x27051956 /* PLC Image Magic Number */ 336#define DEFAULT_NVM_PATH "/usr/local/bin/asus.nvm" 337#define DEFAULT_PIB_PATH "/usr/local/bin/asus.pib" 338#define USER_NVM_PATH "/tmp/user.nvm" 339#define USER_PIB_PATH "/tmp/user.pib" 340#define HDR_PATH "/tmp/plc.hdr" 341#define IMAGE_PATH "/tmp/plc.img" 342#define RD_SIZE 65536 343 344#define PLC_MTD_NAME "plc" 345#define PLC_MTD_DEV "mtd5" 346 347#ifndef MAP_FAILED 348#define MAP_FAILED (-1) 349#endif 350 351typedef struct _plc_image_header { 352 unsigned int magic; /* PLC Image Header Magic Number */ 353 unsigned int hdr_crc; /* PLC Image Header crc checksum */ 354#if defined(PLN12) 355 unsigned int nvm_size; /* PLC .nvm size */ 356 unsigned int nvm_crc; /* PLC .nvm crc checksum */ 357#endif 358 unsigned int pib_size; /* PLC .pib size */ 359 unsigned int pib_crc; /* PLC .pib crc checksum */ 360} plc_image_header; 361 362plc_image_header header; 363 364/* 365 * check crc of header 366 * 367 * : input, file name 368 * 369 * return 370 * 1: match 371 * 0: mismatch or fail 372 */ 373static int hdr_match_crc(plc_image_header *hdr) 374{ 375 unsigned int checksum, checksum_org; 376 377 checksum_org = hdr->hdr_crc; 378 hdr->hdr_crc = 0; 379 checksum = crc_calc(0, (const char *)hdr, sizeof(plc_image_header)); 380 fprintf(stderr, "%s: crc %x/%x of header\n", __func__, checksum_org, checksum); 381 382 if (checksum != checksum_org) { 383 fprintf(stderr, "%s: header crc mismatch!\n", __func__); 384 return 0; 385 } 386 387 return 1; 388} 389 390/* 391 * get file length and crc 392 * 393 * fname: input, file name 394 * len: output, file length 395 * crc: output, file crc 396 */ 397static int get_crc(char* fname, unsigned int *len, unsigned int *crc) 398{ 399 int fd, ret = -1; 400 struct stat fs; 401 unsigned char *ptr = NULL; 402 403 if ((fd = open(fname, O_RDONLY)) < 0) { 404 fprintf(stderr, "%s: Can't open %s\n", __func__, fname); 405 goto open_fail; 406 } 407 408 if (fstat(fd, &fs) < 0) { 409 fprintf(stderr, "%s: Can't stat %s\n", __func__, fname); 410 goto checkcrc_fail; 411 } 412 *len = fs.st_size; 413 414 ptr = (unsigned char *)mmap(0, fs.st_size, PROT_READ, MAP_SHARED, fd, 0); 415 if (ptr == (unsigned char *)MAP_FAILED) { 416 fprintf(stderr, "%s: Can't map %s\n", __func__, fname); 417 goto checkcrc_fail; 418 } 419 *crc = crc_calc(0, (const char *)ptr, fs.st_size); 420 421 ret = 0; 422 423checkcrc_fail: 424 if (ptr != NULL) 425 munmap(ptr, fs.st_size); 426#if defined(_POSIX_SYNCHRONIZED_IO) && !defined(__sun__) && !defined(__FreeBSD__) 427 (void)fdatasync(fd); 428#else 429 (void)fsync(fd); 430#endif 431 close(fd); 432 433open_fail: 434 return ret; 435} 436 437/* 438 * check crc of file and header record 439 * 440 * fname: input, file name 441 * crc: input, header record 442 * 443 * return 444 * 1: match 445 * 0: mismatch or fail 446 */ 447static int match_crc(char *fname, unsigned int crc) 448{ 449 unsigned int len, checksum; 450 451 if (get_crc(fname, &len, &checksum)) { 452 fprintf(stderr, "%s: Can't check crc of %s\n", __func__, fname); 453 return 0; 454 } 455 fprintf(stderr, "%s: crc %x/%x of %s\n", __func__, crc, checksum, fname); 456 457 if (checksum != crc) { 458 fprintf(stderr, "%s: %s crc mismatch!\n", __func__, fname); 459 return 0; 460 } 461 462 return 1; 463} 464 465/* 466 * read .nvm and .pib from flash 467 */ 468#if defined(PLN12) 469static int plc_read_from_flash(char *nvm_path, char *pib_path) 470#else 471static int plc_read_from_flash(char *pib_path) 472#endif 473{ 474 int rfd, wfd, ret = -1; 475 unsigned int rlen, wlen; 476 plc_image_header *hdr = &header; 477 char cmd[32], buf[RD_SIZE]; 478 479 sprintf(cmd, "cat /dev/%s > %s", PLC_MTD_DEV, IMAGE_PATH); 480 system(cmd); 481 482 memset(hdr, 0, sizeof(plc_image_header)); 483 // header 484 if ((rfd = open(IMAGE_PATH, O_RDONLY)) < 0) { 485 fprintf(stderr, "%s: Can't open %s\n", __func__, IMAGE_PATH); 486 goto open_fail; 487 } 488 rlen = read(rfd, hdr, sizeof(plc_image_header)); 489 // check header crc and magic number 490 if (hdr_match_crc(hdr) == 0 || hdr->magic != PLC_MAGIC) 491 goto mismatch; 492 493 memset(buf, 0, sizeof(buf)); 494#if defined(PLN12) 495 // .nvm 496 wlen = hdr->nvm_size; 497 if ((wfd = open(nvm_path, O_RDWR|O_CREAT, 0666)) < 0) { 498 fprintf(stderr, "%s: Can't open %s\n", __func__, nvm_path); 499 goto mismatch; 500 } 501 while (wlen > 0) { 502 if (wlen > RD_SIZE) 503 rlen = read(rfd, buf, RD_SIZE); 504 else 505 rlen = read(rfd, buf, wlen); 506 write(wfd, buf, rlen); 507 wlen -= rlen; 508 } 509 close(wfd); 510 // check .nvm crc 511 if (match_crc(nvm_path, hdr->nvm_crc) == 0) 512 goto mismatch; 513#endif 514 515 // .pib 516 wlen = hdr->pib_size; 517 if ((wfd = open(pib_path, O_RDWR|O_CREAT, 0666)) < 0) { 518 fprintf(stderr, "%s: Can't open %s\n", __func__, pib_path); 519 goto mismatch; 520 } 521 while (wlen > 0) { 522 if (wlen > RD_SIZE) 523 rlen = read(rfd, buf, RD_SIZE); 524 else 525 rlen = read(rfd, buf, wlen); 526 write(wfd, buf, rlen); 527 wlen -= rlen; 528 } 529 close(wfd); 530 // check .pib crc 531 if (match_crc(pib_path, hdr->pib_crc) == 0) 532 goto mismatch; 533 534 ret = 0; 535 536mismatch: 537 close(rfd); 538 539open_fail: 540 unlink(IMAGE_PATH); 541 542 return ret; 543} 544 545/* 546 * write .nvm and .pib to flash 547 */ 548#if defined(PLN12) 549static int plc_write_to_flash(char *nvm_path, char *pib_path) 550#else 551static int plc_write_to_flash(char *pib_path) 552#endif 553{ 554 int fd, fl; 555 plc_image_header *hdr = &header; 556 char cmd[128]; 557 558 memset(hdr, 0, sizeof(plc_image_header)); 559 hdr->magic = PLC_MAGIC; 560 561#if defined(PLN12) 562 // get length and crc of .nvm 563 if (get_crc(nvm_path, &hdr->nvm_size, &hdr->nvm_crc)) { 564 fprintf(stderr, "%s: Can't check crc of %s\n", __func__, nvm_path); 565 return -1; 566 } 567#endif 568 569 // get length and crc of .pib 570 if (get_crc(pib_path, &hdr->pib_size, &hdr->pib_crc)) { 571 fprintf(stderr, "%s: Can't check crc of %s\n", __func__, pib_path); 572 return -1; 573 } 574 575 // create header 576 hdr->hdr_crc = crc_calc(0, (const char *)hdr, sizeof(plc_image_header)); 577 if ((fd = open(HDR_PATH, O_RDWR|O_CREAT, 0666)) < 0) { 578 fprintf(stderr, "%s: Can't open %s\n", __func__, HDR_PATH); 579 return -1; 580 } 581 write(fd, hdr, sizeof(plc_image_header)); 582 close(fd); 583 584 // write to plc partition 585 while (1) { 586 if ((fl = open(PLC_LOCK_FILE, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600)) >= 0) { 587#if defined(PLN12) 588 sprintf(cmd, "cat %s %s %s > %s", HDR_PATH, nvm_path, pib_path, IMAGE_PATH); 589#else 590 sprintf(cmd, "cat %s %s > %s", HDR_PATH, pib_path, IMAGE_PATH); 591#endif 592 system(cmd); 593 sprintf(cmd, "mtd-write -i %s -d %s", IMAGE_PATH, PLC_MTD_NAME); 594 system(cmd); 595 close(PLC_LOCK_FILE); 596 unlink(PLC_LOCK_FILE); 597 break; 598 } 599 else { 600 dbg("%s: PLC file lock! Try again after waiting 1 sec\n", __func__); 601 sleep(1); 602 } 603 } 604 605 unlink(HDR_PATH); 606 unlink(IMAGE_PATH); 607 608 return 0; 609} 610 611/* 612 * write default .nvm and .pib to flash 613 */ 614int default_plc_write_to_flash(void) 615{ 616 FILE *fp; 617 int len, i; 618 char cmd[64], buf[64]; 619 char mac[18], dak[48], nmk[48]; 620 unsigned char emac[ETHER_ADDR_LEN], enmk[PLC_KEY_LEN]; 621 622#if defined(PLN12) 623 doSystem("cp %s %s", DEFAULT_NVM_PATH, BOOT_NVM_PATH); 624#endif 625 doSystem("cp %s %s", DEFAULT_PIB_PATH, BOOT_PIB_PATH); 626 627 // modify .pib 628 // MAC 629 if (!__getPLC_para(emac, OFFSET_PLC_MAC)) { 630 _dprintf("READ PLC MAC: Out of scope\n"); 631 } 632 else { 633 if (emac[0] != 0xff) { 634 if (ether_etoa(emac, mac)) 635 doSystem("/usr/local/bin/modpib %s -M %s", BOOT_PIB_PATH, mac); 636 637 // DAK 638 if (__getPLC_PWD(emac, buf)) { 639 sprintf(cmd, "/usr/local/bin/hpavkey -D %s", buf); 640 fp = popen(cmd, "r"); 641 if (fp) { 642 len = fread(buf, 1, sizeof(buf), fp); 643 pclose(fp); 644 if (len > 1) { 645 buf[len - 1] = '\0'; 646 647 for (i = 0; i < PLC_KEY_LEN; i++) { 648 if (i == 0) 649 sprintf(dak, "%c%c", buf[0], buf[1]); 650 else 651 sprintf(dak, "%s:%c%c", dak, buf[i*2], buf[i*2+1]); 652 } 653 doSystem("/usr/local/bin/modpib %s -D %s", BOOT_PIB_PATH, dak); 654 } 655 } 656 } 657 } 658 } 659 660 // NMK 661 if (!__getPLC_para(enmk, OFFSET_PLC_NMK)) 662 _dprintf("READ PLC NMK: Out of scope\n"); 663 else { 664 if (enmk[0] != 0xff && enmk[1] != 0xff && enmk[2] != 0xff) { 665 if (key_etoa(enmk, nmk)) 666 doSystem("/usr/local/bin/modpib %s -N %s", BOOT_PIB_PATH, nmk); 667 } 668 } 669 670#if defined(PLN12) 671 return plc_write_to_flash(BOOT_NVM_PATH, BOOT_PIB_PATH); 672#else 673 return plc_write_to_flash(BOOT_PIB_PATH); 674#endif 675} 676 677/* 678 * write default .nvm and .pib to flash, if plc partition is empty. 679 * reload .nvm and .pib to /tmp from flash for plchost utility 680 */ 681int load_plc_setting(void) 682{ 683#if defined(PLN12) 684 if (plc_read_from_flash(BOOT_NVM_PATH, BOOT_PIB_PATH)) 685#else 686 if (plc_read_from_flash(BOOT_PIB_PATH)) 687#endif 688 return default_plc_write_to_flash(); 689 return 0; 690} 691 692/* 693 * set plc_flag nvram for save_plc_setting() function 694 * 695 * because of plc-utils/plc/plchost.c cannot include bcmnvram.h 696 * error: conflicting types for 'bool' from 697 * src-qca/include/typedefs.h 698 * plc-utils/tools/types.h 699 */ 700void set_plc_flag(int flag) 701{ 702 nvram_set_int("plc_flag", flag); 703} 704 705/* 706 * write user .nvm or .pib to flash 707 * case1: backup .nvm 708 * case2: backup .pib 709 * case3: backup .nvm and .pib 710 */ 711void save_plc_setting(void) 712{ 713 switch (atoi(nvram_safe_get("plc_flag"))) { 714 case 2: 715 _dprintf("sleep 10 second for wait pairing done!\n"); 716 sleep(10); 717#if defined(PLN12) 718 plc_write_to_flash(BOOT_NVM_PATH, USER_PIB_PATH); 719#else 720 plc_write_to_flash(USER_PIB_PATH); 721#endif 722 break; 723#if defined(PLN12) 724 case 1: 725 plc_write_to_flash(USER_NVM_PATH, BOOT_PIB_PATH); 726 break; 727 case 3: 728 plc_write_to_flash(USER_NVM_PATH, USER_PIB_PATH); 729 break; 730#endif 731 default: 732 fprintf(stderr, "%s: wrong flag!", __func__); 733 } 734 735 set_plc_flag(-1); 736} 737 738void turn_led_pwr_off(void) 739{ 740 if (!nvram_match("asus_mfg", "0")) 741 return; 742 743 nvram_set("plc_ready", "1"); 744 745#if (defined(PLN12) || defined(PLAC56)) 746 led_control(LED_POWER_RED, LED_OFF); 747#endif 748} 749