lcp.c revision 38959
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.63 1998/09/04 18:25:59 brian Exp $
21 *
22 * TODO:
23 *	o Limit data field length by MRU
24 */
25
26#include <sys/types.h>
27#include <netinet/in.h>
28#include <netinet/in_systm.h>
29#include <netinet/ip.h>
30#include <sys/un.h>
31
32#include <signal.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <string.h>
36#include <termios.h>
37#include <unistd.h>
38
39#include "ua.h"
40#include "defs.h"
41#include "command.h"
42#include "mbuf.h"
43#include "log.h"
44#include "timer.h"
45#include "fsm.h"
46#include "iplist.h"
47#include "lcp.h"
48#include "throughput.h"
49#include "lcpproto.h"
50#include "descriptor.h"
51#include "lqr.h"
52#include "hdlc.h"
53#include "ccp.h"
54#include "async.h"
55#include "link.h"
56#include "physical.h"
57#include "prompt.h"
58#include "slcompress.h"
59#include "ipcp.h"
60#include "filter.h"
61#include "mp.h"
62#include "chat.h"
63#include "auth.h"
64#include "chap.h"
65#include "cbcp.h"
66#include "datalink.h"
67#include "bundle.h"
68
69/* for received LQRs */
70struct lqrreq {
71  u_char type;
72  u_char length;
73  u_short proto;		/* Quality protocol */
74  u_int32_t period;		/* Reporting interval */
75};
76
77static int LcpLayerUp(struct fsm *);
78static void LcpLayerDown(struct fsm *);
79static void LcpLayerStart(struct fsm *);
80static void LcpLayerFinish(struct fsm *);
81static void LcpInitRestartCounter(struct fsm *);
82static void LcpSendConfigReq(struct fsm *);
83static void LcpSentTerminateReq(struct fsm *);
84static void LcpSendTerminateAck(struct fsm *, u_char);
85static void LcpDecodeConfig(struct fsm *, u_char *, int, int,
86                            struct fsm_decode *);
87
88static struct fsm_callbacks lcp_Callbacks = {
89  LcpLayerUp,
90  LcpLayerDown,
91  LcpLayerStart,
92  LcpLayerFinish,
93  LcpInitRestartCounter,
94  LcpSendConfigReq,
95  LcpSentTerminateReq,
96  LcpSendTerminateAck,
97  LcpDecodeConfig,
98  fsm_NullRecvResetReq,
99  fsm_NullRecvResetAck
100};
101
102static const char *lcp_TimerNames[] =
103  {"LCP restart", "LCP openmode", "LCP stopped"};
104
105static const char *cftypes[] = {
106  /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */
107  "???",
108  "MRU",	/* 1: Maximum-Receive-Unit */
109  "ACCMAP",	/* 2: Async-Control-Character-Map */
110  "AUTHPROTO",	/* 3: Authentication-Protocol */
111  "QUALPROTO",	/* 4: Quality-Protocol */
112  "MAGICNUM",	/* 5: Magic-Number */
113  "RESERVED",	/* 6: RESERVED */
114  "PROTOCOMP",	/* 7: Protocol-Field-Compression */
115  "ACFCOMP",	/* 8: Address-and-Control-Field-Compression */
116  "FCSALT",	/* 9: FCS-Alternatives */
117  "SDP",	/* 10: Self-Describing-Pad */
118  "NUMMODE",	/* 11: Numbered-Mode */
119  "MULTIPROC",	/* 12: Multi-Link-Procedure */
120  "CALLBACK",	/* 13: Callback */
121  "CONTIME",	/* 14: Connect-Time */
122  "COMPFRAME",	/* 15: Compound-Frames */
123  "NDE",	/* 16: Nominal-Data-Encapsulation */
124  "MRRU",	/* 17: Multilink-MRRU */
125  "SHORTSEQ",	/* 18: Multilink-Short-Sequence-Number-Header */
126  "ENDDISC",	/* 19: Multilink-Endpoint-Discriminator */
127  "PROPRIETRY",	/* 20: Proprietary */
128  "DCEID",	/* 21: DCE-Identifier */
129  "MULTIPP",	/* 22: Multi-Link-Plus-Procedure */
130  "LDBACP",	/* 23: Link Discriminator for BACP */
131};
132
133#define NCFTYPES (sizeof cftypes/sizeof cftypes[0])
134
135int
136lcp_ReportStatus(struct cmdargs const *arg)
137{
138  struct link *l;
139  struct lcp *lcp;
140
141  l = command_ChooseLink(arg);
142  lcp = &l->lcp;
143
144  prompt_Printf(arg->prompt, "%s: %s [%s]\n", l->name, lcp->fsm.name,
145                State2Nam(lcp->fsm.state));
146  prompt_Printf(arg->prompt,
147	        " his side: MRU %d, ACCMAP %08lx, PROTOCOMP %s, ACFCOMP %s,\n"
148	        "           MAGIC %08lx, MRRU %u, SHORTSEQ %s, REJECT %04x\n",
149	        lcp->his_mru, (u_long)lcp->his_accmap,
150                lcp->his_protocomp ? "on" : "off",
151                lcp->his_acfcomp ? "on" : "off",
152                (u_long)lcp->his_magic, lcp->his_mrru,
153                lcp->his_shortseq ? "on" : "off", lcp->his_reject);
154  prompt_Printf(arg->prompt,
155	        " my  side: MRU %d, ACCMAP %08lx, PROTOCOMP %s, ACFCOMP %s,\n"
156                "           MAGIC %08lx, MRRU %u, SHORTSEQ %s, REJECT %04x\n",
157                lcp->want_mru, (u_long)lcp->want_accmap,
158                lcp->want_protocomp ? "on" : "off",
159                lcp->want_acfcomp ? "on" : "off",
160                (u_long)lcp->want_magic, lcp->want_mrru,
161                lcp->want_shortseq ? "on" : "off", lcp->my_reject);
162
163  prompt_Printf(arg->prompt, "\n Defaults: MRU = %d, ", lcp->cfg.mru);
164  prompt_Printf(arg->prompt, "ACCMAP = %08lx\n", (u_long)lcp->cfg.accmap);
165  prompt_Printf(arg->prompt, "           LQR period = %us, ",
166                lcp->cfg.lqrperiod);
167  prompt_Printf(arg->prompt, "Open Mode = %s",
168                lcp->cfg.openmode == OPEN_PASSIVE ? "passive" : "active");
169  if (lcp->cfg.openmode > 0)
170    prompt_Printf(arg->prompt, " (delay %ds)", lcp->cfg.openmode);
171  prompt_Printf(arg->prompt, "\n           FSM retry = %us\n",
172                lcp->cfg.fsmretry);
173  prompt_Printf(arg->prompt, "\n Negotiation:\n");
174  prompt_Printf(arg->prompt, "           ACFCOMP =   %s\n",
175                command_ShowNegval(lcp->cfg.acfcomp));
176  prompt_Printf(arg->prompt, "           CHAP =      %s\n",
177                command_ShowNegval(lcp->cfg.chap));
178  prompt_Printf(arg->prompt, "           LQR =       %s\n",
179                command_ShowNegval(lcp->cfg.lqr));
180  prompt_Printf(arg->prompt, "           PAP =       %s\n",
181                command_ShowNegval(lcp->cfg.pap));
182  prompt_Printf(arg->prompt, "           PROTOCOMP = %s\n",
183                command_ShowNegval(lcp->cfg.protocomp));
184
185  return 0;
186}
187
188static u_int32_t
189GenerateMagic(void)
190{
191  /* Generate random number which will be used as magic number */
192  randinit();
193  return random();
194}
195
196void
197lcp_SetupCallbacks(struct lcp *lcp)
198{
199  lcp->fsm.fn = &lcp_Callbacks;
200  lcp->fsm.FsmTimer.name = lcp_TimerNames[0];
201  lcp->fsm.OpenTimer.name = lcp_TimerNames[1];
202  lcp->fsm.StoppedTimer.name = lcp_TimerNames[2];
203}
204
205void
206lcp_Init(struct lcp *lcp, struct bundle *bundle, struct link *l,
207         const struct fsm_parent *parent)
208{
209  /* Initialise ourselves */
210  int mincode = parent ? 1 : LCP_MINMPCODE;
211
212  fsm_Init(&lcp->fsm, "LCP", PROTO_LCP, mincode, LCP_MAXCODE, 10, LogLCP,
213           bundle, l, parent, &lcp_Callbacks, lcp_TimerNames);
214
215  lcp->cfg.mru = DEF_MRU;
216  lcp->cfg.accmap = 0;
217  lcp->cfg.openmode = 1;
218  lcp->cfg.lqrperiod = DEF_LQRPERIOD;
219  lcp->cfg.fsmretry = DEF_FSMRETRY;
220
221  lcp->cfg.acfcomp = NEG_ENABLED|NEG_ACCEPTED;
222  lcp->cfg.chap = NEG_ACCEPTED;
223  lcp->cfg.lqr = NEG_ACCEPTED;
224  lcp->cfg.pap = NEG_ACCEPTED;
225  lcp->cfg.protocomp = NEG_ENABLED|NEG_ACCEPTED;
226
227  lcp_Setup(lcp, lcp->cfg.openmode);
228}
229
230void
231lcp_Setup(struct lcp *lcp, int openmode)
232{
233  lcp->fsm.open_mode = openmode;
234  lcp->fsm.maxconfig = 10;
235
236  lcp->his_mru = lcp->fsm.bundle->cfg.mtu;
237  if (!lcp->his_mru || lcp->his_mru > DEF_MRU)
238    lcp->his_mru = DEF_MRU;
239  lcp->his_mrru = 0;
240  lcp->his_magic = 0;
241  lcp->his_lqrperiod = 0;
242  lcp->his_acfcomp = 0;
243  lcp->his_auth = 0;
244  lcp->his_callback.opmask = 0;
245  lcp->his_shortseq = 0;
246
247  lcp->want_mru = lcp->cfg.mru;
248  lcp->want_mrru = lcp->fsm.bundle->ncp.mp.cfg.mrru;
249  lcp->want_shortseq = IsEnabled(lcp->fsm.bundle->ncp.mp.cfg.shortseq) ? 1 : 0;
250  lcp->want_acfcomp = IsEnabled(lcp->cfg.acfcomp) ? 1 : 0;
251
252  if (lcp->fsm.parent) {
253    struct physical *p = link2physical(lcp->fsm.link);
254
255    lcp->his_accmap = 0xffffffff;
256    lcp->want_accmap = lcp->cfg.accmap;
257    lcp->his_protocomp = 0;
258    lcp->want_protocomp = IsEnabled(lcp->cfg.protocomp) ? 1 : 0;
259    lcp->want_magic = GenerateMagic();
260    lcp->want_auth = IsEnabled(lcp->cfg.chap) ? PROTO_CHAP :
261                     IsEnabled(lcp->cfg.pap) ?  PROTO_PAP : 0;
262    if (p->type != PHYS_DIRECT)
263      memcpy(&lcp->want_callback, &p->dl->cfg.callback, sizeof(struct callback));
264    else
265      lcp->want_callback.opmask = 0;
266    lcp->want_lqrperiod = IsEnabled(lcp->cfg.lqr) ?
267                          lcp->cfg.lqrperiod * 100 : 0;
268  } else {
269    lcp->his_accmap = lcp->want_accmap = 0;
270    lcp->his_protocomp = lcp->want_protocomp = 1;
271    lcp->want_magic = 0;
272    lcp->want_auth = 0;
273    lcp->want_callback.opmask = 0;
274    lcp->want_lqrperiod = 0;
275  }
276
277  lcp->his_reject = lcp->my_reject = 0;
278  lcp->auth_iwait = lcp->auth_ineed = 0;
279  lcp->LcpFailedMagic = 0;
280}
281
282static void
283LcpInitRestartCounter(struct fsm * fp)
284{
285  /* Set fsm timer load */
286  struct lcp *lcp = fsm2lcp(fp);
287
288  fp->FsmTimer.load = lcp->cfg.fsmretry * SECTICKS;
289  fp->restart = DEF_REQs;
290}
291
292static void
293LcpSendConfigReq(struct fsm *fp)
294{
295  /* Send config REQ please */
296  struct physical *p = link2physical(fp->link);
297  struct lcp *lcp = fsm2lcp(fp);
298  u_char buff[200];
299  struct lcp_opt *o;
300  struct mp *mp;
301  u_int16_t proto;
302
303  if (!p) {
304    log_Printf(LogERROR, "%s: LcpSendConfigReq: Not a physical link !\n",
305              fp->link->name);
306    return;
307  }
308
309  o = (struct lcp_opt *)buff;
310  if (!physical_IsSync(p)) {
311    if (lcp->want_acfcomp && !REJECTED(lcp, TY_ACFCOMP))
312      INC_LCP_OPT(TY_ACFCOMP, 2, o);
313
314    if (lcp->want_protocomp && !REJECTED(lcp, TY_PROTOCOMP))
315      INC_LCP_OPT(TY_PROTOCOMP, 2, o);
316
317    if (!REJECTED(lcp, TY_ACCMAP)) {
318      ua_htonl(&lcp->want_accmap, o->data);
319      INC_LCP_OPT(TY_ACCMAP, 6, o);
320    }
321  }
322
323  if (!REJECTED(lcp, TY_MRU)) {
324    ua_htons(&lcp->want_mru, o->data);
325    INC_LCP_OPT(TY_MRU, 4, o);
326  }
327
328  if (lcp->want_magic && !REJECTED(lcp, TY_MAGICNUM)) {
329    ua_htonl(&lcp->want_magic, o->data);
330    INC_LCP_OPT(TY_MAGICNUM, 6, o);
331  }
332
333  if (lcp->want_lqrperiod && !REJECTED(lcp, TY_QUALPROTO)) {
334    proto = PROTO_LQR;
335    ua_htons(&proto, o->data);
336    ua_htonl(&lcp->want_lqrperiod, o->data + 2);
337    INC_LCP_OPT(TY_QUALPROTO, 8, o);
338  }
339
340  switch (lcp->want_auth) {
341  case PROTO_PAP:
342    proto = PROTO_PAP;
343    ua_htons(&proto, o->data);
344    INC_LCP_OPT(TY_AUTHPROTO, 4, o);
345    break;
346
347  case PROTO_CHAP:
348    proto = PROTO_CHAP;
349    ua_htons(&proto, o->data);
350    o->data[2] = 0x05;
351    INC_LCP_OPT(TY_AUTHPROTO, 5, o);
352    break;
353  }
354
355  if (!REJECTED(lcp, TY_CALLBACK)) {
356    if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) {
357      *o->data = CALLBACK_AUTH;
358      INC_LCP_OPT(TY_CALLBACK, 3, o);
359    } else if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_CBCP)) {
360      *o->data = CALLBACK_CBCP;
361      INC_LCP_OPT(TY_CALLBACK, 3, o);
362    } else if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_E164)) {
363      int sz = strlen(lcp->want_callback.msg);
364
365      if (sz > sizeof o->data - 1) {
366        sz = sizeof o->data - 1;
367        log_Printf(LogWARN, "Truncating E164 data to %d octets (oops!)\n", sz);
368      }
369      *o->data = CALLBACK_E164;
370      memcpy(o->data + 1, lcp->want_callback.msg, sz);
371      INC_LCP_OPT(TY_CALLBACK, sz + 3, o);
372    }
373  }
374
375  if (lcp->want_mrru && !REJECTED(lcp, TY_MRRU)) {
376    ua_htons(&lcp->want_mrru, o->data);
377    INC_LCP_OPT(TY_MRRU, 4, o);
378
379    if (lcp->want_shortseq && !REJECTED(lcp, TY_SHORTSEQ))
380      INC_LCP_OPT(TY_SHORTSEQ, 2, o);
381  }
382
383  mp = &lcp->fsm.bundle->ncp.mp;
384  if (mp->cfg.enddisc.class != 0 && !REJECTED(lcp, TY_ENDDISC)) {
385    *o->data = mp->cfg.enddisc.class;
386    memcpy(o->data+1, mp->cfg.enddisc.address, mp->cfg.enddisc.len);
387    INC_LCP_OPT(TY_ENDDISC, mp->cfg.enddisc.len + 3, o);
388  }
389
390  fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, (u_char *)o - buff);
391}
392
393void
394lcp_SendProtoRej(struct lcp *lcp, u_char *option, int count)
395{
396  /* Don't understand `option' */
397  fsm_Output(&lcp->fsm, CODE_PROTOREJ, lcp->fsm.reqid, option, count);
398}
399
400static void
401LcpSentTerminateReq(struct fsm * fp)
402{
403  /* Term REQ just sent by FSM */
404}
405
406static void
407LcpSendTerminateAck(struct fsm *fp, u_char id)
408{
409  /* Send Term ACK please */
410  struct physical *p = link2physical(fp->link);
411
412  if (p && p->dl->state == DATALINK_CBCP)
413    cbcp_ReceiveTerminateReq(p);
414
415  fsm_Output(fp, CODE_TERMACK, id, NULL, 0);
416}
417
418static void
419LcpLayerStart(struct fsm *fp)
420{
421  /* We're about to start up ! */
422  struct lcp *lcp = fsm2lcp(fp);
423
424  log_Printf(LogLCP, "%s: LayerStart\n", fp->link->name);
425  lcp->LcpFailedMagic = 0;
426}
427
428static void
429LcpLayerFinish(struct fsm *fp)
430{
431  /* We're now down */
432  log_Printf(LogLCP, "%s: LayerFinish\n", fp->link->name);
433}
434
435static int
436LcpLayerUp(struct fsm *fp)
437{
438  /* We're now up */
439  struct physical *p = link2physical(fp->link);
440  struct lcp *lcp = fsm2lcp(fp);
441
442  log_Printf(LogLCP, "%s: LayerUp\n", fp->link->name);
443  async_SetLinkParams(&p->async, lcp);
444  lqr_Start(lcp);
445  hdlc_StartTimer(&p->hdlc);
446  return 1;
447}
448
449static void
450LcpLayerDown(struct fsm *fp)
451{
452  /* About to come down */
453  struct physical *p = link2physical(fp->link);
454
455  log_Printf(LogLCP, "%s: LayerDown\n", fp->link->name);
456  hdlc_StopTimer(&p->hdlc);
457  lqr_StopTimer(p);
458  lcp_Setup(fsm2lcp(fp), 0);
459}
460
461static int
462E164ok(struct callback *cb, char *req, int sz)
463{
464  char list[sizeof cb->msg], *next;
465  int len;
466
467  if (!strcmp(cb->msg, "*"))
468    return 1;
469
470  strncpy(list, cb->msg, sizeof list - 1);
471  list[sizeof list - 1] = '\0';
472  for (next = strtok(list, ","); next; next = strtok(NULL, ",")) {
473    len = strlen(next);
474    if (sz == len && !memcmp(list, req, sz))
475      return 1;
476  }
477  return 0;
478}
479
480static void
481LcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type,
482                struct fsm_decode *dec)
483{
484  /* Deal with incoming PROTO_LCP */
485  struct lcp *lcp = fsm2lcp(fp);
486  int type, length, sz, pos, op, callback_req;
487  u_int32_t magic, accmap;
488  u_short mtu, mru, proto;
489  struct lqrreq *req;
490  char request[20], desc[22];
491  struct mp *mp;
492  struct physical *p = link2physical(fp->link);
493
494  callback_req = 0;
495
496  while (plen >= sizeof(struct fsmconfig)) {
497    type = *cp;
498    length = cp[1];
499
500    if (type < 0 || type >= NCFTYPES)
501      snprintf(request, sizeof request, " <%d>[%d]", type, length);
502    else
503      snprintf(request, sizeof request, " %s[%d]", cftypes[type], length);
504
505    if (length < 2) {
506      log_Printf(LogLCP, "%s:%s: Bad LCP length\n", fp->link->name, request);
507      break;
508    }
509
510    switch (type) {
511    case TY_MRRU:
512      mp = &lcp->fsm.bundle->ncp.mp;
513      ua_ntohs(cp + 2, &mru);
514      log_Printf(LogLCP, "%s %u\n", request, mru);
515
516      switch (mode_type) {
517      case MODE_REQ:
518        if (mp->cfg.mrru) {
519          if (REJECTED(lcp, TY_MRRU))
520            /* Ignore his previous reject so that we REQ next time */
521	    lcp->his_reject &= ~(1 << type);
522
523          mtu = lcp->fsm.bundle->cfg.mtu;
524          if (mru < MIN_MRU || mru < mtu) {
525            /* Push him up to MTU or MIN_MRU */
526            lcp->his_mrru = mru < mtu ? mtu : MIN_MRU;
527	    memcpy(dec->nakend, cp, 2);
528            ua_htons(&lcp->his_mrru, dec->nakend + 2);
529	    dec->nakend += 4;
530	  } else {
531            lcp->his_mrru = mtu ? mtu : mru;
532	    memcpy(dec->ackend, cp, 4);
533	    dec->ackend += 4;
534	  }
535	  break;
536        } else
537	  goto reqreject;
538        break;
539      case MODE_NAK:
540        if (mp->cfg.mrru) {
541          if (REJECTED(lcp, TY_MRRU))
542            /* Must have changed his mind ! */
543	    lcp->his_reject &= ~(1 << type);
544
545          if (mru > MAX_MRU)
546            lcp->want_mrru = MAX_MRU;
547          else if (mru < MIN_MRU)
548            lcp->want_mrru = MIN_MRU;
549          else
550            lcp->want_mrru = mru;
551        }
552        /* else we honour our config and don't send the suggested REQ */
553        break;
554      case MODE_REJ:
555	lcp->his_reject |= (1 << type);
556        lcp->want_mrru = 0;		/* Ah well, no multilink :-( */
557	break;
558      }
559      break;
560
561    case TY_MRU:
562      ua_ntohs(cp + 2, &mru);
563      log_Printf(LogLCP, "%s %d\n", request, mru);
564
565      switch (mode_type) {
566      case MODE_REQ:
567        mtu = lcp->fsm.bundle->cfg.mtu;
568        if (mru < MIN_MRU || (!lcp->want_mrru && mru < mtu)) {
569          /* Push him up to MTU or MIN_MRU */
570          lcp->his_mru = mru < mtu ? mtu : MIN_MRU;
571          memcpy(dec->nakend, cp, 2);
572          ua_htons(&lcp->his_mru, dec->nakend + 2);
573          dec->nakend += 4;
574        } else {
575          lcp->his_mru = mtu ? mtu : mru;
576          memcpy(dec->ackend, cp, 4);
577          dec->ackend += 4;
578        }
579	break;
580      case MODE_NAK:
581        if (mru > MAX_MRU)
582          lcp->want_mru = MAX_MRU;
583        else if (mru < MIN_MRU)
584          lcp->want_mru = MIN_MRU;
585        else
586          lcp->want_mru = mru;
587	break;
588      case MODE_REJ:
589	lcp->his_reject |= (1 << type);
590	break;
591      }
592      break;
593
594    case TY_ACCMAP:
595      ua_ntohl(cp + 2, &accmap);
596      log_Printf(LogLCP, "%s 0x%08lx\n", request, (u_long)accmap);
597
598      switch (mode_type) {
599      case MODE_REQ:
600	lcp->his_accmap = accmap;
601	memcpy(dec->ackend, cp, 6);
602	dec->ackend += 6;
603	break;
604      case MODE_NAK:
605	lcp->want_accmap = accmap;
606	break;
607      case MODE_REJ:
608	lcp->his_reject |= (1 << type);
609	break;
610      }
611      break;
612
613    case TY_AUTHPROTO:
614      ua_ntohs(cp + 2, &proto);
615      switch (proto) {
616      case PROTO_PAP:
617        log_Printf(LogLCP, "%s 0x%04x (PAP)\n", request, proto);
618        break;
619      case PROTO_CHAP:
620        log_Printf(LogLCP, "%s 0x%04x (CHAP 0x%02x)\n", request, proto, cp[4]);
621        break;
622      default:
623        log_Printf(LogLCP, "%s 0x%04x\n", request, proto);
624        break;
625      }
626
627      switch (mode_type) {
628      case MODE_REQ:
629	switch (proto) {
630	case PROTO_PAP:
631	  if (length != 4) {
632	    log_Printf(LogLCP, " Bad length!\n");
633	    goto reqreject;
634	  }
635	  if (IsAccepted(lcp->cfg.pap)) {
636	    lcp->his_auth = proto;
637	    memcpy(dec->ackend, cp, length);
638	    dec->ackend += length;
639	  } else if (IsAccepted(lcp->cfg.chap)) {
640	    *dec->nakend++ = *cp;
641	    *dec->nakend++ = 5;
642	    *dec->nakend++ = (unsigned char) (PROTO_CHAP >> 8);
643	    *dec->nakend++ = (unsigned char) PROTO_CHAP;
644	    *dec->nakend++ = 0x05;
645	  } else
646	    goto reqreject;
647	  break;
648
649	case PROTO_CHAP:
650	  if (length < 5) {
651	    log_Printf(LogLCP, " Bad length!\n");
652	    goto reqreject;
653	  }
654#ifdef HAVE_DES
655          if (IsAccepted(lcp->cfg.chap) && (cp[4] == 0x05 || cp[4] == 0x80))
656#else
657          if (IsAccepted(lcp->cfg.chap) && cp[4] == 0x05)
658#endif
659	  {
660	    lcp->his_auth = proto;
661	    memcpy(dec->ackend, cp, length);
662	    dec->ackend += length;
663#ifdef HAVE_DES
664            link2physical(fp->link)->dl->chap.using_MSChap = cp[4] == 0x80;
665#endif
666	  } else if (IsAccepted(lcp->cfg.pap)) {
667	    *dec->nakend++ = *cp;
668	    *dec->nakend++ = 4;
669	    *dec->nakend++ = (unsigned char) (PROTO_PAP >> 8);
670	    *dec->nakend++ = (unsigned char) PROTO_PAP;
671	  } else
672	    goto reqreject;
673	  break;
674
675	default:
676          log_Printf(LogLCP, "%s 0x%04x - not recognised, NAK\n",
677                    request, proto);
678	  memcpy(dec->nakend, cp, length);
679	  dec->nakend += length;
680	  break;
681	}
682	break;
683      case MODE_NAK:
684	switch (proto) {
685	case PROTO_PAP:
686          if (IsEnabled(lcp->cfg.pap))
687            lcp->want_auth = PROTO_PAP;
688          else {
689            log_Printf(LogLCP, "Peer will only send PAP (not enabled)\n");
690	    lcp->his_reject |= (1 << type);
691          }
692          break;
693	case PROTO_CHAP:
694          if (IsEnabled(lcp->cfg.chap))
695            lcp->want_auth = PROTO_CHAP;
696          else {
697            log_Printf(LogLCP, "Peer will only send CHAP (not enabled)\n");
698	    lcp->his_reject |= (1 << type);
699          }
700          break;
701        default:
702          /* We've been NAK'd with something we don't understand :-( */
703	  lcp->his_reject |= (1 << type);
704          break;
705        }
706	break;
707      case MODE_REJ:
708	lcp->his_reject |= (1 << type);
709	break;
710      }
711      break;
712
713    case TY_QUALPROTO:
714      req = (struct lqrreq *)cp;
715      log_Printf(LogLCP, "%s proto %x, interval %lums\n",
716                request, ntohs(req->proto), (u_long)ntohl(req->period) * 10);
717      switch (mode_type) {
718      case MODE_REQ:
719	if (ntohs(req->proto) != PROTO_LQR || !IsAccepted(lcp->cfg.lqr))
720	  goto reqreject;
721	else {
722	  lcp->his_lqrperiod = ntohl(req->period);
723	  if (lcp->his_lqrperiod < MIN_LQRPERIOD * 100)
724	    lcp->his_lqrperiod = MIN_LQRPERIOD * 100;
725	  req->period = htonl(lcp->his_lqrperiod);
726	  memcpy(dec->ackend, cp, length);
727	  dec->ackend += length;
728	}
729	break;
730      case MODE_NAK:
731	break;
732      case MODE_REJ:
733	lcp->his_reject |= (1 << type);
734	break;
735      }
736      break;
737
738    case TY_MAGICNUM:
739      ua_ntohl(cp + 2, &magic);
740      log_Printf(LogLCP, "%s 0x%08lx\n", request, (u_long)magic);
741
742      switch (mode_type) {
743      case MODE_REQ:
744	if (lcp->want_magic) {
745	  /* Validate magic number */
746	  if (magic == lcp->want_magic) {
747	    log_Printf(LogLCP, "Magic is same (%08lx) - %d times\n",
748                      (u_long)magic, ++lcp->LcpFailedMagic);
749	    lcp->want_magic = GenerateMagic();
750	    memcpy(dec->nakend, cp, 6);
751	    dec->nakend += 6;
752            ualarm(TICKUNIT * (4 + 4 * lcp->LcpFailedMagic), 0);
753            sigpause(0);
754	  } else {
755	    lcp->his_magic = magic;
756	    memcpy(dec->ackend, cp, length);
757	    dec->ackend += length;
758            lcp->LcpFailedMagic = 0;
759	  }
760	} else {
761	  goto reqreject;
762	}
763	break;
764      case MODE_NAK:
765	log_Printf(LogLCP, " Magic 0x%08lx is NAKed!\n", (u_long)magic);
766	lcp->want_magic = GenerateMagic();
767	break;
768      case MODE_REJ:
769	log_Printf(LogLCP, " Magic 0x%08x is REJected!\n", magic);
770	lcp->want_magic = 0;
771	lcp->his_reject |= (1 << type);
772	break;
773      }
774      break;
775
776    case TY_PROTOCOMP:
777      log_Printf(LogLCP, "%s\n", request);
778
779      switch (mode_type) {
780      case MODE_REQ:
781	if (IsAccepted(lcp->cfg.protocomp)) {
782	  lcp->his_protocomp = 1;
783	  memcpy(dec->ackend, cp, 2);
784	  dec->ackend += 2;
785	} else {
786#ifdef OLDMST
787	  /*
788	   * MorningStar before v1.3 needs NAK
789	   */
790	  memcpy(dec->nakend, cp, 2);
791	  dec->nakend += 2;
792#else
793	  goto reqreject;
794#endif
795	}
796	break;
797      case MODE_NAK:
798      case MODE_REJ:
799	lcp->want_protocomp = 0;
800	lcp->his_reject |= (1 << type);
801	break;
802      }
803      break;
804
805    case TY_ACFCOMP:
806      log_Printf(LogLCP, "%s\n", request);
807      switch (mode_type) {
808      case MODE_REQ:
809	if (IsAccepted(lcp->cfg.acfcomp)) {
810	  lcp->his_acfcomp = 1;
811	  memcpy(dec->ackend, cp, 2);
812	  dec->ackend += 2;
813	} else {
814#ifdef OLDMST
815	  /*
816	   * MorningStar before v1.3 needs NAK
817	   */
818	  memcpy(dec->nakend, cp, 2);
819	  dec->nakend += 2;
820#else
821	  goto reqreject;
822#endif
823	}
824	break;
825      case MODE_NAK:
826      case MODE_REJ:
827	lcp->want_acfcomp = 0;
828	lcp->his_reject |= (1 << type);
829	break;
830      }
831      break;
832
833    case TY_SDP:
834      log_Printf(LogLCP, "%s\n", request);
835      switch (mode_type) {
836      case MODE_REQ:
837      case MODE_NAK:
838      case MODE_REJ:
839	break;
840      }
841      break;
842
843    case TY_CALLBACK:
844      if (length == 2)
845        op = CALLBACK_NONE;
846      else
847        op = (int)cp[2];
848      sz = length - 3;
849      switch (op) {
850        case CALLBACK_AUTH:
851          log_Printf(LogLCP, "%s Auth\n", request);
852          break;
853        case CALLBACK_DIALSTRING:
854          log_Printf(LogLCP, "%s Dialstring %.*s\n", request, sz, cp + 3);
855          break;
856        case CALLBACK_LOCATION:
857          log_Printf(LogLCP, "%s Location %.*s\n", request, sz, cp + 3);
858          break;
859        case CALLBACK_E164:
860          log_Printf(LogLCP, "%s E.164 (%.*s)\n", request, sz, cp + 3);
861          break;
862        case CALLBACK_NAME:
863          log_Printf(LogLCP, "%s Name %.*s\n", request, sz, cp + 3);
864          break;
865        case CALLBACK_CBCP:
866          log_Printf(LogLCP, "%s CBCP\n", request);
867          break;
868        default:
869          log_Printf(LogLCP, "%s ???\n", request);
870          break;
871      }
872
873      switch (mode_type) {
874      case MODE_REQ:
875        callback_req = 1;
876        if (p->type != PHYS_DIRECT)
877	  goto reqreject;
878        if ((p->dl->cfg.callback.opmask & CALLBACK_BIT(op)) &&
879            (op != CALLBACK_AUTH || p->link.lcp.auth_ineed) &&
880            (op != CALLBACK_E164 ||
881             E164ok(&p->dl->cfg.callback, cp + 3, sz))) {
882	  lcp->his_callback.opmask = CALLBACK_BIT(op);
883          if (sz > sizeof lcp->his_callback.msg - 1) {
884            sz = sizeof lcp->his_callback.msg - 1;
885            log_Printf(LogWARN, "Truncating option arg to %d octets\n", sz);
886          }
887	  memcpy(lcp->his_callback.msg, cp + 3, sz);
888	  lcp->his_callback.msg[sz] = '\0';
889	  memcpy(dec->ackend, cp, sz + 3);
890	  dec->ackend += sz + 3;
891        } else if ((p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) &&
892                    p->link.lcp.auth_ineed) {
893          *dec->nakend++ = *cp;
894          *dec->nakend++ = 3;
895          *dec->nakend++ = CALLBACK_AUTH;
896        } else if (p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_CBCP)) {
897          *dec->nakend++ = *cp;
898          *dec->nakend++ = 3;
899          *dec->nakend++ = CALLBACK_CBCP;
900        } else if (p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_E164)) {
901          *dec->nakend++ = *cp;
902          *dec->nakend++ = 3;
903          *dec->nakend++ = CALLBACK_E164;
904        } else if (p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) {
905          log_Printf(LogWARN, "Cannot insist on auth callback without"
906                     " PAP or CHAP enabled !\n");
907          *dec->nakend++ = *cp;
908          *dec->nakend++ = 2;
909        } else
910	  goto reqreject;
911        break;
912      case MODE_NAK:
913        /* We don't do what he NAKs want, we do things in our preferred order */
914        if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_AUTH))
915          lcp->want_callback.opmask &= ~CALLBACK_BIT(CALLBACK_AUTH);
916        else if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_CBCP))
917          lcp->want_callback.opmask &= ~CALLBACK_BIT(CALLBACK_CBCP);
918        else if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_E164))
919          lcp->want_callback.opmask &= ~CALLBACK_BIT(CALLBACK_E164);
920        if (lcp->want_callback.opmask == CALLBACK_BIT(CALLBACK_NONE)) {
921          log_Printf(LogPHASE, "Peer NAKd all callbacks, trying none\n");
922          lcp->want_callback.opmask = 0;
923        } else if (!lcp->want_callback.opmask) {
924          log_Printf(LogPHASE, "Peer NAKd last configured callback\n");
925          fsm_Close(&lcp->fsm);
926        }
927        break;
928      case MODE_REJ:
929        if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_NONE)) {
930	  lcp->his_reject |= (1 << type);
931          lcp->want_callback.opmask = 0;
932        } else {
933          log_Printf(LogPHASE, "Peer rejected *required* callback\n");
934          fsm_Close(&lcp->fsm);
935        }
936	break;
937      }
938      break;
939
940    case TY_SHORTSEQ:
941      mp = &lcp->fsm.bundle->ncp.mp;
942      log_Printf(LogLCP, "%s\n", request);
943
944      switch (mode_type) {
945      case MODE_REQ:
946        if (lcp->want_mrru && IsAccepted(mp->cfg.shortseq)) {
947          lcp->his_shortseq = 1;
948	  memcpy(dec->ackend, cp, length);
949	  dec->ackend += length;
950        } else
951	  goto reqreject;
952        break;
953      case MODE_NAK:
954        /*
955         * He's trying to get us to ask for short sequence numbers.
956         * We ignore the NAK and honour our configuration file instead.
957         */
958        break;
959      case MODE_REJ:
960	lcp->his_reject |= (1 << type);
961        lcp->want_shortseq = 0;		/* For when we hit MP */
962	break;
963      }
964      break;
965
966    case TY_ENDDISC:
967      log_Printf(LogLCP, "%s %s\n", request,
968                mp_Enddisc(cp[2], cp + 3, length - 3));
969      switch (mode_type) {
970      case MODE_REQ:
971        if (!p) {
972          log_Printf(LogLCP, " ENDDISC rejected - not a physical link\n");
973	  goto reqreject;
974        } else if (length-3 < sizeof p->dl->peer.enddisc.address &&
975                   cp[2] <= MAX_ENDDISC_CLASS) {
976          p->dl->peer.enddisc.class = cp[2];
977          p->dl->peer.enddisc.len = length-3;
978          memcpy(p->dl->peer.enddisc.address, cp + 3, length - 3);
979          p->dl->peer.enddisc.address[length - 3] = '\0';
980          /* XXX: If mp->active, compare and NAK with mp->peer ? */
981	  memcpy(dec->ackend, cp, length);
982	  dec->ackend += length;
983        } else {
984          if (cp[2] > MAX_ENDDISC_CLASS)
985            log_Printf(LogLCP, " ENDDISC rejected - unrecognised class %d\n",
986                      cp[2]);
987          else
988            log_Printf(LogLCP, " ENDDISC rejected - local max length is %ld\n",
989                      (long)(sizeof p->dl->peer.enddisc.address - 1));
990	  goto reqreject;
991        }
992	break;
993
994      case MODE_NAK:	/* Treat this as a REJ, we don't vary or disc */
995      case MODE_REJ:
996	lcp->his_reject |= (1 << type);
997	break;
998      }
999      break;
1000
1001    default:
1002      sz = (sizeof desc - 2) / 2;
1003      if (sz > length - 2)
1004        sz = length - 2;
1005      pos = 0;
1006      desc[0] = sz ? ' ' : '\0';
1007      for (pos = 0; sz--; pos++)
1008        sprintf(desc+(pos<<1)+1, "%02x", cp[pos+2]);
1009
1010      log_Printf(LogLCP, "%s%s\n", request, desc);
1011
1012      if (mode_type == MODE_REQ) {
1013reqreject:
1014        if (length > sizeof dec->rej - (dec->rejend - dec->rej)) {
1015          length = sizeof dec->rej - (dec->rejend - dec->rej);
1016          log_Printf(LogLCP, "Can't REJ length %d - trunating to %d\n",
1017		    cp[1], length);
1018        }
1019	memcpy(dec->rejend, cp, length);
1020	dec->rejend += length;
1021	lcp->my_reject |= (1 << type);
1022        if (length != cp[1])
1023          length = 0;		/* force our way out of the loop */
1024      }
1025      break;
1026    }
1027    plen -= length;
1028    cp += length;
1029  }
1030
1031  if (mode_type != MODE_NOP) {
1032    if (mode_type == MODE_REQ && p && p->type == PHYS_DIRECT &&
1033        p->dl->cfg.callback.opmask && !callback_req &&
1034        !(p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_NONE))) {
1035      /* We *REQUIRE* that the peer requests callback */
1036      *dec->nakend++ = TY_CALLBACK;
1037      *dec->nakend++ = 3;
1038      if ((p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) &&
1039          p->link.lcp.auth_ineed)
1040        *dec->nakend++ = CALLBACK_AUTH;
1041      else if (p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_CBCP))
1042        *dec->nakend++ = CALLBACK_CBCP;
1043      else if (p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_E164))
1044        *dec->nakend++ = CALLBACK_E164;
1045      else {
1046        log_Printf(LogWARN, "Cannot insist on auth callback without"
1047                   " PAP or CHAP enabled !\n");
1048        dec->nakend[-1] = 2;	/* XXX: Silly ! */
1049      }
1050    }
1051    if (dec->rejend != dec->rej) {
1052      /* rejects are preferred */
1053      dec->ackend = dec->ack;
1054      dec->nakend = dec->nak;
1055    } else if (dec->nakend != dec->nak)
1056      /* then NAKs */
1057      dec->ackend = dec->ack;
1058  }
1059}
1060
1061void
1062lcp_Input(struct lcp *lcp, struct mbuf * bp)
1063{
1064  /* Got PROTO_LCP from link */
1065  fsm_Input(&lcp->fsm, bp);
1066}
1067