2 * Point-to-point Tunneling Protocol (PPTP)
3 * See RFC 2637, pptpd.c
19 uchar localip[IPaddrlen];
32 uchar remoteip[IPaddrlen];
40 int aread(int, int, void*, int);
41 int catchalarm(void*, char*);
42 void dumpctlpkt(uchar*);
45 void ewrite(int, void*, int);
46 void myfatal(char*, ...);
47 #pragma varargck argpos myfatal 1
51 int schedack(int, uchar*, int);
57 fprint(2, "usage: ip/pptp [-Pd] [-k keyspec] [-x pppnetmntpt] [-w window] server\n");
62 threadmain(int argc, char **argv)
74 keyspec = EARGF(usage());
77 localwin = atoi(EARGF(usage()));
80 pppnetmntpt = EARGF(usage());
89 fmtinstall('E', eipfmt);
90 fmtinstall('I', eipfmt);
93 atnotify(catchalarm, 1);
100 catchalarm(void *a, char *msg)
104 if(strstr(msg, "alarm")){
109 fprint(2, "note rcved: %s\n", msg);
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 */
125 Servertimeout = 5*60*1000/Tick,
126 Echointerval = 60*1000/Tick,
163 memset(out, 0, sizeof out);
164 hnputs(out, sizeof out);
166 hnputl(out+4, Magic);
167 hnputs(out+8, Recho);
168 memmove(out+12, in+12, 4);
171 ewrite(ctlfd, out, sizeof out);
180 memset(out, 0, sizeof out);
181 hnputs(out, sizeof out);
183 hnputl(out+4, Magic);
184 hnputs(out+8, Techo);
186 ewrite(ctlfd, out, sizeof out);
196 if(readn(ctlfd, pkt, 2) != 2)
197 myfatal("pptpread: %r");
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");
211 switch(nhgets(pkt+8)){
220 myfatal("unexpected msg type %d", nhgets(pkt+8));
230 if(rdexpect != nhgets(pkt+8))
233 memmove(p, pkt, len);
237 myfatal("cannot change ppp params on the fly");
252 int datoff, flags, len, n, pass;
254 uchar src[IPaddrlen], dst[IPaddrlen];
258 sendul(pidchan, getpid());
260 while((n = read(grefd, pkt, sizeof pkt)) > 0){
262 myfatal("gre pkt buffer too small");
265 fprint(2, "small pkt len %d ignored\n", n);
270 if(ipcmp(src, remoteip) != 0 || ipcmp(dst, localip) != 0)
271 myfatal("%I: gre read bad address src=%I dst=%I",
273 if(nhgets(pkt+10) != GrePPP)
274 myfatal("%I: gre read bad protocol 0x%x",
275 remoteip, nhgets(pkt+10));
277 flags = nhgets(pkt+8);
278 if((flags&0xEF7F) != 0x2001){
280 fprint(2, "bad flags in gre hdr 0x%x\n", flags);
285 len = nhgets(pkt+8+4);
287 fprint(2, "bad payload length %d > %d\n",
294 recordack(nhgetl(pkt+datoff));
298 pass = schedack(nhgetl(pkt+8+8), pkt+datoff, len);
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);
317 sendul(pidchan, getpid());
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);
327 hnputs(pkt+14, remid);
328 hnputl(pkt+16, ++seq);
330 hnputl(pkt+20, myrseq);
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");
348 v6tov4(pkt+0, localip);
349 v6tov4(pkt+4, remoteip);
350 hnputs(pkt+8, 0x2001 | Acknum);
351 hnputs(pkt+10, GrePPP);
353 hnputs(pkt+14, remid);
356 hnputs(pkt+16, myrseq);
358 if(write(grefd, pkt, sizeof pkt) != sizeof pkt)
359 myfatal("gre write: %r");
363 schedack(int n, uchar *dat, int len)
365 static uchar sdat[1600];
366 static int srseq, slen;
369 fprint(2, "skipping pkt %d len %d, have %d\n", n, len, rseq);
373 /* missed one pkt, maybe a swap happened, save pkt */
375 memmove(sdat, dat, len);
382 if(slen && srseq == n-1){
383 fprint(2, "reswapped pkts %d and %d\n", srseq, n);
384 write(topppfd, sdat, slen);
387 fprint(2, "missed pkts %d-%d, got %d len %d\n", rseq+1, n-1, n, len);
389 write(topppfd, dat, len);
392 /* send ack if we haven't recently */
393 if((int)(rseq-rack) > (localwin>>1))
400 gretimeoutproc(void*)
405 nbsendul(tickchan, now);
406 if(now - ctlrcvtime > Servertimeout)
407 myfatal("server timeout");
408 if(now - ctlechotime > Echointerval)
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);
438 uchar pkt[200], *rpkt;
440 memset(pkt, 0, sizeof pkt);
444 hnputl(pkt+4, Magic);
445 hnputs(pkt+8, Tstart);
446 hnputs(pkt+12, PptpProto);
453 strcpy((char*)pkt+28, name);
454 strcpy((char*)pkt+92, "plan 9");
460 ewrite(ctlfd, pkt, 156);
462 rpkt = recvp(rdchan);
464 myfatal("recvp: %r");
465 if(nhgets(rpkt) != 156)
466 myfatal("Rstart wrong length %d != 156", nhgets(rpkt));
468 myfatal("Rstart error %d", rpkt[15]);
475 uchar pkt[200], *rpkt;
479 memset(pkt, 0, sizeof pkt);
482 hnputl(pkt+4, Magic);
483 hnputs(pkt+8, Tcallout);
485 hnputl(pkt+16, 56000);
486 hnputl(pkt+20, 768000);
491 hnputs(pkt+32, localwin);
497 ewrite(ctlfd, pkt, 168);
499 rpkt = recvp(rdchan);
501 myfatal("recvp: %r");
502 if(nhgets(rpkt) != 32)
503 myfatal("Rcallreq wrong length %d != 32", nhgets(rpkt));
505 myfatal("Rcallreq error %d", rpkt[17]);
506 remid = nhgets(pkt+12);
507 remwin = nhgets(pkt+24);
515 uchar pkt[200], *rpkt;
519 memset(pkt, 0, sizeof pkt);
522 hnputl(pkt+4, Magic);
523 hnputs(pkt+8, Tcallreq);
529 ewrite(ctlfd, pkt, 220);
531 rpkt = recvp(rdchan);
533 myfatal("recvp: %r");
534 if(nhgets(rpkt) != 24)
535 myfatal("Rcallreq wrong length %d != 24", nhgets(rpkt));
537 myfatal("Rcallreq error %d", rpkt[17]);
538 remid = nhgets(pkt+12);
539 remwin = nhgets(pkt+18);
548 memset(pkt, 0, sizeof pkt);
551 hnputl(pkt+4, Magic);
552 hnputs(pkt+8, Acallcon);
553 hnputs(pkt+12, remid);
556 hnputs(pkt+20, localwin);
562 ewrite(ctlfd, pkt, 28);
572 addr = netmkaddr(addr, "net", "pptp");
573 ctlfd = dial(addr, nil, tcpdir, nil);
575 myfatal("dial %s: %r", addr);
578 rdchan = chancreate(sizeof(void*), 0);
579 proccreate(pptpctlproc, nil, Stack);
590 strcpy(greaddr, tcpdir);
591 *strrchr(greaddr, '/') = '\0';
592 sprint(strrchr(greaddr, '/')+1, "gre!%I!%d", remoteip, GrePPP);
594 print("local %I remote %I gre %s remid %d remwin %d\n",
595 localip, remoteip, greaddr, remid, remwin);
597 grefd = dial(greaddr, nil, nil, nil);
599 myfatal("dial gre: %r");
601 tickchan = chancreate(sizeof(int), 0);
602 proccreate(gretimeoutproc, nil, Stack);
604 pidchan = chancreate(sizeof(int), 0);
605 proccreate(grereadproc, nil, Stack);
607 proccreate(pppreadproc, nil, Stack);
621 argv[argc++] = "/bin/ip/ppp";
623 argv[argc++] = "-m1450";
630 argv[argc++] = pppnetmntpt;
634 argv[argc++] = keyspec;
652 aread(int timeout, int fd, void *buf, int nbuf)
658 n = read(fd, buf, nbuf);
665 myfatal("short read");
670 ewrite(int fd, void *buf, int nbuf)
672 char e[ERRMAX], path[64];
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);
689 myfatal("out of memory");
694 thread(void(*f)(void*), void *a)
697 pid=rfork(RFNOWAIT|RFMEM|RFPROC);
699 myfatal("rfork: %r");
704 return 0; // never reaches here
708 dumpctlpkt(uchar *pkt)
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));
714 switch(nhgets(pkt+8)){
716 fprint(2, "\tunknown type\n");
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),
723 fprint(2, "\thost %.64s\n", (char*)pkt+28);
724 fprint(2, "\tvendor %.64s\n", (char*)pkt+92);
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],
730 nhgetl(pkt+20), nhgets(pkt+24),
732 fprint(2, "\thost %.64s\n", (char*)pkt+28);
733 fprint(2, "\tvendor %.64s\n", (char*)pkt+92);
737 fprint(2, "\tTstop reason %d\n", pkt[12]);
741 fprint(2, "\tRstop res %d err %d\n", pkt[12], pkt[13]);
745 fprint(2, "\tTecho id %.8ux\n", nhgetl(pkt+12));
749 fprint(2, "\tRecho id %.8ux res %d err %d\n", nhgetl(pkt+12), pkt[16], pkt[17]);
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);
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));
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);
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),
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),
799 fprint(2, "\tTcallclear callid %d\n",
804 fprint(2, "\tAcalldis callid %d res %d err %d cause %d\n",
805 nhgets(pkt+12), pkt[14], pkt[15],
807 fprint(2, "\tstats %.128s\n", (char*)pkt+20);
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));
821 fprint(2, "\tAlinkinfo peerid %d sendaccm 0x%ux recvaccm 0x%ux\n",
822 nhgets(pkt+12), nhgetl(pkt+16),
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);
840 parseip(localip, buf);
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);
849 parseip(remoteip, buf);
854 myfatal(char *fmt, ...)
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));
869 vseprint(sbuf, sbuf+sizeof(sbuf), fmt, arg);
872 fprint(2, "fatal: %s\n", sbuf);