]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/ip/ppp/ppp.c
125893990025cc69a912d6935a16047ea654a427
[plan9front.git] / sys / src / cmd / ip / ppp / ppp.c
1 /*
2  * ppp - point-to-point protocol, rfc1331
3  */
4 #include <u.h>
5 #include <libc.h>
6 #include <auth.h>
7 #include <bio.h>
8 #include <ip.h>
9 #include <libsec.h>
10 #include <ndb.h>
11 #include "ppp.h"
12
13 #define PATH 128
14
15 static  int     baud;
16 static  int     nocompress;
17 static  int     pppframing = 1;
18 static  int     noipcompress;
19 static  int     server;
20 static  int noauth;
21 static  int     nip;            /* number of ip interfaces */
22 static  int     dying;          /* flag to signal to all threads its time to go */
23 static  int     primary;        /* this is the primary IP interface */
24 static  char    *chatfile;
25
26 int     debug;
27 char*   LOG = "ppp";
28 char*   keyspec = "";
29
30 enum
31 {
32         Rmagic= 0x12345
33 };
34
35 /*
36  * Calculate FCS - rfc 1331
37  */
38 ushort fcstab[256] =
39 {
40       0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
41       0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
42       0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
43       0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
44       0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
45       0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
46       0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
47       0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
48       0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
49       0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
50       0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
51       0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
52       0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
53       0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
54       0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
55       0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
56       0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
57       0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
58       0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
59       0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
60       0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
61       0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
62       0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
63       0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
64       0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
65       0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
66       0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
67       0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
68       0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
69       0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
70       0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
71       0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
72 };
73
74 static char *snames[] =
75 {
76         "Sclosed",
77         "Sclosing",
78         "Sreqsent",
79         "Sackrcvd",
80         "Sacksent",
81         "Sopened",
82 };
83
84 static  void            authtimer(PPP*);
85 static  void            chapinit(PPP*);
86 static  void            config(PPP*, Pstate*, int);
87 static  uchar*          escapeuchar(PPP*, ulong, uchar*, ushort*);
88 static  void            getchap(PPP*, Block*);
89 static  Block*          getframe(PPP*, int*);
90 static  void            getlqm(PPP*, Block*);
91 static  int             getopts(PPP*, Pstate*, Block*);
92 static  void            getpap(PPP*, Block*);
93 static  void            init(PPP*);
94 static  void            invalidate(Ipaddr);
95 static  void            ipinproc(PPP*);
96 static  char*           ipopen(PPP*);
97 static  void            mediainproc(PPP*);
98 static  void            newstate(PPP*, Pstate*, int);
99 static  int             nipifcs(char*);
100 static  void            papinit(PPP*);
101 static  void            pinit(PPP*, Pstate*);
102 static  void            ppptimer(PPP*);
103 static  void            printopts(Pstate*, Block*, int);
104 static  void            ptimer(PPP*, Pstate*);
105 static  int             putframe(PPP*, int, Block*);
106 static  void            putlqm(PPP*);
107 static  void            putndb(PPP*, char*);
108 static  void            putpaprequest(PPP*);
109 static  void            rcv(PPP*, Pstate*, Block*);
110 static  void            rejopts(PPP*, Pstate*, Block*, int);
111 static  void            sendechoreq(PPP*, Pstate*);
112 static  void            sendtermreq(PPP*, Pstate*);
113 static  void            setphase(PPP*, int);
114 static  void            terminate(PPP*, int);
115 static  int             validv4(Ipaddr);
116 static  void            dmppkt(char *s, uchar *a, int na);
117 static  void            getauth(PPP*);
118
119 void
120 pppopen(PPP *ppp, int mediain, int mediaout, char *net,
121         Ipaddr ipaddr, Ipaddr remip,
122         int mtu, int framing)
123 {
124         ppp->ipfd = -1;
125         ppp->ipcfd = -1;
126         invalidate(ppp->remote);
127         invalidate(ppp->local);
128         invalidate(ppp->curremote);
129         invalidate(ppp->curlocal);
130         invalidate(ppp->dns[0]);
131         invalidate(ppp->dns[1]);
132         invalidate(ppp->wins[0]);
133         invalidate(ppp->wins[1]);
134
135         ppp->mediain = mediain;
136         ppp->mediaout = mediaout;
137         if(validv4(remip)){
138                 ipmove(ppp->remote, remip);
139                 ppp->remotefrozen = 1;
140         }
141         if(validv4(ipaddr)){
142                 ipmove(ppp->local, ipaddr);
143                 ppp->localfrozen = 1;
144         }
145         ppp->mtu = Defmtu;
146         ppp->mru = mtu;
147         ppp->framing = framing;
148         ppp->net = net;
149
150         init(ppp);
151         switch(rfork(RFPROC|RFMEM|RFNOWAIT)){
152         case -1:
153                 sysfatal("forking mediainproc");
154         case 0:
155                 mediainproc(ppp);
156                 terminate(ppp, 1);
157                 _exits(0);
158         }
159 }
160
161 static void
162 init(PPP* ppp)
163 {
164         if(ppp->inbuf == nil){
165                 ppp->inbuf = allocb(4096);
166                 if(ppp->inbuf == nil)
167                         abort();
168
169                 ppp->outbuf = allocb(4096);
170                 if(ppp->outbuf == nil)
171                         abort();
172
173                 ppp->lcp = mallocz(sizeof(*ppp->lcp), 1);
174                 if(ppp->lcp == nil)
175                         abort();
176                 ppp->lcp->proto = Plcp;
177                 ppp->lcp->state = Sclosed;
178
179                 ppp->ccp = mallocz(sizeof(*ppp->ccp), 1);
180                 if(ppp->ccp == nil)
181                         abort();
182                 ppp->ccp->proto = Pccp;
183                 ppp->ccp->state = Sclosed;
184
185                 ppp->ipcp = mallocz(sizeof(*ppp->ipcp), 1);
186                 if(ppp->ipcp == nil)
187                         abort();
188                 ppp->ipcp->proto = Pipcp;
189                 ppp->ipcp->state = Sclosed;
190
191                 ppp->chap = mallocz(sizeof(*ppp->chap), 1);
192                 if(ppp->chap == nil)
193                         abort();
194                 ppp->chap->proto = APmschap;
195                 ppp->chap->state = Cunauth;
196                 auth_freechal(ppp->chap->cs);
197                 ppp->chap->cs = nil;
198
199                 switch(rfork(RFPROC|RFMEM|RFNOWAIT)){
200                 case -1:
201                         sysfatal("forking ppptimer");
202                 case 0:
203                         ppptimer(ppp);
204                         _exits(0);
205                 }
206         }
207
208         ppp->ctcp = compress_init(ppp->ctcp);
209         pinit(ppp, ppp->lcp);
210         setphase(ppp, Plink);
211 }
212
213 static void
214 setphase(PPP *ppp, int phase)
215 {
216         int oldphase;
217
218         oldphase = ppp->phase;
219
220         ppp->phase = phase;
221         switch(phase){
222         default:
223                 sysfatal("ppp: unknown phase %d", phase);
224         case Pdead:
225                 /* restart or exit? */
226                 pinit(ppp, ppp->lcp);
227                 setphase(ppp, Plink);
228                 break;
229         case Plink:
230                 /* link down */
231                 switch(oldphase) {
232                 case Pauth:
233                         auth_freechal(ppp->chap->cs);
234                         ppp->chap->cs = nil;
235                         ppp->chap->state = Cunauth;
236                         break;
237                 case Pnet:
238                         auth_freechal(ppp->chap->cs);
239                         ppp->chap->cs = nil;
240                         ppp->chap->state = Cunauth;
241                         newstate(ppp, ppp->ccp, Sclosed);
242                         newstate(ppp, ppp->ipcp, Sclosed);
243                 }
244                 break;
245         case Pauth:
246                 if(server)
247                         chapinit(ppp);
248                 else if(ppp->chap->proto == APpasswd)
249                         papinit(ppp);
250                 else
251                         setphase(ppp, Pnet);
252                 break;
253         case Pnet:
254                 pinit(ppp, ppp->ccp);
255                 pinit(ppp, ppp->ipcp);
256                 break;
257         case Pterm:
258                 /* what? */
259                 break;
260         }
261 }
262
263 static void
264 pinit(PPP *ppp, Pstate *p)
265 {
266         p->timeout = 0;
267
268         switch(p->proto){
269         case Plcp:
270                 ppp->magic = truerand();
271                 ppp->xctlmap = 0xffffffff;
272                 ppp->period = 0;
273                 p->optmask = 0xffffffff;
274                 if(!server)
275                         p->optmask &=  ~(Fauth|Fmtu);
276                 ppp->rctlmap = 0;
277                 ppp->ipcp->state = Sclosed;
278                 ppp->ipcp->optmask = 0xffffffff;
279
280                 p->echotimeout = 0;
281
282                 /* quality goo */
283                 ppp->timeout = 0;
284                 memset(&ppp->in, 0, sizeof(ppp->in));
285                 memset(&ppp->out, 0, sizeof(ppp->out));
286                 memset(&ppp->pin, 0, sizeof(ppp->pin));
287                 memset(&ppp->pout, 0, sizeof(ppp->pout));
288                 memset(&ppp->sin, 0, sizeof(ppp->sin));
289                 break;
290         case Pccp:
291                 if(nocompress)
292                         p->optmask = 0;
293                 else
294                         p->optmask = Fcmppc;
295
296                 if(ppp->ctype != nil)
297                         (*ppp->ctype->fini)(ppp->cstate);
298                 ppp->ctype = nil;
299                 ppp->ctries = 0;
300                 ppp->cstate = nil;
301
302                 if(ppp->unctype)
303                         (*ppp->unctype->fini)(ppp->uncstate);
304                 ppp->unctype = nil;
305                 ppp->uncstate = nil;
306                 break;
307         case Pipcp:
308                 p->optmask = 0xffffffff;
309                 ppp->ctcp = compress_init(ppp->ctcp);
310                 break;
311         }
312         p->confid = p->rcvdconfid = -1;
313         config(ppp, p, 1);
314         newstate(ppp, p, Sreqsent);
315 }
316
317 /*
318  *  change protocol to a new state.
319  */
320 static void
321 newstate(PPP *ppp, Pstate *p, int state)
322 {
323         char *err;
324
325         netlog("ppp: %ux %s->%s ctlmap %lux/%lux flags %lux mtu %ld mru %ld\n",
326                 p->proto, snames[p->state], snames[state], ppp->rctlmap,
327                 ppp->xctlmap, p->flags,
328                 ppp->mtu, ppp->mru);
329         syslog(0, "ppp", "%ux %s->%s ctlmap %lux/%lux flags %lux mtu %ld mru %ld",
330                 p->proto, snames[p->state], snames[state], ppp->rctlmap,
331                 ppp->xctlmap, p->flags,
332                 ppp->mtu, ppp->mru);
333
334         if(p->proto == Plcp) {
335                 if(state == Sopened)
336                         setphase(ppp, noauth? Pnet : Pauth);
337                 else if(state == Sclosed)
338                         setphase(ppp, Pdead);
339                 else if(p->state == Sopened)
340                         setphase(ppp, Plink);
341         }
342
343         if(p->proto == Pccp && state == Sopened) {
344                 if(ppp->unctype)
345                         (*ppp->unctype->fini)(ppp->uncstate);
346                 ppp->unctype = nil;
347                 ppp->uncstate = nil;
348                 if(p->optmask & Fcmppc) {
349                         ppp->unctype = &uncmppc;
350                         ppp->uncstate = (*uncmppc.init)(ppp);
351                 }
352                 if(p->optmask & Fcthwack){
353                         ppp->unctype = &uncthwack;
354                         ppp->uncstate = (*uncthwack.init)(ppp);
355                 }
356         }
357
358         if(p->proto == Pipcp && state == Sopened) {
359                 if(server && !noauth && ppp->chap->state != Cauthok)
360                         abort();
361
362                 err = ipopen(ppp);
363                 if(err != nil)
364                         sysfatal("%s", err);
365         }
366
367         p->state = state;
368 }
369
370 /* returns (protocol, information) */
371 static Block*
372 getframe(PPP *ppp, int *protop)
373 {
374         uchar *p, *from, *to;
375         int n, len, proto;
376         ulong c;
377         ushort fcs;
378         Block *buf, *b;
379
380         *protop = 0;
381         if(ppp->framing == 0) {
382                 /* assume data is already framed */
383                 b = allocb(2000);
384                 len = b->lim - b->wptr;
385                 n = read(ppp->mediain, b->wptr, len);
386                 dmppkt("RX", b->wptr, n);
387                 if(n <= 0 || n == len){
388                         freeb(b);
389
390                         return nil;
391                 }
392                 b->wptr += n;
393
394                 /* should probably copy to another block if small */
395
396                 if(pppframing && b->rptr[0] == PPP_addr && b->rptr[1] == PPP_ctl)
397                         b->rptr += 2;
398                 proto = *b->rptr++;
399                 if((proto & 0x1) == 0)
400                         proto = (proto<<8) | *b->rptr++;
401
402                 if(b->rptr >= b->wptr){
403                         freeb(b);
404                         return nil;
405                 }
406
407                 ppp->in.uchars += n;
408                 ppp->in.packets++;
409                 *protop = proto;
410                 netlog("getframe 0x%x\n", proto);
411                 return b;
412         }
413
414         buf = ppp->inbuf;
415         for(;;){
416                 /* read till we hit a frame uchar or run out of room */
417                 for(p = buf->rptr; buf->wptr < buf->lim;){
418                         for(; p < buf->wptr; p++)
419                                 if(*p == HDLC_frame)
420                                         break;
421                         if(p != buf->wptr)
422                                 break;
423
424                         len = buf->lim - buf->wptr;
425                         n = read(ppp->mediain, buf->wptr, len);
426                         if(n <= 0){
427                                 syslog(0, LOG, "medium read returns %d: %r", n);
428                                 buf->wptr = buf->rptr;
429                                 return nil;
430                         }
431                         dmppkt("RX", buf->wptr, n);
432                         buf->wptr += n;
433                 }
434
435                 /* copy into block, undoing escapes, and caculating fcs */
436                 fcs = PPP_initfcs;
437                 b = allocb(p - buf->rptr);
438                 to = b->wptr;
439                 for(from = buf->rptr; from != p;){
440                         c = *from++;
441                         if(c == HDLC_esc){
442                                 if(from == p)
443                                         break;
444                                 c = *from++ ^ 0x20;
445                         } else if((c < 0x20) && (ppp->rctlmap & (1 << c)))
446                                 continue;
447                         *to++ = c;
448                         fcs = (fcs >> 8) ^ fcstab[(fcs ^ c) & 0xff];
449                 }
450
451                 /* copy down what's left in buffer */
452                 p++;
453                 memmove(buf->rptr, p, buf->wptr - p);
454                 n = p - buf->rptr;
455                 buf->wptr -= n;
456                 b->wptr = to - 2;
457
458                 /* return to caller if checksum matches */
459                 if(fcs == PPP_goodfcs){
460                         if(b->rptr[0] == PPP_addr && b->rptr[1] == PPP_ctl)
461                                 b->rptr += 2;
462                         proto = *b->rptr++;
463                         if((proto & 0x1) == 0)
464                                 proto = (proto<<8) | *b->rptr++;
465                         if(b->rptr < b->wptr){
466                                 ppp->in.uchars += n;
467                                 ppp->in.packets++;
468                                 *protop = proto;
469                                 netlog("getframe 0x%x\n", proto);
470                                 return b;
471                         }
472                 } else if(BLEN(b) > 0){
473                         if(ppp->ctcp)
474                                 compress_error(ppp->ctcp);
475                         ppp->in.discards++;
476                         netlog("ppp: discard len %ld/%ld cksum %ux (%ux %ux %ux %ux)\n",
477                                 BLEN(b), BLEN(buf), fcs, b->rptr[0],
478                                 b->rptr[1], b->rptr[2], b->rptr[3]);
479                 }
480
481                 freeb(b);
482         }
483 }
484
485 /* send a PPP frame */
486 static int
487 putframe(PPP *ppp, int proto, Block *b)
488 {
489         Block *buf;
490         uchar *to, *from;
491         ushort fcs;
492         ulong ctlmap;
493         uchar c;
494         Block *bp;
495
496         ppp->out.packets++;
497
498         if(proto == Plcp)
499                 ctlmap = 0xffffffff;
500         else
501                 ctlmap = ppp->xctlmap;
502
503         /* make sure we have head room */
504         if(b->rptr - b->base < 4){
505                 b = padb(b, 4);
506                 b->rptr += 4;
507         }
508
509         netlog("ppp: putframe 0x%ux %ld\n", proto, b->wptr-b->rptr);
510
511         /* add in the protocol and address, we'd better have left room */
512         from = b->rptr;
513         *--from = proto;
514         if(!(ppp->lcp->flags&Fpc) || proto > 0x100 || proto == Plcp)
515                 *--from = proto>>8;
516         if(pppframing && (!(ppp->lcp->flags&Fac) || proto == Plcp)){
517                 *--from = PPP_ctl;
518                 *--from = PPP_addr;
519         }
520
521         qlock(&ppp->outlock);
522         buf = ppp->outbuf;
523
524         if(ppp->framing == 0) {
525                 to = buf->rptr;
526                 for(bp = b; bp; bp = bp->next){
527                         if(bp != b)
528                                 from = bp->rptr;
529                         memmove(to, from, bp->wptr-from);
530                         to += bp->wptr-from;
531                 }
532         } else {
533                 /* escape and checksum the body */
534                 fcs = PPP_initfcs;
535                 to = buf->rptr;
536         
537                 /* add frame marker */
538                 *to++ = HDLC_frame;
539
540                 for(bp = b; bp; bp = bp->next){
541                         if(bp != b)
542                                 from = bp->rptr;
543                         for(; from < bp->wptr; from++){
544                                 c = *from;
545                                 if(c == HDLC_frame || c == HDLC_esc
546                                    || (c < 0x20 && ((1<<c) & ctlmap))){
547                                         *to++ = HDLC_esc;
548                                         *to++ = c ^ 0x20;
549                                 } else 
550                                         *to++ = c;
551                                 fcs = (fcs >> 8) ^ fcstab[(fcs ^ c) & 0xff];
552                         }
553                 }
554
555                 /* add on and escape the checksum */
556                 fcs = ~fcs;
557                 c = fcs;
558                 if(c == HDLC_frame || c == HDLC_esc
559                    || (c < 0x20 && ((1<<c) & ctlmap))){
560                         *to++ = HDLC_esc;
561                         *to++ = c ^ 0x20;
562                 } else 
563                         *to++ = c;
564                 c = fcs>>8;
565                 if(c == HDLC_frame || c == HDLC_esc
566                    || (c < 0x20 && ((1<<c) & ctlmap))){
567                         *to++ = HDLC_esc;
568                         *to++ = c ^ 0x20;
569                 } else 
570                         *to++ = c;
571         
572                 /* add frame marker */
573                 *to++ = HDLC_frame;
574         }
575
576         /* send */
577         buf->wptr = to;
578         dmppkt("TX", buf->rptr, BLEN(buf));
579         if(write(ppp->mediaout, buf->rptr, BLEN(buf)) < 0){
580                 qunlock(&ppp->outlock);
581                 return -1;
582         }
583         ppp->out.uchars += BLEN(buf);
584
585         qunlock(&ppp->outlock);
586         return 0;
587 }
588
589 Block*
590 alloclcp(int code, int id, int len, Lcpmsg **mp)
591 {
592         Block *b;
593         Lcpmsg *m;
594
595         /*
596          *  leave room for header
597          */
598         b = allocb(len);
599
600         m = (Lcpmsg*)b->wptr;
601         m->code = code;
602         m->id = id;
603         b->wptr += 4;
604
605         *mp = m;
606         return b;
607 }
608
609
610 static void
611 putlo(Block *b, int type, ulong val)
612 {
613         *b->wptr++ = type;
614         *b->wptr++ = 6;
615         hnputl(b->wptr, val);
616         b->wptr += 4;
617 }
618
619 static void
620 putv4o(Block *b, int type, Ipaddr val)
621 {
622         *b->wptr++ = type;
623         *b->wptr++ = 6;
624         v6tov4(b->wptr, val);
625         b->wptr += 4;
626 }
627
628 static void
629 putso(Block *b, int type, ulong val)
630 {
631         *b->wptr++ = type;
632         *b->wptr++ = 4;
633         hnputs(b->wptr, val);
634         b->wptr += 2;
635 }
636
637 static void
638 puto(Block *b, int type)
639 {
640         *b->wptr++ = type;
641         *b->wptr++ = 2;
642 }
643
644 /*
645  *  send configuration request
646  */
647 static void
648 config(PPP *ppp, Pstate *p, int newid)
649 {
650         Block *b;
651         Lcpmsg *m;
652         int id;
653
654         if(newid){
655                 id = p->id++;
656                 p->confid = id;
657                 p->timeout = Timeout;
658         } else
659                 id = p->confid;
660         b = alloclcp(Lconfreq, id, 256, &m);
661         USED(m);
662
663         switch(p->proto){
664         case Plcp:
665                 if(p->optmask & Fctlmap)
666                         putlo(b, Octlmap, 0);   /* we don't want anything escaped */
667                 if(p->optmask & Fmagic)
668                         putlo(b, Omagic, ppp->magic);
669                 if(p->optmask & Fmtu)
670                         putso(b, Omtu, ppp->mru);
671                 if(p->optmask & Fauth) {
672                         *b->wptr++ = Oauth;
673                         *b->wptr++ = 5;
674                         hnputs(b->wptr, Pchap);
675                         b->wptr += 2;
676                         *b->wptr++ = ppp->chap->proto;
677                 }
678                 if(p->optmask & Fpc)
679                         puto(b, Opc);
680                 if(p->optmask & Fac)
681                         puto(b, Oac);
682                 break;
683         case Pccp:
684                 if(p->optmask & Fcthwack)
685                         puto(b, Octhwack);
686                 else if(p->optmask & Fcmppc) {
687                         *b->wptr++ = Ocmppc;
688                         *b->wptr++ = 6;
689                         *b->wptr++ = 0;
690                         *b->wptr++ = 0;
691                         *b->wptr++ = 0;
692                         *b->wptr++ = 0x41;
693                 }
694                 break;
695         case Pipcp:
696                 if(p->optmask & Fipaddr)
697 {syslog(0, "ppp", "requesting %I", ppp->local);
698                         putv4o(b, Oipaddr, ppp->local);
699 }
700                 if(primary && (p->optmask & Fipdns))
701                         putv4o(b, Oipdns, ppp->dns[0]);
702                 if(primary && (p->optmask & Fipdns2))
703                         putv4o(b, Oipdns2, ppp->dns[1]);
704                 if(primary && (p->optmask & Fipwins))
705                         putv4o(b, Oipwins, ppp->wins[0]);
706                 if(primary && (p->optmask & Fipwins2))
707                         putv4o(b, Oipwins2, ppp->wins[1]);
708                 /*
709                  * don't ask for header compression while data compression is still pending.
710                  * perhaps we should restart ipcp negotiation if compression negotiation fails.
711                  */
712                 if(!noipcompress && !ppp->ccp->optmask && (p->optmask & Fipcompress)) {
713                         *b->wptr++ = Oipcompress;
714                         *b->wptr++ = 6;
715                         hnputs(b->wptr, Pvjctcp);
716                         b->wptr += 2;
717                         *b->wptr++ = MAX_STATES-1;
718                         *b->wptr++ = 1;
719                 }
720                 break;
721         }
722         hnputs(m->len, BLEN(b));
723         printopts(p, b, 1);
724         putframe(ppp, p->proto, b);
725         freeb(b);
726 }
727
728 static void
729 getipinfo(PPP *ppp)
730 {
731         char *av[3];
732         int ndns, nwins;
733         char ip[64];
734         Ndbtuple *t, *nt;
735
736         if(!validv4(ppp->local))
737                 return;
738
739         av[0] = "dns";
740         av[1] = "wins";
741         sprint(ip, "%I", ppp->local);
742         t = csipinfo(ppp->net, "ip", ip, av, 2);
743         ndns = nwins = 0;
744         for(nt = t; nt != nil; nt = nt->entry){
745                 if(strcmp(nt->attr, "dns") == 0){
746                         if(ndns < 2)
747                                 parseip(ppp->dns[ndns++], nt->val);
748                 } else if(strcmp(nt->attr, "wins") == 0){
749                         if(nwins < 2)
750                                 parseip(ppp->wins[nwins++], nt->val);
751                 }
752         }
753         if(t != nil)
754                 ndbfree(t);
755 }
756
757 /*
758  *  parse configuration request, sends an ack or reject packet
759  *
760  *      returns:        -1 if request was syntacticly incorrect
761  *                       0 if packet was accepted
762  *                       1 if packet was rejected
763  */
764 static int
765 getopts(PPP *ppp, Pstate *p, Block *b)
766 {
767         Lcpmsg *m, *repm;       
768         Lcpopt *o;
769         uchar *cp, *ap;
770         ulong rejecting, nacking, flags, proto, chapproto;
771         ulong mtu, ctlmap, period;
772         ulong x;
773         Block *repb;
774         Comptype *ctype;
775         Ipaddr ipaddr;
776
777         rejecting = 0;
778         nacking = 0;
779         flags = 0;
780
781         /* defaults */
782         invalidate(ipaddr);
783         mtu = ppp->mtu;
784         ctlmap = 0xffffffff;
785         period = 0;
786         ctype = nil;
787         chapproto = 0;
788
789         m = (Lcpmsg*)b->rptr;
790         repb = alloclcp(Lconfack, m->id, BLEN(b), &repm);
791
792         /* copy options into ack packet */
793         memmove(repm->data, m->data, b->wptr - m->data);
794         repb->wptr += b->wptr - m->data;
795
796         /* look for options we don't recognize or like */
797         for(cp = m->data; cp < b->wptr; cp += o->len){
798                 o = (Lcpopt*)cp;
799                 if(cp + o->len > b->wptr || o->len==0){
800                         freeb(repb);
801                         netlog("ppp: bad option length %ux\n", o->type);
802                         return -1;
803                 }
804
805                 switch(p->proto){
806                 case Plcp:
807                         switch(o->type){
808                         case Oac:
809                                 flags |= Fac;
810                                 continue;
811                         case Opc:
812                                 flags |= Fpc;
813                                 continue;
814                         case Omtu:
815                                 mtu = nhgets(o->data);
816                                 continue;
817                         case Omagic:
818                                 if(ppp->magic == nhgetl(o->data))
819                                         netlog("ppp: possible loop\n");
820                                 continue;
821                         case Octlmap:
822                                 ctlmap = nhgetl(o->data);
823                                 continue;
824                         case Oquality:
825                                 proto = nhgets(o->data);
826                                 if(proto != Plqm)
827                                         break;
828                                 x = nhgetl(o->data+2)*10;
829                                 period = (x+Period-1)/Period;
830                                 continue;
831                         case Oauth:
832                                 proto = nhgets(o->data);
833                                 if(proto == Ppasswd && !server){
834                                         chapproto = APpasswd;
835                                         continue;
836                                 }
837                                 if(proto != Pchap)
838                                         break;
839                                 if(o->data[2] != APmd5 && o->data[2] != APmschap)
840                                         break;
841                                 chapproto = o->data[2];
842                                 continue;
843                         }
844                         break;
845                 case Pccp:
846                         if(nocompress)
847                                 break;
848                         switch(o->type){
849                         case Octhwack:
850                                 break;
851                         /*
852                                 if(o->len == 2){
853                                         ctype = &cthwack;
854                                         continue;
855                                 }
856                                 if(!nacking){
857                                         nacking = 1;
858                                         repb->wptr = repm->data;
859                                         repm->code = Lconfnak;
860                                 }
861                                 puto(repb, Octhwack);
862                                 continue;
863                         */
864                         case Ocmppc:
865                                 x = nhgetl(o->data);
866
867                                 // hack for Mac
868                                 // if(x == 0)
869                                 //      continue;
870
871                                 /* stop ppp loops */
872                                 if((x&0x41) == 0 || ppp->ctries++ > 5) {
873                                         /*
874                                          * turn off requests as well - I don't think this
875                                          * is needed in the standard
876                                          */
877                                         p->optmask &= ~Fcmppc;
878                                         break;
879                                 }
880                                 if(rejecting)
881                                         continue;
882                                 if(x & 1) {
883                                         ctype = &cmppc;
884                                         ppp->sendencrypted = (o->data[3]&0x40) == 0x40;
885                                         continue;
886                                 }
887                                 if(!nacking){
888                                         nacking = 1;
889                                         repb->wptr = repm->data;
890                                         repm->code = Lconfnak;
891                                 }
892                                 *repb->wptr++ = Ocmppc;
893                                 *repb->wptr++ = 6;
894                                 *repb->wptr++ = 0;
895                                 *repb->wptr++ = 0;
896                                 *repb->wptr++ = 0;
897                                 *repb->wptr++ = 0x41;
898                                 continue;
899                         }
900                         break;
901                 case Pipcp:
902                         switch(o->type){
903                         case Oipaddr:   
904                                 v4tov6(ipaddr, o->data);
905                                 if(!validv4(ppp->remote))
906                                         continue;
907                                 if(!validv4(ipaddr) && !rejecting){
908                                         /* other side requesting an address */
909                                         if(!nacking){
910                                                 nacking = 1;
911                                                 repb->wptr = repm->data;
912                                                 repm->code = Lconfnak;
913                                         }
914                                         putv4o(repb, Oipaddr, ppp->remote);
915                                 }
916                                 continue;
917                         case Oipdns:
918                                 ap = ppp->dns[0];
919                                 goto ipinfo;
920                         case Oipdns2:   
921                                 ap = ppp->dns[1];
922                                 goto ipinfo;
923                         case Oipwins:   
924                                 ap = ppp->wins[0];
925                                 goto ipinfo;
926                         case Oipwins2:
927                                 ap = ppp->wins[1];
928                                 goto ipinfo;
929                         ipinfo:
930                                 if(!validv4(ap))
931                                         getipinfo(ppp);
932                                 if(!validv4(ap))
933                                         break;
934                                 v4tov6(ipaddr, o->data);
935                                 if(!validv4(ipaddr) && !rejecting){
936                                         /* other side requesting an address */
937                                         if(!nacking){
938                                                 nacking = 1;
939                                                 repb->wptr = repm->data;
940                                                 repm->code = Lconfnak;
941                                         }
942                                         putv4o(repb, o->type, ap);
943                                 }
944                                 continue;
945                         case Oipcompress:
946                                 /*
947                                  * don't compress tcp header if we've negotiated data compression.
948                                  * tcp header compression has very poor performance if there is an error.
949                                  */
950                                 proto = nhgets(o->data);
951                                 if(noipcompress || proto != Pvjctcp || ppp->ctype != nil)
952                                         break;
953                                 if(compress_negotiate(ppp->ctcp, o->data+2) < 0)
954                                         break;
955                                 flags |= Fipcompress;
956                                 continue;
957                         }
958                         break;
959                 }
960
961                 /* come here if option is not recognized */
962                 if(!rejecting){
963                         rejecting = 1;
964                         repb->wptr = repm->data;
965                         repm->code = Lconfrej;
966                 }
967                 netlog("ppp: bad %ux option %d\n", p->proto, o->type);
968                 memmove(repb->wptr, o, o->len);
969                 repb->wptr += o->len;
970         }
971
972         /* permanent changes only after we know that we liked the packet */
973         if(!rejecting && !nacking){
974                 switch(p->proto){
975                 case Plcp:
976                         ppp->period = period;
977                         ppp->xctlmap = ctlmap;
978                         if(mtu > Maxmtu)
979                                 mtu = Maxmtu;
980                         if(mtu < Minmtu)
981                                 mtu = Minmtu;
982                         ppp->mtu = mtu;
983                         if(chapproto)
984                                 ppp->chap->proto = chapproto;
985                         
986                         break;
987                 case Pccp:
988                         if(ppp->ctype != nil){
989                                 (*ppp->ctype->fini)(ppp->cstate);
990                                 ppp->cstate = nil;
991                         }
992                         ppp->ctype = ctype;
993                         if(ctype)
994                                 ppp->cstate = (*ctype->init)(ppp);
995                         break;
996                 case Pipcp:
997                         if(validv4(ipaddr) && ppp->remotefrozen == 0)
998                                 ipmove(ppp->remote, ipaddr);
999                         break;
1000                 }
1001                 p->flags = flags;
1002         }
1003
1004         hnputs(repm->len, BLEN(repb));
1005         printopts(p, repb, 1);
1006         putframe(ppp, p->proto, repb);
1007         freeb(repb);
1008
1009         return rejecting || nacking;
1010 }
1011 static void
1012 dmppkt(char *s, uchar *a, int na)
1013 {
1014         int i;
1015
1016         if (debug < 3)
1017                 return;
1018
1019         fprint(2, "%s", s);
1020         for(i = 0; i < na; i++)
1021                 fprint(2, " %.2ux", a[i]);
1022         fprint(2, "\n");
1023 }
1024
1025 static void
1026 dropoption(Pstate *p, Lcpopt *o)
1027 {
1028         unsigned n = o->type;
1029
1030         switch(n){
1031         case Oipaddr:
1032                 break;
1033         case Oipdns:
1034                 p->optmask &= ~Fipdns;
1035                 break;
1036         case Oipwins:
1037                 p->optmask &= ~Fipwins;
1038                 break;
1039         case Oipdns2:
1040                 p->optmask &= ~Fipdns2;
1041                 break;
1042         case Oipwins2:
1043                 p->optmask &= ~Fipwins2;
1044                 break;
1045         default:
1046                 if(o->type < 8*sizeof(p->optmask))
1047                         p->optmask &= ~(1<<o->type);
1048                 break;
1049         }
1050 }
1051
1052 /*
1053  *  parse configuration rejection, just stop sending anything that they
1054  *  don't like (except for ipcp address nak).
1055  */
1056 static void
1057 rejopts(PPP *ppp, Pstate *p, Block *b, int code)
1058 {
1059         Lcpmsg *m;
1060         Lcpopt *o;
1061         uchar newip[IPaddrlen];
1062
1063         /* just give up trying what the other side doesn't like */
1064         m = (Lcpmsg*)b->rptr;
1065         for(b->rptr = m->data; b->rptr < b->wptr; b->rptr += o->len){
1066                 o = (Lcpopt*)b->rptr;
1067                 if(b->rptr + o->len > b->wptr){
1068                         netlog("ppp: bad roption length %ux\n", o->type);
1069                         return;
1070                 }
1071
1072                 if(code == Lconfrej){
1073                         dropoption(p, o);
1074                         netlog("ppp: %ux rejecting %d\n",
1075                                         p->proto, o->type);
1076                         continue;
1077                 }
1078
1079                 switch(p->proto){
1080                 case Plcp:
1081                         switch(o->type){
1082                         case Octlmap:
1083                                 ppp->rctlmap = nhgetl(o->data);
1084                                 break;
1085                         case Oauth:
1086                                 /* don't allow client to request no auth */
1087                                 /* could try different auth protocol here */
1088                                 fprint(2, "ppp: can not reject CHAP\n");
1089                                 exits("ppp: CHAP");
1090                                 break;
1091                         default:
1092                                 if(o->type < 8*sizeof(p->optmask))
1093                                         p->optmask &= ~(1<<o->type);
1094                                 break;
1095                         };
1096                         break;
1097                 case Pccp:
1098                         switch(o->type){
1099                         default:
1100                                 dropoption(p, o);
1101                                 break;
1102                         }
1103                         break;
1104                 case Pipcp:
1105                         switch(o->type){
1106                         case Oipaddr:
1107 syslog(0, "ppp", "rejected addr %I with %V", ppp->local, o->data);
1108                                 /* if we're a server, don't let other end change our addr */
1109                                 if(ppp->localfrozen){
1110                                         dropoption(p, o);
1111                                         break;
1112                                 }
1113
1114                                 /* accept whatever server tells us */
1115                                 if(!validv4(ppp->local)){
1116                                         v4tov6(ppp->local, o->data);
1117                                         dropoption(p, o);
1118                                         break;
1119                                 }
1120
1121                                 /* if he didn't like our addr, ask for a generic one */
1122                                 v4tov6(newip, o->data);
1123                                 if(!validv4(newip)){
1124                                         invalidate(ppp->local);
1125                                         break;
1126                                 }
1127
1128                                 /* if he gives us something different, use it anyways */
1129                                 v4tov6(ppp->local, o->data);
1130                                 dropoption(p, o);
1131                                 break;
1132                         case Oipdns:
1133                                 if (!validv4(ppp->dns[0])){
1134                                         v4tov6(ppp->dns[0], o->data);
1135                                         dropoption(p, o);
1136                                         break;
1137                                 }
1138                                 v4tov6(newip, o->data);
1139                                 if(!validv4(newip)){
1140                                         invalidate(ppp->dns[0]);
1141                                         break;
1142                                 }
1143                                 v4tov6(ppp->dns[0], o->data);
1144                                 dropoption(p, o);
1145                                 break;
1146                         case Oipwins:
1147                                 if (!validv4(ppp->wins[0])){
1148                                         v4tov6(ppp->wins[0], o->data);
1149                                         dropoption(p, o);
1150                                         break;
1151                                 }
1152                                 v4tov6(newip, o->data);
1153                                 if(!validv4(newip)){
1154                                         invalidate(ppp->wins[0]);
1155                                         break;
1156                                 }
1157                                 v4tov6(ppp->wins[0], o->data);
1158                                 dropoption(p, o);
1159                                 break;
1160                         case Oipdns2:
1161                                 if (!validv4(ppp->dns[1])){
1162                                         v4tov6(ppp->dns[1], o->data);
1163                                         dropoption(p, o);
1164                                         break;
1165                                 }
1166                                 v4tov6(newip, o->data);
1167                                 if(!validv4(newip)){
1168                                         invalidate(ppp->dns[1]);
1169                                         break;
1170                                 }
1171                                 v4tov6(ppp->dns[1], o->data);
1172                                 dropoption(p, o);
1173                                 break;
1174                         case Oipwins2:
1175                                 if (!validv4(ppp->wins[1])){
1176                                         v4tov6(ppp->wins[1], o->data);
1177                                         dropoption(p, o);
1178                                         break;
1179                                 }
1180                                 v4tov6(newip, o->data);
1181                                 if(!validv4(newip)){
1182                                         invalidate(ppp->wins[1]);
1183                                         break;
1184                                 }
1185                                 v4tov6(ppp->wins[1], o->data);
1186                                 dropoption(p, o);
1187                                 break;
1188                         default:
1189                                 dropoption(p, o);
1190                                 break;
1191                         }
1192                         break;
1193                 }
1194         }
1195 }
1196
1197
1198 /*
1199  *  put a messages through the lcp or ipcp state machine.  They are
1200  *  very similar.
1201  */
1202 static void
1203 rcv(PPP *ppp, Pstate *p, Block *b)
1204 {
1205         ulong len;
1206         int err;
1207         Lcpmsg *m;
1208         int proto;
1209
1210         if(BLEN(b) < 4){
1211                 netlog("ppp: short lcp message\n");
1212                 freeb(b);
1213                 return;
1214         }
1215         m = (Lcpmsg*)b->rptr;
1216         len = nhgets(m->len);
1217         if(BLEN(b) < len){
1218                 netlog("ppp: short lcp message\n");
1219                 freeb(b);
1220                 return;
1221         }
1222
1223         netlog("ppp: %ux rcv %d len %ld id %d/%d/%d\n",
1224                 p->proto, m->code, len, m->id, p->confid, p->id);
1225
1226         if(p->proto != Plcp && ppp->lcp->state != Sopened){
1227                 netlog("ppp: non-lcp with lcp not open\n");
1228                 freeb(b);
1229                 return;
1230         }
1231
1232         qlock(ppp);
1233         switch(m->code){
1234         case Lconfreq:
1235                 printopts(p, b, 0);
1236                 err = getopts(ppp, p, b);
1237                 if(err < 0)
1238                         break;
1239
1240                 if(m->id == p->rcvdconfid)
1241                         break;                  /* don't change state for duplicates */
1242
1243                 switch(p->state){
1244                 case Sackrcvd:
1245                         if(err)
1246                                 break;
1247                         newstate(ppp, p, Sopened);
1248                         break;
1249                 case Sclosed:
1250                 case Sopened:
1251                         config(ppp, p, 1);
1252                         if(err == 0)
1253                                 newstate(ppp, p, Sacksent);
1254                         else
1255                                 newstate(ppp, p, Sreqsent);
1256                         break;
1257                 case Sreqsent:
1258                 case Sacksent:
1259                         if(err == 0)
1260                                 newstate(ppp, p, Sacksent);
1261                         else
1262                                 newstate(ppp, p, Sreqsent);
1263                         break;
1264                 }
1265                 break;
1266         case Lconfack:
1267                 if(p->confid != m->id){
1268                         /* ignore if it isn't the message we're sending */
1269                         netlog("ppp: dropping confack\n");
1270                         break;
1271                 }
1272                 p->confid = -1;         /* ignore duplicates */
1273                 p->id++;                /* avoid sending duplicates */
1274
1275                 netlog("ppp: recv confack\n");
1276                 switch(p->state){
1277                 case Sopened:
1278                 case Sackrcvd:
1279                         config(ppp, p, 1);
1280                         newstate(ppp, p, Sreqsent);
1281                         break;
1282                 case Sreqsent:
1283                         newstate(ppp, p, Sackrcvd);
1284                         break;
1285                 case Sacksent:
1286                         newstate(ppp, p, Sopened);
1287                         break;
1288                 }
1289                 break;
1290         case Lconfrej:
1291         case Lconfnak:
1292                 if(p->confid != m->id) {
1293                         /* ignore if it isn't the message we're sending */
1294                         netlog("ppp: dropping confrej or confnak\n");
1295                         break;
1296                 }
1297                 p->confid = -1;         /* ignore duplicates */
1298                 p->id++;                /* avoid sending duplicates */
1299
1300                 switch(p->state){
1301                 case Sopened:
1302                 case Sackrcvd:
1303                         config(ppp, p, 1);
1304                         newstate(ppp, p, Sreqsent);
1305                         break;
1306                 case Sreqsent:
1307                 case Sacksent:
1308                         printopts(p, b, 0);
1309                         rejopts(ppp, p, b, m->code);
1310                         config(ppp, p, 1);
1311                         break;
1312                 }
1313                 break;
1314         case Ltermreq:
1315                 m->code = Ltermack;
1316                 putframe(ppp, p->proto, b);
1317
1318                 switch(p->state){
1319                 case Sackrcvd:
1320                 case Sacksent:
1321                         newstate(ppp, p, Sreqsent);
1322                         break;
1323                 case Sopened:
1324                         newstate(ppp, p, Sclosing);
1325                         break;
1326                 }
1327                 break;
1328         case Ltermack:
1329                 if(p->termid != m->id)  /* ignore if it isn't the message we're sending */
1330                         break;
1331
1332                 if(p->proto == Plcp)
1333                         ppp->ipcp->state = Sclosed;
1334                 switch(p->state){
1335                 case Sclosing:
1336                         newstate(ppp, p, Sclosed);
1337                         break;
1338                 case Sackrcvd:
1339                         newstate(ppp, p, Sreqsent);
1340                         break;
1341                 case Sopened:
1342                         config(ppp, p, 0);
1343                         newstate(ppp, p, Sreqsent);
1344                         break;
1345                 }
1346                 break;
1347         case Lcoderej:
1348                 //newstate(ppp, p, Sclosed);
1349                 syslog(0, LOG, "code reject %d", m->data[0]);
1350                 break;
1351         case Lprotorej:
1352                 proto = nhgets(m->data);
1353                 netlog("ppp: proto reject %ux", proto);
1354                 if(proto == Pccp)
1355                         newstate(ppp, ppp->ccp, Sclosed);
1356                 break;
1357         case Lechoreq:
1358                 if(BLEN(b) < 8){
1359                         netlog("ppp: short lcp echo request\n");
1360                         freeb(b);
1361                         return;
1362                 }
1363                 m->code = Lechoack;
1364                 hnputl(m->data, ppp->magic);
1365                 putframe(ppp, p->proto, b);
1366                 break;
1367         case Lechoack:
1368                 p->echoack = 1;
1369                 break;
1370         case Ldiscard:
1371                 /* nothing to do */
1372                 break;
1373         case Lresetreq:
1374                 if(p->proto != Pccp)
1375                         break;
1376                 ppp->stat.compreset++;
1377                 if(ppp->ctype != nil)
1378                         b = (*ppp->ctype->resetreq)(ppp->cstate, b);
1379                 if(b != nil) {
1380                         m = (Lcpmsg*)b->rptr;
1381                         m->code = Lresetack;
1382                         putframe(ppp, p->proto, b);
1383                 }
1384                 break;
1385         case Lresetack:
1386                 if(p->proto != Pccp)
1387                         break;
1388                 if(ppp->unctype != nil)
1389                         (*ppp->unctype->resetack)(ppp->uncstate, b);
1390                 break;
1391         }
1392
1393         qunlock(ppp);
1394         freeb(b);
1395 }
1396
1397 /*
1398  *  timer for protocol state machine
1399  */
1400 static void
1401 ptimer(PPP *ppp, Pstate *p)
1402 {
1403         if(p->state == Sopened || p->state == Sclosed)
1404                 return;
1405
1406         p->timeout--;
1407         switch(p->state){
1408         case Sclosing:
1409                 sendtermreq(ppp, p);
1410                 break;
1411         case Sreqsent:
1412         case Sacksent:
1413                 if(p->timeout <= 0)
1414                         newstate(ppp, p, Sclosed);
1415                 else {
1416                         config(ppp, p, 0);
1417                 }
1418                 break;
1419         case Sackrcvd:
1420                 if(p->timeout <= 0)
1421                         newstate(ppp, p, Sclosed);
1422                 else {
1423                         config(ppp, p, 0);
1424                         newstate(ppp, p, Sreqsent);
1425                 }
1426                 break;
1427         }
1428 }
1429
1430 /* paptimer -- pap timer event handler
1431  *
1432  * If PAP authorization hasn't come through, resend an authreqst.  If
1433  * the maximum number of requests have been sent (~ 30 seconds), give
1434  * up.
1435  *
1436  */
1437 static void
1438 authtimer(PPP* ppp)
1439 {
1440         if(ppp->chap->proto != APpasswd)
1441                 return;
1442
1443         if(ppp->chap->id < 21)
1444                 putpaprequest(ppp);
1445         else {
1446                 terminate(ppp, 0);
1447                 netlog("ppp: pap timed out--not authorized\n");
1448         }
1449 }
1450
1451
1452 /*
1453  *  timer for ppp
1454  */
1455 static void
1456 ppptimer(PPP *ppp)
1457 {
1458         while(!dying){
1459                 sleep(Period);
1460                 qlock(ppp);
1461
1462                 netlog("ppp: ppptimer\n");
1463                 ptimer(ppp, ppp->lcp);
1464                 if(ppp->lcp->state == Sopened) {
1465                         switch(ppp->phase){
1466                         case Pnet:
1467                                 ptimer(ppp, ppp->ccp);
1468                                 ptimer(ppp, ppp->ipcp);
1469                                 break;
1470                         case Pauth:
1471                                 authtimer(ppp);
1472                                 break;
1473                         }
1474                 }
1475
1476                 /* link quality measurement */
1477                 if(ppp->period && --(ppp->timeout) <= 0){
1478                         ppp->timeout = ppp->period;
1479                         putlqm(ppp);
1480                 }
1481
1482                 qunlock(ppp);
1483         }
1484 }
1485
1486 static void
1487 setdefroute(char *net, Ipaddr gate)
1488 {
1489         int fd;
1490         char path[128];
1491
1492         snprint(path, sizeof path, "%s/iproute", net);
1493         fd = open(path, ORDWR);
1494         if(fd < 0)
1495                 return;
1496         fprint(fd, "add 0 0 %I", gate);
1497         close(fd);
1498 }
1499
1500 enum
1501 {
1502         Mofd=   32,
1503 };
1504 struct
1505 {
1506         Lock;
1507
1508         int     fd[Mofd];
1509         int     cfd[Mofd];
1510         int     n;
1511 } old;
1512
1513 static char*
1514 ipopen(PPP *ppp)
1515 {
1516         static int ipinprocpid;
1517         int n, cfd, fd;
1518         char path[128];
1519         char buf[128];
1520
1521         if(ipinprocpid <= 0){
1522                 snprint(path, sizeof path, "%s/ipifc/clone", ppp->net);
1523                 cfd = open(path, ORDWR);
1524                 if(cfd < 0)
1525                         return "can't open ip interface";
1526
1527                 n = read(cfd, buf, sizeof(buf) - 1);
1528                 if(n <= 0){
1529                         close(cfd);
1530                         return "can't open ip interface";
1531                 }
1532                 buf[n] = 0;
1533
1534                 netlog("ppp: setting up IP interface local %I remote %I (valid %d)\n",
1535                         ppp->local, ppp->remote, validv4(ppp->remote));
1536                 if(!validv4(ppp->remote))
1537                         ipmove(ppp->remote, ppp->local);
1538
1539                 snprint(path, sizeof path, "%s/ipifc/%s/data", ppp->net, buf);
1540                 fd = open(path, ORDWR);
1541                 if(fd < 0){
1542                         close(cfd);
1543                         return "can't open ip interface";
1544                 }
1545
1546                 if(fprint(cfd, "bind pkt") < 0)
1547                         return "binding pkt to ip interface";
1548                 if(fprint(cfd, "add %I 255.255.255.255 %I %lud proxy", ppp->local,
1549                         ppp->remote, ppp->mtu-10) < 0){
1550                         close(cfd);
1551                         return "can't set addresses";
1552                 }
1553                 if(primary)
1554                         setdefroute(ppp->net, ppp->remote);
1555                 ppp->ipfd = fd;
1556                 ppp->ipcfd = cfd;
1557
1558                 /* signal main() that ip is configured */
1559                 rendezvous((void*)Rmagic, 0);
1560
1561                 switch(ipinprocpid = rfork(RFPROC|RFMEM|RFNOWAIT)){
1562                 case -1:
1563                         sysfatal("forking ipinproc");
1564                 case 0:
1565                         ipinproc(ppp);
1566                         terminate(ppp, 1);
1567                         _exits(0);
1568                 }
1569         } else {
1570                 /* we may have changed addresses */
1571                 if(ipcmp(ppp->local, ppp->curlocal) != 0 ||
1572                    ipcmp(ppp->remote, ppp->curremote) != 0){
1573                         snprint(buf, sizeof buf, "remove %I 255.255.255.255 %I",
1574                             ppp->curlocal, ppp->curremote);
1575                         if(fprint(ppp->ipcfd, "%s", buf) < 0)
1576                                 syslog(0, "ppp", "can't %s: %r", buf);
1577                         snprint(buf, sizeof buf, "add %I 255.255.255.255 %I %lud proxy",
1578                             ppp->local, ppp->remote, ppp->mtu-10);
1579                         if(fprint(ppp->ipcfd, "%s", buf) < 0)
1580                                 syslog(0, "ppp", "can't %s: %r", buf);
1581                 }
1582                 syslog(0, "ppp", "%I/%I -> %I/%I", ppp->curlocal, ppp->curremote,
1583                    ppp->local, ppp->remote);
1584         }
1585         ipmove(ppp->curlocal, ppp->local);
1586         ipmove(ppp->curremote, ppp->remote);
1587
1588         return nil;
1589 }
1590
1591 /* return next input IP packet */
1592 Block*
1593 pppread(PPP *ppp)
1594 {
1595         Block *b, *reply;
1596         int proto, len;
1597         Lcpmsg *m;
1598
1599         while(!dying){
1600                 b = getframe(ppp, &proto);
1601                 if(b == nil)
1602                         return nil;
1603
1604 Again:
1605                 switch(proto){
1606                 case Plcp:
1607                         rcv(ppp, ppp->lcp, b);
1608                         break;
1609                 case Pccp:
1610                         rcv(ppp, ppp->ccp, b);
1611                         break;
1612                 case Pipcp:
1613                         rcv(ppp, ppp->ipcp, b);
1614                         break;
1615                 case Pip:
1616                         if(ppp->ipcp->state == Sopened)
1617                                 return b;
1618                         netlog("ppp: IP recved: link not up\n");
1619                         freeb(b);
1620                         break;
1621                 case Plqm:
1622                         getlqm(ppp, b);
1623                         break;
1624                 case Pchap:
1625                         getchap(ppp, b);
1626                         break;
1627                 case Ppasswd:
1628                         getpap(ppp, b);
1629                         break;
1630                 case Pvjctcp:
1631                 case Pvjutcp:
1632                         if(ppp->ipcp->state != Sopened){
1633                                 netlog("ppp: VJ tcp recved: link not up\n");
1634                                 freeb(b);
1635                                 break;
1636                         }
1637                         ppp->stat.vjin++;
1638                         b = tcpuncompress(ppp->ctcp, b, proto);
1639                         if(b != nil)
1640                                 return b;
1641                         ppp->stat.vjfail++;
1642                         break;
1643                 case Pcdata:
1644                         ppp->stat.uncomp++;
1645                         if(ppp->ccp->state != Sopened){
1646                                 netlog("ppp: compressed data recved: link not up\n");
1647                                 freeb(b);
1648                                 break;
1649                         }
1650                         if(ppp->unctype == nil) {
1651                                 netlog("ppp: compressed data recved: no compression\n");
1652                                 freeb(b);
1653                                 break;
1654                         }
1655                         len = BLEN(b);
1656                         b = (*ppp->unctype->uncompress)(ppp, b, &proto, &reply);
1657                         if(reply != nil){
1658                                 /* send resetreq */
1659                                 ppp->stat.uncompreset++;
1660                                 putframe(ppp, Pccp, reply);
1661                                 freeb(reply);
1662                         }
1663                         if(b == nil)
1664                                 break;
1665                         ppp->stat.uncompin += len;
1666                         ppp->stat.uncompout += BLEN(b);
1667 /* netlog("ppp: uncompressed frame %ux %d %d (%d uchars)\n", proto, b->rptr[0], b->rptr[1], BLEN(b)); /* */
1668                         goto Again;     
1669                 default:
1670                         syslog(0, LOG, "unknown proto %ux", proto);
1671                         if(ppp->lcp->state == Sopened){
1672                                 /* reject the protocol */
1673                                 b->rptr -= 6;
1674                                 m = (Lcpmsg*)b->rptr;
1675                                 m->code = Lprotorej;
1676                                 m->id = ++ppp->lcp->id;
1677                                 hnputs(m->data, proto);
1678                                 hnputs(m->len, BLEN(b));
1679                                 putframe(ppp, Plcp, b);
1680                         }
1681                         freeb(b);
1682                         break;
1683                 }
1684         }
1685         return nil;
1686 }
1687
1688 /* transmit an IP packet */
1689 int
1690 pppwrite(PPP *ppp, Block *b)
1691 {
1692         int proto;
1693         int len;
1694
1695         qlock(ppp);
1696         /* can't send ip packets till we're established */
1697         if(ppp->ipcp->state != Sopened) {
1698                 qunlock(ppp);
1699                 syslog(0, LOG, "IP write: link not up");
1700                 len = blen(b);
1701                 freeb(b);
1702                 return len;
1703         }
1704
1705         proto = Pip;
1706         ppp->stat.ipsend++;
1707
1708         if(ppp->ipcp->flags & Fipcompress){
1709                 b = compress(ppp->ctcp, b, &proto);
1710                 if(b == nil){
1711                         qunlock(ppp);
1712                         return 0;
1713                 }
1714                 if(proto != Pip)
1715                         ppp->stat.vjout++;
1716         }
1717
1718         if(ppp->ctype != nil) {
1719                 len = blen(b);
1720                 b = (*ppp->ctype->compress)(ppp, proto, b, &proto);
1721                 if(proto == Pcdata) {
1722                         ppp->stat.comp++;
1723                         ppp->stat.compin += len;
1724                         ppp->stat.compout += blen(b);
1725                 }
1726         } 
1727
1728         if(putframe(ppp, proto, b) < 0) {
1729                 qunlock(ppp);
1730                 freeb(b);
1731                 return -1;
1732         }
1733         qunlock(ppp);
1734
1735         len = blen(b);
1736         freeb(b);
1737         return len;
1738 }
1739
1740 static void
1741 terminate(PPP *ppp, int kill)
1742 {
1743         close(ppp->ipfd);
1744         ppp->ipfd = -1;
1745         close(ppp->ipcfd);
1746         ppp->ipcfd = -1;
1747         close(ppp->mediain);
1748         close(ppp->mediaout);
1749         ppp->mediain = -1;
1750         ppp->mediaout = -1;
1751         dying = 1;
1752
1753         if(kill)
1754                 postnote(PNGROUP, getpid(), "die");
1755 }
1756
1757 typedef struct Iphdr Iphdr;
1758 struct Iphdr
1759 {
1760         uchar   vihl;           /* Version and header length */
1761         uchar   tos;            /* Type of service */
1762         uchar   length[2];      /* packet length */
1763         uchar   id[2];          /* Identification */
1764         uchar   frag[2];        /* Fragment information */
1765         uchar   ttl;            /* Time to live */
1766         uchar   proto;          /* Protocol */
1767         uchar   cksum[2];       /* Header checksum */
1768         uchar   src[4];         /* Ip source (uchar ordering unimportant) */
1769         uchar   dst[4];         /* Ip destination (uchar ordering unimportant) */
1770 };
1771
1772 static void
1773 ipinproc(PPP *ppp)
1774 {
1775         Block *b;
1776         int m, n;
1777         Iphdr *ip;
1778
1779         while(!dying){
1780
1781                 b = allocb(Buflen);
1782                 n = read(ppp->ipfd, b->wptr, b->lim-b->wptr);
1783                 if(n < 0)
1784                         break;
1785
1786                 /* trim packet if there's padding (e.g. from ether) */
1787                 ip = (Iphdr*)b->rptr;
1788                 m = nhgets(ip->length);
1789                 if(m < n && m > 0)
1790                         n = m;
1791                 b->wptr += n;
1792
1793                 if(pppwrite(ppp, b) < 0)
1794                         break;
1795         }
1796 }
1797
1798 static void
1799 catchdie(void*, char *msg)
1800 {
1801         if(strstr(msg, "die") != nil)
1802                 noted(NCONT);
1803         else
1804                 noted(NDFLT);
1805 }
1806
1807 static void
1808 hexdump(uchar *a, int na)
1809 {
1810         int i;
1811         char buf[80];
1812
1813         fprint(2, "dump %p %d\n", a, na);
1814         buf[0] = '\0';
1815         for(i=0; i<na; i++){
1816                 sprint(buf+strlen(buf), " %.2ux", a[i]);
1817                 if(i%16 == 7)
1818                         sprint(buf+strlen(buf), " --");
1819                 if(i%16==15){
1820                         sprint(buf+strlen(buf), "\n");
1821                         write(2, buf, strlen(buf));
1822                         buf[0] = '\0';
1823                 }
1824         }
1825         if(i%16){
1826                 sprint(buf+strlen(buf), "\n");
1827                 write(2, buf, strlen(buf));
1828         }
1829 }
1830
1831 static void
1832 mediainproc(PPP *ppp)
1833 {
1834         Block *b;
1835         Ipaddr remote;
1836
1837         notify(catchdie);
1838         while(!dying){
1839                 b = pppread(ppp);
1840                 if(b == nil){
1841                         syslog(0, LOG, "pppread return nil");
1842                         break;
1843                 }
1844                 ppp->stat.iprecv++;
1845                 if(ppp->ipcp->state != Sopened) {
1846                         ppp->stat.iprecvnotup++;
1847                         freeb(b);
1848                         continue;
1849                 }
1850
1851                 if(server) {
1852                         v4tov6(remote, b->rptr+12);
1853                         if(ipcmp(remote, ppp->remote) != 0) {
1854                                 ppp->stat.iprecvbadsrc++;
1855                                 freeb(b);
1856                                 continue;
1857                         }
1858                 }
1859                 if(debug > 1){
1860                         netlog("ip write pkt %p %d\n", b->rptr, blen(b));
1861                         hexdump(b->rptr, blen(b));
1862                 }
1863                 if(write(ppp->ipfd, b->rptr, blen(b)) < 0) {
1864                         syslog(0, LOG, "error writing to pktifc");
1865                         freeb(b);
1866                         break;
1867                 }
1868
1869                 freeb(b);
1870         }
1871
1872         netlog(": remote=%I: ppp shutting down\n", ppp->remote);
1873         syslog(0, LOG, ": remote=%I: ppp shutting down", ppp->remote);
1874         syslog(0, LOG, "\t\tppp send = %lud/%lud recv= %lud/%lud",
1875                 ppp->out.packets, ppp->out.uchars,
1876                 ppp->in.packets, ppp->in.uchars);
1877         syslog(0, LOG, "\t\tip send=%lud", ppp->stat.ipsend);
1878         syslog(0, LOG, "\t\tip recv=%lud notup=%lud badsrc=%lud",
1879                 ppp->stat.iprecv, ppp->stat.iprecvnotup, ppp->stat.iprecvbadsrc);
1880         syslog(0, LOG, "\t\tcompress=%lud in=%lud out=%lud reset=%lud",
1881                 ppp->stat.comp, ppp->stat.compin, ppp->stat.compout, ppp->stat.compreset);
1882         syslog(0, LOG, "\t\tuncompress=%lud in=%lud out=%lud reset=%lud",
1883                 ppp->stat.uncomp, ppp->stat.uncompin, ppp->stat.uncompout,
1884                 ppp->stat.uncompreset);
1885         syslog(0, LOG, "\t\tvjin=%lud vjout=%lud vjfail=%lud", 
1886                 ppp->stat.vjin, ppp->stat.vjout, ppp->stat.vjfail);
1887 }
1888
1889 /*
1890  *  link quality management
1891  */
1892 static void
1893 getlqm(PPP *ppp, Block *b)
1894 {
1895         Qualpkt *p;
1896
1897         p = (Qualpkt*)b->rptr;
1898         if(BLEN(b) == sizeof(Qualpkt)){
1899                 ppp->in.reports++;
1900                 ppp->pout.reports = nhgetl(p->peeroutreports);
1901                 ppp->pout.packets = nhgetl(p->peeroutpackets);
1902                 ppp->pout.uchars = nhgetl(p->peeroutuchars);
1903                 ppp->pin.reports = nhgetl(p->peerinreports);
1904                 ppp->pin.packets = nhgetl(p->peerinpackets);
1905                 ppp->pin.discards = nhgetl(p->peerindiscards);
1906                 ppp->pin.errors = nhgetl(p->peerinerrors);
1907                 ppp->pin.uchars = nhgetl(p->peerinuchars);
1908
1909                 /* save our numbers at time of reception */
1910                 memmove(&ppp->sin, &ppp->in, sizeof(Qualstats));
1911
1912         }
1913         freeb(b);
1914         if(ppp->period == 0)
1915                 putlqm(ppp);
1916
1917 }
1918
1919 static void
1920 putlqm(PPP *ppp)
1921 {
1922         Qualpkt *p;
1923         Block *b;
1924
1925         b = allocb(sizeof(Qualpkt));
1926         b->wptr += sizeof(Qualpkt);
1927         p = (Qualpkt*)b->rptr;
1928         hnputl(p->magic, 0);
1929
1930         /* heresay (what he last told us) */
1931         hnputl(p->lastoutreports, ppp->pout.reports);
1932         hnputl(p->lastoutpackets, ppp->pout.packets);
1933         hnputl(p->lastoutuchars, ppp->pout.uchars);
1934
1935         /* our numbers at time of last reception */
1936         hnputl(p->peerinreports, ppp->sin.reports);
1937         hnputl(p->peerinpackets, ppp->sin.packets);
1938         hnputl(p->peerindiscards, ppp->sin.discards);
1939         hnputl(p->peerinerrors, ppp->sin.errors);
1940         hnputl(p->peerinuchars, ppp->sin.uchars);
1941
1942         /* our numbers now */
1943         hnputl(p->peeroutreports, ppp->out.reports+1);
1944         hnputl(p->peeroutpackets, ppp->out.packets+1);
1945         hnputl(p->peeroutuchars, ppp->out.uchars+53/*hack*/);
1946
1947         putframe(ppp, Plqm, b);
1948         freeb(b);
1949         ppp->out.reports++;
1950 }
1951
1952 /*
1953  * init challenge response dialog
1954  */
1955 static void
1956 chapinit(PPP *ppp)
1957 {
1958         Block *b;
1959         Lcpmsg *m;
1960         Chap *c;
1961         int len;
1962         char *aproto;
1963
1964         getauth(ppp);
1965
1966         c = ppp->chap;
1967         c->id++;
1968
1969         switch(c->proto){
1970         default:
1971                 abort();
1972         case APmd5:
1973                 aproto = "chap";
1974                 break;
1975         case APmschap:
1976                 aproto = "mschap";
1977                 break;
1978         }
1979         if((c->cs = auth_challenge("proto=%q role=server", aproto)) == nil)
1980                 sysfatal("auth_challenge: %r");
1981         syslog(0, LOG, ": remote=%I: sending %d byte challenge", ppp->remote, c->cs->nchal);
1982         len = 4 + 1 + c->cs->nchal + strlen(ppp->chapname);
1983         b = alloclcp(Cchallenge, c->id, len, &m);
1984
1985         *b->wptr++ = c->cs->nchal;
1986         memmove(b->wptr, c->cs->chal, c->cs->nchal);
1987         b->wptr += c->cs->nchal;
1988         memmove(b->wptr, ppp->chapname, strlen(ppp->chapname));
1989         b->wptr += strlen(ppp->chapname);
1990         hnputs(m->len, len);
1991         putframe(ppp, Pchap, b);
1992         freeb(b);
1993
1994         c->state = Cchalsent;
1995 }
1996
1997 /*
1998  * BUG factotum should do this
1999  */
2000 enum {
2001         MShashlen = 16,
2002         MSresplen = 24,
2003         MSchallen = 8,
2004 };
2005
2006 void
2007 desencrypt(uchar data[8], uchar key[7])
2008 {
2009         ulong ekey[32];
2010
2011         key_setup(key, ekey);
2012         block_cipher(ekey, data, 0);
2013 }
2014
2015 void
2016 nthash(uchar hash[MShashlen], char *passwd)
2017 {
2018         uchar buf[512];
2019         int i;
2020         
2021         for(i=0; *passwd && i<sizeof(buf); passwd++) {
2022                 buf[i++] = *passwd;
2023                 buf[i++] = 0;
2024         }
2025         memset(hash, 0, 16);
2026         md4(buf, i, hash, 0);
2027 }
2028
2029 void
2030 mschalresp(uchar resp[MSresplen], uchar hash[MShashlen], uchar chal[MSchallen])
2031 {
2032         int i;
2033         uchar buf[21];
2034         
2035         memset(buf, 0, sizeof(buf));
2036         memcpy(buf, hash, MShashlen);
2037
2038         for(i=0; i<3; i++) {
2039                 memmove(resp+i*MSchallen, chal, MSchallen);
2040                 desencrypt(resp+i*MSchallen, buf+i*7);
2041         }
2042 }
2043
2044 /*
2045  *  challenge response dialog
2046  */
2047 extern  int     _asrdresp(int, uchar*, int);
2048
2049 static void
2050 getchap(PPP *ppp, Block *b)
2051 {
2052         AuthInfo *ai;
2053         Lcpmsg *m;
2054         int len, vlen, i, id, n, nresp;
2055         char md5buf[512], code;
2056         Chap *c;
2057         Chapreply cr;
2058         MSchapreply mscr;
2059         char uid[PATH];
2060         uchar digest[16], *p, *resp, sdigest[SHA1dlen];
2061         uchar mshash[MShashlen], mshash2[MShashlen];
2062         DigestState *s;
2063         uchar msresp[2*MSresplen+1];
2064
2065         m = (Lcpmsg*)b->rptr;
2066         len = nhgets(m->len);
2067         if(BLEN(b) < len){
2068                 syslog(0, LOG, "short chap message");
2069                 freeb(b);
2070                 return;
2071         }
2072
2073         qlock(ppp);
2074
2075         switch(m->code){
2076         case Cchallenge:
2077                 getauth(ppp);
2078
2079                 vlen = m->data[0];
2080                 if(vlen > len - 5) {
2081                         netlog("PPP: chap: bad challenge len\n");
2082                         break;
2083                 }
2084
2085                 id = m->id;
2086                 switch(ppp->chap->proto){
2087                 default:
2088                         abort();
2089                 case APmd5:
2090                         md5buf[0] = m->id;
2091                         strcpy(md5buf+1, ppp->secret);
2092                         n = strlen(ppp->secret) + 1;
2093                         memmove(md5buf+n, m->data+1, vlen);
2094                         n += vlen;
2095                         md5((uchar*)md5buf, n, digest, nil);
2096                         resp = digest;
2097                         nresp = 16;
2098                         break;
2099                 case APmschap:
2100                         nthash(mshash, ppp->secret);
2101                         memset(msresp, 0, sizeof msresp);
2102                         mschalresp(msresp+MSresplen, mshash, m->data+1);
2103                         resp = msresp;
2104                         nresp = sizeof msresp;
2105                         nthash(mshash, ppp->secret);
2106                         md4(mshash, 16, mshash2, 0);
2107                         s = sha1(mshash2, 16, 0, 0);
2108                         sha1(mshash2, 16, 0, s);
2109                         sha1(m->data+1, 8, sdigest, s);
2110                         memmove(ppp->key, sdigest, 16);
2111                         break;
2112                 }
2113                 len = 4 + 1 + nresp + strlen(ppp->chapname);
2114                 freeb(b);
2115                 b = alloclcp(Cresponse, id, len, &m);
2116                 *b->wptr++ = nresp;
2117                 memmove(b->wptr, resp, nresp);
2118                 b->wptr += nresp;
2119                 memmove(b->wptr, ppp->chapname, strlen(ppp->chapname));
2120                 b->wptr += strlen(ppp->chapname);
2121                 hnputs(m->len, len);
2122                 netlog("PPP: sending response len %d\n", len);
2123                 putframe(ppp, Pchap, b);
2124                 break;
2125         case Cresponse:
2126                 c = ppp->chap;
2127                 vlen = m->data[0];
2128                 if(m->id != c->id) {
2129                         netlog("PPP: chap: bad response id\n");
2130                         break;
2131                 }
2132                 switch(c->proto) {
2133                 default:
2134                         sysfatal("unknown chap protocol: %d", c->proto);
2135                 case APmd5:
2136                         if(vlen > len - 5 || vlen != 16) {
2137                                 netlog("PPP: chap: bad response len\n");
2138                                 break;
2139                         }
2140
2141                         cr.id = m->id;
2142                         memmove(cr.resp, m->data+1, 16);
2143                         memset(uid, 0, sizeof(uid));
2144                         n = len-5-vlen;
2145                         if(n >= PATH)
2146                                 n = PATH-1;
2147                         memmove(uid, m->data+1+vlen, n);
2148                         c->cs->user = uid;
2149                         c->cs->resp = &cr;
2150                         c->cs->nresp = sizeof cr;
2151                         break;
2152                 case APmschap:
2153                         if(vlen > len - 5 || vlen != 49) {
2154                                 netlog("PPP: chap: bad response len\n");
2155                                 break;
2156                         }
2157                         memset(&mscr, 0, sizeof(mscr));
2158                         memmove(mscr.LMresp, m->data+1, 24);
2159                         memmove(mscr.NTresp, m->data+24+1, 24);
2160                         n = len-5-vlen;
2161                         p = m->data+1+vlen;
2162                         /* remove domain name */
2163                         for(i=0; i<n; i++) {
2164                                 if(p[i] == '\\') {
2165                                         p += i+1;
2166                                         n -= i+1;
2167                                         break;
2168                                 }
2169                         }
2170                         if(n >= PATH)
2171                                 n = PATH-1;
2172                         memset(uid, 0, sizeof(uid));
2173                         memmove(uid, p, n);
2174                         c->cs->user = uid;
2175                         c->cs->resp = &mscr;
2176                         c->cs->nresp = sizeof mscr;
2177                         break;
2178                 } 
2179
2180                 syslog(0, LOG, ": remote=%I vlen %d proto %d response user %s nresp %d", ppp->remote, vlen, c->proto, c->cs->user, c->cs->nresp);
2181                 if((ai = auth_response(c->cs)) == nil || auth_chuid(ai, nil) < 0){
2182                         c->state = Cunauth;
2183                         code = Cfailure;
2184                         syslog(0, LOG, ": remote=%I: auth failed: %r, uid=%s", ppp->remote, uid);
2185                 }else{
2186                         c->state = Cauthok;
2187                         code = Csuccess;
2188                         syslog(0, LOG, ": remote=%I: auth ok: uid=%s nsecret=%d", ppp->remote, uid, ai->nsecret);
2189                         if(c->proto == APmschap){
2190                                 if(ai->nsecret != sizeof(ppp->key))
2191                                         sysfatal("could not get the encryption key");
2192                                 memmove(ppp->key, ai->secret, sizeof(ppp->key));
2193                         }
2194                 }
2195                 auth_freeAI(ai);
2196                 auth_freechal(c->cs);
2197                 c->cs = nil;
2198                 freeb(b);
2199
2200                 /* send reply */
2201                 len = 4;
2202                 b = alloclcp(code, c->id, len, &m);
2203                 hnputs(m->len, len);
2204                 putframe(ppp, Pchap, b);
2205
2206                 if(c->state == Cauthok) {
2207                         setphase(ppp, Pnet);
2208                 } else {
2209                         /* restart chapp negotiation */
2210                         chapinit(ppp);
2211                 }
2212                 
2213                 break;
2214         case Csuccess:
2215                 netlog("ppp: chap succeeded\n");
2216                 break;
2217         case Cfailure:
2218                 netlog("ppp: chap failed\n");
2219                 break;
2220         default:
2221                 syslog(0, LOG, "chap code %d?", m->code);
2222                 break;
2223         }
2224         qunlock(ppp);
2225         freeb(b);
2226 }
2227
2228 static void
2229 putpaprequest(PPP *ppp)
2230 {
2231         Block *b;
2232         Lcpmsg *m;
2233         Chap *c;
2234         int len, nlen, slen;
2235
2236         getauth(ppp);
2237
2238         c = ppp->chap;
2239         c->id++;
2240         netlog("PPP: pap: send authreq %d %s %s\n", c->id, ppp->chapname, "****");
2241
2242         nlen = strlen(ppp->chapname);
2243         slen = strlen(ppp->secret);
2244         len = 4 + 1 + nlen + 1 + slen;
2245         b = alloclcp(Pauthreq, c->id, len, &m);
2246
2247         *b->wptr++ = nlen;
2248         memmove(b->wptr, ppp->chapname, nlen);
2249         b->wptr += nlen;
2250         *b->wptr++ = slen;
2251         memmove(b->wptr, ppp->secret, slen);
2252         b->wptr += slen;
2253         hnputs(m->len, len);
2254
2255         putframe(ppp, Ppasswd, b);
2256         freeb(b);
2257 }
2258
2259 static void
2260 papinit(PPP *ppp)
2261 {
2262         ppp->chap->id = 0;
2263         putpaprequest(ppp);
2264 }
2265
2266 static void
2267 getpap(PPP *ppp, Block *b)
2268 {
2269         Lcpmsg *m;
2270         int len;
2271
2272         m = (Lcpmsg*)b->rptr;
2273         len = 4;
2274         if(BLEN(b) < 4 || BLEN(b) < (len = nhgets(m->len))){
2275                 syslog(0, LOG, "short pap message (%ld < %d)", BLEN(b), len);
2276                 freeb(b);
2277                 return;
2278         }
2279         if(len < sizeof(Lcpmsg))
2280                 m->data[0] = 0;
2281
2282         qlock(ppp);
2283         switch(m->code){
2284         case Pauthreq:
2285                 netlog("PPP: pap auth request, not supported\n");
2286                 break;
2287         case Pauthack:
2288                 if(ppp->phase == Pauth
2289                 && ppp->chap->proto == APpasswd
2290                 && m->id <= ppp-> chap->id){
2291                         netlog("PPP: pap succeeded\n");
2292                         setphase(ppp, Pnet);
2293                 }
2294                 break;
2295         case Pauthnak:
2296                 if(ppp->phase == Pauth
2297                 && ppp->chap->proto == APpasswd
2298                 && m->id <= ppp-> chap->id){
2299                         netlog("PPP: pap failed (%d:%.*s)\n",
2300                                 m->data[0], m->data[0], (char*)m->data+1);
2301                         terminate(ppp, 0);
2302                 }
2303                 break;
2304         default:
2305                 netlog("PPP: unknown pap messsage %d\n", m->code);
2306         }
2307         qunlock(ppp);
2308         freeb(b);
2309 }
2310
2311 static void
2312 printopts(Pstate *p, Block *b, int send)
2313 {
2314         Lcpmsg *m;      
2315         Lcpopt *o;
2316         int proto, x, period;
2317         uchar *cp;
2318         char *code, *dir;
2319
2320         m = (Lcpmsg*)b->rptr;
2321         switch(m->code) {
2322         default: code = "<unknown>"; break;
2323         case Lconfreq: code = "confrequest"; break;
2324         case Lconfack: code = "confack"; break;
2325         case Lconfnak: code = "confnak"; break;
2326         case Lconfrej: code = "confreject"; break;
2327         }
2328
2329         if(send)
2330                 dir = "send";
2331         else
2332                 dir = "recv";
2333
2334         netlog("ppp: %s %s: id=%d\n", dir, code, m->id);
2335
2336         for(cp = m->data; cp < b->wptr; cp += o->len){
2337                 o = (Lcpopt*)cp;
2338                 if(cp + o->len > b->wptr){
2339                         netlog("\tbad option length %ux\n", o->type);
2340                         return;
2341                 }
2342
2343                 switch(p->proto){
2344                 case Plcp:
2345                         switch(o->type){
2346                         default:
2347                                 netlog("\tunknown %d len=%d\n", o->type, o->len);
2348                                 break;
2349                         case Omtu:
2350                                 netlog("\tmtu = %d\n", nhgets(o->data));
2351                                 break;
2352                         case Octlmap:
2353                                 netlog("\tctlmap = %ux\n", nhgetl(o->data));
2354                                 break;
2355                         case Oauth:
2356                                 netlog("\tauth = %ux", nhgetl(o->data));
2357                                 proto = nhgets(o->data);
2358                                 switch(proto) {
2359                                 default:
2360                                         netlog("unknown auth proto %d\n", proto);
2361                                         break;
2362                                 case Ppasswd:
2363                                         netlog("password\n");
2364                                         break;
2365                                 case Pchap:
2366                                         netlog("chap %ux\n", o->data[2]);
2367                                         break;
2368                                 }
2369                                 break;
2370                         case Oquality:
2371                                 proto = nhgets(o->data);
2372                                 switch(proto) {
2373                                 default:
2374                                         netlog("\tunknown quality proto %d\n", proto);
2375                                         break;
2376                                 case Plqm:
2377                                         x = nhgetl(o->data+2)*10;
2378                                         period = (x+Period-1)/Period;
2379                                         netlog("\tlqm period = %d\n", period);
2380                                         break;
2381                                 }
2382                         case Omagic:
2383                                 netlog("\tmagic = %ux\n", nhgetl(o->data));
2384                                 break;
2385                         case Opc:
2386                                 netlog("\tprotocol compress\n");
2387                                 break;
2388                         case Oac:
2389                                 netlog("\taddr compress\n");
2390                                 break;
2391                         }
2392                         break;
2393                 case Pccp:
2394                         switch(o->type){
2395                         default:
2396                                 netlog("\tunknown %d len=%d\n", o->type, o->len);
2397                                 break;
2398                         case Ocoui:     
2399                                 netlog("\tOUI\n");
2400                                 break;
2401                         case Ocstac:
2402                                 netlog("\tstac LZS\n");
2403                                 break;
2404                         case Ocmppc:    
2405                                 netlog("\tMicrosoft PPC len=%d %ux\n", o->len, nhgetl(o->data));
2406                                 break;
2407                         case Octhwack:  
2408                                 netlog("\tThwack\n");
2409                                 break;
2410                         }
2411                         break;
2412                 case Pecp:
2413                         switch(o->type){
2414                         default:
2415                                 netlog("\tunknown %d len=%d\n", o->type, o->len);
2416                                 break;
2417                         case Oeoui:     
2418                                 netlog("\tOUI\n");
2419                                 break;
2420                         case Oedese:
2421                                 netlog("\tDES\n");
2422                                 break;
2423                         }
2424                         break;
2425                 case Pipcp:
2426                         switch(o->type){
2427                         default:
2428                                 netlog("\tunknown %d len=%d\n", o->type, o->len);
2429                                 break;
2430                         case Oipaddrs:  
2431                                 netlog("\tip addrs - deprecated\n");
2432                                 break;
2433                         case Oipcompress:
2434                                 netlog("\tip compress\n");
2435                                 break;
2436                         case Oipaddr:   
2437                                 netlog("\tip addr %V\n", o->data);
2438                                 break;
2439                         case Oipdns:    
2440                                 netlog("\tdns addr %V\n", o->data);
2441                                 break;
2442                         case Oipwins:   
2443                                 netlog("\twins addr %V\n", o->data);
2444                                 break;
2445                         case Oipdns2:   
2446                                 netlog("\tdns2 addr %V\n", o->data);
2447                                 break;
2448                         case Oipwins2:  
2449                                 netlog("\twins2 addr %V\n", o->data);
2450                                 break;
2451                         }
2452                         break;
2453                 }
2454         }
2455 }
2456
2457 static void
2458 sendtermreq(PPP *ppp, Pstate *p)
2459 {
2460         Block *b;
2461         Lcpmsg *m;
2462
2463         p->termid = ++(p->id);
2464         b = alloclcp(Ltermreq, p->termid, 4, &m);
2465         hnputs(m->len, 4);
2466         putframe(ppp, p->proto, b);
2467         freeb(b);
2468         newstate(ppp, p, Sclosing);
2469 }
2470
2471 static void
2472 sendechoreq(PPP *ppp, Pstate *p)
2473 {
2474         Block *b;
2475         Lcpmsg *m;
2476
2477         p->termid = ++(p->id);
2478         b = alloclcp(Lechoreq, p->id, 4, &m);
2479         hnputs(m->len, 4);
2480         putframe(ppp, p->proto, b);
2481         freeb(b);
2482 }
2483
2484 enum
2485 {
2486         CtrlD   = 0x4,
2487         CtrlE   = 0x5,
2488         CtrlO   = 0xf,
2489         Cr      = 13,
2490         View    = 0x80,
2491 };
2492
2493 int conndone;
2494
2495 static void
2496 xfer(int fd)
2497 {
2498         int i, n;
2499         uchar xbuf[128];
2500
2501         for(;;) {
2502                 n = read(fd, xbuf, sizeof(xbuf));
2503                 if(n < 0)
2504                         break;
2505                 if(conndone)
2506                         break;
2507                 for(i = 0; i < n; i++)
2508                         if(xbuf[i] == Cr)
2509                                 xbuf[i] = ' ';
2510                 write(1, xbuf, n);
2511         }
2512         close(fd);
2513 }
2514
2515 static int
2516 readcr(int fd, char *buf, int nbuf)
2517 {
2518         char c;
2519         int n, tot;
2520
2521         tot = 0;
2522         while((n=read(fd, &c, 1)) == 1){
2523                 if(c == '\n'){
2524                         buf[tot] = 0;
2525                         return tot;
2526                 }
2527                 buf[tot++] = c;
2528                 if(tot == nbuf)
2529                         sysfatal("line too long in readcr");
2530         }
2531         return n;
2532 }
2533
2534 static void
2535 connect(int fd, int cfd)
2536 {
2537         int n, ctl;
2538         char xbuf[128];
2539
2540         if (chatfile) {
2541                 int chatfd, lineno, nb;
2542                 char *buf, *p, *s, response[128];
2543                 Dir *dir;
2544
2545                 if ((chatfd = open(chatfile, OREAD)) < 0)
2546                         sysfatal("cannot open %s: %r", chatfile);
2547
2548                 if ((dir = dirfstat(chatfd)) == nil)
2549                         sysfatal("cannot fstat %s: %r",chatfile);
2550
2551                 buf = (char *)malloc(dir->length + 1);
2552                 assert(buf);
2553
2554                 if ((nb = read(chatfd, buf, dir->length)) < 0)
2555                         sysfatal("cannot read chatfile %s: %r", chatfile);
2556                 assert(nb == dir->length);
2557                 buf[dir->length] = '\0';
2558                 free(dir);
2559                 close(chatfd);
2560
2561                 p = buf;
2562                 lineno = 0;
2563                 for(;;) {
2564                         char *_args[3];
2565
2566                         if ((s = strchr(p, '\n')) == nil)
2567                                 break;
2568                         *s++ = '\0';
2569                 
2570                         lineno++;
2571
2572                         if (*p == '#') {
2573                                 p = s; 
2574                                 continue;
2575                         }
2576
2577                         if (tokenize(p, _args, 3) != 2)
2578                                 sysfatal("invalid line %d (line expected: 'send' 'expect')", 
2579                                                 lineno);
2580
2581                         if (debug)
2582                                 print("sending %s, expecting %s\n", _args[0], _args[1]);
2583
2584                         if(strlen(_args[0])){
2585                                 nb = fprint(fd, "%s\r", _args[0]);
2586                                 assert(nb > 0);
2587                         }
2588
2589                         if (strlen(_args[1]) > 0) {
2590                                 if ((nb = readcr(fd, response, sizeof response-1)) < 0)
2591                                         sysfatal("cannot read response from: %r");
2592
2593                                 if (debug)
2594                                         print("response %s\n", response);
2595
2596                                 if (nb == 0)
2597                                         sysfatal("eof on input?");
2598
2599                                 if (cistrstr(response, _args[1]) == nil)
2600                                         sysfatal("expected %s, got %s", _args[1], response);
2601                         }
2602                         p = s;
2603                 }
2604                 free(buf);
2605                 return;
2606         }
2607
2608         print("Connect to file system now, type ctrl-d when done.\n");
2609         print("...(Use the view or down arrow key to send a break)\n");
2610         print("...(Use ctrl-e to set even parity or ctrl-o for odd)\n");
2611
2612         ctl = open("/dev/consctl", OWRITE);
2613         if(ctl < 0)
2614                 sysfatal("opening consctl");
2615         fprint(ctl, "rawon");
2616
2617         fd = dup(fd, -1);
2618         conndone = 0;
2619         switch(rfork(RFPROC|RFMEM|RFNOWAIT)){
2620         case -1:
2621                 sysfatal("forking xfer");
2622         case 0:
2623                 xfer(fd);
2624                 _exits(nil);
2625         }
2626
2627         for(;;){
2628                 read(0, xbuf, 1);
2629                 switch(xbuf[0]&0xff) {
2630                 case CtrlD:     /* done */
2631                         conndone = 1;
2632                         close(ctl);
2633                         print("\n");
2634                         return;
2635                 case CtrlE:     /* set even parity */
2636                         fprint(cfd, "pe");
2637                         break;
2638                 case CtrlO:     /* set odd parity */
2639                         fprint(cfd, "po");
2640                         break;
2641                 case View:      /* send a break */
2642                         fprint(cfd, "k500");
2643                         break;
2644                 default:
2645                         n = write(fd, xbuf, 1);
2646                         if(n < 0) {
2647                                 errstr(xbuf, sizeof(xbuf));
2648                                 conndone = 1;
2649                                 close(ctl);
2650                                 print("[remote write error (%s)]\n", xbuf);
2651                                 return;
2652                         }
2653                 }
2654         }
2655 }
2656
2657 int interactive;
2658
2659 void
2660 usage(void)
2661 {
2662         fprint(2, "usage: ppp [-CPSacdfu] [-b baud] [-k keyspec] [-m mtu] "
2663                 "[-M chatfile] [-p dev] [-x netmntpt] [-t modemcmd] "
2664                 "[local-addr [remote-addr]]\n");
2665         exits("usage");
2666 }
2667
2668 void
2669 main(int argc, char **argv)
2670 {
2671         int mtu, baud, framing, user, mediain, mediaout, cfd;
2672         Ipaddr ipaddr, remip;
2673         char *dev, *modemcmd;
2674         char net[128];
2675         PPP *ppp;
2676         char buf[128];
2677
2678         rfork(RFREND|RFNOTEG|RFNAMEG);
2679
2680         fmtinstall('I', eipfmt);
2681         fmtinstall('V', eipfmt);
2682         fmtinstall('E', eipfmt);
2683
2684         dev = nil;
2685
2686         invalidate(ipaddr);
2687         invalidate(remip);
2688
2689         mtu = Defmtu;
2690         baud = 0;
2691         framing = 0;
2692         setnetmtpt(net, sizeof(net), nil);
2693         user = 0;
2694         modemcmd = nil;
2695
2696         ARGBEGIN{
2697         case 'a':
2698                 noauth = 1;
2699                 break;
2700         case 'b':
2701                 baud = atoi(EARGF(usage()));
2702                 if(baud < 0)
2703                         baud = 0;
2704                 break;
2705         case 'c':
2706                 nocompress = 1;
2707                 break;
2708         case 'C':
2709                 noipcompress = 1;
2710                 break;
2711         case 'd':
2712                 debug++;
2713                 break;
2714         case 'f':
2715                 framing = 1;
2716                 break;
2717         case 'F':
2718                 pppframing = 0;
2719                 break;
2720         case 'k':
2721                 keyspec = EARGF(usage());
2722                 break;
2723         case 'm':
2724                 mtu = atoi(EARGF(usage()));
2725                 if(mtu < Minmtu)
2726                         mtu = Minmtu;
2727                 if(mtu > Maxmtu)
2728                         mtu = Maxmtu;
2729                 break;
2730         case 'M':
2731                 chatfile = EARGF(usage());
2732                 break;
2733         case 'p':
2734                 dev = EARGF(usage());
2735                 break;
2736         case 'P':
2737                 primary = 1;
2738                 break;
2739         case 'S':
2740                 server = 1;
2741                 break;
2742         case 't':
2743                 modemcmd = EARGF(usage());
2744                 break;
2745         case 'u':
2746                 user = 1;
2747                 break;
2748         case 'x':
2749                 setnetmtpt(net, sizeof net, EARGF(usage()));
2750                 break;
2751         default:
2752                 fprint(2, "unknown option %c\n", ARGC());
2753                 usage();
2754         }ARGEND;
2755
2756         switch(argc){
2757         case 2:
2758                 if (parseip(remip, argv[1]) == -1)
2759                         sysfatal("bad remote ip %s", argv[1]);
2760         case 1:
2761                 if (parseip(ipaddr, argv[0]) == -1)
2762                         sysfatal("bad ip %s", argv[0]);
2763         case 0:
2764                 break;
2765         default:
2766                 usage();
2767         }
2768
2769         nip = nipifcs(net);
2770         if(nip == 0 && !server)
2771                 primary = 1;
2772
2773         if(dev != nil){
2774                 mediain = open(dev, ORDWR);
2775                 if(mediain < 0){
2776                         if(strchr(dev, '!')){
2777                                 if((mediain = dial(dev, 0, 0, &cfd)) == -1){
2778                                         fprint(2, "ppp: couldn't dial %s: %r\n", dev);
2779                                         exits(dev);
2780                                 }
2781                         } else {
2782                                 fprint(2, "ppp: couldn't open %s\n", dev);
2783                                 exits(dev);
2784                         }
2785                 } else {
2786                         snprint(buf, sizeof buf, "%sctl", dev);
2787                         cfd = open(buf, ORDWR);
2788                 }
2789                 if(cfd > 0){
2790                         if(baud)
2791                                 fprint(cfd, "b%d", baud);
2792                         fprint(cfd, "m1");      /* cts/rts flow control (and fifo's) on */
2793                         fprint(cfd, "q64000");  /* increase q size to 64k */
2794                         fprint(cfd, "n1");      /* nonblocking writes on */
2795                         fprint(cfd, "r1");      /* rts on */
2796                         fprint(cfd, "d1");      /* dtr on */
2797                         fprint(cfd, "c1");      /* dcdhup on */
2798                         if(user || chatfile)
2799                                 connect(mediain, cfd);
2800                         close(cfd);
2801                 } else {
2802                         if(user || chatfile)
2803                                 connect(mediain, -1);
2804                 }
2805                 mediaout = mediain;
2806         } else {
2807                 mediain = open("/fd/0", OREAD);
2808                 if(mediain < 0){
2809                         fprint(2, "ppp: couldn't open /fd/0\n");
2810                         exits("/fd/0");
2811                 }
2812                 mediaout = open("/fd/1", OWRITE);
2813                 if(mediaout < 0){
2814                         fprint(2, "ppp: couldn't open /fd/0\n");
2815                         exits("/fd/1");
2816                 }
2817         }
2818
2819         if(modemcmd != nil && mediaout >= 0)
2820                 fprint(mediaout, "%s\r", modemcmd);
2821
2822         ppp = mallocz(sizeof(*ppp), 1);
2823         pppopen(ppp, mediain, mediaout, net, ipaddr, remip, mtu, framing);
2824
2825         /* wait until ip is configured */
2826         rendezvous((void*)Rmagic, 0);
2827
2828         if(primary){
2829                 /* create a /net/ndb entry */
2830                 putndb(ppp, net);
2831         }
2832
2833         exits(0);
2834 }
2835
2836 void
2837 netlog(char *fmt, ...)
2838 {
2839         va_list arg;
2840         char *m;
2841         static long start;
2842         long now;
2843
2844         if(debug == 0)
2845                 return;
2846
2847         now = time(0);
2848         if(start == 0)
2849                 start = now;
2850
2851         va_start(arg, fmt);
2852         m = vsmprint(fmt, arg);
2853         fprint(2, "%ld %s", now-start, m);
2854         free(m);
2855         va_end(arg);
2856 }
2857
2858 /*
2859  *  return non-zero if this is a valid v4 address
2860  */
2861 static int
2862 validv4(Ipaddr addr)
2863 {
2864         return memcmp(addr, v4prefix, IPv4off) == 0 && memcmp(addr, v4prefix, IPaddrlen) != 0;
2865 }
2866
2867 static void
2868 invalidate(Ipaddr addr)
2869 {
2870         ipmove(addr, IPnoaddr);
2871 }
2872
2873 /*
2874  *  return number of networks
2875  */
2876 static int
2877 nipifcs(char *net)
2878 {
2879         static Ipifc *ifc;
2880         Ipifc *nifc;
2881         Iplifc *lifc;
2882         int n;
2883
2884         n = 0;
2885         ifc = readipifc(net, ifc, -1);
2886         for(nifc = ifc; nifc != nil; nifc = nifc->next)
2887                 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next)
2888                         n++;
2889         return n;
2890 }
2891
2892 /*
2893  *   make an ndb entry and put it into /net/ndb for the servers to see
2894  */
2895 static void
2896 putndb(PPP *ppp, char *net)
2897 {
2898         char buf[1024];
2899         char file[64];
2900         char *p, *e;
2901         int fd;
2902
2903         e = buf + sizeof(buf);
2904         p = buf;
2905         p = seprint(p, e, "ip=%I ipmask=255.255.255.255 ipgw=%I\n", ppp->local,
2906                         ppp->remote);
2907         if(validv4(ppp->dns[0]))
2908                 p = seprint(p, e, "\tdns=%I\n", ppp->dns[0]);
2909         if(validv4(ppp->dns[1]))
2910                 p = seprint(p, e, "\tdns=%I\n", ppp->dns[1]);
2911         if(validv4(ppp->wins[0]))
2912                 p = seprint(p, e, "\twins=%I\n", ppp->wins[0]);
2913         if(validv4(ppp->wins[1]))
2914                 p = seprint(p, e, "\twins=%I\n", ppp->wins[1]);
2915         seprint(file, file+sizeof file, "%s/ndb", net);
2916         fd = open(file, OWRITE);
2917         if(fd < 0)
2918                 return;
2919         write(fd, buf, p-buf);
2920         close(fd);
2921         seprint(file, file+sizeof file, "%s/cs", net);
2922         fd = open(file, OWRITE);
2923         write(fd, "refresh", 7);
2924         close(fd);
2925         seprint(file, file+sizeof file, "%s/dns", net);
2926         fd = open(file, OWRITE);
2927         write(fd, "refresh", 7);
2928         close(fd);
2929 }
2930
2931 static void
2932 getauth(PPP *ppp)
2933 {
2934         UserPasswd *up;
2935
2936         if(*ppp->chapname)
2937                 return;
2938
2939         up = auth_getuserpasswd(auth_getkey,"proto=pass service=ppp %s", keyspec);
2940         if(up != nil){
2941                 strcpy(ppp->chapname, up->user);
2942                 strcpy(ppp->secret, up->passwd);
2943         }               
2944 }