1 /* 2 * Point-to-point Tunneling Protocol (PPTP) 3 * See RFC 2637, pptpd.c 4 */ 5 6 #include <u.h> 7 #include <libc.h> 8 #include <bio.h> 9 #include <ip.h> 10 #include <thread.h> 11 12 int ack; 13 int alarmed; 14 int ctlechotime; 15 int ctlfd; 16 int ctlrcvtime; 17 int debug; 18 int grefd; 19 uchar localip[IPaddrlen]; 20 int localwin; 21 char *keyspec; 22 int now; 23 char *pppnetmntpt; 24 int pid; 25 Channel *pidchan; 26 int pppfd; 27 int primary; 28 int rack; 29 Channel *rdchan; 30 int rdexpect; 31 int remid; 32 uchar remoteip[IPaddrlen]; 33 int remwin; 34 int rseq; 35 int seq; 36 char tcpdir[40]; 37 Channel *tickchan; 38 int topppfd; 39 40 int aread(int, int, void*, int); 41 int catchalarm(void*, char*); 42 void dumpctlpkt(uchar*); 43 void getaddrs(void); 44 void *emalloc(long); 45 void ewrite(int, void*, int); 46 void myfatal(char*, ...); 47 #pragma varargck argpos myfatal 1 48 int pptp(char*); 49 void pushppp(int); 50 void recordack(int); 51 int schedack(int, uchar*, int); 52 void waitacks(void); 53 54 void 55 usage(void) 56 { 57 fprint(2, "usage: ip/pptp [-Pd] [-s user:secret] [-x pppnetmntpt] [-w window] server\n"); 58 exits("usage"); 59 } 60 61 void 62 threadmain(int argc, char **argv) 63 { 64 int fd; 65 66 ARGBEGIN{ 67 case 'P': 68 primary = 1; 69 break; 70 case 'd': 71 debug++; 72 break; 73 case 'k': 74 keyspec = EARGF(usage()); 75 break; 76 case 'w': 77 localwin = atoi(EARGF(usage())); 78 break; 79 case 'x': 80 pppnetmntpt = EARGF(usage()); 81 break; 82 default: 83 usage(); 84 }ARGEND 85 86 if(argc != 1) 87 usage(); 88 89 fmtinstall('E', eipfmt); 90 fmtinstall('I', eipfmt); 91 92 rfork(RFNOTEG); 93 atnotify(catchalarm, 1); 94 fd = pptp(argv[0]); 95 pushppp(fd); 96 exits(nil); 97 } 98 99 int 100 catchalarm(void *a, char *msg) 101 { 102 USED(a); 103 104 if(strstr(msg, "alarm")){ 105 alarmed = 1; 106 return 1; 107 } 108 if(debug) 109 fprint(2, "note rcved: %s\n", msg); 110 return 0; 111 } 112 113 enum { 114 Stack = 8192, 115 116 PptpProto = 0x0100, 117 118 Magic = 0x1a2b3c4d, 119 Window = 16, /* default window size */ 120 Timeout = 60, /* timeout in seconds for control channel */ 121 Pktsize = 2000, /* maximum packet size */ 122 Tick = 500, /* tick length in milliseconds */ 123 Sendtimeout = 4, /* in ticks */ 124 125 Servertimeout = 5*60*1000/Tick, 126 Echointerval = 60*1000/Tick, 127 }; 128 129 enum { 130 Syncframe = 0x1, 131 Asyncframe = 0x2, 132 Analog = 0x1, 133 Digital = 0x2, 134 Version = 0x100, 135 }; 136 137 enum { 138 Tstart = 1, 139 Rstart = 2, 140 Tstop = 3, 141 Rstop = 4, 142 Techo = 5, 143 Recho = 6, 144 Tcallout = 7, 145 Rcallout = 8, 146 Tcallreq = 9, 147 Rcallreq = 10, 148 Acallcon = 11, 149 Tcallclear = 12, 150 Acalldis = 13, 151 Awaninfo = 14, 152 Alinkinfo = 15, 153 }; 154 155 void 156 recho(uchar *in) 157 { 158 uchar out[20]; 159 160 if(nhgets(in) < 16) 161 return; 162 163 memset(out, 0, sizeof out); 164 hnputs(out, sizeof out); 165 hnputs(out+2, 1); 166 hnputl(out+4, Magic); 167 hnputs(out+8, Recho); 168 memmove(out+12, in+12, 4); 169 out[16] = 1; 170 171 ewrite(ctlfd, out, sizeof out); 172 } 173 174 void 175 sendecho(void) 176 { 177 uchar out[16]; 178 179 ctlechotime = now; 180 memset(out, 0, sizeof out); 181 hnputs(out, sizeof out); 182 hnputs(out+2, 1); 183 hnputl(out+4, Magic); 184 hnputs(out+8, Techo); 185 186 ewrite(ctlfd, out, sizeof out); 187 } 188 189 void 190 pptpctlproc(void*) 191 { 192 uchar pkt[1600], *p; 193 int len; 194 195 for(;;){ 196 if(readn(ctlfd, pkt, 2) != 2) 197 myfatal("pptpread: %r"); 198 len = nhgets(pkt); 199 if(len < 12) 200 myfatal("pptpread: bad length %d", len); 201 if(readn(ctlfd, pkt+2, len-2) != len-2) 202 myfatal("pptpread: %r"); 203 if(nhgetl(pkt+4) != Magic) 204 myfatal("pptpread bad magic"); 205 if(nhgets(pkt+2) != 1) 206 myfatal("pptpread bad message type"); 207 if(debug) 208 dumpctlpkt(pkt); 209 ctlrcvtime = now; 210 211 switch(nhgets(pkt+8)){ 212 case Tstart: 213 case Tstop: 214 case Tcallout: 215 case Tcallreq: 216 case Tcallclear: 217 case Acallcon: 218 case Acalldis: 219 case Awaninfo: 220 myfatal("unexpected msg type %d", nhgets(pkt+8)); 221 case Techo: 222 recho(pkt); 223 break; 224 case Recho: 225 break; 226 case Rstart: 227 case Rstop: 228 case Rcallout: 229 case Rcallreq: 230 if(rdexpect != nhgets(pkt+8)) 231 continue; 232 p = emalloc(len); 233 memmove(p, pkt, len); 234 sendp(rdchan, p); 235 break; 236 case Alinkinfo: 237 myfatal("cannot change ppp params on the fly"); 238 } 239 } 240 } 241 242 enum { 243 Seqnum = 0x1000, 244 Acknum = 0x0080, 245 246 GrePPP = 0x880B, 247 }; 248 249 void 250 grereadproc(void*) 251 { 252 int datoff, flags, len, n, pass; 253 uchar pkt[1600]; 254 uchar src[IPaddrlen], dst[IPaddrlen]; 255 256 rfork(RFFDG); 257 close(pppfd); 258 sendul(pidchan, getpid()); 259 260 while((n = read(grefd, pkt, sizeof pkt)) > 0){ 261 if(n == sizeof pkt) 262 myfatal("gre pkt buffer too small"); 263 if(n < 16){ 264 if(debug) 265 fprint(2, "small pkt len %d ignored\n", n); 266 continue; 267 } 268 v4tov6(src, pkt); 269 v4tov6(dst, pkt+4); 270 if(ipcmp(src, remoteip) != 0 || ipcmp(dst, localip) != 0) 271 myfatal("%I: gre read bad address src=%I dst=%I", 272 remoteip, src, dst); 273 if(nhgets(pkt+10) != GrePPP) 274 myfatal("%I: gre read bad protocol 0x%x", 275 remoteip, nhgets(pkt+10)); 276 277 flags = nhgets(pkt+8); 278 if((flags&0xEF7F) != 0x2001){ 279 if(debug) 280 fprint(2, "bad flags in gre hdr 0x%x\n", flags); 281 continue; 282 } 283 datoff = 8+8; 284 pass = 0; 285 len = nhgets(pkt+8+4); 286 if(len > n-datoff){ 287 fprint(2, "bad payload length %d > %d\n", 288 len, n-datoff); 289 continue; 290 } 291 if(flags&Seqnum) 292 datoff += 4; 293 if(flags&Acknum){ 294 recordack(nhgetl(pkt+datoff)); 295 datoff += 4; 296 } 297 if(flags&Seqnum) 298 pass = schedack(nhgetl(pkt+8+8), pkt+datoff, len); 299 if(debug) 300 fprint(2, "got gre callid %d len %d flag 0x%x pass %d seq %d rseq %d\n", nhgets(pkt+8+6), 301 len, flags, pass, nhgetl(pkt+8+8), rseq); 302 } 303 threadexits(nil); 304 } 305 306 void 307 pppreadproc(void*) 308 { 309 int n, myrseq; 310 uchar pkt[1600]; 311 enum { 312 Hdr = 8+16, 313 }; 314 315 rfork(RFFDG); 316 close(pppfd); 317 sendul(pidchan, getpid()); 318 319 while((n = read(topppfd, pkt+Hdr, sizeof pkt-Hdr)) > 0){ 320 if(n == sizeof pkt-Hdr) 321 myfatal("ppp pkt buffer too small"); 322 v6tov4(pkt+0, localip); 323 v6tov4(pkt+4, remoteip); 324 hnputs(pkt+8, 0x2001 | Seqnum | Acknum); 325 hnputs(pkt+10, GrePPP); 326 hnputs(pkt+12, n); 327 hnputs(pkt+14, remid); 328 hnputl(pkt+16, ++seq); 329 myrseq = rseq; 330 hnputl(pkt+20, myrseq); 331 rack = myrseq; 332 if(debug) 333 fprint(2, "wrote gre callid %d len %d flag 0x%x seq %d rseq %d\n", nhgets(pkt+8+6), 334 n, nhgets(pkt+8), nhgetl(pkt+16), nhgetl(pkt+20)); 335 if(write(grefd, pkt, n+Hdr) != n+Hdr) 336 myfatal("gre write: %r"); 337 waitacks(); 338 } 339 threadexits(nil); 340 } 341 342 void 343 sendack(void) 344 { 345 int myrseq; 346 uchar pkt[20]; 347 348 v6tov4(pkt+0, localip); 349 v6tov4(pkt+4, remoteip); 350 hnputs(pkt+8, 0x2001 | Acknum); 351 hnputs(pkt+10, GrePPP); 352 hnputs(pkt+12, 0); 353 hnputs(pkt+14, remid); 354 myrseq = rseq; 355 rack = myrseq; 356 hnputs(pkt+16, myrseq); 357 358 if(write(grefd, pkt, sizeof pkt) != sizeof pkt) 359 myfatal("gre write: %r"); 360 } 361 362 int 363 schedack(int n, uchar *dat, int len) 364 { 365 static uchar sdat[1600]; 366 static int srseq, slen; 367 368 if(n-rseq <= 0){ 369 fprint(2, "skipping pkt %d len %d, have %d\n", n, len, rseq); 370 return 0; 371 } 372 373 /* missed one pkt, maybe a swap happened, save pkt */ 374 if(n==rseq+2){ 375 memmove(sdat, dat, len); 376 slen = len; 377 srseq = n; 378 return 0; 379 } 380 381 if(n-rseq > 1){ 382 if(slen && srseq == n-1){ 383 fprint(2, "reswapped pkts %d and %d\n", srseq, n); 384 write(topppfd, sdat, slen); 385 slen = 0; 386 }else 387 fprint(2, "missed pkts %d-%d, got %d len %d\n", rseq+1, n-1, n, len); 388 } 389 write(topppfd, dat, len); 390 rseq = n; 391 392 /* send ack if we haven't recently */ 393 if((int)(rseq-rack) > (localwin>>1)) 394 sendack(); 395 396 return 1; 397 } 398 399 void 400 gretimeoutproc(void*) 401 { 402 for(;;){ 403 sleep(Tick); 404 now++; 405 nbsendul(tickchan, now); 406 if(now - ctlrcvtime > Servertimeout) 407 myfatal("server timeout"); 408 if(now - ctlechotime > Echointerval) 409 sendecho(); 410 } 411 } 412 413 void 414 recordack(int n) 415 { 416 ack = n; 417 } 418 419 void 420 waitacks(void) 421 { 422 /* 423 int start; 424 425 start = now; 426 while(seq-ack > remwin && now-start < Sendtimeout){ 427 print("seq %d ack %d remwin %d now %d start %d\n", 428 seq, ack, remwin, now, start); 429 recvul(tickchan); 430 } 431 */ 432 } 433 434 void 435 tstart(void) 436 { 437 char *name; 438 uchar pkt[200], *rpkt; 439 440 memset(pkt, 0, sizeof pkt); 441 442 hnputs(pkt+0, 156); 443 hnputs(pkt+2, 1); 444 hnputl(pkt+4, Magic); 445 hnputs(pkt+8, Tstart); 446 hnputs(pkt+12, PptpProto); 447 hnputl(pkt+16, 1); 448 hnputl(pkt+20, 1); 449 hnputs(pkt+24, 1); 450 name = sysname(); 451 if(name == nil) 452 name = "gnot"; 453 strcpy((char*)pkt+28, name); 454 strcpy((char*)pkt+92, "plan 9"); 455 456 if(debug) 457 dumpctlpkt(pkt); 458 459 rdexpect = Rstart; 460 ewrite(ctlfd, pkt, 156); 461 462 rpkt = recvp(rdchan); 463 if(rpkt == nil) 464 myfatal("recvp: %r"); 465 if(nhgets(rpkt) != 156) 466 myfatal("Rstart wrong length %d != 156", nhgets(rpkt)); 467 if(rpkt[14] != 1) 468 myfatal("Rstart error %d", rpkt[15]); 469 free(rpkt); 470 } 471 472 void 473 tcallout(void) 474 { 475 uchar pkt[200], *rpkt; 476 477 pid = getpid(); 478 479 memset(pkt, 0, sizeof pkt); 480 hnputs(pkt+0, 168); 481 hnputs(pkt+2, 1); 482 hnputl(pkt+4, Magic); 483 hnputs(pkt+8, Tcallout); 484 485 hnputl(pkt+16, 56000); 486 hnputl(pkt+20, 768000); 487 hnputl(pkt+24, 3); 488 hnputl(pkt+28, 3); 489 if(localwin == 0) 490 localwin = Window; 491 hnputs(pkt+32, localwin); 492 493 if(debug) 494 dumpctlpkt(pkt); 495 496 rdexpect = Rcallout; 497 ewrite(ctlfd, pkt, 168); 498 499 rpkt = recvp(rdchan); 500 if(rpkt == nil) 501 myfatal("recvp: %r"); 502 if(nhgets(rpkt) != 32) 503 myfatal("Rcallreq wrong length %d != 32", nhgets(rpkt)); 504 if(rpkt[16] != 1) 505 myfatal("Rcallreq error %d", rpkt[17]); 506 remid = nhgets(pkt+12); 507 remwin = nhgets(pkt+24); 508 free(rpkt); 509 } 510 511 /* 512 void 513 tcallreq(void) 514 { 515 uchar pkt[200], *rpkt; 516 517 pid = getpid(); 518 519 memset(pkt, 0, sizeof pkt); 520 hnputs(pkt+0, 220); 521 hnputs(pkt+2, 1); 522 hnputl(pkt+4, Magic); 523 hnputs(pkt+8, Tcallreq); 524 525 if(debug) 526 dumpctlpkt(pkt); 527 528 rdexpect = Rcallreq; 529 ewrite(ctlfd, pkt, 220); 530 531 rpkt = recvp(rdchan); 532 if(rpkt == nil) 533 myfatal("recvp: %r"); 534 if(nhgets(rpkt) != 24) 535 myfatal("Rcallreq wrong length %d != 24", nhgets(rpkt)); 536 if(rpkt[16] != 1) 537 myfatal("Rcallreq error %d", rpkt[17]); 538 remid = nhgets(pkt+12); 539 remwin = nhgets(pkt+18); 540 free(rpkt); 541 } 542 543 void 544 acallcon(void) 545 { 546 uchar pkt[200]; 547 548 memset(pkt, 0, sizeof pkt); 549 hnputs(pkt+0, 28); 550 hnputs(pkt+2, 1); 551 hnputl(pkt+4, Magic); 552 hnputs(pkt+8, Acallcon); 553 hnputs(pkt+12, remid); 554 if(localwin == 0) 555 localwin = Window; 556 hnputs(pkt+20, localwin); 557 hnputl(pkt+24, 1); 558 559 if(debug) 560 dumpctlpkt(pkt); 561 562 ewrite(ctlfd, pkt, 28); 563 } 564 */ 565 566 int 567 pptp(char *addr) 568 { 569 int p[2]; 570 char greaddr[128]; 571 572 addr = netmkaddr(addr, "net", "pptp"); 573 ctlfd = dial(addr, nil, tcpdir, nil); 574 if(ctlfd < 0) 575 myfatal("dial %s: %r", addr); 576 getaddrs(); 577 578 rdchan = chancreate(sizeof(void*), 0); 579 proccreate(pptpctlproc, nil, Stack); 580 581 tstart(); 582 tcallout(); 583 584 if(pipe(p) < 0) 585 myfatal("pipe: %r"); 586 587 pppfd = p[0]; 588 topppfd = p[1]; 589 590 strcpy(greaddr, tcpdir); 591 *strrchr(greaddr, '/') = '\0'; 592 sprint(strrchr(greaddr, '/')+1, "gre!%I!%d", remoteip, GrePPP); 593 594 print("local %I remote %I gre %s remid %d remwin %d\n", 595 localip, remoteip, greaddr, remid, remwin); 596 597 grefd = dial(greaddr, nil, nil, nil); 598 if(grefd < 0) 599 myfatal("dial gre: %r"); 600 601 tickchan = chancreate(sizeof(int), 0); 602 proccreate(gretimeoutproc, nil, Stack); 603 604 pidchan = chancreate(sizeof(int), 0); 605 proccreate(grereadproc, nil, Stack); 606 recvul(pidchan); 607 proccreate(pppreadproc, nil, Stack); 608 recvul(pidchan); 609 610 close(topppfd); 611 return pppfd; 612 } 613 614 void 615 pushppp(int fd) 616 { 617 char *argv[16]; 618 int argc; 619 620 argc = 0; 621 argv[argc++] = "/bin/ip/ppp"; 622 argv[argc++] = "-C"; 623 argv[argc++] = "-m1450"; 624 if(debug) 625 argv[argc++] = "-d"; 626 if(primary) 627 argv[argc++] = "-P"; 628 if(pppnetmntpt){ 629 argv[argc++] = "-x"; 630 argv[argc++] = pppnetmntpt; 631 } 632 if(keyspec){ 633 argv[argc++] = "-k"; 634 argv[argc++] = keyspec; 635 } 636 argv[argc] = nil; 637 638 switch(fork()){ 639 case -1: 640 myfatal("fork: %r"); 641 default: 642 return; 643 case 0: 644 dup(fd, 0); 645 dup(fd, 1); 646 exec(argv[0], argv); 647 myfatal("exec: %r"); 648 } 649 } 650 651 int 652 aread(int timeout, int fd, void *buf, int nbuf) 653 { 654 int n; 655 656 alarmed = 0; 657 alarm(timeout); 658 n = read(fd, buf, nbuf); 659 alarm(0); 660 if(alarmed) 661 return -1; 662 if(n < 0) 663 myfatal("read: %r"); 664 if(n == 0) 665 myfatal("short read"); 666 return n; 667 } 668 669 void 670 ewrite(int fd, void *buf, int nbuf) 671 { 672 char e[ERRMAX], path[64]; 673 674 if(write(fd, buf, nbuf) != nbuf){ 675 rerrstr(e, sizeof e); 676 strcpy(path, "unknown"); 677 fd2path(fd, path, sizeof path); 678 myfatal("write %d to %s: %s", nbuf, path, e); 679 } 680 } 681 682 void* 683 emalloc(long n) 684 { 685 void *v; 686 687 v = malloc(n); 688 if(v == nil) 689 myfatal("out of memory"); 690 return v; 691 } 692 693 int 694 thread(void(*f)(void*), void *a) 695 { 696 int pid; 697 pid=rfork(RFNOWAIT|RFMEM|RFPROC); 698 if(pid < 0) 699 myfatal("rfork: %r"); 700 if(pid != 0) 701 return pid; 702 (*f)(a); 703 _exits(nil); 704 return 0; // never reaches here 705 } 706 707 void 708 dumpctlpkt(uchar *pkt) 709 { 710 fprint(2, "pkt len %d mtype %d cookie 0x%.8ux type %d\n", 711 nhgets(pkt), nhgets(pkt+2), 712 nhgetl(pkt+4), nhgets(pkt+8)); 713 714 switch(nhgets(pkt+8)){ 715 default: 716 fprint(2, "\tunknown type\n"); 717 break; 718 case Tstart: 719 fprint(2, "\tTstart proto %d framing %d bearer %d maxchan %d firmware %d\n", 720 nhgets(pkt+12), nhgetl(pkt+16), 721 nhgetl(pkt+20), nhgets(pkt+24), 722 nhgets(pkt+26)); 723 fprint(2, "\thost %.64s\n", (char*)pkt+28); 724 fprint(2, "\tvendor %.64s\n", (char*)pkt+92); 725 break; 726 case Rstart: 727 fprint(2, "\tRstart proto %d res %d err %d framing %d bearer %d maxchan %d firmware %d\n", 728 nhgets(pkt+12), pkt[14], pkt[15], 729 nhgetl(pkt+16), 730 nhgetl(pkt+20), nhgets(pkt+24), 731 nhgets(pkt+26)); 732 fprint(2, "\thost %.64s\n", (char*)pkt+28); 733 fprint(2, "\tvendor %.64s\n", (char*)pkt+92); 734 break; 735 736 case Tstop: 737 fprint(2, "\tTstop reason %d\n", pkt[12]); 738 break; 739 740 case Rstop: 741 fprint(2, "\tRstop res %d err %d\n", pkt[12], pkt[13]); 742 break; 743 744 case Techo: 745 fprint(2, "\tTecho id %.8ux\n", nhgetl(pkt+12)); 746 break; 747 748 case Recho: 749 fprint(2, "\tRecho id %.8ux res %d err %d\n", nhgetl(pkt+12), pkt[16], pkt[17]); 750 break; 751 752 case Tcallout: 753 fprint(2, "\tTcallout id %d serno %d bps %d-%d\n", 754 nhgets(pkt+12), nhgets(pkt+14), 755 nhgetl(pkt+16), nhgetl(pkt+20)); 756 fprint(2, "\tbearer 0x%x framing 0x%x recvwin %d delay %d\n", 757 nhgetl(pkt+24), nhgetl(pkt+28), 758 nhgets(pkt+32), nhgets(pkt+34)); 759 fprint(2, "\tphone len %d num %.64s\n", 760 nhgets(pkt+36), (char*)pkt+40); 761 fprint(2, "\tsubaddr %.64s\n", (char*)pkt+104); 762 break; 763 764 case Rcallout: 765 fprint(2, "\tRcallout id %d peerid %d res %d err %d cause %d\n", 766 nhgets(pkt+12), nhgets(pkt+14), 767 pkt[16], pkt[17], nhgets(pkt+18)); 768 fprint(2, "\tconnect %d recvwin %d delay %d chan 0x%.8ux\n", 769 nhgetl(pkt+20), nhgets(pkt+24), 770 nhgets(pkt+26), nhgetl(pkt+28)); 771 break; 772 773 case Tcallreq: 774 fprint(2, "\tTcallreq id %d serno %d bearer 0x%x id 0x%x\n", 775 nhgets(pkt+12), nhgets(pkt+14), 776 nhgetl(pkt+16), nhgetl(pkt+20)); 777 fprint(2, "\tdialed len %d num %.64s\n", 778 nhgets(pkt+24), (char*)pkt+28); 779 fprint(2, "\tdialing len %d num %.64s\n", 780 nhgets(pkt+26), (char*)pkt+92); 781 fprint(2, "\tsubaddr %.64s\n", (char*)pkt+156); 782 break; 783 784 case Rcallreq: 785 fprint(2, "\tRcallout id %d peerid %d res %d err %d recvwin %d delay %d\n", 786 nhgets(pkt+12), nhgets(pkt+14), 787 pkt[16], pkt[17], nhgets(pkt+18), 788 nhgets(pkt+20)); 789 break; 790 791 case Acallcon: 792 fprint(2, "\tAcallcon peerid %d connect %d recvwin %d delay %d framing 0x%x\n", 793 nhgets(pkt+12), nhgetl(pkt+16), 794 nhgets(pkt+20), nhgets(pkt+22), 795 nhgetl(pkt+24)); 796 break; 797 798 case Tcallclear: 799 fprint(2, "\tTcallclear callid %d\n", 800 nhgets(pkt+12)); 801 break; 802 803 case Acalldis: 804 fprint(2, "\tAcalldis callid %d res %d err %d cause %d\n", 805 nhgets(pkt+12), pkt[14], pkt[15], 806 nhgets(pkt+16)); 807 fprint(2, "\tstats %.128s\n", (char*)pkt+20); 808 break; 809 810 case Awaninfo: 811 fprint(2, "\tAwaninfo peerid %d\n", nhgets(pkt+12)); 812 fprint(2, "\tcrc errors %d\n", nhgetl(pkt+16)); 813 fprint(2, "\tframe errors %d\n", nhgetl(pkt+20)); 814 fprint(2, "\thardware overruns %d\n", nhgetl(pkt+24)); 815 fprint(2, "\tbuffer overruns %d\n", nhgetl(pkt+28)); 816 fprint(2, "\ttime-out errors %d\n", nhgetl(pkt+32)); 817 fprint(2, "\talignment errors %d\n", nhgetl(pkt+36)); 818 break; 819 820 case Alinkinfo: 821 fprint(2, "\tAlinkinfo peerid %d sendaccm 0x%ux recvaccm 0x%ux\n", 822 nhgets(pkt+12), nhgetl(pkt+16), 823 nhgetl(pkt+20)); 824 break; 825 } 826 } 827 828 void 829 getaddrs(void) 830 { 831 char buf[128]; 832 int fd, n; 833 834 sprint(buf, "%s/local", tcpdir); 835 if((fd = open(buf, OREAD)) < 0) 836 myfatal("could not open %s: %r", buf); 837 if((n = read(fd, buf, sizeof(buf))) < 0) 838 myfatal("could not read %s: %r", buf); 839 buf[n] = 0; 840 parseip(localip, buf); 841 close(fd); 842 843 sprint(buf, "%s/remote", tcpdir); 844 if((fd = open(buf, OREAD)) < 0) 845 myfatal("could not open %s: %r", buf); 846 if((n = read(fd, buf, sizeof(buf))) < 0) 847 myfatal("could not read %s: %r", buf); 848 buf[n] = 0; 849 parseip(remoteip, buf); 850 close(fd); 851 } 852 853 void 854 myfatal(char *fmt, ...) 855 { 856 char sbuf[512]; 857 va_list arg; 858 uchar buf[16]; 859 860 memset(buf, 0, sizeof(buf)); 861 hnputs(buf+0, sizeof(buf)); /* length */ 862 hnputs(buf+2, 1); /* message type */ 863 hnputl(buf+4, Magic); /* magic */ 864 hnputs(buf+8, Tstop); /* op */ 865 buf[12] = 3; /* local shutdown */ 866 write(ctlfd, buf, sizeof(buf)); 867 868 va_start(arg, fmt); 869 vseprint(sbuf, sbuf+sizeof(sbuf), fmt, arg); 870 va_end(arg); 871 872 fprint(2, "fatal: %s\n", sbuf); 873 threadexitsall(nil); 874 } 875