1 /*- 2 * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer, 10 * without modification. 11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 13 * redistribution must be conditioned upon including a substantially 14 * similar Disclaimer requirement for further binary redistribution. 15 * 16 * NO WARRANTY 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 20 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 22 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 * THE POSSIBILITY OF SUCH DAMAGES. 28 */ 29 #include "diag.h" 30 31 #include "ah.h" 32 #include "ah_internal.h" 33 /* XXX cheat, 5212 has a superset of the key table defs */ 34 #include "ar5212/ar5212reg.h" 35 36 #include "dumpregs.h" 37 38 #include <getopt.h> 39 #include <stdlib.h> 40 #include <string.h> 41 #include <ctype.h> 42 #include <err.h> 43 44 #include "ctrl.h" 45 46 typedef struct { 47 HAL_REVS revs; 48 u_int32_t regdata[0xffff / sizeof(u_int32_t)]; 49 #define MAXREGS 5*1024 50 struct dumpreg *regs[MAXREGS]; 51 u_int nregs; 52 u_int show_names : 1, 53 show_addrs : 1; 54 } dumpregs_t; 55 static dumpregs_t state; 56 57 #undef OS_REG_READ 58 #define OS_REG_READ(ah, off) state.regdata[(off) >> 2] 59 60 static int ath_hal_anyregs(int what); 61 static int ath_hal_setupregs(struct ath_diag *atd, int what); 62 static u_int ath_hal_setupdiagregs(const HAL_REGRANGE regs[], u_int nr); 63 static void ath_hal_dumpregs(FILE *fd, int what); 64 static void ath_hal_dumprange(FILE *fd, u_int a, u_int b); 65 static void ath_hal_dumpkeycache(FILE *fd, int nkeys); 66 static void ath_hal_dumpint(FILE *fd, int what); 67 static void ath_hal_dumpqcu(FILE *fd, int what); 68 static void ath_hal_dumpdcu(FILE *fd, int what); 69 static void ath_hal_dumpbb(FILE *fd, int what); 70 71 static void 72 usage(void) 73 { 74 fprintf(stderr, "usage: athregs [-i interface] [-abdkmqxz]\n"); 75 fprintf(stderr, "-a display all registers\n"); 76 fprintf(stderr, "-b display baseband registers\n"); 77 fprintf(stderr, "-d display DCU registers\n"); 78 fprintf(stderr, "-k display key cache registers\n"); 79 fprintf(stderr, "-m display \"MAC\" registers (default)\n"); 80 fprintf(stderr, "-q display QCU registers\n"); 81 fprintf(stderr, "-x display XR registers\n"); 82 fprintf(stderr, "-z display interrupt registers\n"); 83 fprintf(stderr, "\n"); 84 fprintf(stderr, "-A display register address\n"); 85 fprintf(stderr, "-N suppress display of register name\n"); 86 exit(-1); 87 } 88 89 int 90 main(int argc, char *argv[]) 91 { 92 struct ath_diag atd; 93 const char *ifname; 94 u_int32_t *data; 95 u_int32_t *dp, *ep; 96 int what, c, i; 97 struct ath_driver_req req; 98 99 ath_driver_req_init(&req); 100 101 ifname = getenv("ATH"); 102 if (!ifname) 103 ifname = ATH_DEFAULT; 104 105 what = 0; 106 state.show_addrs = 0; 107 state.show_names = 1; 108 while ((c = getopt(argc, argv, "i:aAbdkmNqxz")) != -1) 109 switch (c) { 110 case 'a': 111 what |= DUMP_ALL; 112 break; 113 case 'A': 114 state.show_addrs = 1; 115 break; 116 case 'b': 117 what |= DUMP_BASEBAND; 118 break; 119 case 'd': 120 what |= DUMP_DCU; 121 break; 122 case 'k': 123 what |= DUMP_KEYCACHE; 124 break; 125 case 'i': 126 ifname = optarg; 127 break; 128 case 'm': 129 what |= DUMP_BASIC; 130 break; 131 case 'N': 132 state.show_names = 0; 133 break; 134 case 'q': 135 what |= DUMP_QCU; 136 break; 137 case 'x': 138 what |= DUMP_XR; 139 break; 140 case 'z': 141 what |= DUMP_INTERRUPT; 142 break; 143 default: 144 usage(); 145 /*NOTREACHED*/ 146 } 147 148 /* Initialise the driver interface */ 149 if (ath_driver_req_open(&req, ifname) < 0) { 150 exit(127); 151 } 152 153 /* 154 * Whilst we're doing the ath_diag pieces, we have to set this 155 * ourselves. 156 */ 157 strncpy(atd.ad_name, ifname, sizeof (atd.ad_name)); 158 159 argc -= optind; 160 argv += optind; 161 if (what == 0) 162 what = DUMP_BASIC; 163 164 atd.ad_id = HAL_DIAG_REVS; 165 atd.ad_out_data = (caddr_t) &state.revs; 166 atd.ad_out_size = sizeof(state.revs); 167 168 if (ath_driver_req_fetch_diag(&req, SIOCGATHDIAG, &atd) < 0) 169 err(1, "%s", atd.ad_name); 170 171 if (ath_hal_setupregs(&atd, what) == 0) 172 errx(-1, "no registers are known for this part " 173 "(devid 0x%x mac %d.%d phy %d)", state.revs.ah_devid, 174 state.revs.ah_macVersion, state.revs.ah_macRev, 175 state.revs.ah_phyRev); 176 177 atd.ad_out_size = ath_hal_setupdiagregs((HAL_REGRANGE *) atd.ad_in_data, 178 atd.ad_in_size / sizeof(HAL_REGRANGE)); 179 atd.ad_out_data = (caddr_t) malloc(atd.ad_out_size); 180 if (atd.ad_out_data == NULL) { 181 fprintf(stderr, "Cannot malloc output buffer, size %u\n", 182 atd.ad_out_size); 183 exit(-1); 184 } 185 atd.ad_id = HAL_DIAG_REGS | ATH_DIAG_IN | ATH_DIAG_DYN; 186 187 if (ath_driver_req_fetch_diag(&req, SIOCGATHDIAG, &atd) < 0) 188 err(1, "%s", atd.ad_name); 189 190 /* 191 * Expand register data into global space that can be 192 * indexed directly by register offset. 193 */ 194 dp = (u_int32_t *)atd.ad_out_data; 195 ep = (u_int32_t *)(atd.ad_out_data + atd.ad_out_size); 196 while (dp < ep) { 197 u_int r = dp[0]; /* start of range */ 198 u_int e = dp[1]; /* end of range */ 199 dp++; 200 dp++; 201 /* convert offsets to indices */ 202 r >>= 2; e >>= 2; 203 do { 204 if (dp >= ep) { 205 fprintf(stderr, "Warning, botched return data;" 206 "register at offset 0x%x not present\n", 207 r << 2); 208 break; 209 } 210 state.regdata[r++] = *dp++; 211 } while (r <= e); 212 } 213 214 if (what & DUMP_BASIC) 215 ath_hal_dumpregs(stdout, DUMP_BASIC); 216 if ((what & DUMP_INTERRUPT) && ath_hal_anyregs(DUMP_INTERRUPT)) { 217 if (what & DUMP_BASIC) 218 putchar('\n'); 219 if (state.show_addrs) 220 ath_hal_dumpregs(stdout, DUMP_INTERRUPT); 221 else 222 ath_hal_dumpint(stdout, what); 223 } 224 if ((what & DUMP_QCU) && ath_hal_anyregs(DUMP_QCU)) { 225 if (what & (DUMP_BASIC|DUMP_INTERRUPT)) 226 putchar('\n'); 227 if (state.show_addrs) 228 ath_hal_dumpregs(stdout, DUMP_QCU); 229 else 230 ath_hal_dumpqcu(stdout, what); 231 } 232 if ((what & DUMP_DCU) && ath_hal_anyregs(DUMP_DCU)) { 233 if (what & (DUMP_BASIC|DUMP_INTERRUPT|DUMP_QCU)) 234 putchar('\n'); 235 if (state.show_addrs) 236 ath_hal_dumpregs(stdout, DUMP_DCU); 237 else 238 ath_hal_dumpdcu(stdout, what); 239 } 240 if (what & DUMP_KEYCACHE) { 241 if (state.show_addrs) { 242 if (what & (DUMP_BASIC|DUMP_INTERRUPT|DUMP_QCU|DUMP_DCU)) 243 putchar('\n'); 244 ath_hal_dumpregs(stdout, DUMP_KEYCACHE); 245 } else 246 ath_hal_dumpkeycache(stdout, 128); 247 } 248 if (what & DUMP_BASEBAND) { 249 if (what &~ DUMP_BASEBAND) 250 fprintf(stdout, "\n"); 251 ath_hal_dumpbb(stdout, what); 252 } 253 ath_driver_req_close(&req); 254 return 0; 255 } 256 257 static int 258 regcompar(const void *a, const void *b) 259 { 260 const struct dumpreg *ra = *(const struct dumpreg **)a; 261 const struct dumpreg *rb = *(const struct dumpreg **)b; 262 return ra->addr - rb->addr; 263 } 264 265 void 266 register_regs(struct dumpreg *chipregs, u_int nchipregs, 267 int def_srev_min, int def_srev_max, int def_phy_min, int def_phy_max) 268 { 269 const int existing_regs = state.nregs; 270 int i, j; 271 272 for (i = 0; i < nchipregs; i++) { 273 struct dumpreg *nr = &chipregs[i]; 274 if (nr->srevMin == 0) 275 nr->srevMin = def_srev_min; 276 if (nr->srevMax == 0) 277 nr->srevMax = def_srev_max; 278 if (nr->phyMin == 0) 279 nr->phyMin = def_phy_min; 280 if (nr->phyMax == 0) 281 nr->phyMax = def_phy_max; 282 for (j = 0; j < existing_regs; j++) { 283 struct dumpreg *r = state.regs[j]; 284 /* 285 * Check if we can just expand the mac+phy 286 * coverage for the existing entry. 287 */ 288 if (nr->addr == r->addr && 289 (nr->name == r->name || 290 nr->name != NULL && r->name != NULL && 291 strcmp(nr->name, r->name) == 0)) { 292 if (nr->srevMin < r->srevMin && 293 (r->srevMin <= nr->srevMax && 294 nr->srevMax+1 <= r->srevMax)) { 295 r->srevMin = nr->srevMin; 296 goto skip; 297 } 298 if (nr->srevMax > r->srevMax && 299 (r->srevMin <= nr->srevMin && 300 nr->srevMin <= r->srevMax)) { 301 r->srevMax = nr->srevMax; 302 goto skip; 303 } 304 } 305 if (r->addr > nr->addr) 306 break; 307 } 308 /* 309 * New item, add to the end, it'll be sorted below. 310 */ 311 if (state.nregs == MAXREGS) 312 errx(-1, "too many registers; bump MAXREGS"); 313 state.regs[state.nregs++] = nr; 314 skip: 315 ; 316 } 317 qsort(state.regs, state.nregs, sizeof(struct dumpreg *), regcompar); 318 } 319 320 void 321 register_keycache(u_int nslots, 322 int def_srev_min, int def_srev_max, int def_phy_min, int def_phy_max) 323 { 324 #define SET(r, a) do { \ 325 r->addr = a; r->type = DUMP_KEYCACHE; r++; \ 326 } while(0) 327 struct dumpreg *keyregs, *r; 328 int i; 329 330 keyregs = (struct dumpreg *) calloc(nslots, 8*sizeof(struct dumpreg)); 331 if (keyregs == NULL) 332 errx(-1, "no space to %d keycache slots\n", nslots); 333 r = keyregs; 334 for (i = 0; i < nslots; i++) { 335 SET(r, AR_KEYTABLE_KEY0(i)); 336 SET(r, AR_KEYTABLE_KEY1(i)); 337 SET(r, AR_KEYTABLE_KEY2(i)); 338 SET(r, AR_KEYTABLE_KEY3(i)); 339 SET(r, AR_KEYTABLE_KEY4(i)); 340 SET(r, AR_KEYTABLE_TYPE(i)); 341 SET(r, AR_KEYTABLE_MAC0(i)); 342 SET(r, AR_KEYTABLE_MAC1(i)); 343 } 344 register_regs(keyregs, 8*nslots, 345 def_srev_min, def_srev_max, def_phy_min, def_phy_max); 346 #undef SET 347 } 348 349 void 350 register_range(u_int brange, u_int erange, int type, 351 int def_srev_min, int def_srev_max, int def_phy_min, int def_phy_max) 352 { 353 struct dumpreg *bbregs, *r; 354 int i, nregs; 355 356 nregs = (erange - brange) / sizeof(uint32_t); 357 bbregs = (struct dumpreg *) calloc(nregs, sizeof(struct dumpreg)); 358 if (bbregs == NULL) 359 errx(-1, "no space for %d register slots (type %d)\n", 360 nregs, type); 361 r = bbregs; 362 for (i = 0; i < nregs; i++) { 363 r->addr = brange + (i<<2); 364 r->type = type; 365 r++; 366 } 367 register_regs(bbregs, nregs, 368 def_srev_min, def_srev_max, def_phy_min, def_phy_max); 369 } 370 371 static __inline int 372 match(const struct dumpreg *dr, const HAL_REVS *revs) 373 { 374 if (!MAC_MATCH(dr, revs->ah_macVersion, revs->ah_macRev)) 375 return 0; 376 if ((dr->type & DUMP_BASEBAND) && !PHY_MATCH(dr, revs->ah_phyRev)) 377 return 0; 378 return 1; 379 } 380 381 static int 382 ath_hal_anyregs(int what) 383 { 384 const HAL_REVS *revs = &state.revs; 385 int i; 386 387 for (i = 0; i < state.nregs; i++) { 388 const struct dumpreg *dr = state.regs[i]; 389 if ((what & dr->type) && match(dr, revs)) 390 return 1; 391 } 392 return 0; 393 } 394 395 static int 396 ath_hal_setupregs(struct ath_diag *atd, int what) 397 { 398 const HAL_REVS *revs = &state.revs; 399 HAL_REGRANGE r; 400 size_t space = 0; 401 u_int8_t *cp; 402 int i, brun, erun; 403 404 brun = erun = -1; 405 for (i = 0; i < state.nregs; i++) { 406 const struct dumpreg *dr = state.regs[i]; 407 if ((what & dr->type) && match(dr, revs)) { 408 if (erun + 4 != dr->addr) { 409 if (brun != -1) 410 space += sizeof(HAL_REGRANGE); 411 brun = erun = dr->addr; 412 } else 413 erun = dr->addr; 414 } 415 } 416 space += sizeof(HAL_REGRANGE); 417 418 atd->ad_in_data = (caddr_t) malloc(space); 419 if (atd->ad_in_data == NULL) { 420 fprintf(stderr, "Cannot malloc memory for registers!\n"); 421 exit(-1); 422 } 423 atd->ad_in_size = space; 424 cp = (u_int8_t *) atd->ad_in_data; 425 brun = erun = -1; 426 for (i = 0; i < state.nregs; i++) { 427 const struct dumpreg *dr = state.regs[i]; 428 if ((what & dr->type) && match(dr, revs)) { 429 if (erun + 4 != dr->addr) { 430 if (brun != -1) { 431 r.start = brun, r.end = erun; 432 memcpy(cp, &r, sizeof(r)); 433 cp += sizeof(r); 434 } 435 brun = erun = dr->addr; 436 } else 437 erun = dr->addr; 438 } 439 } 440 if (brun != -1) { 441 r.start = brun, r.end = erun; 442 memcpy(cp, &r, sizeof(r)); 443 cp += sizeof(r); 444 } 445 return space / sizeof(uint32_t); 446 } 447 448 static void 449 ath_hal_dumpregs(FILE *fd, int what) 450 { 451 const HAL_REVS *revs = &state.revs; 452 const char *sep = ""; 453 int i, count, itemsperline; 454 455 count = 0; 456 itemsperline = 4; 457 if (state.show_names && state.show_addrs) 458 itemsperline--; 459 for (i = 0; i < state.nregs; i++) { 460 const struct dumpreg *dr = state.regs[i]; 461 if ((what & dr->type) && match(dr, revs)) { 462 if (state.show_names && dr->name != NULL) { 463 fprintf(fd, "%s%-8s", sep, dr->name); 464 if (state.show_addrs) 465 fprintf(fd, " [%04x]", dr->addr); 466 } else 467 fprintf(fd, "%s%04x", sep, dr->addr); 468 fprintf(fd, " %08x", OS_REG_READ(ah, dr->addr)); 469 sep = " "; 470 if ((++count % itemsperline) == 0) 471 sep = "\n"; 472 } 473 } 474 if (count) 475 fprintf(fd, "\n"); 476 } 477 478 static void 479 ath_hal_dumprange(FILE *fd, u_int a, u_int b) 480 { 481 u_int r; 482 483 for (r = a; r+16 <= b; r += 5*4) 484 fprintf(fd, 485 "%04x %08x %04x %08x %04x %08x %04x %08x %04x %08x\n" 486 , r, OS_REG_READ(ah, r) 487 , r+4, OS_REG_READ(ah, r+4) 488 , r+8, OS_REG_READ(ah, r+8) 489 , r+12, OS_REG_READ(ah, r+12) 490 , r+16, OS_REG_READ(ah, r+16) 491 ); 492 switch (b-r) { 493 case 16: 494 fprintf(fd 495 , "%04x %08x %04x %08x %04x %08x %04x %08x\n" 496 , r, OS_REG_READ(ah, r) 497 , r+4, OS_REG_READ(ah, r+4) 498 , r+8, OS_REG_READ(ah, r+8) 499 , r+12, OS_REG_READ(ah, r+12) 500 ); 501 break; 502 case 12: 503 fprintf(fd, "%04x %08x %04x %08x %04x %08x\n" 504 , r, OS_REG_READ(ah, r) 505 , r+4, OS_REG_READ(ah, r+4) 506 , r+8, OS_REG_READ(ah, r+8) 507 ); 508 break; 509 case 8: 510 fprintf(fd, "%04x %08x %04x %08x\n" 511 , r, OS_REG_READ(ah, r) 512 , r+4, OS_REG_READ(ah, r+4) 513 ); 514 break; 515 case 4: 516 fprintf(fd, "%04x %08x\n" 517 , r, OS_REG_READ(ah, r) 518 ); 519 break; 520 } 521 } 522 523 static void 524 ath_hal_dumpint(FILE *fd, int what) 525 { 526 int i; 527 528 /* Interrupt registers */ 529 fprintf(fd, "IMR: %08x S0 %08x S1 %08x S2 %08x S3 %08x S4 %08x\n" 530 , OS_REG_READ(ah, AR_IMR) 531 , OS_REG_READ(ah, AR_IMR_S0) 532 , OS_REG_READ(ah, AR_IMR_S1) 533 , OS_REG_READ(ah, AR_IMR_S2) 534 , OS_REG_READ(ah, AR_IMR_S3) 535 , OS_REG_READ(ah, AR_IMR_S4) 536 ); 537 fprintf(fd, "ISR: %08x S0 %08x S1 %08x S2 %08x S3 %08x S4 %08x\n" 538 , OS_REG_READ(ah, AR_ISR) 539 , OS_REG_READ(ah, AR_ISR_S0) 540 , OS_REG_READ(ah, AR_ISR_S1) 541 , OS_REG_READ(ah, AR_ISR_S2) 542 , OS_REG_READ(ah, AR_ISR_S3) 543 , OS_REG_READ(ah, AR_ISR_S4) 544 ); 545 } 546 547 static void 548 ath_hal_dumpqcu(FILE *fd, int what) 549 { 550 int i; 551 552 /* QCU registers */ 553 fprintf(fd, "%-8s %08x %-8s %08x %-8s %08x\n" 554 , "Q_TXE", OS_REG_READ(ah, AR_Q_TXE) 555 , "Q_TXD", OS_REG_READ(ah, AR_Q_TXD) 556 , "Q_RDYTIMSHD", OS_REG_READ(ah, AR_Q_RDYTIMESHDN) 557 ); 558 fprintf(fd, "Q_ONESHOTARM_SC %08x Q_ONESHOTARM_CC %08x\n" 559 , OS_REG_READ(ah, AR_Q_ONESHOTARM_SC) 560 , OS_REG_READ(ah, AR_Q_ONESHOTARM_CC) 561 ); 562 for (i = 0; i < 10; i++) 563 fprintf(fd, "Q[%u] TXDP %08x CBR %08x RDYT %08x MISC %08x STS %08x\n" 564 , i 565 , OS_REG_READ(ah, AR_QTXDP(i)) 566 , OS_REG_READ(ah, AR_QCBRCFG(i)) 567 , OS_REG_READ(ah, AR_QRDYTIMECFG(i)) 568 , OS_REG_READ(ah, AR_QMISC(i)) 569 , OS_REG_READ(ah, AR_QSTS(i)) 570 ); 571 } 572 573 static void 574 ath_hal_dumpdcu(FILE *fd, int what) 575 { 576 int i; 577 578 /* DCU registers */ 579 for (i = 0; i < 10; i++) 580 fprintf(fd, "D[%u] MASK %08x IFS %08x RTRY %08x CHNT %08x MISC %06x\n" 581 , i 582 , OS_REG_READ(ah, AR_DQCUMASK(i)) 583 , OS_REG_READ(ah, AR_DLCL_IFS(i)) 584 , OS_REG_READ(ah, AR_DRETRY_LIMIT(i)) 585 , OS_REG_READ(ah, AR_DCHNTIME(i)) 586 , OS_REG_READ(ah, AR_DMISC(i)) 587 ); 588 } 589 590 static void 591 ath_hal_dumpbb(FILE *fd, int what) 592 { 593 const HAL_REVS *revs = &state.revs; 594 int i, brun, erun; 595 596 brun = erun = 0; 597 for (i = 0; i < state.nregs; i++) { 598 const struct dumpreg *dr = state.regs[i]; 599 if (!match(dr, revs)) 600 continue; 601 if (dr->type & DUMP_BASEBAND) { 602 if (brun == 0) { 603 brun = erun = dr->addr; 604 } else if (dr->addr == erun + sizeof(uint32_t)) { 605 erun = dr->addr; 606 } else { 607 ath_hal_dumprange(fd, brun, erun); 608 brun = erun = dr->addr; 609 } 610 } else { 611 if (brun != 0) 612 ath_hal_dumprange(fd, brun, erun); 613 brun = erun = 0; 614 } 615 } 616 if (brun != 0) 617 ath_hal_dumprange(fd, brun, erun); 618 } 619 620 static u_int 621 ath_hal_setupdiagregs(const HAL_REGRANGE regs[], u_int nr) 622 { 623 u_int space; 624 int i; 625 626 space = 0; 627 for (i = 0; i < nr; i++) { 628 u_int n = sizeof(HAL_REGRANGE) + sizeof(u_int32_t); /* reg range + first */ 629 if (regs[i].end) { 630 if (regs[i].end < regs[i].start) { 631 fprintf(stderr, "%s: bad register range, " 632 "end 0x%x < start 0x%x\n", 633 __func__, regs[i].end, regs[i].end); 634 exit(-1); 635 } 636 n += regs[i].end - regs[i].start; 637 } 638 space += n; 639 } 640 return space; 641 } 642 643 /* 644 * Format an Ethernet MAC for printing. 645 */ 646 static const char* 647 ether_sprintf(const u_int8_t *mac) 648 { 649 static char etherbuf[18]; 650 snprintf(etherbuf, sizeof(etherbuf), "%02x:%02x:%02x:%02x:%02x:%02x", 651 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 652 return etherbuf; 653 } 654 655 #ifndef isclr 656 #define setbit(a,i) ((a)[(i)/NBBY] |= 1<<((i)%NBBY)) 657 #define clrbit(a,i) ((a)[(i)/NBBY] &= ~(1<<((i)%NBBY))) 658 #define isset(a,i) ((a)[(i)/NBBY] & (1<<((i)%NBBY))) 659 #define isclr(a,i) (((a)[(i)/NBBY] & (1<<((i)%NBBY))) == 0) 660 #endif 661 662 static void 663 ath_hal_dumpkeycache(FILE *fd, int nkeys) 664 { 665 static const char *keytypenames[] = { 666 "WEP-40", /* AR_KEYTABLE_TYPE_40 */ 667 "WEP-104", /* AR_KEYTABLE_TYPE_104 */ 668 "#2", 669 "WEP-128", /* AR_KEYTABLE_TYPE_128 */ 670 "TKIP", /* AR_KEYTABLE_TYPE_TKIP */ 671 "AES-OCB", /* AR_KEYTABLE_TYPE_AES */ 672 "AES-CCM", /* AR_KEYTABLE_TYPE_CCM */ 673 "CLR", /* AR_KEYTABLE_TYPE_CLR */ 674 }; 675 int micEnabled = SREV(state.revs.ah_macVersion, state.revs.ah_macRev) < SREV(4,8) ? 0 : 676 OS_REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_CRPT_MIC_ENABLE; 677 u_int8_t mac[IEEE80211_ADDR_LEN]; 678 u_int8_t ismic[128/NBBY]; 679 int entry; 680 int first = 1; 681 682 memset(ismic, 0, sizeof(ismic)); 683 for (entry = 0; entry < nkeys; entry++) { 684 u_int32_t macLo, macHi, type; 685 u_int32_t key0, key1, key2, key3, key4; 686 687 macHi = OS_REG_READ(ah, AR_KEYTABLE_MAC1(entry)); 688 if ((macHi & AR_KEYTABLE_VALID) == 0 && isclr(ismic, entry)) 689 continue; 690 macLo = OS_REG_READ(ah, AR_KEYTABLE_MAC0(entry)); 691 macHi <<= 1; 692 if (macLo & (1<<31)) 693 macHi |= 1; 694 macLo <<= 1; 695 mac[4] = macHi & 0xff; 696 mac[5] = macHi >> 8; 697 mac[0] = macLo & 0xff; 698 mac[1] = macLo >> 8; 699 mac[2] = macLo >> 16; 700 mac[3] = macLo >> 24; 701 type = OS_REG_READ(ah, AR_KEYTABLE_TYPE(entry)); 702 if ((type & 7) == AR_KEYTABLE_TYPE_TKIP && micEnabled) 703 setbit(ismic, entry+64); 704 key0 = OS_REG_READ(ah, AR_KEYTABLE_KEY0(entry)); 705 key1 = OS_REG_READ(ah, AR_KEYTABLE_KEY1(entry)); 706 key2 = OS_REG_READ(ah, AR_KEYTABLE_KEY2(entry)); 707 key3 = OS_REG_READ(ah, AR_KEYTABLE_KEY3(entry)); 708 key4 = OS_REG_READ(ah, AR_KEYTABLE_KEY4(entry)); 709 if (first) { 710 fprintf(fd, "\n"); 711 first = 0; 712 } 713 fprintf(fd, "KEY[%03u] MAC %s %-7s %02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x\n" 714 , entry 715 , ether_sprintf(mac) 716 , isset(ismic, entry) ? "MIC" : keytypenames[type & 7] 717 , (key0 >> 0) & 0xff 718 , (key0 >> 8) & 0xff 719 , (key0 >> 16) & 0xff 720 , (key0 >> 24) & 0xff 721 , (key1 >> 0) & 0xff 722 , (key1 >> 8) & 0xff 723 , (key2 >> 0) & 0xff 724 , (key2 >> 8) & 0xff 725 , (key2 >> 16) & 0xff 726 , (key2 >> 24) & 0xff 727 , (key3 >> 0) & 0xff 728 , (key3 >> 8) & 0xff 729 , (key4 >> 0) & 0xff 730 , (key4 >> 8) & 0xff 731 , (key4 >> 16) & 0xff 732 , (key4 >> 24) & 0xff 733 ); 734 } 735 } 736