8 typedef struct Call Call;
9 typedef struct Event Event;
11 #define SDB if(debug) fprint(2,
17 Nchan = 10, /* maximum number of channels */
18 Window = 8, /* default window size */
19 Timeout = 60, /* timeout in seconds for control channel */
20 Pktsize = 2000, /* maximum packet size */
21 Tick = 500, /* tick length in milliseconds */
22 Sendtimeout = 4, /* in ticks */
68 int pac; /* server is acting as a PAC */
70 int recvwindow; /* recv windows */
71 int sendwindow; /* send windows */
77 uint seq; /* current seq number - for send */
78 uint ack; /* current acked mesg - for send */
79 uint rseq; /* highest recv seq number for in order packet */
80 uint rack; /* highest ack sent */
82 Event eack; /* recved ack - for send */
85 uchar remoteip[IPaddrlen]; /* remote ip address */
86 int dhcpfd[2]; /* pipe to dhcpclient */
117 uchar local[IPaddrlen];
118 uchar remote[IPaddrlen];
120 uchar ipaddr[IPaddrlen]; /* starting ip addresss to allocate */
127 double rcvtime; /* time at which last request was received */
128 int echoid; /* id of last echo request */
135 GRE_chksum = (1<<15),
136 GRE_routing = (1<<14),
153 void myfatal(char *fmt, ...);
155 #define PSHORT(p, v) ((p)[0]=((v)>>8), (p)[1]=(v))
156 #define PLONG(p, v) (PSHORT(p, (v)>>16), PSHORT(p+2, (v)))
157 #define PSTRING(d,s,n) strncpy((char*)(d), s, n)
158 #define GSHORT(p) (((p)[0]<<8) | ((p)[1]<<0))
159 #define GLONG(p) ((GSHORT((p))<<16) | ((GSHORT((p)+2))<<0))
160 #define GSTRING(d,s,n) strncpy(d, (char*)(s), n), d[(n)-1] = 0
164 int sstart(uchar*, int);
165 int sstop(uchar*, int);
166 int secho(uchar*, int);
167 int scallout(uchar*, int);
168 int scallreq(uchar*, int);
169 int scallcon(uchar*, int);
170 int scallclear(uchar*, int);
171 int scalldis(uchar*, int);
172 int swaninfo(uchar*, int);
173 int slinkinfo(uchar*, int);
175 Call *callalloc(int id);
176 void callclose(Call*);
177 void callfree(Call*);
178 Call *calllookup(int id);
180 void gretimeout(void*);
186 void greack(Call *c);
188 void timeoutthread(void*);
190 int argatoi(char *p);
192 int ipaddralloc(Call *c);
194 void *emallocz(int size);
195 void esignal(Event *e);
196 void ewait(Event *e);
197 int proc(char **argv, int fd0, int fd1, int fd2);
198 double realtime(void);
199 ulong thread(void(*f)(void*), void *a);
202 main(int argc, char *argv[])
205 case 'd': debug++; break;
206 case 'p': srv.pppdir = ARGF(); break;
207 case 'P': srv.pppexec = ARGF(); break;
208 case 'w': srv.recvwindow = argatoi(ARGF()); break;
209 case 'D': drop = atof(ARGF()); break;
214 fmtinstall('I', eipfmt);
215 fmtinstall('E', eipfmt);
216 fmtinstall('V', eipfmt);
217 fmtinstall('M', eipfmt);
219 rfork(RFNOTEG|RFREND);
224 srv.tcpdir = argv[0];
228 syslog(0, LOG, ": src=%I: pptp started: %d", srv.remote, getpid());
230 SDB "\n\n\n%I: pptp started\n", srv.remote EDB
234 thread(timeoutthread, 0);
238 syslog(0, LOG, ": src=%I: server exits", srv.remote);
246 fprint(2, "usage: pptpd [-dD] [-p ppp-net] [-w window] tcpdir\n");
260 n2 = read(0, buf+n, sizeof(buf)-n);
262 myfatal("bad read on ctl channel: %r");
272 srv.rcvtime = realtime();
280 myfatal("bad magic number: got %x", magic);
282 myfatal("bad message type: %d", type);
285 myfatal("unknown control op: %d", op);
286 case Tstart: /* start-control-connection-request */
307 n2 = scallclear(p, n);
316 n2 = slinkinfo(p, n);
322 myfatal("op=%d: bad length: got %d expected %d", op, len, n2);
328 /* move down partial message */
329 if(p != buf && n != 0)
336 sstart(uchar *p, int n)
338 int ver, frame, bearer, maxchan, firm;
339 char host[64], vendor[64], *sysname;
346 bearer = GLONG(p+20);
347 maxchan = GSHORT(p+24);
349 GSTRING(host, p+28, 64);
350 GSTRING(vendor, p+92, 64);
352 SDB "%I: start ver = %x f = %d b = %d maxchan = %d firm = %d host = %s vendor = %s\n",
353 srv.remote, ver, frame, bearer, maxchan, firm, host, vendor EDB
356 myfatal("bad version: got %x expected %x", ver, Version);
359 myfatal("multiple start messages");
363 sysname = getenv("sysname");
365 strcpy(host, "gnot");
367 strncpy(host, sysname, 64);
370 memset(buf, 0, sizeof(buf));
372 PSHORT(buf+0, sizeof(buf)); /* length */
373 PSHORT(buf+2, 1); /* message type */
374 PLONG(buf+4, Magic); /* magic */
375 PSHORT(buf+8, Rstart); /* op */
376 PSHORT(buf+12, Version); /* version */
377 buf[14] = 1; /* result = ok */
378 PLONG(buf+16, Syncframe|Asyncframe); /* frameing */
379 PLONG(buf+20, Digital|Analog); /* berear capabilities */
380 PSHORT(buf+24, Nchan); /* max channels */
381 PSHORT(buf+26, 1); /* driver version */
382 PSTRING(buf+28, host, 64); /* host name */
383 PSTRING(buf+92, "plan 9", 64); /* vendor */
385 if(write(1, buf, sizeof(buf)) < sizeof(buf))
386 myfatal("write failed: %r");
392 sstop(uchar *p, int n)
401 SDB "%I: stop %d\n", srv.remote, reason EDB
403 memset(buf, 0, sizeof(buf));
404 PSHORT(buf+0, sizeof(buf)); /* length */
405 PSHORT(buf+2, 1); /* message type */
406 PLONG(buf+4, Magic); /* magic */
407 PSHORT(buf+8, Rstop); /* op */
408 buf[12] = 1; /* ok */
410 if(write(1, buf, sizeof(buf)) < sizeof(buf))
411 myfatal("write failed: %r");
417 secho(uchar *p, int n)
426 SDB "%I: echo %d\n", srv.remote, id EDB
428 memset(buf, 0, sizeof(buf));
429 PSHORT(buf+0, sizeof(buf)); /* length */
430 PSHORT(buf+2, 1); /* message type */
431 PLONG(buf+4, Magic); /* magic */
432 PSHORT(buf+8, Recho); /* op */
433 PLONG(buf+12, id); /* id */
436 if(write(1, buf, sizeof(buf)) < sizeof(buf))
437 myfatal("write failed: %r");
443 scallout(uchar *p, int n)
446 int minbps, maxbps, bearer, frame;
449 char phone[64], sub[64], buf[32];
456 myfatal("%I: did not recieve start message", srv.remote);
459 serial = GSHORT(p+14);
460 minbps = GLONG(p+16);
461 maxbps = GLONG(p+20);
462 bearer = GLONG(p+24);
464 window = GSHORT(p+32);
465 delay = GSHORT(p+34);
466 nphone = GSHORT(p+36);
467 GSTRING(phone, p+40, 64);
468 GSTRING(sub, p+104, 64);
470 SDB "%I: callout id = %d serial = %d bps=[%d,%d] b=%x f=%x win = %d delay = %d np=%d phone=%s sub=%s\n",
471 srv.remote, id, serial, minbps, maxbps, bearer, frame, window, delay, nphone, phone, sub EDB
474 c->sendwindow = window;
477 c->recvwindow = srv.recvwindow;
479 memset(buf, 0, sizeof(buf));
480 PSHORT(buf+0, sizeof(buf)); /* length */
481 PSHORT(buf+2, 1); /* message type */
482 PLONG(buf+4, Magic); /* magic */
483 PSHORT(buf+8, Rcallout); /* op */
484 PSHORT(buf+12, id); /* call id */
485 PSHORT(buf+14, id); /* peer id */
486 buf[16] = 1; /* ok */
487 PLONG(buf+20, 10000000); /* speed */
488 PSHORT(buf+24, c->recvwindow); /* window size */
489 PSHORT(buf+26, 0); /* delay */
490 PLONG(buf+28, 0); /* channel id */
492 if(write(1, buf, sizeof(buf)) < sizeof(buf))
493 myfatal("write failed: %r");
499 scallreq(uchar *p, int n)
504 myfatal("callreq: not done yet");
509 scallcon(uchar *p, int n)
514 myfatal("callcon: not done yet");
519 scallclear(uchar *p, int n)
529 SDB "%I: callclear id=%d\n", srv.remote, id EDB
531 if(c = calllookup(id)) {
536 memset(buf, 0, sizeof(buf));
537 PSHORT(buf+0, sizeof(buf)); /* length */
538 PSHORT(buf+2, 1); /* message type */
539 PLONG(buf+4, Magic); /* magic */
540 PSHORT(buf+8, Acalldis); /* op */
541 PSHORT(buf+12, id); /* id */
542 buf[14] = 3; /* reply to callclear */
544 if(write(1, buf, sizeof(buf)) < sizeof(buf))
545 myfatal("write failed: %r");
551 scalldis(uchar *p, int n)
561 SDB "%I: calldis id=%d res=%d\n", srv.remote, id, res EDB
563 if(c = calllookup(id)) {
572 swaninfo(uchar *p, int n)
581 SDB "%I: waninfo id = %d\n", srv.remote, id EDB
585 c->err.crc = GLONG(p+16);
586 c->err.frame = GLONG(p+20);
587 c->err.hardware = GLONG(p+24);
588 c->err.overrun = GLONG(p+28);
589 c->err.timeout = GLONG(p+32);
590 c->err.align = GLONG(p+36);
600 slinkinfo(uchar *p, int n)
604 int sendaccm, recvaccm;
609 sendaccm = GLONG(p+16);
610 recvaccm = GLONG(p+20);
612 SDB "%I: linkinfo id=%d saccm=%ux raccm=%ux\n", srv.remote, id, sendaccm, recvaccm EDB
614 if(c = calllookup(id)) {
615 c->sendaccm = sendaccm;
616 c->recvaccm = recvaccm;
629 char buf[300], *argv[30], local[20], remote[20], **p;
635 for(c=srv.hash[h]; c; c=c->next)
637 myfatal("callalloc: duplicate id: %d", id);
638 c = emallocz(sizeof(Call));
645 myfatal("callalloc: could not alloc remote ip address");
648 myfatal("callalloc: pipe failed: %r");
650 sprint(buf, "%s/ipifc/clone", srv.pppdir);
651 fd = open(buf, OWRITE);
653 myfatal("callalloc: could not open %s: %r", buf);
655 n = sprint(buf, "iprouting");
656 if(write(fd, buf, n) < n)
657 myfatal("callalloc: write to ifc failed: %r");
667 sprint(local, "%I", srv.ipaddr);
669 sprint(remote, "%I", c->remoteip);
673 proc(argv, pfd[0], pfd[0], 2);
679 c->next = srv.hash[h];
687 thread(gretimeout, c);
689 syslog(0, LOG, ": src=%I: call started: id=%d: remote ip=%I", srv.remote, id, c->remoteip);
701 syslog(0, LOG, ": src=%I: call closed: id=%d: send=%d sendack=%d recv=%d recvack=%d dropped=%d missing=%d sendwait=%d sendtimeout=%d",
702 srv.remote, c->id, c->stat.send, c->stat.sendack, c->stat.recv, c->stat.recvack,
703 c->stat.dropped, c->stat.missing, c->stat.sendwait, c->stat.sendtimeout);
719 for(c=srv.hash[h],oc=0; c; oc=c,c=c->next)
723 srv.hash[h] = c->next;
743 /* already unhooked from hash list - see callclose */
744 assert(c->closed == 1);
746 assert(c->next == 0);
748 SDB "call free\n" EDB
761 for(c=srv.hash[h]; c; c=c->next)
778 sprint(buf, "%s/local", srv.tcpdir);
779 if((fd = open(buf, OREAD)) < 0)
780 myfatal("could not open %s: %r", buf);
781 if((n = read(fd, buf, sizeof(buf))) < 0)
782 myfatal("could not read %s: %r", buf);
784 parseip(srv.local, buf);
787 sprint(buf, "%s/remote", srv.tcpdir);
788 if((fd = open(buf, OREAD)) < 0)
789 myfatal("could not open %s: %r", buf);
790 if((n = read(fd, buf, sizeof(buf))) < 0)
791 myfatal("could not read %s: %r", buf);
793 parseip(srv.remote, buf);
800 srv.pppexec = "/bin/ip/ppp";
802 if(myipaddr(srv.ipaddr, srv.pppdir) < 0)
803 myfatal("could not read local ip addr: %r");
804 if(srv.recvwindow == 0)
805 srv.recvwindow = Window;
814 SDB "srv.tcpdir = %s\n", srv.tcpdir EDB
815 strcpy(addr, srv.tcpdir);
816 p = strrchr(addr, '/');
818 myfatal("bad tcp dir: %s", srv.tcpdir);
820 p = strrchr(addr, '/');
822 myfatal("bad tcp dir: %s", srv.tcpdir);
823 sprint(p, "/gre!%I!34827", srv.remote);
825 SDB "addr = %s\n", addr EDB
827 fd = dial(addr, 0, 0, &cfd);
830 myfatal("%I: dial %s failed: %r", srv.remote, addr);
841 uchar buf[Pktsize], *p;
843 int flag, prot, len, callid;
844 uchar src[IPaddrlen], dst[IPaddrlen];
847 static double t, last;
850 n = read(srv.grefd, buf, sizeof(buf));
852 myfatal("%I: bad read on gre: %r", srv.remote);
854 myfatal("%I: gre read: buf too small", srv.remote);
863 if(ipcmp(src, srv.remote) != 0 || ipcmp(dst, srv.local) != 0)
864 myfatal("%I: gre read bad address src=%I dst=%I", srv.remote, src, dst);
867 myfatal("%I: gre read gave bad protocol", srv.remote);
869 if(flag & (GRE_chksum|GRE_routing)){
874 myfatal("%I: gre packet does not contain a key: f=%ux",
878 callid = GSHORT(p+2);
881 c = calllookup(callid);
883 SDB "%I: unknown callid: %d\n", srv.remote, callid EDB
903 /* skip routing if present */
904 if(flag&GRE_routing) {
905 while((i=p[3]) != 0) {
912 myfatal("%I: bad len in gre packet", srv.remote);
914 if((int)(ack-c->ack) > 0) {
926 SDB "%I: %.3f (%.3f): gre %d: recv ack a=%ux n=%d flag=%ux\n", srv.remote, t, t-last,
927 c->id, ack, n, flag EDB
931 SDB "%I: %.3f (%.3f): gre %d: recv s=%ux a=%ux len=%d\n", srv.remote, t, t-last,
932 c->id, rseq, ack, len EDB
935 * the following handles the case of a single pair of packets
936 * received out of order
939 if(n > 0 && (drop == 0. || frand() > drop)) {
940 c->stat.missing += n-1;
942 write(c->pppfd, p, len);
944 /* out of sequence - drop on the floor */
947 SDB "%I: %.3f: gre %d: recv out of order or dup packet: seq=%ux len=%d\n",
948 srv.remote, realtime(), c->id, rseq, len EDB
953 if((int)(rseq-c->rseq) > 0)
959 /* open up client window */
960 if((int)(c->rseq-c->rack) > (c->recvwindow>>1))
977 SDB "%I: %.3f: gre %d: send ack %ux\n", srv.remote, realtime(), c->id, c->rseq EDB
979 v6tov4(buf+0, srv.local); /* source */
980 v6tov4(buf+4, srv.remote); /* source */
981 PSHORT(buf+8, GRE_key|GRE_ack|1);
982 PSHORT(buf+10, GRE_ppp);
984 PSHORT(buf+14, c->id);
985 PLONG(buf+16, c->rseq);
987 write(srv.grefd, buf, sizeof(buf));
1016 uchar buf[2000], *p;
1023 n = read(c->pppfd, p, sizeof(buf)-24);
1029 /* add gre header */
1033 while(c->seq-c->ack>c->sendwindow && c->tick-tick<Sendtimeout && !c->closed) {
1035 SDB "window full seq = %d ack = %ux window = %ux\n", c->seq, c->ack, c->sendwindow EDB
1041 if(c->tick-tick >= Sendtimeout) {
1042 c->stat.sendtimeout++;
1043 SDB "send timeout = %d ack = %ux window = %ux\n", c->seq, c->ack, c->sendwindow EDB
1046 v6tov4(buf+0, srv.local); /* source */
1047 v6tov4(buf+4, srv.remote); /* source */
1048 PSHORT(buf+8, GRE_key|GRE_seq|GRE_ack|1);
1049 PSHORT(buf+10, GRE_ppp);
1051 PSHORT(buf+14, c->id);
1052 PLONG(buf+16, c->seq);
1053 PLONG(buf+20, c->rseq);
1058 SDB "%I: %.3f: gre %d: send s=%ux a=%ux len=%d\n", srv.remote, realtime(),
1059 c->id, c->seq, c->rseq, n EDB
1061 if(drop == 0. || frand() > drop)
1062 if(write(srv.grefd, buf, n+24)<n+24)
1063 myfatal("pppread: write failed: %r");
1068 SDB "pppread exit: %d\n", c->id);
1075 timeoutthread(void*)
1081 if(realtime() - srv.rcvtime > 5*60)
1082 myfatal("server timedout");
1088 /* use syslog() rather than fprint(2, ...) */
1090 myfatal(char *fmt, ...)
1096 /* NT don't seem to like us just going away */
1097 memset(buf, 0, sizeof(buf));
1098 PSHORT(buf+0, sizeof(buf)); /* length */
1099 PSHORT(buf+2, 1); /* message type */
1100 PLONG(buf+4, Magic); /* magic */
1101 PSHORT(buf+8, Tstop); /* op */
1102 buf[12] = 3; /* local shutdown */
1104 write(1, buf, sizeof(buf));
1107 vseprint(sbuf, sbuf+sizeof(sbuf), fmt, arg);
1110 SDB "%I: fatal: %s\n", srv.remote, sbuf EDB
1111 syslog(0, LOG, ": src=%I: fatal: %s", srv.remote, sbuf);
1118 postnote(PNGROUP, getpid(), "die");
1131 i = strtol(p, &q, 0);
1138 dhcpclientwatch(void *a)
1144 if(read(c->dhcpfd[0], buf, sizeof(buf)) <= 0)
1148 myfatal("dhcpclient terminated");
1154 ipaddralloc(Call *c)
1160 argv[0] = "/bin/ip/dhcpclient";
1162 argv[2] = srv.pppdir;
1166 myfatal("ipaddralloc: pipe failed: %r");
1168 myfatal("ipaddralloc: pipe failed: %r");
1170 if(proc(argv, pfd[0][0], pfd[1][1], 2) < 0)
1171 myfatal("ipaddralloc: proc failed: %r");
1175 c->dhcpfd[0] = pfd[1][0];
1176 c->dhcpfd[1] = pfd[0][1];
1178 Binit(&bio, pfd[1][0], OREAD);
1180 p = Brdline(&bio, '\n');
1183 if(strncmp(p, "ip=", 3) == 0) {
1185 parseip(c->remoteip, p);
1186 } else if(strncmp(p, "end\n", 4) == 0)
1194 thread(dhcpclientwatch, c);
1196 return ipcmp(c->remoteip, IPnoaddr) != 0;
1209 assert(e->ready == 0);
1211 rendezvous(e, (void*)1);
1220 assert(e->wait == 0);
1226 rendezvous(e, (void*)2);
1230 qunlock(&e->waitlk);
1234 thread(void(*f)(void*), void *a)
1237 pid=rfork(RFNOWAIT|RFMEM|RFPROC);
1239 myfatal("rfork failed: %r");
1243 return 0; // never reaches here
1251 return times(0) / 1000.0;
1260 myfatal("malloc failed: %r");
1271 if((fd = open("#d", OREAD)) < 0)
1274 n = dirreadall(fd, &d);
1275 for(p = d; n > 0; n--, p++) {
1284 proc(char **argv, int fd0, int fd1, int fd2)
1287 char *arg0, file[200];
1293 if(access(file, 1) < 0) {
1294 if(strncmp(arg0, "/", 1)==0
1295 || strncmp(arg0, "#", 1)==0
1296 || strncmp(arg0, "./", 2)==0
1297 || strncmp(arg0, "../", 3)==0)
1299 sprint(file, "/bin/%s", arg0);
1300 if(access(file, 1) < 0)
1304 flag = RFPROC|RFFDG|RFENVG|RFNOWAIT;
1305 if((r = rfork(flag)) != 0) {
1338 myfatal("proc: exec failed: %r");