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
usage(void)55 usage(void)
56 {
57 fprint(2, "usage: ip/pptp [-Pd] [-k keyspec] [-x pppnetmntpt] [-w window] server\n");
58 exits("usage");
59 }
60
61 void
threadmain(int argc,char ** argv)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
catchalarm(void * a,char * msg)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
recho(uchar * in)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
sendecho(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
pptpctlproc(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 || len+2 >= sizeof pkt)
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
grereadproc(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
pppreadproc(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
sendack(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
schedack(int n,uchar * dat,int len)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
gretimeoutproc(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
recordack(int n)414 recordack(int n)
415 {
416 ack = n;
417 }
418
419 void
waitacks(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
tstart(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
tcallout(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
pptp(char * addr)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
pushppp(int fd)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
aread(int timeout,int fd,void * buf,int nbuf)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
ewrite(int fd,void * buf,int nbuf)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*
emalloc(long n)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
thread(void (* f)(void *),void * a)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
dumpctlpkt(uchar * pkt)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
getaddrs(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
myfatal(char * fmt,...)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