]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/ip/pptpd.c
snoopy(8): avoid extra spaces in dhcp filter output
[plan9front.git] / sys / src / cmd / ip / pptpd.c
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <ip.h>
5
6 #define LOG     "pptpd"
7
8 typedef struct Call     Call;
9 typedef struct Event Event;
10
11 #define SDB     if(debug) fprint(2, 
12 #define EDB     );
13
14 enum {
15         Magic   = 0x1a2b3c4d,
16         Nhash   = 17,
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 */
23 };
24
25 enum {
26         Syncframe       = 0x1,
27         Asyncframe      = 0x2,
28         Analog          = 0x1,
29         Digital         = 0x2,
30         Version         = 0x100,
31 };
32
33 enum {
34         Tstart          = 1,
35         Rstart          = 2,
36         Tstop           = 3,
37         Rstop           = 4,
38         Techo           = 5,
39         Recho           = 6,
40         Tcallout        = 7,
41         Rcallout        = 8,
42         Tcallreq        = 9,
43         Rcallreq        = 10,
44         Acallcon        = 11,
45         Tcallclear      = 12,
46         Acalldis        = 13,
47         Awaninfo        = 14,
48         Alinkinfo       = 15,
49 };
50
51
52 struct Event {
53         QLock;
54         QLock waitlk;
55         int     wait;
56         int ready;
57 };
58
59 struct Call {
60         int     ref;
61         QLock   lk;
62         int     id;
63         int     serial;
64         int     pppfd;
65
66         int     closed;
67
68         int     pac;    /* server is acting as a PAC */
69
70         int     recvwindow;     /* recv windows */
71         int     sendwindow;     /* send windows */
72         int     delay;
73
74         int     sendaccm;
75         int     recvaccm;
76
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 */
81
82         Event   eack;           /* recved ack - for send */
83         ulong   tick;
84
85         uchar   remoteip[IPaddrlen];    /* remote ip address */
86         int     dhcpfd[2];      /* pipe to dhcpclient */
87
88         /* error stats */
89         struct {
90                 int     crc;
91                 int     frame;
92                 int     hardware;
93                 int     overrun;
94                 int     timeout;
95                 int     align;
96         } err;
97
98         struct {
99                 int     send;
100                 int     sendack;
101                 int     recv;
102                 int     recvack;
103                 int     dropped;
104                 int     missing;
105                 int     sendwait;
106                 int     sendtimeout;
107         } stat;
108
109         Call    *next;
110 };
111
112 struct {
113         QLock   lk;
114         int     start;
115         int     grefd;
116         int     grecfd;
117         uchar   local[IPaddrlen];
118         uchar   remote[IPaddrlen];
119         char    *tcpdir;
120         uchar   ipaddr[IPaddrlen];              /* starting ip addresss to allocate */
121
122         int     recvwindow;
123
124         char    *pppdir;
125         char    *pppexec;
126
127         double  rcvtime;        /* time at which last request was received */
128         int     echoid;         /* id of last echo request */
129
130         Call    *hash[Nhash];
131 } srv;
132
133 /* GRE flag bits */
134 enum {
135         GRE_chksum      = (1<<15),
136         GRE_routing     = (1<<14),
137         GRE_key         = (1<<13),
138         GRE_seq         = (1<<12),
139         GRE_srcrt       = (1<<11),
140         GRE_recur       = (7<<8),
141         GRE_ack         = (1<<7),
142         GRE_ver         = 0x7,
143 };
144
145 /* GRE protocols */
146 enum {
147         GRE_ppp         = 0x880b,
148 };
149
150 int     debug;
151 double  drop;
152
153 void    myfatal(char *fmt, ...);
154
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
161
162 void    serve(void);
163
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);
174
175 Call    *callalloc(int id);
176 void    callclose(Call*);
177 void    callfree(Call*);
178 Call    *calllookup(int id);
179
180 void    gretimeout(void*);
181 void    pppread(void*);
182
183 void    srvinit(void);
184 void    greinit(void);
185 void    greread(void*);
186 void    greack(Call *c);
187
188 void    timeoutthread(void*);
189
190 int     argatoi(char *p);
191 void    usage(void);
192 int     ipaddralloc(Call *c);
193
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);
200
201 void
202 main(int argc, char *argv[])
203 {
204         ARGBEGIN{
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;
210         default:
211                 usage();
212         }ARGEND
213
214         fmtinstall('I', eipfmt);
215         fmtinstall('E', eipfmt);
216         fmtinstall('V', eipfmt);
217         fmtinstall('M', eipfmt);
218
219         rfork(RFNOTEG|RFREND);
220
221         if(argc != 1)
222                 usage();
223
224         srv.tcpdir = argv[0];
225
226         srvinit();
227
228         syslog(0, LOG, ": src=%I: pptp started: %d", srv.remote, getpid());
229
230         SDB  "\n\n\n%I: pptp started\n", srv.remote EDB
231
232         greinit();
233
234         thread(timeoutthread, 0);
235
236         serve();
237
238         syslog(0, LOG, ": src=%I: server exits", srv.remote);
239
240         postnote(PNGROUP, getpid(), "die");
241         exits(0);
242 }
243
244 void
245 usage(void)
246 {
247         fprint(2, "usage: pptpd [-dD] [-p ppp-net] [-w window] tcpdir\n");
248         exits("usage");
249 }
250
251 void
252 serve(void)
253 {
254         uchar buf[2000], *p;
255         int n, n2, len;
256         int magic;
257         int op, type;
258
259         n = 0;
260         for(;;) {
261                 n2 = read(0, buf+n, sizeof(buf)-n);
262                 if(n2 < 0)
263                         myfatal("bad read on ctl channel: %r");
264                 if(n2 == 0)
265                         break;
266                 n += n2;
267                 p = buf;
268                 for(;;) {
269                         if(n < 12)
270                                 break;
271
272                         qlock(&srv.lk);
273                         srv.rcvtime = realtime();
274                         qunlock(&srv.lk);
275
276                         len = GSHORT(p);
277                         type = GSHORT(p+2);
278                         magic = GLONG(p+4);
279                         op = GSHORT(p+8);
280                         if(magic != Magic)
281                                 myfatal("bad magic number: got %x", magic);
282                         if(type != 1)
283                                 myfatal("bad message type: %d", type);
284                         switch(op) {
285                         default:
286                                 myfatal("unknown control op: %d", op);
287                         case Tstart:            /* start-control-connection-request */
288                                 n2 = sstart(p, n);
289                                 break;
290                         case Tstop:
291                                 n2 = sstop(p, n);
292                                 if(n2 > 0)
293                                         return;
294                                 break;
295                         case Techo:
296                                 n2 = secho(p, n);
297                                 break;
298                         case Tcallout:
299                                 n2 = scallout(p, n);
300                                 break;
301                         case Tcallreq:
302                                 n2 = scallreq(p, n);
303                                 break;
304                         case Acallcon:
305                                 n2 = scallcon(p, n);
306                                 break;
307                         case Tcallclear:
308                                 n2 = scallclear(p, n);
309                                 break;
310                         case Acalldis:
311                                 n2 = scalldis(p, n);
312                                 break;
313                         case Awaninfo:
314                                 n2 = swaninfo(p, n);
315                                 break;
316                         case Alinkinfo:
317                                 n2 = slinkinfo(p, n);
318                                 break;
319                         }       
320                         if(n2 == 0)
321                                 break;
322                         if(n2 != len)
323                                 myfatal("op=%d: bad length: got %d expected %d", op, len, n2);
324                         n -= n2;
325                         p += n2;
326                         
327                 }
328
329                 /* move down partial message */
330                 if(p != buf && n != 0)
331                         memmove(buf, p, n);
332         }
333
334 }
335
336 int
337 sstart(uchar *p, int n)
338 {
339         int ver, frame, bearer, maxchan, firm;
340         char host[64], vendor[64], *sysname;
341         uchar buf[156];
342
343         if(n < 156)
344                 return 0;
345         ver = GSHORT(p+12);
346         frame = GLONG(p+16);
347         bearer = GLONG(p+20);
348         maxchan = GSHORT(p+24);
349         firm = GSHORT(p+26);
350         GSTRING(host, p+28, 64);
351         GSTRING(vendor, p+92, 64);
352
353         SDB "%I: start ver = %x f = %d b = %d maxchan = %d firm = %d host = %s vendor = %s\n",
354                 srv.remote, ver, frame, bearer, maxchan, firm, host, vendor EDB
355
356         if(ver != Version)
357                 myfatal("bad version: got %x expected %x", ver, Version);
358
359         if(srv.start)
360                 myfatal("multiple start messages");
361
362         srv.start = 1;
363
364         sysname = getenv("sysname");
365         if(sysname == 0)
366                 strcpy(host, "gnot");
367         else
368                 strncpy(host, sysname, 64);
369         free(sysname);
370
371         memset(buf, 0, sizeof(buf));
372
373         PSHORT(buf+0, sizeof(buf));     /* length */
374         PSHORT(buf+2, 1);               /* message type */
375         PLONG(buf+4, Magic);            /* magic */
376         PSHORT(buf+8, Rstart);          /* op */
377         PSHORT(buf+12, Version);        /* version */
378         buf[14] = 1;                    /* result = ok */
379         PLONG(buf+16, Syncframe|Asyncframe);    /* frameing */
380         PLONG(buf+20, Digital|Analog);  /* berear capabilities */
381         PSHORT(buf+24, Nchan);          /* max channels */
382         PSHORT(buf+26, 1);              /* driver version */
383         PSTRING(buf+28, host, 64);      /* host name */
384         PSTRING(buf+92, "plan 9", 64);  /* vendor */
385
386         if(write(1, buf, sizeof(buf)) < sizeof(buf))
387                 myfatal("write failed: %r");
388
389         return 156;
390 }
391
392 int
393 sstop(uchar *p, int n)
394 {
395         int reason;
396         uchar buf[16];
397
398         if(n < 16)
399                 return 0;
400         reason = p[12];
401         
402         SDB "%I: stop %d\n", srv.remote, reason EDB
403
404         memset(buf, 0, sizeof(buf));
405         PSHORT(buf+0, sizeof(buf));     /* length */
406         PSHORT(buf+2, 1);               /* message type */
407         PLONG(buf+4, Magic);            /* magic */
408         PSHORT(buf+8, Rstop);           /* op */
409         buf[12] = 1;                    /* ok */
410
411         if(write(1, buf, sizeof(buf)) < sizeof(buf))
412                 myfatal("write failed: %r");
413
414         return 16;
415 }
416
417 int
418 secho(uchar *p, int n)
419 {
420         int id;
421         uchar buf[20];
422
423         if(n < 16)
424                 return 0;
425         id = GLONG(p+12);
426         
427         SDB "%I: echo %d\n", srv.remote, id EDB
428
429         memset(buf, 0, sizeof(buf));
430         PSHORT(buf+0, sizeof(buf));     /* length */
431         PSHORT(buf+2, 1);               /* message type */
432         PLONG(buf+4, Magic);            /* magic */
433         PSHORT(buf+8, Recho);           /* op */
434         PLONG(buf+12, id);              /* id */
435         p[16] = 1;                      /* ok */
436
437         if(write(1, buf, sizeof(buf)) < sizeof(buf))
438                 myfatal("write failed: %r");
439
440         return 16;
441 }
442
443 int
444 scallout(uchar *p, int n)
445 {
446         int id, serial;
447         int minbps, maxbps, bearer, frame;
448         int window, delay;
449         int nphone;
450         char phone[64], sub[64], buf[32];
451         Call *c;
452
453         if(n < 168)
454                 return 0;
455
456         if(!srv.start)
457                 myfatal("%I: did not recieve start message", srv.remote);
458         
459         id = GSHORT(p+12);
460         serial = GSHORT(p+14);
461         minbps = GLONG(p+16);
462         maxbps = GLONG(p+20);
463         bearer = GLONG(p+24);
464         frame = GLONG(p+28);
465         window = GSHORT(p+32);
466         delay = GSHORT(p+34);
467         nphone = GSHORT(p+36);
468         GSTRING(phone, p+40, 64);
469         GSTRING(sub, p+104, 64);
470
471         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",
472                 srv.remote, id, serial, minbps, maxbps, bearer, frame, window, delay, nphone, phone, sub EDB
473
474         c = callalloc(id);
475         c->sendwindow = window;
476         c->delay = delay;
477         c->pac = 1;
478         c->recvwindow = srv.recvwindow;
479
480         memset(buf, 0, sizeof(buf));
481         PSHORT(buf+0, sizeof(buf));     /* length */
482         PSHORT(buf+2, 1);               /* message type */
483         PLONG(buf+4, Magic);            /* magic */
484         PSHORT(buf+8, Rcallout);        /* op */
485         PSHORT(buf+12, id);             /* call id */
486         PSHORT(buf+14, id);             /* peer id */
487         buf[16] = 1;                    /* ok */
488         PLONG(buf+20, 10000000);        /* speed */
489         PSHORT(buf+24, c->recvwindow);  /* window size */
490         PSHORT(buf+26, 0);              /* delay */
491         PLONG(buf+28, 0);               /* channel id */
492         
493         if(write(1, buf, sizeof(buf)) < sizeof(buf))
494                 myfatal("write failed: %r");
495
496         return 168;
497 }
498
499 int
500 scallreq(uchar *p, int n)
501 {
502         USED(p);
503         USED(n);
504
505         myfatal("callreq: not done yet");
506         return 0;
507 }
508
509 int
510 scallcon(uchar *p, int n)
511 {
512         USED(p);
513         USED(n);
514
515         myfatal("callcon: not done yet");
516         return 0;
517 }
518
519 int
520 scallclear(uchar *p, int n)
521 {
522         Call *c;
523         int id;
524         uchar buf[148];
525
526         if(n < 16)
527                 return 0;
528         id = GSHORT(p+12);
529         
530         SDB "%I: callclear id=%d\n", srv.remote, id EDB
531         
532         if(c = calllookup(id)) {
533                 callclose(c);
534                 callfree(c);
535         }
536
537         memset(buf, 0, sizeof(buf));
538         PSHORT(buf+0, sizeof(buf));     /* length */
539         PSHORT(buf+2, 1);               /* message type */
540         PLONG(buf+4, Magic);            /* magic */
541         PSHORT(buf+8, Acalldis);        /* op */
542         PSHORT(buf+12, id);             /* id */
543         buf[14] = 3;                    /* reply to callclear */
544
545         if(write(1, buf, sizeof(buf)) < sizeof(buf))
546                 myfatal("write failed: %r");
547
548         return 16;
549 }
550
551 int
552 scalldis(uchar *p, int n)
553 {
554         Call *c;
555         int id, res;
556
557         if(n < 148)
558                 return 0;
559         id = GSHORT(p+12);
560         res = p[14];
561
562         SDB "%I: calldis id=%d res=%d\n", srv.remote, id, res EDB
563
564         if(c = calllookup(id)) {
565                 callclose(c);
566                 callfree(c);
567         }
568
569         return 148;
570 }
571
572 int
573 swaninfo(uchar *p, int n)
574 {
575         Call *c;
576         int id;
577
578         if(n < 40)
579                 return 0;
580         
581         id = GSHORT(p+12);
582         SDB "%I: waninfo id = %d\n", srv.remote, id EDB
583         
584         c = calllookup(id);
585         if(c != 0) {
586                 c->err.crc = GLONG(p+16);
587                 c->err.frame = GLONG(p+20);
588                 c->err.hardware = GLONG(p+24);
589                 c->err.overrun = GLONG(p+28);
590                 c->err.timeout = GLONG(p+32);
591                 c->err.align = GLONG(p+36);
592
593                 callfree(c);
594         }
595
596         
597         return 40;
598 }
599
600 int
601 slinkinfo(uchar *p, int n)
602 {
603         Call *c;
604         int id;
605         int sendaccm, recvaccm;
606
607         if(n < 24)
608                 return 0;
609         id = GSHORT(p+12);
610         sendaccm = GLONG(p+16);
611         recvaccm = GLONG(p+20);
612
613         SDB "%I: linkinfo id=%d saccm=%ux raccm=%ux\n", srv.remote, id, sendaccm, recvaccm EDB
614
615         if(c = calllookup(id)) {
616                 c->sendaccm = sendaccm;
617                 c->recvaccm = recvaccm;
618
619                 callfree(c);
620         }
621         
622         return 24;
623 }
624
625 Call*
626 callalloc(int id)
627 {
628         uint h;
629         Call *c;
630         char *argv[30], local[20], remote[20], **p;
631         int pfd[2];
632
633         h = id%Nhash;
634
635         qlock(&srv.lk);
636         for(c=srv.hash[h]; c; c=c->next)
637                 if(c->id == id)
638                         myfatal("callalloc: duplicate id: %d", id);
639         c = emallocz(sizeof(Call));
640         c->ref = 1;
641         c->id = id;
642         c->sendaccm = ~0;
643         c->recvaccm = ~0;
644
645         if(!ipaddralloc(c))
646                 myfatal("callalloc: could not alloc remote ip address");
647
648         if(pipe(pfd) < 0)
649                 myfatal("callalloc: pipe failed: %r");
650
651         p = argv;
652         *p++ = srv.pppexec;
653         *p++ = "-SC";
654         *p++ = "-x";
655         *p++ = srv.pppdir;
656         if(debug)
657                 *p++ = "-d";
658         sprint(local, "%I", srv.ipaddr);
659         *p++ = local;
660         sprint(remote, "%I", c->remoteip);
661         *p++ = remote;
662         *p = 0;
663
664         proc(argv, pfd[0], pfd[0], 2);
665
666         close(pfd[0]);
667
668         c->pppfd = pfd[1];
669
670         c->next = srv.hash[h];
671         srv.hash[h] = c;
672
673         qunlock(&srv.lk);
674
675         c->ref++;
676         thread(pppread, c);
677         c->ref++;
678         thread(gretimeout, c);
679
680         syslog(0, LOG, ": src=%I: call started: id=%d: remote ip=%I", srv.remote, id, c->remoteip);
681
682         return c;
683 }
684
685 void
686 callclose(Call *c)
687 {
688         Call *oc;
689         int id;
690         uint h;
691
692         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",
693                 srv.remote, c->id, c->stat.send, c->stat.sendack, c->stat.recv, c->stat.recvack,
694                 c->stat.dropped, c->stat.missing, c->stat.sendwait, c->stat.sendtimeout);
695
696         qlock(&srv.lk);
697         if(c->closed) {
698                 qunlock(&srv.lk);
699                 return;
700         }
701         c->closed = 1;
702
703         close(c->dhcpfd[0]);
704         close(c->dhcpfd[1]);
705         close(c->pppfd);
706         c->pppfd = -1;
707
708         h = c->id%Nhash;
709         id = c->id;
710         for(c=srv.hash[h],oc=0; c; oc=c,c=c->next)
711                 if(c->id == id)
712                         break;
713         if(oc == 0)
714                 srv.hash[h] = c->next;
715         else
716                 oc->next = c->next;
717         c->next = 0;
718         qunlock(&srv.lk);
719
720         callfree(c);
721 }
722
723 void
724 callfree(Call *c)
725 {       
726         int ref;
727         
728         qlock(&srv.lk);
729         ref = --c->ref;
730         qunlock(&srv.lk);
731         if(ref > 0)
732                 return;
733         
734         /* already unhooked from hash list - see callclose */
735         assert(c->closed == 1);
736         assert(ref == 0);
737         assert(c->next == 0);
738
739 SDB "call free\n" EDB   
740         free(c);
741 }
742
743 Call*
744 calllookup(int id)
745 {
746         uint h;
747         Call *c;
748
749         h = id%Nhash;
750
751         qlock(&srv.lk);
752         for(c=srv.hash[h]; c; c=c->next)
753                 if(c->id == id)
754                         break;
755         if(c != 0)
756                 c->ref++;
757         qunlock(&srv.lk);
758
759         return c;
760 }
761
762
763 void
764 srvinit(void)
765 {
766         char buf[100];
767         int fd, n;
768
769         sprint(buf, "%s/local", srv.tcpdir);
770         if((fd = open(buf, OREAD)) < 0)
771                 myfatal("could not open %s: %r", buf);
772         if((n = read(fd, buf, sizeof(buf))) < 0)
773                 myfatal("could not read %s: %r", buf);
774         buf[n] = 0;
775         parseip(srv.local, buf);
776         close(fd);
777
778         sprint(buf, "%s/remote", 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);
783         buf[n] = 0;
784         parseip(srv.remote, buf);
785         close(fd);
786
787         if(srv.pppdir == 0)
788                 srv.pppdir = "/net";
789
790         if(srv.pppexec == 0)
791                 srv.pppexec = "/bin/ip/ppp";
792
793         if(myipaddr(srv.ipaddr, srv.pppdir) < 0)
794                 myfatal("could not read local ip addr: %r");
795         if(srv.recvwindow == 0)
796                 srv.recvwindow = Window;
797 }
798
799 void
800 greinit(void)
801 {
802         char addr[100], *p;
803         int fd, cfd;
804
805         SDB "srv.tcpdir = %s\n", srv.tcpdir EDB
806         strcpy(addr, srv.tcpdir);
807         p = strrchr(addr, '/');
808         if(p == 0)
809                 myfatal("bad tcp dir: %s", srv.tcpdir);
810         *p = 0;
811         p = strrchr(addr, '/');
812         if(p == 0)
813                 myfatal("bad tcp dir: %s", srv.tcpdir);
814         sprint(p, "/gre!%I!34827", srv.remote);
815
816         SDB "addr = %s\n", addr EDB
817
818         fd = dial(addr, 0, 0, &cfd);
819
820         if(fd < 0)
821                 myfatal("%I: dial %s failed: %r", srv.remote, addr);
822
823         srv.grefd = fd;
824         srv.grecfd = cfd;
825
826         thread(greread, 0);
827 }
828
829 void
830 greread(void *)
831 {
832         uchar buf[Pktsize], *p;
833         int n, i;
834         int flag, prot, len, callid;
835         uchar src[IPaddrlen], dst[IPaddrlen];
836         uint rseq, ack;
837         Call *c;
838         static double t, last;
839
840         for(;;) {
841                 n = read(srv.grefd, buf, sizeof(buf));
842                 if(n < 0)
843                         myfatal("%I: bad read on gre: %r", srv.remote);
844                 if(n == sizeof(buf))
845                         myfatal("%I: gre read: buf too small", srv.remote);
846
847                 p = buf;
848                 v4tov6(src, p);
849                 v4tov6(dst, p+4);
850                 flag = GSHORT(p+8);
851                 prot = GSHORT(p+10);
852                 p += 12; n -= 12;
853
854                 if(ipcmp(src, srv.remote) != 0 || ipcmp(dst, srv.local) != 0)
855                         myfatal("%I: gre read bad address src=%I dst=%I", srv.remote, src, dst);
856
857                 if(prot != GRE_ppp)
858                         myfatal("%I: gre read gave bad protocol", srv.remote);
859
860                 if(flag & (GRE_chksum|GRE_routing)){
861                         p += 4; n -= 4;
862                 }
863
864                 if(!(flag&GRE_key))
865                         myfatal("%I: gre packet does not contain a key: f=%ux",
866                                 srv.remote, flag);
867
868                 len = GSHORT(p);
869                 callid = GSHORT(p+2);
870                 p += 4; n -= 4;
871
872                 c = calllookup(callid);
873                 if(c == 0) {
874                         SDB "%I: unknown callid: %d\n", srv.remote, callid EDB
875                         continue;
876                 }
877
878                 qlock(&c->lk);
879
880                 c->stat.recv++;
881
882                 if(flag&GRE_seq) {
883                         rseq = GLONG(p);
884                         p += 4; n -= 4;
885                 } else
886                         rseq = c->rseq;
887
888                 if(flag&GRE_ack){
889                         ack = GLONG(p);
890                         p += 4; n -= 4;
891                 } else
892                         ack = c->ack;
893
894                 /* skip routing if present */
895                 if(flag&GRE_routing) {
896                         while((i=p[3]) != 0) {
897                                 n -= i;
898                                 p += i;
899                         }
900                 }
901
902                 if(len > n)
903                         myfatal("%I: bad len in gre packet", srv.remote);
904
905                 if((int)(ack-c->ack) > 0) {
906                         c->ack = ack;
907                         esignal(&c->eack);
908                 }
909
910                 if(debug)
911                         t = realtime();
912
913                 if(len == 0) {
914                         /* ack packet */
915                         c->stat.recvack++;
916
917 SDB "%I: %.3f (%.3f): gre %d: recv ack a=%ux n=%d flag=%ux\n", srv.remote, t, t-last,
918         c->id, ack, n, flag EDB
919
920                 } else {
921
922 SDB "%I: %.3f (%.3f): gre %d: recv s=%ux a=%ux len=%d\n", srv.remote, t, t-last,
923         c->id, rseq, ack, len EDB
924
925                         /*
926                          * the following handles the case of a single pair of packets
927                          * received out of order
928                          */
929                         n = rseq-c->rseq;
930                         if(n > 0 && (drop == 0. || frand() > drop)) {
931                                 c->stat.missing += n-1;
932                                 /* current packet */
933                                 write(c->pppfd, p, len);
934                         } else {
935                                 /* out of sequence - drop on the floor */
936                                 c->stat.dropped++;
937
938 SDB "%I: %.3f: gre %d: recv out of order or dup packet: seq=%ux len=%d\n",
939 srv.remote, realtime(), c->id, rseq, len EDB
940
941                         }
942                 }
943
944                 if((int)(rseq-c->rseq) > 0)
945                         c->rseq = rseq;
946
947                 if(debug)
948                         last=t;
949
950                 /* open up client window */
951                 if((int)(c->rseq-c->rack) > (c->recvwindow>>1))
952                         greack(c);
953
954                 qunlock(&c->lk);
955
956
957                 callfree(c);
958         }
959 }
960
961 void
962 greack(Call *c)
963 {
964         uchar buf[20];
965
966         c->stat.sendack++;
967
968 SDB "%I: %.3f: gre %d: send ack %ux\n", srv.remote, realtime(), c->id, c->rseq EDB
969
970         v6tov4(buf+0, srv.local);               /* source */
971         v6tov4(buf+4, srv.remote);              /* source */
972         PSHORT(buf+8, GRE_key|GRE_ack|1);
973         PSHORT(buf+10, GRE_ppp);
974         PSHORT(buf+12, 0);
975         PSHORT(buf+14, c->id);
976         PLONG(buf+16, c->rseq);
977
978         write(srv.grefd, buf, sizeof(buf));
979
980         c->rack = c->rseq;
981
982 }
983
984 void
985 gretimeout(void *a)
986 {
987         Call *c;
988
989         c = a;
990
991         while(!c->closed) {
992                 sleep(Tick);
993                 qlock(&c->lk);
994                 c->tick++;
995                 qunlock(&c->lk);
996                 esignal(&c->eack);
997         }
998         callfree(c);
999         exits(0);
1000 }
1001
1002
1003 void
1004 pppread(void *a)
1005 {
1006         Call *c;
1007         uchar buf[2000], *p;
1008         int n;
1009         ulong tick;
1010
1011         c = a;
1012         for(;;) {
1013                 p = buf+24;
1014                 n = read(c->pppfd, p, sizeof(buf)-24);
1015                 if(n <= 0)
1016                         break;
1017                 
1018                 qlock(&c->lk);
1019
1020                 /* add gre header */
1021                 c->seq++;
1022                 tick = c->tick;
1023
1024                 while(c->seq-c->ack>c->sendwindow && c->tick-tick<Sendtimeout && !c->closed) {
1025                         c->stat.sendwait++;
1026 SDB "window full seq = %d ack = %ux window = %ux\n", c->seq, c->ack, c->sendwindow EDB
1027                         qunlock(&c->lk);
1028                         ewait(&c->eack);
1029                         qlock(&c->lk);
1030                 }
1031                 
1032                 if(c->tick-tick >= Sendtimeout) {
1033                         c->stat.sendtimeout++;
1034 SDB "send timeout = %d ack = %ux window = %ux\n", c->seq, c->ack, c->sendwindow EDB
1035                 }
1036
1037                 v6tov4(buf+0, srv.local);               /* source */
1038                 v6tov4(buf+4, srv.remote);              /* source */
1039                 PSHORT(buf+8, GRE_key|GRE_seq|GRE_ack|1);
1040                 PSHORT(buf+10, GRE_ppp);
1041                 PSHORT(buf+12, n);
1042                 PSHORT(buf+14, c->id);
1043                 PLONG(buf+16, c->seq);
1044                 PLONG(buf+20, c->rseq);
1045
1046                 c->stat.send++;
1047                 c->rack = c->rseq;
1048
1049 SDB "%I: %.3f: gre %d: send s=%ux a=%ux len=%d\n", srv.remote, realtime(),
1050         c->id,  c->seq, c->rseq, n EDB
1051
1052                 if(drop == 0. || frand() > drop)
1053                         if(write(srv.grefd, buf, n+24)<n+24)
1054                                 myfatal("pppread: write failed: %r");
1055
1056                 qunlock(&c->lk);
1057         }
1058
1059         SDB "pppread exit: %d\n", c->id);
1060         
1061         callfree(c);
1062         exits(0);
1063 }
1064
1065 void
1066 timeoutthread(void*)
1067 {
1068         for(;;) {
1069                 sleep(30*1000);
1070
1071                 qlock(&srv.lk);
1072                 if(realtime() - srv.rcvtime > 5*60)
1073                         myfatal("server timedout");
1074                 qunlock(&srv.lk);
1075         }
1076 }
1077
1078
1079 /* use syslog() rather than fprint(2, ...) */
1080 void
1081 myfatal(char *fmt, ...)
1082 {
1083         char sbuf[512];
1084         va_list arg;
1085         uchar buf[16];
1086
1087         /* NT don't seem to like us just going away */
1088         memset(buf, 0, sizeof(buf));
1089         PSHORT(buf+0, sizeof(buf));     /* length */
1090         PSHORT(buf+2, 1);               /* message type */
1091         PLONG(buf+4, Magic);            /* magic */
1092         PSHORT(buf+8, Tstop);           /* op */
1093         buf[12] = 3;                    /* local shutdown */
1094
1095         write(1, buf, sizeof(buf));
1096
1097         va_start(arg, fmt);
1098         vseprint(sbuf, sbuf+sizeof(sbuf), fmt, arg);
1099         va_end(arg);
1100
1101         SDB "%I: fatal: %s\n", srv.remote, sbuf EDB
1102         syslog(0, LOG, ": src=%I: fatal: %s", srv.remote, sbuf);
1103
1104         close(0);
1105         close(1);
1106         close(srv.grefd);
1107         close(srv.grecfd);
1108
1109         postnote(PNGROUP, getpid(), "die");
1110         exits(sbuf);
1111 }
1112
1113 int
1114 argatoi(char *p)
1115 {
1116         char *q;
1117         int i;
1118
1119         if(p == 0)
1120                 usage();
1121
1122         i = strtol(p, &q, 0);
1123         if(q == p)
1124                 usage();
1125         return i;
1126 }
1127
1128 void
1129 dhcpclientwatch(void *a)
1130 {
1131         Call *c = a;
1132         uchar buf[1];
1133
1134         for(;;) {
1135                 if(read(c->dhcpfd[0], buf, sizeof(buf)) <= 0)
1136                         break;
1137         }
1138         if(!c->closed)
1139                 myfatal("dhcpclient terminated");
1140         callfree(c);
1141         exits(0);
1142 }
1143
1144 int
1145 ipaddralloc(Call *c)
1146 {
1147         int pfd[2][2];
1148         char *argv[4], *p;
1149         Biobuf bio;
1150
1151         argv[0] = "/bin/ip/dhcpclient";
1152         argv[1] = "-x";
1153         argv[2] = srv.pppdir;
1154         argv[3] = 0;
1155
1156         if(pipe(pfd[0])<0)
1157                 myfatal("ipaddralloc: pipe failed: %r");
1158         if(pipe(pfd[1])<0)
1159                 myfatal("ipaddralloc: pipe failed: %r");
1160
1161         if(proc(argv, pfd[0][0], pfd[1][1], 2) < 0)
1162                 myfatal("ipaddralloc: proc failed: %r");
1163
1164         close(pfd[0][0]);
1165         close(pfd[1][1]);
1166         c->dhcpfd[0] = pfd[1][0];
1167         c->dhcpfd[1] = pfd[0][1];
1168
1169         Binit(&bio, pfd[1][0], OREAD);
1170         for(;;) {
1171                 p = Brdline(&bio, '\n');
1172                 if(p == 0)
1173                         break;
1174                 if(strncmp(p, "ip=", 3) == 0) {
1175                         p += 3;
1176                         parseip(c->remoteip, p);
1177                 } else if(strncmp(p, "end\n", 4) == 0)
1178                         break;
1179         }
1180
1181         Bterm(&bio);
1182
1183         c->ref++;
1184
1185         thread(dhcpclientwatch, c);
1186
1187         return ipcmp(c->remoteip, IPnoaddr) != 0;
1188 }
1189
1190
1191 void
1192 esignal(Event *e)
1193 {       
1194         qlock(e);
1195         if(e->wait == 0) {
1196                 e->ready = 1;
1197                 qunlock(e);
1198                 return;
1199         }
1200         assert(e->ready == 0);
1201         e->wait = 0;
1202         rendezvous(e, (void*)1);
1203         qunlock(e);
1204 }
1205
1206 void
1207 ewait(Event *e)
1208 {
1209         qlock(&e->waitlk);
1210         qlock(e);
1211         assert(e->wait == 0);
1212         if(e->ready) {
1213                 e->ready = 0;
1214         } else {        
1215                 e->wait = 1;
1216                 qunlock(e);
1217                 rendezvous(e, (void*)2);
1218                 qlock(e);
1219         }
1220         qunlock(e);
1221         qunlock(&e->waitlk);
1222 }
1223
1224 ulong
1225 thread(void(*f)(void*), void *a)
1226 {
1227         int pid;
1228         pid=rfork(RFNOWAIT|RFMEM|RFPROC);
1229         if(pid < 0)
1230                 myfatal("rfork failed: %r");
1231         if(pid != 0)
1232                 return pid;
1233         (*f)(a);
1234         return 0; // never reaches here
1235 }
1236
1237 double
1238 realtime(void)
1239 {
1240         long times(long*);
1241
1242         return times(0) / 1000.0;
1243 }
1244
1245 void *
1246 emallocz(int size)
1247 {
1248         void *p;
1249         p = malloc(size);
1250         if(p == 0)
1251                 myfatal("malloc failed: %r");
1252         memset(p, 0, size);
1253         return p;
1254 }
1255
1256 static void
1257 fdclose(void)
1258 {
1259         int fd, n, i;
1260         Dir *d, *p;
1261
1262         if((fd = open("#d", OREAD)) < 0)
1263                 return;
1264
1265         n = dirreadall(fd, &d);
1266         for(p = d; n > 0; n--, p++) {
1267                 i = atoi(p->name);
1268                 if(i > 2)
1269                         close(i);
1270         }
1271         free(d);
1272 }
1273
1274 int
1275 proc(char **argv, int fd0, int fd1, int fd2)
1276 {
1277         int r, flag;
1278         char *arg0, file[200];
1279
1280         arg0 = argv[0];
1281
1282         strcpy(file, arg0);
1283
1284         if(access(file, 1) < 0) {
1285                 if(strncmp(arg0, "/", 1)==0
1286                 || strncmp(arg0, "#", 1)==0
1287                 || strncmp(arg0, "./", 2)==0
1288                 || strncmp(arg0, "../", 3)==0)
1289                         return 0;
1290                 sprint(file, "/bin/%s", arg0);
1291                 if(access(file, 1) < 0)
1292                         return 0;
1293         }
1294
1295         flag = RFPROC|RFFDG|RFENVG|RFNOWAIT;
1296         if((r = rfork(flag)) != 0) {
1297                 if(r < 0)
1298                         return 0;
1299                 return r;
1300         }
1301
1302         if(fd0 != 0) {
1303                 if(fd1 == 0)
1304                         fd1 = dup(0, -1);
1305                 if(fd2 == 0)
1306                         fd2 = dup(0, -1);
1307                 close(0);
1308                 if(fd0 >= 0)
1309                         dup(fd0, 0);
1310         }
1311
1312         if(fd1 != 1) {
1313                 if(fd2 == 1)
1314                         fd2 = dup(1, -1);
1315                 close(1);
1316                 if(fd1 >= 0)
1317                         dup(fd1, 1);
1318         }
1319
1320         if(fd2 != 2) {
1321                 close(2);
1322                 if(fd2 >= 0)
1323                         dup(fd2, 2);
1324         }
1325
1326         fdclose();
1327
1328         exec(file, argv);
1329         myfatal("proc: exec failed: %r");
1330         return 0;
1331 }
1332