]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/ip/pptpd.c
ip/ipconfig: treat /32 mask as /0
[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         exits(0);
241 }
242
243 void
244 usage(void)
245 {
246         fprint(2, "usage: pptpd [-dD] [-p ppp-net] [-w window] tcpdir\n");
247         exits("usage");
248 }
249
250 void
251 serve(void)
252 {
253         uchar buf[2000], *p;
254         int n, n2, len;
255         int magic;
256         int op, type;
257
258         n = 0;
259         for(;;) {
260                 n2 = read(0, buf+n, sizeof(buf)-n);
261                 if(n2 < 0)
262                         myfatal("bad read on ctl channel: %r");
263                 if(n2 == 0)
264                         break;
265                 n += n2;
266                 p = buf;
267                 for(;;) {
268                         if(n < 12)
269                                 break;
270
271                         qlock(&srv.lk);
272                         srv.rcvtime = realtime();
273                         qunlock(&srv.lk);
274
275                         len = GSHORT(p);
276                         type = GSHORT(p+2);
277                         magic = GLONG(p+4);
278                         op = GSHORT(p+8);
279                         if(magic != Magic)
280                                 myfatal("bad magic number: got %x", magic);
281                         if(type != 1)
282                                 myfatal("bad message type: %d", type);
283                         switch(op) {
284                         default:
285                                 myfatal("unknown control op: %d", op);
286                         case Tstart:            /* start-control-connection-request */
287                                 n2 = sstart(p, n);
288                                 break;
289                         case Tstop:
290                                 n2 = sstop(p, n);
291                                 if(n2 > 0)
292                                         return;
293                                 break;
294                         case Techo:
295                                 n2 = secho(p, n);
296                                 break;
297                         case Tcallout:
298                                 n2 = scallout(p, n);
299                                 break;
300                         case Tcallreq:
301                                 n2 = scallreq(p, n);
302                                 break;
303                         case Acallcon:
304                                 n2 = scallcon(p, n);
305                                 break;
306                         case Tcallclear:
307                                 n2 = scallclear(p, n);
308                                 break;
309                         case Acalldis:
310                                 n2 = scalldis(p, n);
311                                 break;
312                         case Awaninfo:
313                                 n2 = swaninfo(p, n);
314                                 break;
315                         case Alinkinfo:
316                                 n2 = slinkinfo(p, n);
317                                 break;
318                         }       
319                         if(n2 == 0)
320                                 break;
321                         if(n2 != len)
322                                 myfatal("op=%d: bad length: got %d expected %d", op, len, n2);
323                         n -= n2;
324                         p += n2;
325                         
326                 }
327
328                 /* move down partial message */
329                 if(p != buf && n != 0)
330                         memmove(buf, p, n);
331         }
332
333 }
334
335 int
336 sstart(uchar *p, int n)
337 {
338         int ver, frame, bearer, maxchan, firm;
339         char host[64], vendor[64], *sysname;
340         uchar buf[156];
341
342         if(n < 156)
343                 return 0;
344         ver = GSHORT(p+12);
345         frame = GLONG(p+16);
346         bearer = GLONG(p+20);
347         maxchan = GSHORT(p+24);
348         firm = GSHORT(p+26);
349         GSTRING(host, p+28, 64);
350         GSTRING(vendor, p+92, 64);
351
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
354
355         if(ver != Version)
356                 myfatal("bad version: got %x expected %x", ver, Version);
357
358         if(srv.start)
359                 myfatal("multiple start messages");
360
361         srv.start = 1;
362
363         sysname = getenv("sysname");
364         if(sysname == 0)
365                 strcpy(host, "gnot");
366         else
367                 strncpy(host, sysname, 64);
368         free(sysname);
369
370         memset(buf, 0, sizeof(buf));
371
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 */
384
385         if(write(1, buf, sizeof(buf)) < sizeof(buf))
386                 myfatal("write failed: %r");
387
388         return 156;
389 }
390
391 int
392 sstop(uchar *p, int n)
393 {
394         int reason;
395         uchar buf[16];
396
397         if(n < 16)
398                 return 0;
399         reason = p[12];
400         
401         SDB "%I: stop %d\n", srv.remote, reason EDB
402
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 */
409
410         if(write(1, buf, sizeof(buf)) < sizeof(buf))
411                 myfatal("write failed: %r");
412
413         return 16;
414 }
415
416 int
417 secho(uchar *p, int n)
418 {
419         int id;
420         uchar buf[20];
421
422         if(n < 16)
423                 return 0;
424         id = GLONG(p+12);
425         
426         SDB "%I: echo %d\n", srv.remote, id EDB
427
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 */
434         p[16] = 1;                      /* ok */
435
436         if(write(1, buf, sizeof(buf)) < sizeof(buf))
437                 myfatal("write failed: %r");
438
439         return 16;
440 }
441
442 int
443 scallout(uchar *p, int n)
444 {
445         int id, serial;
446         int minbps, maxbps, bearer, frame;
447         int window, delay;
448         int nphone;
449         char phone[64], sub[64], buf[32];
450         Call *c;
451
452         if(n < 168)
453                 return 0;
454
455         if(!srv.start)
456                 myfatal("%I: did not recieve start message", srv.remote);
457         
458         id = GSHORT(p+12);
459         serial = GSHORT(p+14);
460         minbps = GLONG(p+16);
461         maxbps = GLONG(p+20);
462         bearer = GLONG(p+24);
463         frame = GLONG(p+28);
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);
469
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
472
473         c = callalloc(id);
474         c->sendwindow = window;
475         c->delay = delay;
476         c->pac = 1;
477         c->recvwindow = srv.recvwindow;
478
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 */
491         
492         if(write(1, buf, sizeof(buf)) < sizeof(buf))
493                 myfatal("write failed: %r");
494
495         return 168;
496 }
497
498 int
499 scallreq(uchar *p, int n)
500 {
501         USED(p);
502         USED(n);
503
504         myfatal("callreq: not done yet");
505         return 0;
506 }
507
508 int
509 scallcon(uchar *p, int n)
510 {
511         USED(p);
512         USED(n);
513
514         myfatal("callcon: not done yet");
515         return 0;
516 }
517
518 int
519 scallclear(uchar *p, int n)
520 {
521         Call *c;
522         int id;
523         uchar buf[148];
524
525         if(n < 16)
526                 return 0;
527         id = GSHORT(p+12);
528         
529         SDB "%I: callclear id=%d\n", srv.remote, id EDB
530         
531         if(c = calllookup(id)) {
532                 callclose(c);
533                 callfree(c);
534         }
535
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 */
543
544         if(write(1, buf, sizeof(buf)) < sizeof(buf))
545                 myfatal("write failed: %r");
546
547         return 16;
548 }
549
550 int
551 scalldis(uchar *p, int n)
552 {
553         Call *c;
554         int id, res;
555
556         if(n < 148)
557                 return 0;
558         id = GSHORT(p+12);
559         res = p[14];
560
561         SDB "%I: calldis id=%d res=%d\n", srv.remote, id, res EDB
562
563         if(c = calllookup(id)) {
564                 callclose(c);
565                 callfree(c);
566         }
567
568         return 148;
569 }
570
571 int
572 swaninfo(uchar *p, int n)
573 {
574         Call *c;
575         int id;
576
577         if(n < 40)
578                 return 0;
579         
580         id = GSHORT(p+12);
581         SDB "%I: waninfo id = %d\n", srv.remote, id EDB
582         
583         c = calllookup(id);
584         if(c != 0) {
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);
591
592                 callfree(c);
593         }
594
595         
596         return 40;
597 }
598
599 int
600 slinkinfo(uchar *p, int n)
601 {
602         Call *c;
603         int id;
604         int sendaccm, recvaccm;
605
606         if(n < 24)
607                 return 0;
608         id = GSHORT(p+12);
609         sendaccm = GLONG(p+16);
610         recvaccm = GLONG(p+20);
611
612         SDB "%I: linkinfo id=%d saccm=%ux raccm=%ux\n", srv.remote, id, sendaccm, recvaccm EDB
613
614         if(c = calllookup(id)) {
615                 c->sendaccm = sendaccm;
616                 c->recvaccm = recvaccm;
617
618                 callfree(c);
619         }
620         
621         return 24;
622 }
623
624 Call*
625 callalloc(int id)
626 {
627         uint h;
628         Call *c;
629         char buf[300], *argv[30], local[20], remote[20], **p;
630         int fd, pfd[2], n;
631
632         h = id%Nhash;
633
634         qlock(&srv.lk);
635         for(c=srv.hash[h]; c; c=c->next)
636                 if(c->id == id)
637                         myfatal("callalloc: duplicate id: %d", id);
638         c = emallocz(sizeof(Call));
639         c->ref = 1;
640         c->id = id;
641         c->sendaccm = ~0;
642         c->recvaccm = ~0;
643
644         if(!ipaddralloc(c))
645                 myfatal("callalloc: could not alloc remote ip address");
646
647         if(pipe(pfd) < 0)
648                 myfatal("callalloc: pipe failed: %r");
649
650         sprint(buf, "%s/ipifc/clone", srv.pppdir);
651         fd = open(buf, OWRITE);
652         if(fd < 0)
653                 myfatal("callalloc: could not open %s: %r", buf);
654
655         n = sprint(buf, "iprouting");
656         if(write(fd, buf, n) < n)
657                 myfatal("callalloc: write to ifc failed: %r");
658         close(fd);
659
660         p = argv;
661         *p++ = srv.pppexec;
662         *p++ = "-SC";
663         *p++ = "-x";
664         *p++ = srv.pppdir;
665         if(debug)
666                 *p++ = "-d";
667         sprint(local, "%I", srv.ipaddr);
668         *p++ = local;
669         sprint(remote, "%I", c->remoteip);
670         *p++ = remote;
671         *p = 0;
672
673         proc(argv, pfd[0], pfd[0], 2);
674
675         close(pfd[0]);
676
677         c->pppfd = pfd[1];
678
679         c->next = srv.hash[h];
680         srv.hash[h] = c;
681
682         qunlock(&srv.lk);
683
684         c->ref++;
685         thread(pppread, c);
686         c->ref++;
687         thread(gretimeout, c);
688
689         syslog(0, LOG, ": src=%I: call started: id=%d: remote ip=%I", srv.remote, id, c->remoteip);
690
691         return c;
692 }
693
694 void
695 callclose(Call *c)
696 {
697         Call *oc;
698         int id;
699         uint h;
700
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);
704
705         qlock(&srv.lk);
706         if(c->closed) {
707                 qunlock(&srv.lk);
708                 return;
709         }
710         c->closed = 1;
711
712         close(c->dhcpfd[0]);
713         close(c->dhcpfd[1]);
714         close(c->pppfd);
715         c->pppfd = -1;
716
717         h = c->id%Nhash;
718         id = c->id;
719         for(c=srv.hash[h],oc=0; c; oc=c,c=c->next)
720                 if(c->id == id)
721                         break;
722         if(oc == 0)
723                 srv.hash[h] = c->next;
724         else
725                 oc->next = c->next;
726         c->next = 0;
727         qunlock(&srv.lk);
728
729         callfree(c);
730 }
731
732 void
733 callfree(Call *c)
734 {       
735         int ref;
736         
737         qlock(&srv.lk);
738         ref = --c->ref;
739         qunlock(&srv.lk);
740         if(ref > 0)
741                 return;
742         
743         /* already unhooked from hash list - see callclose */
744         assert(c->closed == 1);
745         assert(ref == 0);
746         assert(c->next == 0);
747
748 SDB "call free\n" EDB   
749         free(c);
750 }
751
752 Call*
753 calllookup(int id)
754 {
755         uint h;
756         Call *c;
757
758         h = id%Nhash;
759
760         qlock(&srv.lk);
761         for(c=srv.hash[h]; c; c=c->next)
762                 if(c->id == id)
763                         break;
764         if(c != 0)
765                 c->ref++;
766         qunlock(&srv.lk);
767
768         return c;
769 }
770
771
772 void
773 srvinit(void)
774 {
775         char buf[100];
776         int fd, n;
777
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);
783         buf[n] = 0;
784         parseip(srv.local, buf);
785         close(fd);
786
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);
792         buf[n] = 0;
793         parseip(srv.remote, buf);
794         close(fd);
795
796         if(srv.pppdir == 0)
797                 srv.pppdir = "/net";
798
799         if(srv.pppexec == 0)
800                 srv.pppexec = "/bin/ip/ppp";
801
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;
806 }
807
808 void
809 greinit(void)
810 {
811         char addr[100], *p;
812         int fd, cfd;
813
814         SDB "srv.tcpdir = %s\n", srv.tcpdir EDB
815         strcpy(addr, srv.tcpdir);
816         p = strrchr(addr, '/');
817         if(p == 0)
818                 myfatal("bad tcp dir: %s", srv.tcpdir);
819         *p = 0;
820         p = strrchr(addr, '/');
821         if(p == 0)
822                 myfatal("bad tcp dir: %s", srv.tcpdir);
823         sprint(p, "/gre!%I!34827", srv.remote);
824
825         SDB "addr = %s\n", addr EDB
826
827         fd = dial(addr, 0, 0, &cfd);
828
829         if(fd < 0)
830                 myfatal("%I: dial %s failed: %r", srv.remote, addr);
831
832         srv.grefd = fd;
833         srv.grecfd = cfd;
834
835         thread(greread, 0);
836 }
837
838 void
839 greread(void *)
840 {
841         uchar buf[Pktsize], *p;
842         int n, i;
843         int flag, prot, len, callid;
844         uchar src[IPaddrlen], dst[IPaddrlen];
845         uint rseq, ack;
846         Call *c;
847         static double t, last;
848
849         for(;;) {
850                 n = read(srv.grefd, buf, sizeof(buf));
851                 if(n < 0)
852                         myfatal("%I: bad read on gre: %r", srv.remote);
853                 if(n == sizeof(buf))
854                         myfatal("%I: gre read: buf too small", srv.remote);
855
856                 p = buf;
857                 v4tov6(src, p);
858                 v4tov6(dst, p+4);
859                 flag = GSHORT(p+8);
860                 prot = GSHORT(p+10);
861                 p += 12; n -= 12;
862
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);
865
866                 if(prot != GRE_ppp)
867                         myfatal("%I: gre read gave bad protocol", srv.remote);
868
869                 if(flag & (GRE_chksum|GRE_routing)){
870                         p += 4; n -= 4;
871                 }
872
873                 if(!(flag&GRE_key))
874                         myfatal("%I: gre packet does not contain a key: f=%ux",
875                                 srv.remote, flag);
876
877                 len = GSHORT(p);
878                 callid = GSHORT(p+2);
879                 p += 4; n -= 4;
880
881                 c = calllookup(callid);
882                 if(c == 0) {
883                         SDB "%I: unknown callid: %d\n", srv.remote, callid EDB
884                         continue;
885                 }
886
887                 qlock(&c->lk);
888
889                 c->stat.recv++;
890
891                 if(flag&GRE_seq) {
892                         rseq = GLONG(p);
893                         p += 4; n -= 4;
894                 } else
895                         rseq = c->rseq;
896
897                 if(flag&GRE_ack){
898                         ack = GLONG(p);
899                         p += 4; n -= 4;
900                 } else
901                         ack = c->ack;
902
903                 /* skip routing if present */
904                 if(flag&GRE_routing) {
905                         while((i=p[3]) != 0) {
906                                 n -= i;
907                                 p += i;
908                         }
909                 }
910
911                 if(len > n)
912                         myfatal("%I: bad len in gre packet", srv.remote);
913
914                 if((int)(ack-c->ack) > 0) {
915                         c->ack = ack;
916                         esignal(&c->eack);
917                 }
918
919                 if(debug)
920                         t = realtime();
921
922                 if(len == 0) {
923                         /* ack packet */
924                         c->stat.recvack++;
925
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
928
929                 } else {
930
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
933
934                         /*
935                          * the following handles the case of a single pair of packets
936                          * received out of order
937                          */
938                         n = rseq-c->rseq;
939                         if(n > 0 && (drop == 0. || frand() > drop)) {
940                                 c->stat.missing += n-1;
941                                 /* current packet */
942                                 write(c->pppfd, p, len);
943                         } else {
944                                 /* out of sequence - drop on the floor */
945                                 c->stat.dropped++;
946
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
949
950                         }
951                 }
952
953                 if((int)(rseq-c->rseq) > 0)
954                         c->rseq = rseq;
955
956                 if(debug)
957                         last=t;
958
959                 /* open up client window */
960                 if((int)(c->rseq-c->rack) > (c->recvwindow>>1))
961                         greack(c);
962
963                 qunlock(&c->lk);
964
965
966                 callfree(c);
967         }
968 }
969
970 void
971 greack(Call *c)
972 {
973         uchar buf[20];
974
975         c->stat.sendack++;
976
977 SDB "%I: %.3f: gre %d: send ack %ux\n", srv.remote, realtime(), c->id, c->rseq EDB
978
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);
983         PSHORT(buf+12, 0);
984         PSHORT(buf+14, c->id);
985         PLONG(buf+16, c->rseq);
986
987         write(srv.grefd, buf, sizeof(buf));
988
989         c->rack = c->rseq;
990
991 }
992
993 void
994 gretimeout(void *a)
995 {
996         Call *c;
997
998         c = a;
999
1000         while(!c->closed) {
1001                 sleep(Tick);
1002                 qlock(&c->lk);
1003                 c->tick++;
1004                 qunlock(&c->lk);
1005                 esignal(&c->eack);
1006         }
1007         callfree(c);
1008         exits(0);
1009 }
1010
1011
1012 void
1013 pppread(void *a)
1014 {
1015         Call *c;
1016         uchar buf[2000], *p;
1017         int n;
1018         ulong tick;
1019
1020         c = a;
1021         for(;;) {
1022                 p = buf+24;
1023                 n = read(c->pppfd, p, sizeof(buf)-24);
1024                 if(n <= 0)
1025                         break;
1026                 
1027                 qlock(&c->lk);
1028
1029                 /* add gre header */
1030                 c->seq++;
1031                 tick = c->tick;
1032
1033                 while(c->seq-c->ack>c->sendwindow && c->tick-tick<Sendtimeout && !c->closed) {
1034                         c->stat.sendwait++;
1035 SDB "window full seq = %d ack = %ux window = %ux\n", c->seq, c->ack, c->sendwindow EDB
1036                         qunlock(&c->lk);
1037                         ewait(&c->eack);
1038                         qlock(&c->lk);
1039                 }
1040                 
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
1044                 }
1045
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);
1050                 PSHORT(buf+12, n);
1051                 PSHORT(buf+14, c->id);
1052                 PLONG(buf+16, c->seq);
1053                 PLONG(buf+20, c->rseq);
1054
1055                 c->stat.send++;
1056                 c->rack = c->rseq;
1057
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
1060
1061                 if(drop == 0. || frand() > drop)
1062                         if(write(srv.grefd, buf, n+24)<n+24)
1063                                 myfatal("pppread: write failed: %r");
1064
1065                 qunlock(&c->lk);
1066         }
1067
1068         SDB "pppread exit: %d\n", c->id);
1069         
1070         callfree(c);
1071         exits(0);
1072 }
1073
1074 void
1075 timeoutthread(void*)
1076 {
1077         for(;;) {
1078                 sleep(30*1000);
1079
1080                 qlock(&srv.lk);
1081                 if(realtime() - srv.rcvtime > 5*60)
1082                         myfatal("server timedout");
1083                 qunlock(&srv.lk);
1084         }
1085 }
1086
1087
1088 /* use syslog() rather than fprint(2, ...) */
1089 void
1090 myfatal(char *fmt, ...)
1091 {
1092         char sbuf[512];
1093         va_list arg;
1094         uchar buf[16];
1095
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 */
1103
1104         write(1, buf, sizeof(buf));
1105
1106         va_start(arg, fmt);
1107         vseprint(sbuf, sbuf+sizeof(sbuf), fmt, arg);
1108         va_end(arg);
1109
1110         SDB "%I: fatal: %s\n", srv.remote, sbuf EDB
1111         syslog(0, LOG, ": src=%I: fatal: %s", srv.remote, sbuf);
1112
1113         close(0);
1114         close(1);
1115         close(srv.grefd);
1116         close(srv.grecfd);
1117
1118         postnote(PNGROUP, getpid(), "die");
1119         exits(sbuf);
1120 }
1121
1122 int
1123 argatoi(char *p)
1124 {
1125         char *q;
1126         int i;
1127
1128         if(p == 0)
1129                 usage();
1130
1131         i = strtol(p, &q, 0);
1132         if(q == p)
1133                 usage();
1134         return i;
1135 }
1136
1137 void
1138 dhcpclientwatch(void *a)
1139 {
1140         Call *c = a;
1141         uchar buf[1];
1142
1143         for(;;) {
1144                 if(read(c->dhcpfd[0], buf, sizeof(buf)) <= 0)
1145                         break;
1146         }
1147         if(!c->closed)
1148                 myfatal("dhcpclient terminated");
1149         callfree(c);
1150         exits(0);
1151 }
1152
1153 int
1154 ipaddralloc(Call *c)
1155 {
1156         int pfd[2][2];
1157         char *argv[4], *p;
1158         Biobuf bio;
1159
1160         argv[0] = "/bin/ip/dhcpclient";
1161         argv[1] = "-x";
1162         argv[2] = srv.pppdir;
1163         argv[3] = 0;
1164
1165         if(pipe(pfd[0])<0)
1166                 myfatal("ipaddralloc: pipe failed: %r");
1167         if(pipe(pfd[1])<0)
1168                 myfatal("ipaddralloc: pipe failed: %r");
1169
1170         if(proc(argv, pfd[0][0], pfd[1][1], 2) < 0)
1171                 myfatal("ipaddralloc: proc failed: %r");
1172
1173         close(pfd[0][0]);
1174         close(pfd[1][1]);
1175         c->dhcpfd[0] = pfd[1][0];
1176         c->dhcpfd[1] = pfd[0][1];
1177
1178         Binit(&bio, pfd[1][0], OREAD);
1179         for(;;) {
1180                 p = Brdline(&bio, '\n');
1181                 if(p == 0)
1182                         break;
1183                 if(strncmp(p, "ip=", 3) == 0) {
1184                         p += 3;
1185                         parseip(c->remoteip, p);
1186                 } else if(strncmp(p, "end\n", 4) == 0)
1187                         break;
1188         }
1189
1190         Bterm(&bio);
1191
1192         c->ref++;
1193
1194         thread(dhcpclientwatch, c);
1195
1196         return ipcmp(c->remoteip, IPnoaddr) != 0;
1197 }
1198
1199
1200 void
1201 esignal(Event *e)
1202 {       
1203         qlock(e);
1204         if(e->wait == 0) {
1205                 e->ready = 1;
1206                 qunlock(e);
1207                 return;
1208         }
1209         assert(e->ready == 0);
1210         e->wait = 0;
1211         rendezvous(e, (void*)1);
1212         qunlock(e);
1213 }
1214
1215 void
1216 ewait(Event *e)
1217 {
1218         qlock(&e->waitlk);
1219         qlock(e);
1220         assert(e->wait == 0);
1221         if(e->ready) {
1222                 e->ready = 0;
1223         } else {        
1224                 e->wait = 1;
1225                 qunlock(e);
1226                 rendezvous(e, (void*)2);
1227                 qlock(e);
1228         }
1229         qunlock(e);
1230         qunlock(&e->waitlk);
1231 }
1232
1233 ulong
1234 thread(void(*f)(void*), void *a)
1235 {
1236         int pid;
1237         pid=rfork(RFNOWAIT|RFMEM|RFPROC);
1238         if(pid < 0)
1239                 myfatal("rfork failed: %r");
1240         if(pid != 0)
1241                 return pid;
1242         (*f)(a);
1243         return 0; // never reaches here
1244 }
1245
1246 double
1247 realtime(void)
1248 {
1249         long times(long*);
1250
1251         return times(0) / 1000.0;
1252 }
1253
1254 void *
1255 emallocz(int size)
1256 {
1257         void *p;
1258         p = malloc(size);
1259         if(p == 0)
1260                 myfatal("malloc failed: %r");
1261         memset(p, 0, size);
1262         return p;
1263 }
1264
1265 static void
1266 fdclose(void)
1267 {
1268         int fd, n, i;
1269         Dir *d, *p;
1270
1271         if((fd = open("#d", OREAD)) < 0)
1272                 return;
1273
1274         n = dirreadall(fd, &d);
1275         for(p = d; n > 0; n--, p++) {
1276                 i = atoi(p->name);
1277                 if(i > 2)
1278                         close(i);
1279         }
1280         free(d);
1281 }
1282
1283 int
1284 proc(char **argv, int fd0, int fd1, int fd2)
1285 {
1286         int r, flag;
1287         char *arg0, file[200];
1288
1289         arg0 = argv[0];
1290
1291         strcpy(file, arg0);
1292
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)
1298                         return 0;
1299                 sprint(file, "/bin/%s", arg0);
1300                 if(access(file, 1) < 0)
1301                         return 0;
1302         }
1303
1304         flag = RFPROC|RFFDG|RFENVG|RFNOWAIT;
1305         if((r = rfork(flag)) != 0) {
1306                 if(r < 0)
1307                         return 0;
1308                 return r;
1309         }
1310
1311         if(fd0 != 0) {
1312                 if(fd1 == 0)
1313                         fd1 = dup(0, -1);
1314                 if(fd2 == 0)
1315                         fd2 = dup(0, -1);
1316                 close(0);
1317                 if(fd0 >= 0)
1318                         dup(fd0, 0);
1319         }
1320
1321         if(fd1 != 1) {
1322                 if(fd2 == 1)
1323                         fd2 = dup(1, -1);
1324                 close(1);
1325                 if(fd1 >= 0)
1326                         dup(fd1, 1);
1327         }
1328
1329         if(fd2 != 2) {
1330                 close(2);
1331                 if(fd2 >= 0)
1332                         dup(fd2, 2);
1333         }
1334
1335         fdclose();
1336
1337         exec(file, argv);
1338         myfatal("proc: exec failed: %r");
1339         return 0;
1340 }
1341