Deleted Added
full compact
1/*
2 * PPP Link Control Protocol (LCP) Module
3 *
4 * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
5 *
6 * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
7 *
8 * Redistribution and use in source and binary forms are permitted
9 * provided that the above copyright notice and this paragraph are
10 * duplicated in all such forms and that any documentation,
11 * advertising materials, and other materials related to such
12 * distribution and use acknowledge that the software was developed
13 * by the Internet Initiative Japan, Inc. The name of the
14 * IIJ may not be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19 *
20 * $Id: lcp.c,v 1.39 1997/10/15 01:01:17 brian Exp $
20 * $Id: lcp.c,v 1.40 1997/10/26 01:02:57 brian Exp $
21 *
22 * TODO:
23 * o Validate magic number received from peer.
24 * o Limit data field length by MRU
25 */
26#include <sys/param.h>
27#include <netinet/in.h>
28#include <arpa/inet.h>
29
30#include <signal.h>
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34#include <sys/time.h>
35#include <termios.h>
36#include <unistd.h>
37
38#include "mbuf.h"
39#include "log.h"
40#include "defs.h"
41#include "timer.h"
42#include "fsm.h"
43#include "lcp.h"
44#include "ipcp.h"
45#include "lcpproto.h"
46#include "os.h"
47#include "hdlc.h"
48#include "ccp.h"
49#include "lqr.h"
50#include "phase.h"
51#include "loadalias.h"
52#include "command.h"
53#include "vars.h"
54#include "auth.h"
55#include "pap.h"
56#include "chap.h"
57#include "async.h"
58#include "main.h"
59#include "ip.h"
60#include "modem.h"
61
62struct lcpstate LcpInfo;
63
64static void LcpSendConfigReq(struct fsm *);
65static void LcpSendTerminateReq(struct fsm *);
66static void LcpSendTerminateAck(struct fsm *);
67static void LcpDecodeConfig(u_char *, int, int);
68static void LcpInitRestartCounter(struct fsm *);
69static void LcpLayerUp(struct fsm *);
70static void LcpLayerDown(struct fsm *);
71static void LcpLayerStart(struct fsm *);
72static void LcpLayerFinish(struct fsm *);
73
74#define REJECTED(p, x) (p->his_reject & (1<<x))
75
76static char *cftypes[] = {
77 "???", "MRU", "ACCMAP", "AUTHPROTO", "QUALPROTO", "MAGICNUM",
78 "RESERVED", "PROTOCOMP", "ACFCOMP", "FCSALT", "SDP",
79};
80
81struct fsm LcpFsm = {
82 "LCP", /* Name of protocol */
83 PROTO_LCP, /* Protocol Number */
84 LCP_MAXCODE,
85 OPEN_ACTIVE,
86 ST_INITIAL, /* State of machine */
87 0, 0, 0,
88 0,
89 {0, 0, 0, NULL, NULL, NULL},
90 {0, 0, 0, NULL, NULL, NULL},
91 LogLCP,
92
93 LcpLayerUp,
94 LcpLayerDown,
95 LcpLayerStart,
96 LcpLayerFinish,
97 LcpInitRestartCounter,
98 LcpSendConfigReq,
99 LcpSendTerminateReq,
100 LcpSendTerminateAck,
101 LcpDecodeConfig,
102};
103
104static struct pppTimer LcpReportTimer;
105static int LcpFailedMagic;
106
107static void
108LcpReportTime()
109{
110 if (LogIsKept(LogDEBUG)) {
111 time_t t;
112
113 time(&t);
114 LogPrintf(LogDEBUG, "LcpReportTime: %s\n", ctime(&t));
115 }
116 StopTimer(&LcpReportTimer);
117 LcpReportTimer.state = TIMER_STOPPED;
118 StartTimer(&LcpReportTimer);
119 HdlcErrorCheck();
120}
121
122int
123ReportLcpStatus()
124{
125 struct lcpstate *lcp = &LcpInfo;
126 struct fsm *fp = &LcpFsm;
127
128 if (!VarTerm)
129 return 1;
130
131 fprintf(VarTerm, "%s [%s]\n", fp->name, StateNames[fp->state]);
132 fprintf(VarTerm,
133 " his side: MRU %ld, ACCMAP %08lx, PROTOCOMP %d, ACFCOMP %d, MAGIC %08lx,\n"
134 " REJECT %04lx\n",
135 lcp->his_mru, lcp->his_accmap, lcp->his_protocomp, lcp->his_acfcomp,
136 lcp->his_magic, lcp->his_reject);
137 fprintf(VarTerm,
138 " my side: MRU %ld, ACCMAP %08lx, PROTOCOMP %d, ACFCOMP %d, MAGIC %08lx,\n"
139 " REJECT %04lx\n",
140 lcp->want_mru, lcp->want_accmap, lcp->want_protocomp, lcp->want_acfcomp,
141 lcp->want_magic, lcp->my_reject);
142 fprintf(VarTerm, "\nDefaults: MRU = %ld, ACCMAP = %08x\t", VarMRU, VarAccmap);
143 fprintf(VarTerm, "Open Mode: %s\n", (VarOpenMode == OPEN_ACTIVE) ? "active" : "passive");
144 return 0;
145}
146
147/*
148 * Generate random number which will be used as magic number.
149 */
150static u_long
151GenerateMagic()
152{
153 randinit();
154 return (random());
155}
156
157void
158LcpInit()
159{
160 struct lcpstate *lcp = &LcpInfo;
161
162 FsmInit(&LcpFsm);
163 HdlcInit();
164
165 memset(lcp, '\0', sizeof(struct lcpstate));
166 lcp->want_mru = VarMRU;
167 lcp->his_mru = DEF_MRU;
168 lcp->his_accmap = 0xffffffff;
169 lcp->want_accmap = VarAccmap;
170 lcp->want_magic = GenerateMagic();
171 lcp->want_auth = lcp->his_auth = 0;
172 if (Enabled(ConfChap))
173 lcp->want_auth = PROTO_CHAP;
174 else if (Enabled(ConfPap))
175 lcp->want_auth = PROTO_PAP;
176 if (Enabled(ConfLqr))
177 lcp->want_lqrperiod = VarLqrTimeout * 100;
178 if (Enabled(ConfAcfcomp))
179 lcp->want_acfcomp = 1;
180 if (Enabled(ConfProtocomp))
181 lcp->want_protocomp = 1;
182 LcpFsm.maxconfig = 10;
183}
184
185static void
186LcpInitRestartCounter(struct fsm * fp)
187{
188 fp->FsmTimer.load = VarRetryTimeout * SECTICKS;
189 fp->restart = 5;
190}
191
192void
193PutConfValue(u_char ** cpp, char **types, u_char type, int len, u_long val)
194{
195 u_char *cp;
196 struct in_addr ina;
197
198 cp = *cpp;
199 *cp++ = type;
200 *cp++ = len;
201 if (len == 6) {
202 if (type == TY_IPADDR) {
203 ina.s_addr = htonl(val);
204 LogPrintf(LogLCP, " %s [%d] %s\n",
205 types[type], len, inet_ntoa(ina));
206 } else {
207 LogPrintf(LogLCP, " %s [%d] %08x\n", types[type], len, val);
208 }
209 *cp++ = (val >> 24) & 0377;
210 *cp++ = (val >> 16) & 0377;
211 } else
212 LogPrintf(LogLCP, " %s [%d] %d\n", types[type], len, val);
213 *cp++ = (val >> 8) & 0377;
214 *cp++ = val & 0377;
215 *cpp = cp;
216}
217
218static void
219LcpSendConfigReq(struct fsm * fp)
220{
221 u_char *cp;
222 struct lcpstate *lcp = &LcpInfo;
223 struct lqrreq *req;
224
225 LogPrintf(LogLCP, "LcpSendConfigReq\n");
226 cp = ReqBuff;
227 if (!DEV_IS_SYNC) {
228 if (lcp->want_acfcomp && !REJECTED(lcp, TY_ACFCOMP)) {
229 *cp++ = TY_ACFCOMP;
230 *cp++ = 2;
231 LogPrintf(LogLCP, " %s\n", cftypes[TY_ACFCOMP]);
232 }
233 if (lcp->want_protocomp && !REJECTED(lcp, TY_PROTOCOMP)) {
234 *cp++ = TY_PROTOCOMP;
235 *cp++ = 2;
236 LogPrintf(LogLCP, " %s\n", cftypes[TY_PROTOCOMP]);
237 }
238 if (!REJECTED(lcp, TY_ACCMAP))
239 PutConfValue(&cp, cftypes, TY_ACCMAP, 6, lcp->want_accmap);
240 }
241 if (!REJECTED(lcp, TY_MRU))
242 PutConfValue(&cp, cftypes, TY_MRU, 4, lcp->want_mru);
243 if (lcp->want_magic && !REJECTED(lcp, TY_MAGICNUM))
244 PutConfValue(&cp, cftypes, TY_MAGICNUM, 6, lcp->want_magic);
245 if (lcp->want_lqrperiod && !REJECTED(lcp, TY_QUALPROTO)) {
246 req = (struct lqrreq *) cp;
247 req->type = TY_QUALPROTO;
248 req->length = sizeof(struct lqrreq);
249 req->proto = htons(PROTO_LQR);
250 req->period = htonl(lcp->want_lqrperiod);
251 cp += sizeof(struct lqrreq);
252 LogPrintf(LogLCP, " %s (%d)\n", cftypes[TY_QUALPROTO], lcp->want_lqrperiod);
253 }
254 switch (lcp->want_auth) {
255 case PROTO_PAP:
256 PutConfValue(&cp, cftypes, TY_AUTHPROTO, 4, lcp->want_auth);
257 break;
258 case PROTO_CHAP:
259 PutConfValue(&cp, cftypes, TY_AUTHPROTO, 5, lcp->want_auth);
260#ifdef HAVE_DES
261 *cp++ = VarMSChap ? 0x80 : 0x05; /* Use MSChap vs. RFC 1994 (MD5) */
262#else
263 *cp++ = 0x05; /* Use MD5 */
264#endif
265 break;
266 }
267 FsmOutput(fp, CODE_CONFIGREQ, fp->reqid++, ReqBuff, cp - ReqBuff);
268}
269
270void
271LcpSendProtoRej(u_char * option, int count)
272{
273 struct fsm *fp = &LcpFsm;
274
275 LogPrintf(LogLCP, "LcpSendProtoRej\n");
276 FsmOutput(fp, CODE_PROTOREJ, fp->reqid, option, count);
277}
278
279static void
280LcpSendTerminateReq(struct fsm * fp)
281{
282 /* Most thins are done in fsm layer. Nothing to to. */
283}
284
285static void
286LcpSendTerminateAck(struct fsm * fp)
287{
288 LogPrintf(LogLCP, "LcpSendTerminateAck.\n");
289 FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0);
290}
291
292static void
293LcpLayerStart(struct fsm * fp)
294{
295 LogPrintf(LogLCP, "LcpLayerStart\n");
296 NewPhase(PHASE_ESTABLISH);
297}
298
299static void
300StopAllTimers()
301{
302 StopTimer(&LcpReportTimer);
303 StopTimer(&IpcpReportTimer);
304 StopIdleTimer();
305 StopTimer(&AuthPapInfo.authtimer);
306 StopTimer(&AuthChapInfo.authtimer);
307 StopLqrTimer();
308}
309
310static void
311LcpLayerFinish(struct fsm * fp)
312{
313 LogPrintf(LogLCP, "LcpLayerFinish\n");
314 OsCloseLink(1);
315 NewPhase(PHASE_DEAD);
316 StopAllTimers();
317 (void) OsInterfaceDown(0);
318 /* We're down at last. Lets tell background and direct mode to get out */
319 NewPhase(PHASE_TERMINATE);
320 LcpInit();
321 IpcpInit();
322 CcpInit();
323 Prompt();
324}
325
326static void
327LcpLayerUp(struct fsm * fp)
328{
329 LogPrintf(LogLCP, "LcpLayerUp\n");
330 OsSetInterfaceParams(23, LcpInfo.his_mru, ModemSpeed());
331 SetLinkParams(&LcpInfo);
332
333 NewPhase(PHASE_AUTHENTICATE);
334
335 StartLqm();
336 StopTimer(&LcpReportTimer);
337 LcpReportTimer.state = TIMER_STOPPED;
338 LcpReportTimer.load = 60 * SECTICKS;
339 LcpReportTimer.func = LcpReportTime;
340 StartTimer(&LcpReportTimer);
341}
342
343static void
344LcpLayerDown(struct fsm * fp)
345{
346 StopAllTimers();
347 OsLinkdown();
348 LogPrintf(LogLCP, "LcpLayerDown\n");
349 /*
350 * OsLinkdown() brings CCP & IPCP down, then waits 'till we go from
351 * STOPPING to STOPPED. At this point, the FSM gives us a LayerFinish
352 */
353}
354
355void
356LcpUp()
357{
358 FsmUp(&LcpFsm);
359 LcpFailedMagic = 0;
360}
361
362void
363LcpDown()
364{ /* Sudden death */
365 LcpFailedMagic = 0;
366 NewPhase(PHASE_DEAD);
367 StopAllTimers();
368 FsmDown(&LcpFsm);
369 /*
370 * We now wait for the FsmDown() to result in a LcpLayerDown() (if we're
371 * open).
372 */
373}
374
375void
376LcpOpen(int mode)
377{
378 LcpFsm.open_mode = mode;
379 LcpFailedMagic = 0;
380 FsmOpen(&LcpFsm);
381}
382
383void
384LcpClose()
385{
386 FsmClose(&LcpFsm);
387 LcpFailedMagic = 0;
388}
389
390/*
391 * XXX: Should validate option length
392 */
393static void
394LcpDecodeConfig(u_char * cp, int plen, int mode)
395{
396 char *request;
397 int type, length, mru, mtu;
398 u_long *lp, magic, accmap;
399 u_short *sp, proto;
400 struct lqrreq *req;
401
402 ackp = AckBuff;
403 nakp = NakBuff;
404 rejp = RejBuff;
405
406 while (plen >= sizeof(struct fsmconfig)) {
407 type = *cp;
408 length = cp[1];
409 if (type <= TY_ACFCOMP)
410 request = cftypes[type];
411 else
412 request = "???";
413
414 switch (type) {
415 case TY_MRU:
416 sp = (u_short *) (cp + 2);
417 mru = htons(*sp);
418 LogPrintf(LogLCP, " %s %d\n", request, mru);
419
420 switch (mode) {
421 case MODE_REQ:
422 mtu = VarPrefMTU;
423 if (mtu == 0)
424 mtu = MAX_MTU;
425 if (mru > mtu) {
426 *sp = htons(mtu);
427 memcpy(nakp, cp, 4);
428 nakp += 4;
429 } else if (mru < MIN_MRU) {
430 *sp = htons(MIN_MRU);
431 memcpy(nakp, cp, 4);
432 nakp += 4;
433 } else {
434 LcpInfo.his_mru = mru;
435 memcpy(ackp, cp, 4);
436 ackp += 4;
437 }
438 break;
439 case MODE_NAK:
440 if (mru >= MIN_MRU || mru <= MAX_MRU)
441 LcpInfo.want_mru = mru;
442 break;
443 case MODE_REJ:
444 LcpInfo.his_reject |= (1 << type);
445 break;
446 }
447 break;
448 case TY_ACCMAP:
449 lp = (u_long *) (cp + 2);
450 accmap = htonl(*lp);
451 LogPrintf(LogLCP, " %s %08x\n", request, accmap);
452
453 switch (mode) {
454 case MODE_REQ:
455 LcpInfo.his_accmap = accmap;
456 memcpy(ackp, cp, 6);
457 ackp += 6;
458 break;
459 case MODE_NAK:
460 LcpInfo.want_accmap = accmap;
461 break;
462 case MODE_REJ:
463 LcpInfo.his_reject |= (1 << type);
464 break;
465 }
466 break;
467 case TY_AUTHPROTO:
468 sp = (u_short *) (cp + 2);
469 proto = ntohs(*sp);
470 LogPrintf(LogLCP, " %s proto = %04x\n", request, proto);
471
472 switch (mode) {
473 case MODE_REQ:
474 switch (proto) {
475 case PROTO_PAP:
476 if (length != 4) {
477 LogPrintf(LogLCP, " %s bad length (%d)\n", request, length);
478 goto reqreject;
479 }
480 if (Acceptable(ConfPap)) {
481 LcpInfo.his_auth = proto;
482 memcpy(ackp, cp, length);
483 ackp += length;
484 } else if (Acceptable(ConfChap)) {
485 *nakp++ = *cp;
486 *nakp++ = 5;
487 *nakp++ = (unsigned char) (PROTO_CHAP >> 8);
488 *nakp++ = (unsigned char) PROTO_CHAP;
489 *nakp++ = 5;
490 } else
491 goto reqreject;
492 break;
493 case PROTO_CHAP:
494 if (length < 5) {
495 LogPrintf(LogLCP, " %s bad length (%d)\n", request, length);
496 goto reqreject;
497 }
498#ifdef HAVE_DES
499 if (Acceptable(ConfChap) && (cp[4] == 5 || cp[4] == 0x80))
500#else
501 if (Acceptable(ConfChap) && cp[4] == 5)
502#endif
503 {
504 LcpInfo.his_auth = proto;
505 memcpy(ackp, cp, length);
506 ackp += length;
507#ifdef HAVE_DES
508 VarMSChap = cp[4] = 0x80;
509#endif
510 } else if (Acceptable(ConfPap)) {
511 *nakp++ = *cp;
512 *nakp++ = 4;
513 *nakp++ = (unsigned char) (PROTO_PAP >> 8);
514 *nakp++ = (unsigned char) PROTO_PAP;
515 } else
516 goto reqreject;
517 break;
518 default:
519 LogPrintf(LogLCP, " %s not implemented, NAK.\n", request);
520 memcpy(nakp, cp, length);
521 nakp += length;
522 break;
523 }
524 break;
525 case MODE_NAK:
526 break;
527 case MODE_REJ:
528 LcpInfo.his_reject |= (1 << type);
529 break;
530 }
531 break;
532 case TY_QUALPROTO:
533 req = (struct lqrreq *) cp;
534 LogPrintf(LogLCP, " %s proto: %x, interval: %dms\n",
535 request, ntohs(req->proto), ntohl(req->period) * 10);
536 switch (mode) {
537 case MODE_REQ:
538 if (ntohs(req->proto) != PROTO_LQR || !Acceptable(ConfLqr))
539 goto reqreject;
540 else {
541 LcpInfo.his_lqrperiod = ntohl(req->period);
542 if (LcpInfo.his_lqrperiod < 500)
543 LcpInfo.his_lqrperiod = 500;
544 req->period = htonl(LcpInfo.his_lqrperiod);
545 memcpy(ackp, cp, length);
546 ackp += length;
547 }
548 break;
549 case MODE_NAK:
550 break;
551 case MODE_REJ:
552 LcpInfo.his_reject |= (1 << type);
553 break;
554 }
555 break;
556 case TY_MAGICNUM:
557 lp = (u_long *) (cp + 2);
558 magic = ntohl(*lp);
559 LogPrintf(LogLCP, " %s %08x\n", request, magic);
560
561 switch (mode) {
562 case MODE_REQ:
563 if (LcpInfo.want_magic) {
564 /* Validate magic number */
565 if (magic == LcpInfo.want_magic) {
566 LogPrintf(LogLCP, "Magic is same (%08x) - %d times\n",
567 magic, ++LcpFailedMagic);
568 LcpInfo.want_magic = GenerateMagic();
569 memcpy(nakp, cp, 6);
570 nakp += 6;
571 ualarm(TICKUNIT * (4 + 4 * LcpFailedMagic), 0);
572 sigpause(0);
573 } else {
574 LcpInfo.his_magic = magic;
575 memcpy(ackp, cp, length);
576 ackp += length;
577 LcpFailedMagic = 0;
578 }
579 } else {
580 LcpInfo.my_reject |= (1 << type);
581 goto reqreject;
582 }
583 break;
584 case MODE_NAK:
585 LogPrintf(LogLCP, " %s magic %08x has NAKed\n", request, magic);
586 LcpInfo.want_magic = GenerateMagic();
587 break;
588 case MODE_REJ:
589 LogPrintf(LogLCP, " %s magic has REJected\n", request);
590 LcpInfo.want_magic = 0;
591 LcpInfo.his_reject |= (1 << type);
592 break;
593 }
594 break;
595 case TY_PROTOCOMP:
596 LogPrintf(LogLCP, " %s\n", request);
597
598 switch (mode) {
599 case MODE_REQ:
600 if (Acceptable(ConfProtocomp)) {
601 LcpInfo.his_protocomp = 1;
602 memcpy(ackp, cp, 2);
603 ackp += 2;
604 } else {
605#ifdef OLDMST
606 /*
607 * MorningStar before v1.3 needs NAK
608 */
609 memcpy(nakp, cp, 2);
610 nakp += 2;
611#else
612 memcpy(rejp, cp, 2);
613 rejp += 2;
614 LcpInfo.my_reject |= (1 << type);
615#endif
616 }
617 break;
618 case MODE_NAK:
619 case MODE_REJ:
620 LcpInfo.want_protocomp = 0;
621 LcpInfo.his_reject |= (1 << type);
622 break;
623 }
624 break;
625 case TY_ACFCOMP:
626 LogPrintf(LogLCP, " %s\n", request);
627 switch (mode) {
628 case MODE_REQ:
629 if (Acceptable(ConfAcfcomp)) {
630 LcpInfo.his_acfcomp = 1;
631 memcpy(ackp, cp, 2);
632 ackp += 2;
633 } else {
634#ifdef OLDMST
635 /*
636 * MorningStar before v1.3 needs NAK
637 */
638 memcpy(nakp, cp, 2);
639 nakp += 2;
640#else
641 memcpy(rejp, cp, 2);
642 rejp += 2;
643 LcpInfo.my_reject |= (1 << type);
644#endif
645 }
646 break;
647 case MODE_NAK:
648 case MODE_REJ:
649 LcpInfo.want_acfcomp = 0;
650 LcpInfo.his_reject |= (1 << type);
651 break;
652 }
653 break;
654 case TY_SDP:
655 LogPrintf(LogLCP, " %s\n", request);
656 switch (mode) {
657 case MODE_REQ:
658 case MODE_NAK:
659 case MODE_REJ:
660 break;
661 }
662 break;
663 default:
664 LogPrintf(LogLCP, " ???[%02x]\n", type);
665 if (mode == MODE_REQ) {
666 reqreject:
667 memcpy(rejp, cp, length);
668 rejp += length;
669 LcpInfo.my_reject |= (1 << type);
670 }
671 break;
672 }
673 /* to avoid inf. loop */
674 if (length == 0) {
675 LogPrintf(LogLCP, "LCP size zero\n");
676 break;
677 }
678 plen -= length;
679 cp += length;
680 }
681}
682
683void
684LcpInput(struct mbuf * bp)
685{
686 FsmInput(&LcpFsm, bp);
687}