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