178189Sbrian/*- 278189Sbrian * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org> 378189Sbrian * based on work by Toshiharu OHNO <tony-o@iij.ad.jp> 478189Sbrian * Internet Initiative Japan, Inc (IIJ) 578189Sbrian * All rights reserved. 66059Samurai * 778189Sbrian * Redistribution and use in source and binary forms, with or without 878189Sbrian * modification, are permitted provided that the following conditions 978189Sbrian * are met: 1078189Sbrian * 1. Redistributions of source code must retain the above copyright 1178189Sbrian * notice, this list of conditions and the following disclaimer. 1278189Sbrian * 2. Redistributions in binary form must reproduce the above copyright 1378189Sbrian * notice, this list of conditions and the following disclaimer in the 1478189Sbrian * documentation and/or other materials provided with the distribution. 156059Samurai * 1678189Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1778189Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1878189Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1978189Sbrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2078189Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2178189Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2278189Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2378189Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2478189Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2578189Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2678189Sbrian * SUCH DAMAGE. 276059Samurai * 2850479Speter * $FreeBSD: releng/11.0/usr.sbin/ppp/lcp.c 162062 2006-09-06 06:23:55Z brian $ 296059Samurai */ 3036285Sbrian 3143313Sbrian#include <sys/param.h> 3229043Sbrian#include <netinet/in.h> 3336285Sbrian#include <netinet/in_systm.h> 3436285Sbrian#include <netinet/ip.h> 3581634Sbrian#include <sys/socket.h> 3636285Sbrian#include <sys/un.h> 3730715Sbrian 3829700Sbrian#include <signal.h> 39102500Sbrian#include <stdarg.h> 4030715Sbrian#include <stdio.h> 4130715Sbrian#include <stdlib.h> 4237210Sbrian#include <string.h> 4330715Sbrian#include <termios.h> 4430715Sbrian#include <unistd.h> 4530715Sbrian 4646686Sbrian#include "layer.h" 4738814Sbrian#include "ua.h" 4837009Sbrian#include "defs.h" 4931343Sbrian#include "command.h" 5030715Sbrian#include "mbuf.h" 5130715Sbrian#include "log.h" 5230715Sbrian#include "timer.h" 536059Samurai#include "fsm.h" 5436285Sbrian#include "iplist.h" 5536285Sbrian#include "throughput.h" 5646686Sbrian#include "proto.h" 5736285Sbrian#include "descriptor.h" 5836285Sbrian#include "lqr.h" 596059Samurai#include "hdlc.h" 6063484Sbrian#include "lcp.h" 6113389Sphk#include "ccp.h" 6236285Sbrian#include "async.h" 6336285Sbrian#include "link.h" 6436285Sbrian#include "physical.h" 6536285Sbrian#include "prompt.h" 6636285Sbrian#include "slcompress.h" 6781634Sbrian#include "ncpaddr.h" 6836285Sbrian#include "ipcp.h" 6936285Sbrian#include "filter.h" 7036285Sbrian#include "mp.h" 7136285Sbrian#include "chat.h" 726735Samurai#include "auth.h" 7330715Sbrian#include "chap.h" 7438174Sbrian#include "cbcp.h" 7536285Sbrian#include "datalink.h" 7643313Sbrian#ifndef NORADIUS 7743313Sbrian#include "radius.h" 7843313Sbrian#endif 7981634Sbrian#include "ipv6cp.h" 8081634Sbrian#include "ncp.h" 8136285Sbrian#include "bundle.h" 826059Samurai 8331514Sbrian/* for received LQRs */ 8431514Sbrianstruct lqrreq { 8594894Sbrian struct fsm_opt_hdr hdr; 8631514Sbrian u_short proto; /* Quality protocol */ 8737210Sbrian u_int32_t period; /* Reporting interval */ 8831514Sbrian}; 8931514Sbrian 9036285Sbrianstatic int LcpLayerUp(struct fsm *); 9126516Sbrianstatic void LcpLayerDown(struct fsm *); 9226516Sbrianstatic void LcpLayerStart(struct fsm *); 9326516Sbrianstatic void LcpLayerFinish(struct fsm *); 9444305Sbrianstatic void LcpInitRestartCounter(struct fsm *, int); 9536285Sbrianstatic void LcpSendConfigReq(struct fsm *); 9636285Sbrianstatic void LcpSentTerminateReq(struct fsm *); 9736285Sbrianstatic void LcpSendTerminateAck(struct fsm *, u_char); 9894894Sbrianstatic void LcpDecodeConfig(struct fsm *, u_char *, u_char *, int, 9936285Sbrian struct fsm_decode *); 1006059Samurai 10136285Sbrianstatic struct fsm_callbacks lcp_Callbacks = { 10236285Sbrian LcpLayerUp, 10336285Sbrian LcpLayerDown, 10436285Sbrian LcpLayerStart, 10536285Sbrian LcpLayerFinish, 10636285Sbrian LcpInitRestartCounter, 10736285Sbrian LcpSendConfigReq, 10836285Sbrian LcpSentTerminateReq, 10936285Sbrian LcpSendTerminateAck, 11036285Sbrian LcpDecodeConfig, 11136285Sbrian fsm_NullRecvResetReq, 11236285Sbrian fsm_NullRecvResetAck 11336285Sbrian}; 11436285Sbrian 11555146Sbrianstatic const char * const lcp_TimerNames[] = 11636285Sbrian {"LCP restart", "LCP openmode", "LCP stopped"}; 11736285Sbrian 11858034Sbrianstatic const char * 119134789Sbrianprotoname(unsigned proto) 12058034Sbrian{ 12158034Sbrian static const char * const cftypes[] = { 12258034Sbrian /* Check out the latest ``Assigned numbers'' rfc (1700) */ 12358034Sbrian NULL, 12458034Sbrian "MRU", /* 1: Maximum-Receive-Unit */ 12558034Sbrian "ACCMAP", /* 2: Async-Control-Character-Map */ 12658034Sbrian "AUTHPROTO", /* 3: Authentication-Protocol */ 12758034Sbrian "QUALPROTO", /* 4: Quality-Protocol */ 12858034Sbrian "MAGICNUM", /* 5: Magic-Number */ 12958034Sbrian "RESERVED", /* 6: RESERVED */ 13058034Sbrian "PROTOCOMP", /* 7: Protocol-Field-Compression */ 13158034Sbrian "ACFCOMP", /* 8: Address-and-Control-Field-Compression */ 13258034Sbrian "FCSALT", /* 9: FCS-Alternatives */ 13358034Sbrian "SDP", /* 10: Self-Describing-Pad */ 13458034Sbrian "NUMMODE", /* 11: Numbered-Mode */ 13558034Sbrian "MULTIPROC", /* 12: Multi-Link-Procedure */ 13658034Sbrian "CALLBACK", /* 13: Callback */ 13758034Sbrian "CONTIME", /* 14: Connect-Time */ 13858034Sbrian "COMPFRAME", /* 15: Compound-Frames */ 13958034Sbrian "NDE", /* 16: Nominal-Data-Encapsulation */ 14058034Sbrian "MRRU", /* 17: Multilink-MRRU */ 14158034Sbrian "SHORTSEQ", /* 18: Multilink-Short-Sequence-Number-Header */ 14258034Sbrian "ENDDISC", /* 19: Multilink-Endpoint-Discriminator */ 14358034Sbrian "PROPRIETRY", /* 20: Proprietary */ 14458034Sbrian "DCEID", /* 21: DCE-Identifier */ 14558034Sbrian "MULTIPP", /* 22: Multi-Link-Plus-Procedure */ 14658034Sbrian "LDBACP", /* 23: Link Discriminator for BACP */ 14758034Sbrian }; 1486059Samurai 149134789Sbrian if (proto > sizeof cftypes / sizeof *cftypes || cftypes[proto] == NULL) 15058034Sbrian return HexStr(proto, NULL, 0); 15131171Sbrian 15258034Sbrian return cftypes[proto]; 15358034Sbrian} 15458034Sbrian 15536285Sbrianint 15636285Sbrianlcp_ReportStatus(struct cmdargs const *arg) 1576059Samurai{ 15836285Sbrian struct link *l; 15936285Sbrian struct lcp *lcp; 1606059Samurai 16137210Sbrian l = command_ChooseLink(arg); 16236285Sbrian lcp = &l->lcp; 1636059Samurai 16436285Sbrian prompt_Printf(arg->prompt, "%s: %s [%s]\n", l->name, lcp->fsm.name, 16536285Sbrian State2Nam(lcp->fsm.state)); 16636285Sbrian prompt_Printf(arg->prompt, 16794894Sbrian " his side: MRU %d, ACCMAP %08lx, PROTOCOMP %s, ACFCOMP %s,\n" 16894894Sbrian " MAGIC %08lx, MRRU %u, SHORTSEQ %s, REJECT %04x\n", 16994894Sbrian lcp->his_mru, (u_long)lcp->his_accmap, 17036285Sbrian lcp->his_protocomp ? "on" : "off", 17136285Sbrian lcp->his_acfcomp ? "on" : "off", 17236285Sbrian (u_long)lcp->his_magic, lcp->his_mrru, 17336285Sbrian lcp->his_shortseq ? "on" : "off", lcp->his_reject); 17436285Sbrian prompt_Printf(arg->prompt, 17594894Sbrian " my side: MRU %d, ACCMAP %08lx, PROTOCOMP %s, ACFCOMP %s,\n" 17636285Sbrian " MAGIC %08lx, MRRU %u, SHORTSEQ %s, REJECT %04x\n", 17736285Sbrian lcp->want_mru, (u_long)lcp->want_accmap, 17836285Sbrian lcp->want_protocomp ? "on" : "off", 17936285Sbrian lcp->want_acfcomp ? "on" : "off", 18036285Sbrian (u_long)lcp->want_magic, lcp->want_mrru, 18136285Sbrian lcp->want_shortseq ? "on" : "off", lcp->my_reject); 1826059Samurai 18380385Sbrian if (lcp->cfg.mru) 18480385Sbrian prompt_Printf(arg->prompt, "\n Defaults: MRU = %d (max %d), ", 18580385Sbrian lcp->cfg.mru, lcp->cfg.max_mru); 18680385Sbrian else 18780385Sbrian prompt_Printf(arg->prompt, "\n Defaults: MRU = any (max %d), ", 18880385Sbrian lcp->cfg.max_mru); 18978410Sbrian if (lcp->cfg.mtu) 19078410Sbrian prompt_Printf(arg->prompt, "MTU = %d (max %d), ", 19178410Sbrian lcp->cfg.mtu, lcp->cfg.max_mtu); 19278410Sbrian else 19378410Sbrian prompt_Printf(arg->prompt, "MTU = any (max %d), ", lcp->cfg.max_mtu); 19436285Sbrian prompt_Printf(arg->prompt, "ACCMAP = %08lx\n", (u_long)lcp->cfg.accmap); 19536285Sbrian prompt_Printf(arg->prompt, " LQR period = %us, ", 19636285Sbrian lcp->cfg.lqrperiod); 19736285Sbrian prompt_Printf(arg->prompt, "Open Mode = %s", 19836285Sbrian lcp->cfg.openmode == OPEN_PASSIVE ? "passive" : "active"); 19936285Sbrian if (lcp->cfg.openmode > 0) 20036285Sbrian prompt_Printf(arg->prompt, " (delay %ds)", lcp->cfg.openmode); 20144305Sbrian prompt_Printf(arg->prompt, "\n FSM retry = %us, max %u Config" 20244305Sbrian " REQ%s, %u Term REQ%s\n", lcp->cfg.fsm.timeout, 20344305Sbrian lcp->cfg.fsm.maxreq, lcp->cfg.fsm.maxreq == 1 ? "" : "s", 20444305Sbrian lcp->cfg.fsm.maxtrm, lcp->cfg.fsm.maxtrm == 1 ? "" : "s"); 20563484Sbrian prompt_Printf(arg->prompt, " Ident: %s\n", lcp->cfg.ident); 20636285Sbrian prompt_Printf(arg->prompt, "\n Negotiation:\n"); 20736285Sbrian prompt_Printf(arg->prompt, " ACFCOMP = %s\n", 20836285Sbrian command_ShowNegval(lcp->cfg.acfcomp)); 20936285Sbrian prompt_Printf(arg->prompt, " CHAP = %s\n", 21044106Sbrian command_ShowNegval(lcp->cfg.chap05)); 21193418Sbrian#ifndef NODES 21269357Sbrian prompt_Printf(arg->prompt, " CHAP80 = %s\n", 21344106Sbrian command_ShowNegval(lcp->cfg.chap80nt)); 21444106Sbrian prompt_Printf(arg->prompt, " LANMan = %s\n", 21544106Sbrian command_ShowNegval(lcp->cfg.chap80lm)); 21667910Sbrian prompt_Printf(arg->prompt, " CHAP81 = %s\n", 21767910Sbrian command_ShowNegval(lcp->cfg.chap81)); 21844106Sbrian#endif 21936285Sbrian prompt_Printf(arg->prompt, " LQR = %s\n", 22036285Sbrian command_ShowNegval(lcp->cfg.lqr)); 221138799Sbrian prompt_Printf(arg->prompt, " LCP ECHO = %s\n", 222138799Sbrian lcp->cfg.echo ? "enabled" : "disabled"); 22336285Sbrian prompt_Printf(arg->prompt, " PAP = %s\n", 22436285Sbrian command_ShowNegval(lcp->cfg.pap)); 22536285Sbrian prompt_Printf(arg->prompt, " PROTOCOMP = %s\n", 22636285Sbrian command_ShowNegval(lcp->cfg.protocomp)); 22726516Sbrian 22826516Sbrian return 0; 2296059Samurai} 2306059Samurai 23132439Sbrianstatic u_int32_t 23231343SbrianGenerateMagic(void) 2336059Samurai{ 23436285Sbrian /* Generate random number which will be used as magic number */ 23530715Sbrian randinit(); 23636285Sbrian return random(); 2376059Samurai} 2386059Samurai 2396059Samuraivoid 24036285Sbrianlcp_SetupCallbacks(struct lcp *lcp) 2416059Samurai{ 24236285Sbrian lcp->fsm.fn = &lcp_Callbacks; 24336285Sbrian lcp->fsm.FsmTimer.name = lcp_TimerNames[0]; 24436285Sbrian lcp->fsm.OpenTimer.name = lcp_TimerNames[1]; 24536285Sbrian lcp->fsm.StoppedTimer.name = lcp_TimerNames[2]; 2466059Samurai} 2476059Samurai 24836285Sbrianvoid 24936285Sbrianlcp_Init(struct lcp *lcp, struct bundle *bundle, struct link *l, 25036285Sbrian const struct fsm_parent *parent) 2516059Samurai{ 25236285Sbrian /* Initialise ourselves */ 25336285Sbrian int mincode = parent ? 1 : LCP_MINMPCODE; 2546059Samurai 25544305Sbrian fsm_Init(&lcp->fsm, "LCP", PROTO_LCP, mincode, LCP_MAXCODE, LogLCP, 25636285Sbrian bundle, l, parent, &lcp_Callbacks, lcp_TimerNames); 2576059Samurai 25880385Sbrian lcp->cfg.mru = 0; 25978410Sbrian lcp->cfg.max_mru = MAX_MRU; 26078410Sbrian lcp->cfg.mtu = 0; 26178410Sbrian lcp->cfg.max_mtu = MAX_MTU; 26236285Sbrian lcp->cfg.accmap = 0; 26336285Sbrian lcp->cfg.openmode = 1; 26436285Sbrian lcp->cfg.lqrperiod = DEF_LQRPERIOD; 26544305Sbrian lcp->cfg.fsm.timeout = DEF_FSMRETRY; 26644305Sbrian lcp->cfg.fsm.maxreq = DEF_FSMTRIES; 26744305Sbrian lcp->cfg.fsm.maxtrm = DEF_FSMTRIES; 26831514Sbrian 26936285Sbrian lcp->cfg.acfcomp = NEG_ENABLED|NEG_ACCEPTED; 27044106Sbrian lcp->cfg.chap05 = NEG_ACCEPTED; 27193418Sbrian#ifndef NODES 27244106Sbrian lcp->cfg.chap80nt = NEG_ACCEPTED; 27379164Sbrian lcp->cfg.chap80lm = 0; 27468906Sbrian lcp->cfg.chap81 = NEG_ACCEPTED; 27544106Sbrian#endif 27636285Sbrian lcp->cfg.lqr = NEG_ACCEPTED; 277138799Sbrian lcp->cfg.echo = 0; 27836285Sbrian lcp->cfg.pap = NEG_ACCEPTED; 27936285Sbrian lcp->cfg.protocomp = NEG_ENABLED|NEG_ACCEPTED; 28063484Sbrian *lcp->cfg.ident = '\0'; 28136285Sbrian 28236285Sbrian lcp_Setup(lcp, lcp->cfg.openmode); 2836059Samurai} 2846059Samurai 28536285Sbrianvoid 28636285Sbrianlcp_Setup(struct lcp *lcp, int openmode) 28736285Sbrian{ 28878410Sbrian struct physical *p = link2physical(lcp->fsm.link); 28978410Sbrian 29036285Sbrian lcp->fsm.open_mode = openmode; 29131514Sbrian 29278410Sbrian lcp->his_mru = DEF_MRU; 29336285Sbrian lcp->his_mrru = 0; 29436285Sbrian lcp->his_magic = 0; 29536285Sbrian lcp->his_lqrperiod = 0; 29636285Sbrian lcp->his_acfcomp = 0; 29736285Sbrian lcp->his_auth = 0; 29844106Sbrian lcp->his_authtype = 0; 29938174Sbrian lcp->his_callback.opmask = 0; 30036285Sbrian lcp->his_shortseq = 0; 30185094Sbrian lcp->mru_req = 0; 30231514Sbrian 30380385Sbrian if ((lcp->want_mru = lcp->cfg.mru) == 0) 30480385Sbrian lcp->want_mru = DEF_MRU; 30536285Sbrian lcp->want_mrru = lcp->fsm.bundle->ncp.mp.cfg.mrru; 30636285Sbrian lcp->want_shortseq = IsEnabled(lcp->fsm.bundle->ncp.mp.cfg.shortseq) ? 1 : 0; 30736285Sbrian lcp->want_acfcomp = IsEnabled(lcp->cfg.acfcomp) ? 1 : 0; 30831514Sbrian 30936285Sbrian if (lcp->fsm.parent) { 31036285Sbrian lcp->his_accmap = 0xffffffff; 31136285Sbrian lcp->want_accmap = lcp->cfg.accmap; 31236285Sbrian lcp->his_protocomp = 0; 31336285Sbrian lcp->want_protocomp = IsEnabled(lcp->cfg.protocomp) ? 1 : 0; 31436285Sbrian lcp->want_magic = GenerateMagic(); 31544106Sbrian 31644106Sbrian if (IsEnabled(lcp->cfg.chap05)) { 31744106Sbrian lcp->want_auth = PROTO_CHAP; 31844106Sbrian lcp->want_authtype = 0x05; 31993418Sbrian#ifndef NODES 32044106Sbrian } else if (IsEnabled(lcp->cfg.chap80nt) || 32144106Sbrian IsEnabled(lcp->cfg.chap80lm)) { 32244106Sbrian lcp->want_auth = PROTO_CHAP; 32344106Sbrian lcp->want_authtype = 0x80; 32467910Sbrian } else if (IsEnabled(lcp->cfg.chap81)) { 32567910Sbrian lcp->want_auth = PROTO_CHAP; 32667910Sbrian lcp->want_authtype = 0x81; 32744106Sbrian#endif 32844106Sbrian } else if (IsEnabled(lcp->cfg.pap)) { 32944106Sbrian lcp->want_auth = PROTO_PAP; 33044106Sbrian lcp->want_authtype = 0; 33144106Sbrian } else { 33244106Sbrian lcp->want_auth = 0; 33344106Sbrian lcp->want_authtype = 0; 33444106Sbrian } 33544106Sbrian 33638174Sbrian if (p->type != PHYS_DIRECT) 33767912Sbrian memcpy(&lcp->want_callback, &p->dl->cfg.callback, 33867912Sbrian sizeof(struct callback)); 33938174Sbrian else 34038174Sbrian lcp->want_callback.opmask = 0; 34136285Sbrian lcp->want_lqrperiod = IsEnabled(lcp->cfg.lqr) ? 34236285Sbrian lcp->cfg.lqrperiod * 100 : 0; 34336285Sbrian } else { 34436285Sbrian lcp->his_accmap = lcp->want_accmap = 0; 34536285Sbrian lcp->his_protocomp = lcp->want_protocomp = 1; 34636285Sbrian lcp->want_magic = 0; 34736285Sbrian lcp->want_auth = 0; 34844106Sbrian lcp->want_authtype = 0; 34938174Sbrian lcp->want_callback.opmask = 0; 35036285Sbrian lcp->want_lqrperiod = 0; 35136285Sbrian } 35231514Sbrian 35336285Sbrian lcp->his_reject = lcp->my_reject = 0; 35436285Sbrian lcp->auth_iwait = lcp->auth_ineed = 0; 35536285Sbrian lcp->LcpFailedMagic = 0; 35636285Sbrian} 35731514Sbrian 35836285Sbrianstatic void 35944305SbrianLcpInitRestartCounter(struct fsm *fp, int what) 36036285Sbrian{ 36136285Sbrian /* Set fsm timer load */ 36236285Sbrian struct lcp *lcp = fsm2lcp(fp); 36331514Sbrian 36444305Sbrian fp->FsmTimer.load = lcp->cfg.fsm.timeout * SECTICKS; 36544305Sbrian switch (what) { 36644305Sbrian case FSM_REQ_TIMER: 36744305Sbrian fp->restart = lcp->cfg.fsm.maxreq; 36844305Sbrian break; 36944305Sbrian case FSM_TRM_TIMER: 37044305Sbrian fp->restart = lcp->cfg.fsm.maxtrm; 37144305Sbrian break; 37244305Sbrian default: 37344305Sbrian fp->restart = 1; 37444305Sbrian break; 37544305Sbrian } 37636285Sbrian} 37736285Sbrian 3786059Samuraistatic void 37936285SbrianLcpSendConfigReq(struct fsm *fp) 3806059Samurai{ 38136285Sbrian /* Send config REQ please */ 38236285Sbrian struct physical *p = link2physical(fp->link); 38336285Sbrian struct lcp *lcp = fsm2lcp(fp); 38436285Sbrian u_char buff[200]; 38594894Sbrian struct fsm_opt *o; 38636285Sbrian struct mp *mp; 38738814Sbrian u_int16_t proto; 38879811Sbrian u_short maxmru; 3896059Samurai 39036285Sbrian if (!p) { 39136285Sbrian log_Printf(LogERROR, "%s: LcpSendConfigReq: Not a physical link !\n", 39236285Sbrian fp->link->name); 39336285Sbrian return; 39436285Sbrian } 39536285Sbrian 39694894Sbrian o = (struct fsm_opt *)buff; 39736285Sbrian if (!physical_IsSync(p)) { 39831514Sbrian if (lcp->want_acfcomp && !REJECTED(lcp, TY_ACFCOMP)) 39994894Sbrian INC_FSM_OPT(TY_ACFCOMP, 2, o); 40031514Sbrian 40131514Sbrian if (lcp->want_protocomp && !REJECTED(lcp, TY_PROTOCOMP)) 40294894Sbrian INC_FSM_OPT(TY_PROTOCOMP, 2, o); 40331514Sbrian 40436285Sbrian if (!REJECTED(lcp, TY_ACCMAP)) { 40538814Sbrian ua_htonl(&lcp->want_accmap, o->data); 40694894Sbrian INC_FSM_OPT(TY_ACCMAP, 6, o); 40736285Sbrian } 4086059Samurai } 40931514Sbrian 41079811Sbrian maxmru = p ? physical_DeviceMTU(p) : 0; 41179811Sbrian if (lcp->cfg.max_mru && (!maxmru || maxmru > lcp->cfg.max_mru)) 41279811Sbrian maxmru = lcp->cfg.max_mru; 41379811Sbrian if (maxmru && lcp->want_mru > maxmru) { 41479811Sbrian log_Printf(LogWARN, "%s: Reducing configured MRU from %u to %u\n", 41579811Sbrian fp->link->name, lcp->want_mru, maxmru); 41679811Sbrian lcp->want_mru = maxmru; 41779811Sbrian } 41880655Sbrian if (!REJECTED(lcp, TY_MRU)) { 41938814Sbrian ua_htons(&lcp->want_mru, o->data); 42094894Sbrian INC_FSM_OPT(TY_MRU, 4, o); 42136285Sbrian } 42231514Sbrian 42336285Sbrian if (lcp->want_magic && !REJECTED(lcp, TY_MAGICNUM)) { 42438814Sbrian ua_htonl(&lcp->want_magic, o->data); 42594894Sbrian INC_FSM_OPT(TY_MAGICNUM, 6, o); 42636285Sbrian } 42731514Sbrian 42836285Sbrian if (lcp->want_lqrperiod && !REJECTED(lcp, TY_QUALPROTO)) { 42938814Sbrian proto = PROTO_LQR; 43038814Sbrian ua_htons(&proto, o->data); 43138814Sbrian ua_htonl(&lcp->want_lqrperiod, o->data + 2); 43294894Sbrian INC_FSM_OPT(TY_QUALPROTO, 8, o); 43336285Sbrian } 43431514Sbrian 4356059Samurai switch (lcp->want_auth) { 4366059Samurai case PROTO_PAP: 43738814Sbrian proto = PROTO_PAP; 43838814Sbrian ua_htons(&proto, o->data); 43994894Sbrian INC_FSM_OPT(TY_AUTHPROTO, 4, o); 4406059Samurai break; 44131514Sbrian 4426059Samurai case PROTO_CHAP: 44338814Sbrian proto = PROTO_CHAP; 44438814Sbrian ua_htons(&proto, o->data); 44544106Sbrian o->data[2] = lcp->want_authtype; 44694894Sbrian INC_FSM_OPT(TY_AUTHPROTO, 5, o); 4476059Samurai break; 4486059Samurai } 4496059Samurai 45038174Sbrian if (!REJECTED(lcp, TY_CALLBACK)) { 45138174Sbrian if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) { 45238174Sbrian *o->data = CALLBACK_AUTH; 45394894Sbrian INC_FSM_OPT(TY_CALLBACK, 3, o); 45438174Sbrian } else if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_CBCP)) { 45538174Sbrian *o->data = CALLBACK_CBCP; 45694894Sbrian INC_FSM_OPT(TY_CALLBACK, 3, o); 45738174Sbrian } else if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_E164)) { 458134789Sbrian size_t sz = strlen(lcp->want_callback.msg); 45938174Sbrian 46038174Sbrian if (sz > sizeof o->data - 1) { 46138174Sbrian sz = sizeof o->data - 1; 462134833Smarcel log_Printf(LogWARN, "Truncating E164 data to %zu octets (oops!)\n", 463134833Smarcel sz); 46438174Sbrian } 46538174Sbrian *o->data = CALLBACK_E164; 46638174Sbrian memcpy(o->data + 1, lcp->want_callback.msg, sz); 46794894Sbrian INC_FSM_OPT(TY_CALLBACK, sz + 3, o); 46838174Sbrian } 46938174Sbrian } 47038174Sbrian 47136285Sbrian if (lcp->want_mrru && !REJECTED(lcp, TY_MRRU)) { 47238814Sbrian ua_htons(&lcp->want_mrru, o->data); 47394894Sbrian INC_FSM_OPT(TY_MRRU, 4, o); 4746059Samurai 47536285Sbrian if (lcp->want_shortseq && !REJECTED(lcp, TY_SHORTSEQ)) 47694894Sbrian INC_FSM_OPT(TY_SHORTSEQ, 2, o); 47736285Sbrian } 4786059Samurai 47936285Sbrian mp = &lcp->fsm.bundle->ncp.mp; 48047858Sbrian if (mp->cfg.enddisc.class != 0 && IsEnabled(mp->cfg.negenddisc) && 48147858Sbrian !REJECTED(lcp, TY_ENDDISC)) { 48236285Sbrian *o->data = mp->cfg.enddisc.class; 48336285Sbrian memcpy(o->data+1, mp->cfg.enddisc.address, mp->cfg.enddisc.len); 48494894Sbrian INC_FSM_OPT(TY_ENDDISC, mp->cfg.enddisc.len + 3, o); 48536285Sbrian } 4866059Samurai 48747695Sbrian fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, (u_char *)o - buff, 48847695Sbrian MB_LCPOUT); 4896059Samurai} 4906059Samurai 49136285Sbrianvoid 49236285Sbrianlcp_SendProtoRej(struct lcp *lcp, u_char *option, int count) 4936059Samurai{ 49436285Sbrian /* Don't understand `option' */ 49547695Sbrian fsm_Output(&lcp->fsm, CODE_PROTOREJ, lcp->fsm.reqid, option, count, 49647695Sbrian MB_LCPOUT); 4976059Samurai} 4986059Samurai 49963484Sbrianint 50063484Sbrianlcp_SendIdentification(struct lcp *lcp) 50163484Sbrian{ 50263484Sbrian static u_char id; /* Use a private id */ 50363484Sbrian u_char msg[DEF_MRU - 3]; 50463484Sbrian const char *argv[2]; 50563484Sbrian char *exp[2]; 50663484Sbrian 50763484Sbrian if (*lcp->cfg.ident == '\0') 50863484Sbrian return 0; 50963484Sbrian 51063484Sbrian argv[0] = lcp->cfg.ident; 51163484Sbrian argv[1] = NULL; 51263484Sbrian 51363484Sbrian command_Expand(exp, 1, argv, lcp->fsm.bundle, 1, getpid()); 51463484Sbrian 51563484Sbrian ua_htonl(&lcp->want_magic, msg); 51663484Sbrian strncpy(msg + 4, exp[0], sizeof msg - 5); 51763484Sbrian msg[sizeof msg - 1] = '\0'; 51863484Sbrian 51963484Sbrian fsm_Output(&lcp->fsm, CODE_IDENT, id++, msg, 4 + strlen(msg + 4), MB_LCPOUT); 52094894Sbrian log_Printf(LogLCP, " MAGICNUM %08x\n", lcp->want_magic); 52194894Sbrian log_Printf(LogLCP, " TEXT %s\n", msg + 4); 52263484Sbrian 52385991Sbrian command_Free(1, exp); 52463484Sbrian return 1; 52563484Sbrian} 52663484Sbrian 52763484Sbrianvoid 52863484Sbrianlcp_RecvIdentification(struct lcp *lcp, char *data) 52963484Sbrian{ 53094894Sbrian log_Printf(LogLCP, " MAGICNUM %08x\n", lcp->his_magic); 53194894Sbrian log_Printf(LogLCP, " TEXT %s\n", data); 53263484Sbrian} 53363484Sbrian 5346059Samuraistatic void 535134789SbrianLcpSentTerminateReq(struct fsm *fp __unused) 5366735Samurai{ 53736285Sbrian /* Term REQ just sent by FSM */ 5386735Samurai} 5396735Samurai 5406735Samuraistatic void 54136285SbrianLcpSendTerminateAck(struct fsm *fp, u_char id) 5426059Samurai{ 54336285Sbrian /* Send Term ACK please */ 54438174Sbrian struct physical *p = link2physical(fp->link); 54538174Sbrian 54638174Sbrian if (p && p->dl->state == DATALINK_CBCP) 54738174Sbrian cbcp_ReceiveTerminateReq(p); 54838174Sbrian 54947695Sbrian fsm_Output(fp, CODE_TERMACK, id, NULL, 0, MB_LCPOUT); 5506059Samurai} 5516059Samurai 5526059Samuraistatic void 55336285SbrianLcpLayerStart(struct fsm *fp) 5546059Samurai{ 55536285Sbrian /* We're about to start up ! */ 55636285Sbrian struct lcp *lcp = fsm2lcp(fp); 5576059Samurai 55837210Sbrian log_Printf(LogLCP, "%s: LayerStart\n", fp->link->name); 55936285Sbrian lcp->LcpFailedMagic = 0; 56044305Sbrian fp->more.reqs = fp->more.naks = fp->more.rejs = lcp->cfg.fsm.maxreq * 3; 56185094Sbrian lcp->mru_req = 0; 5626059Samurai} 5636059Samurai 5646059Samuraistatic void 56536285SbrianLcpLayerFinish(struct fsm *fp) 5666059Samurai{ 56736285Sbrian /* We're now down */ 56837210Sbrian log_Printf(LogLCP, "%s: LayerFinish\n", fp->link->name); 5696059Samurai} 5706059Samurai 57136285Sbrianstatic int 57236285SbrianLcpLayerUp(struct fsm *fp) 5736059Samurai{ 57436285Sbrian /* We're now up */ 57536285Sbrian struct physical *p = link2physical(fp->link); 57636285Sbrian struct lcp *lcp = fsm2lcp(fp); 5776059Samurai 57837210Sbrian log_Printf(LogLCP, "%s: LayerUp\n", fp->link->name); 57993418Sbrian physical_SetAsyncParams(p, lcp->want_accmap, lcp->his_accmap); 58036285Sbrian lqr_Start(lcp); 58136285Sbrian hdlc_StartTimer(&p->hdlc); 58244305Sbrian fp->more.reqs = fp->more.naks = fp->more.rejs = lcp->cfg.fsm.maxreq * 3; 58344305Sbrian 58463484Sbrian lcp_SendIdentification(lcp); 58563484Sbrian 58636285Sbrian return 1; 5876059Samurai} 5886059Samurai 58936285Sbrianstatic void 59036285SbrianLcpLayerDown(struct fsm *fp) 5916059Samurai{ 59236285Sbrian /* About to come down */ 59336285Sbrian struct physical *p = link2physical(fp->link); 5946059Samurai 59537210Sbrian log_Printf(LogLCP, "%s: LayerDown\n", fp->link->name); 59636285Sbrian hdlc_StopTimer(&p->hdlc); 59736285Sbrian lqr_StopTimer(p); 59837160Sbrian lcp_Setup(fsm2lcp(fp), 0); 5996059Samurai} 6006059Samurai 60138174Sbrianstatic int 60238174SbrianE164ok(struct callback *cb, char *req, int sz) 60338174Sbrian{ 60438174Sbrian char list[sizeof cb->msg], *next; 60538174Sbrian int len; 60638174Sbrian 60738174Sbrian if (!strcmp(cb->msg, "*")) 60838174Sbrian return 1; 60938174Sbrian 61038174Sbrian strncpy(list, cb->msg, sizeof list - 1); 61138174Sbrian list[sizeof list - 1] = '\0'; 61238174Sbrian for (next = strtok(list, ","); next; next = strtok(NULL, ",")) { 61338174Sbrian len = strlen(next); 61438174Sbrian if (sz == len && !memcmp(list, req, sz)) 61538174Sbrian return 1; 61638174Sbrian } 61738174Sbrian return 0; 61838174Sbrian} 61938174Sbrian 62094894Sbrianstatic int 62194894Sbrianlcp_auth_nak(struct lcp *lcp, struct fsm_decode *dec) 62294894Sbrian{ 62394894Sbrian struct fsm_opt nak; 62494894Sbrian 62594894Sbrian nak.hdr.id = TY_AUTHPROTO; 62694894Sbrian 62794894Sbrian if (IsAccepted(lcp->cfg.pap)) { 62894894Sbrian nak.hdr.len = 4; 62994894Sbrian nak.data[0] = (unsigned char)(PROTO_PAP >> 8); 63094894Sbrian nak.data[1] = (unsigned char)PROTO_PAP; 63194894Sbrian fsm_nak(dec, &nak); 63294894Sbrian return 1; 63394894Sbrian } 63494894Sbrian 63594894Sbrian nak.hdr.len = 5; 63694894Sbrian nak.data[0] = (unsigned char)(PROTO_CHAP >> 8); 63794894Sbrian nak.data[1] = (unsigned char)PROTO_CHAP; 63894894Sbrian 63994894Sbrian if (IsAccepted(lcp->cfg.chap05)) { 64094894Sbrian nak.data[2] = 0x05; 64194894Sbrian fsm_nak(dec, &nak); 64294894Sbrian#ifndef NODES 64394894Sbrian } else if (IsAccepted(lcp->cfg.chap80nt) || 64494894Sbrian IsAccepted(lcp->cfg.chap80lm)) { 64594894Sbrian nak.data[2] = 0x80; 64694894Sbrian fsm_nak(dec, &nak); 64794894Sbrian } else if (IsAccepted(lcp->cfg.chap81)) { 64894894Sbrian nak.data[2] = 0x81; 64994894Sbrian fsm_nak(dec, &nak); 65094894Sbrian#endif 65194894Sbrian } else { 65294894Sbrian return 0; 65394894Sbrian } 65494894Sbrian 65594894Sbrian return 1; 65694894Sbrian} 65794894Sbrian 6586059Samuraistatic void 65994894SbrianLcpDecodeConfig(struct fsm *fp, u_char *cp, u_char *end, int mode_type, 66036285Sbrian struct fsm_decode *dec) 6616059Samurai{ 66236285Sbrian /* Deal with incoming PROTO_LCP */ 66336285Sbrian struct lcp *lcp = fsm2lcp(fp); 664134789Sbrian int pos, op, callback_req, chap_type; 665134789Sbrian size_t sz; 66636285Sbrian u_int32_t magic, accmap; 66779811Sbrian u_short mru, phmtu, maxmtu, maxmru, wantmtu, wantmru, proto; 668139973Sbrian struct lqrreq req; 66931514Sbrian char request[20], desc[22]; 67036285Sbrian struct mp *mp; 67136285Sbrian struct physical *p = link2physical(fp->link); 67294894Sbrian struct fsm_opt *opt, nak; 6736059Samurai 674134789Sbrian sz = 0; 675134789Sbrian op = callback_req = 0; 67638174Sbrian 677134789Sbrian while (end - cp >= (int)sizeof(opt->hdr)) { 67894894Sbrian if ((opt = fsm_readopt(&cp)) == NULL) 67994894Sbrian break; 68031514Sbrian 68194894Sbrian snprintf(request, sizeof request, " %s[%d]", protoname(opt->hdr.id), 68294894Sbrian opt->hdr.len); 6836059Samurai 68494894Sbrian switch (opt->hdr.id) { 68536285Sbrian case TY_MRRU: 68636285Sbrian mp = &lcp->fsm.bundle->ncp.mp; 68794894Sbrian ua_ntohs(opt->data, &mru); 68836285Sbrian log_Printf(LogLCP, "%s %u\n", request, mru); 68936285Sbrian 69036285Sbrian switch (mode_type) { 69136285Sbrian case MODE_REQ: 69236285Sbrian if (mp->cfg.mrru) { 69336285Sbrian if (REJECTED(lcp, TY_MRRU)) 69436285Sbrian /* Ignore his previous reject so that we REQ next time */ 69594894Sbrian lcp->his_reject &= ~(1 << opt->hdr.id); 69636285Sbrian 69778410Sbrian if (mru > MAX_MRU) { 69878410Sbrian /* Push him down to MAX_MRU */ 69978410Sbrian lcp->his_mrru = MAX_MRU; 70094894Sbrian nak.hdr.id = TY_MRRU; 70194894Sbrian nak.hdr.len = 4; 70294894Sbrian ua_htons(&lcp->his_mrru, nak.data); 70394894Sbrian fsm_nak(dec, &nak); 70478410Sbrian } else if (mru < MIN_MRU) { 70562041Sbrian /* Push him up to MIN_MRU */ 70662041Sbrian lcp->his_mrru = MIN_MRU; 70794894Sbrian nak.hdr.id = TY_MRRU; 70894894Sbrian nak.hdr.len = 4; 70994894Sbrian ua_htons(&lcp->his_mrru, nak.data); 71094894Sbrian fsm_nak(dec, &nak); 71194894Sbrian } else { 71262041Sbrian lcp->his_mrru = mru; 71394894Sbrian fsm_ack(dec, opt); 71494894Sbrian } 71594894Sbrian break; 71694894Sbrian } else { 71794894Sbrian fsm_rej(dec, opt); 71894894Sbrian lcp->my_reject |= (1 << opt->hdr.id); 71994894Sbrian } 72036285Sbrian break; 72136285Sbrian case MODE_NAK: 72236285Sbrian if (mp->cfg.mrru) { 72336285Sbrian if (REJECTED(lcp, TY_MRRU)) 72436285Sbrian /* Must have changed his mind ! */ 72594894Sbrian lcp->his_reject &= ~(1 << opt->hdr.id); 72636285Sbrian 72736285Sbrian if (mru > MAX_MRU) 72836285Sbrian lcp->want_mrru = MAX_MRU; 72936285Sbrian else if (mru < MIN_MRU) 73036285Sbrian lcp->want_mrru = MIN_MRU; 73136285Sbrian else 73236285Sbrian lcp->want_mrru = mru; 73336285Sbrian } 73436285Sbrian /* else we honour our config and don't send the suggested REQ */ 73536285Sbrian break; 73636285Sbrian case MODE_REJ: 73794894Sbrian lcp->his_reject |= (1 << opt->hdr.id); 73836285Sbrian lcp->want_mrru = 0; /* Ah well, no multilink :-( */ 73994894Sbrian break; 74036285Sbrian } 74136285Sbrian break; 74236285Sbrian 7436059Samurai case TY_MRU: 74485094Sbrian lcp->mru_req = 1; 74594894Sbrian ua_ntohs(opt->data, &mru); 74636285Sbrian log_Printf(LogLCP, "%s %d\n", request, mru); 7476059Samurai 74831034Sbrian switch (mode_type) { 7496059Samurai case MODE_REQ: 75079811Sbrian maxmtu = p ? physical_DeviceMTU(p) : 0; 75179811Sbrian if (lcp->cfg.max_mtu && (!maxmtu || maxmtu > lcp->cfg.max_mtu)) 75279811Sbrian maxmtu = lcp->cfg.max_mtu; 75380385Sbrian wantmtu = lcp->cfg.mtu; 75479811Sbrian if (maxmtu && wantmtu > maxmtu) { 75579811Sbrian log_Printf(LogWARN, "%s: Reducing configured MTU from %u to %u\n", 75679811Sbrian fp->link->name, wantmtu, maxmtu); 75779811Sbrian wantmtu = maxmtu; 75879811Sbrian } 75979811Sbrian 76079811Sbrian if (maxmtu && mru > maxmtu) { 76179811Sbrian lcp->his_mru = maxmtu; 76294894Sbrian nak.hdr.id = TY_MRU; 76394894Sbrian nak.hdr.len = 4; 76494894Sbrian ua_htons(&lcp->his_mru, nak.data); 76594894Sbrian fsm_nak(dec, &nak); 76680385Sbrian } else if (wantmtu && mru < wantmtu) { 76736285Sbrian /* Push him up to MTU or MIN_MRU */ 76879811Sbrian lcp->his_mru = wantmtu; 76994894Sbrian nak.hdr.id = TY_MRU; 77094894Sbrian nak.hdr.len = 4; 77194894Sbrian ua_htons(&lcp->his_mru, nak.data); 77294894Sbrian fsm_nak(dec, &nak); 77336285Sbrian } else { 77480385Sbrian lcp->his_mru = mru; 77594894Sbrian fsm_ack(dec, opt); 77636285Sbrian } 77794894Sbrian break; 7786059Samurai case MODE_NAK: 77979811Sbrian maxmru = p ? physical_DeviceMTU(p) : 0; 78079811Sbrian if (lcp->cfg.max_mru && (!maxmru || maxmru > lcp->cfg.max_mru)) 78179811Sbrian maxmru = lcp->cfg.max_mru; 78279811Sbrian wantmru = lcp->cfg.mru > maxmru ? maxmru : lcp->cfg.mru; 78379811Sbrian 78480385Sbrian if (wantmru && mru > wantmru) 78579811Sbrian lcp->want_mru = wantmru; 78680385Sbrian else if (mru > maxmru) 78780385Sbrian lcp->want_mru = maxmru; 78879811Sbrian else if (mru < MIN_MRU) 78936285Sbrian lcp->want_mru = MIN_MRU; 79036285Sbrian else 79136285Sbrian lcp->want_mru = mru; 79294894Sbrian break; 7936059Samurai case MODE_REJ: 79494894Sbrian lcp->his_reject |= (1 << opt->hdr.id); 795162062Sbrian /* Set the MTU to what we want anyway - the peer won't care! */ 796162062Sbrian if (lcp->his_mru > lcp->want_mru) 797162062Sbrian lcp->his_mru = lcp->want_mru; 79894894Sbrian break; 7996059Samurai } 8006059Samurai break; 80131514Sbrian 8026059Samurai case TY_ACCMAP: 80394894Sbrian ua_ntohl(opt->data, &accmap); 80436285Sbrian log_Printf(LogLCP, "%s 0x%08lx\n", request, (u_long)accmap); 8056059Samurai 80631034Sbrian switch (mode_type) { 8076059Samurai case MODE_REQ: 80894894Sbrian lcp->his_accmap = accmap; 80994894Sbrian fsm_ack(dec, opt); 81094894Sbrian break; 8116059Samurai case MODE_NAK: 81294894Sbrian lcp->want_accmap = accmap; 81394894Sbrian break; 8146059Samurai case MODE_REJ: 81594894Sbrian lcp->his_reject |= (1 << opt->hdr.id); 81694894Sbrian break; 8176059Samurai } 8186059Samurai break; 81931514Sbrian 8206059Samurai case TY_AUTHPROTO: 82194894Sbrian ua_ntohs(opt->data, &proto); 82294894Sbrian chap_type = opt->hdr.len == 5 ? opt->data[2] : 0; 82394894Sbrian 82444106Sbrian log_Printf(LogLCP, "%s 0x%04x (%s)\n", request, proto, 82594894Sbrian Auth2Nam(proto, chap_type)); 8266059Samurai 82731034Sbrian switch (mode_type) { 8286059Samurai case MODE_REQ: 82994894Sbrian switch (proto) { 83094894Sbrian case PROTO_PAP: 83194894Sbrian if (opt->hdr.len == 4 && IsAccepted(lcp->cfg.pap)) { 83294894Sbrian lcp->his_auth = proto; 83394894Sbrian lcp->his_authtype = 0; 83494894Sbrian fsm_ack(dec, opt); 83594894Sbrian } else if (!lcp_auth_nak(lcp, dec)) { 83694894Sbrian lcp->my_reject |= (1 << opt->hdr.id); 83794894Sbrian fsm_rej(dec, opt); 83894894Sbrian } 83994894Sbrian break; 84031514Sbrian 84194894Sbrian case PROTO_CHAP: 84294894Sbrian if ((chap_type == 0x05 && IsAccepted(lcp->cfg.chap05)) 84393418Sbrian#ifndef NODES 84494894Sbrian || (chap_type == 0x80 && (IsAccepted(lcp->cfg.chap80nt) || 84544106Sbrian (IsAccepted(lcp->cfg.chap80lm)))) 84694894Sbrian || (chap_type == 0x81 && IsAccepted(lcp->cfg.chap81)) 84729840Sbrian#endif 84844106Sbrian ) { 84994894Sbrian lcp->his_auth = proto; 85094894Sbrian lcp->his_authtype = chap_type; 85194894Sbrian fsm_ack(dec, opt); 85294894Sbrian } else { 85394894Sbrian#ifdef NODES 85494894Sbrian if (chap_type == 0x80) { 85544106Sbrian log_Printf(LogWARN, "CHAP 0x80 not available without DES\n"); 85694894Sbrian } else if (chap_type == 0x81) { 85767910Sbrian log_Printf(LogWARN, "CHAP 0x81 not available without DES\n"); 85867910Sbrian } else 85940480Sbrian#endif 86094894Sbrian if (chap_type != 0x05) 86144106Sbrian log_Printf(LogWARN, "%s not supported\n", 86294894Sbrian Auth2Nam(PROTO_CHAP, chap_type)); 86344106Sbrian 86494894Sbrian if (!lcp_auth_nak(lcp, dec)) { 86594894Sbrian lcp->my_reject |= (1 << opt->hdr.id); 86694894Sbrian fsm_rej(dec, opt); 86794894Sbrian } 86840480Sbrian } 86994894Sbrian break; 87031514Sbrian 87194894Sbrian default: 87294894Sbrian log_Printf(LogLCP, "%s 0x%04x - not recognised\n", 87331616Sbrian request, proto); 87494894Sbrian if (!lcp_auth_nak(lcp, dec)) { 87594894Sbrian lcp->my_reject |= (1 << opt->hdr.id); 87694894Sbrian fsm_rej(dec, opt); 87794894Sbrian } 87894894Sbrian break; 87994894Sbrian } 88094894Sbrian break; 88194894Sbrian 8826059Samurai case MODE_NAK: 88394894Sbrian switch (proto) { 88494894Sbrian case PROTO_PAP: 88544106Sbrian if (IsEnabled(lcp->cfg.pap)) { 88636285Sbrian lcp->want_auth = PROTO_PAP; 88744106Sbrian lcp->want_authtype = 0; 88844106Sbrian } else { 88936285Sbrian log_Printf(LogLCP, "Peer will only send PAP (not enabled)\n"); 89094894Sbrian lcp->his_reject |= (1 << opt->hdr.id); 89131616Sbrian } 89231616Sbrian break; 89394894Sbrian case PROTO_CHAP: 89494894Sbrian if (chap_type == 0x05 && IsEnabled(lcp->cfg.chap05)) { 89536285Sbrian lcp->want_auth = PROTO_CHAP; 89644106Sbrian lcp->want_authtype = 0x05; 89793418Sbrian#ifndef NODES 89894894Sbrian } else if (chap_type == 0x80 && (IsEnabled(lcp->cfg.chap80nt) || 89994894Sbrian IsEnabled(lcp->cfg.chap80lm))) { 90044106Sbrian lcp->want_auth = PROTO_CHAP; 90144106Sbrian lcp->want_authtype = 0x80; 90294894Sbrian } else if (chap_type == 0x81 && IsEnabled(lcp->cfg.chap81)) { 90367910Sbrian lcp->want_auth = PROTO_CHAP; 90467910Sbrian lcp->want_authtype = 0x81; 90544106Sbrian#endif 90644106Sbrian } else { 90794894Sbrian#ifdef NODES 90894894Sbrian if (chap_type == 0x80) { 90944106Sbrian log_Printf(LogLCP, "Peer will only send MSCHAP (not available" 91044106Sbrian " without DES)\n"); 91194894Sbrian } else if (chap_type == 0x81) { 91267910Sbrian log_Printf(LogLCP, "Peer will only send MSCHAPV2 (not available" 91367910Sbrian " without DES)\n"); 91467910Sbrian } else 91544106Sbrian#endif 91644305Sbrian log_Printf(LogLCP, "Peer will only send %s (not %s)\n", 91794894Sbrian Auth2Nam(PROTO_CHAP, chap_type), 91893418Sbrian#ifndef NODES 91994894Sbrian (chap_type == 0x80 || chap_type == 0x81) ? "configured" : 92044305Sbrian#endif 92144305Sbrian "supported"); 92294894Sbrian lcp->his_reject |= (1 << opt->hdr.id); 92331616Sbrian } 92431616Sbrian break; 92531616Sbrian default: 92631616Sbrian /* We've been NAK'd with something we don't understand :-( */ 92794894Sbrian lcp->his_reject |= (1 << opt->hdr.id); 92831616Sbrian break; 92931616Sbrian } 93094894Sbrian break; 93194894Sbrian 9326059Samurai case MODE_REJ: 93394894Sbrian lcp->his_reject |= (1 << opt->hdr.id); 93494894Sbrian break; 9356059Samurai } 9366059Samurai break; 93731514Sbrian 9386059Samurai case TY_QUALPROTO: 939139973Sbrian memcpy(&req, opt, sizeof req); 94037210Sbrian log_Printf(LogLCP, "%s proto %x, interval %lums\n", 941139973Sbrian request, ntohs(req.proto), (u_long)ntohl(req.period) * 10); 94231034Sbrian switch (mode_type) { 9436059Samurai case MODE_REQ: 944139973Sbrian if (ntohs(req.proto) != PROTO_LQR || !IsAccepted(lcp->cfg.lqr)) { 94594894Sbrian fsm_rej(dec, opt); 94694894Sbrian lcp->my_reject |= (1 << opt->hdr.id); 94794894Sbrian } else { 948139973Sbrian lcp->his_lqrperiod = ntohl(req.period); 94994894Sbrian if (lcp->his_lqrperiod < MIN_LQRPERIOD * 100) 95094894Sbrian lcp->his_lqrperiod = MIN_LQRPERIOD * 100; 951139973Sbrian req.period = htonl(lcp->his_lqrperiod); 95294894Sbrian fsm_ack(dec, opt); 95394894Sbrian } 95494894Sbrian break; 9556059Samurai case MODE_NAK: 956139973Sbrian lcp->want_lqrperiod = ntohl(req.period); 95794894Sbrian break; 9586059Samurai case MODE_REJ: 95994894Sbrian lcp->his_reject |= (1 << opt->hdr.id); 96094894Sbrian break; 9616059Samurai } 9626059Samurai break; 96331514Sbrian 9646059Samurai case TY_MAGICNUM: 96594894Sbrian ua_ntohl(opt->data, &magic); 96636285Sbrian log_Printf(LogLCP, "%s 0x%08lx\n", request, (u_long)magic); 9676059Samurai 96831034Sbrian switch (mode_type) { 9696059Samurai case MODE_REQ: 97094894Sbrian if (lcp->want_magic) { 97194894Sbrian /* Validate magic number */ 97294894Sbrian if (magic == lcp->want_magic) { 97394894Sbrian sigset_t emptyset; 97483404Sbrian 97594894Sbrian log_Printf(LogLCP, "Magic is same (%08lx) - %d times\n", 97636285Sbrian (u_long)magic, ++lcp->LcpFailedMagic); 97794894Sbrian lcp->want_magic = GenerateMagic(); 97894894Sbrian fsm_nak(dec, opt); 97936285Sbrian ualarm(TICKUNIT * (4 + 4 * lcp->LcpFailedMagic), 0); 98094894Sbrian sigemptyset(&emptyset); 98194894Sbrian sigsuspend(&emptyset); 98294894Sbrian } else { 98394894Sbrian lcp->his_magic = magic; 98436285Sbrian lcp->LcpFailedMagic = 0; 98594894Sbrian fsm_ack(dec, opt); 98694894Sbrian } 98794894Sbrian } else { 98894894Sbrian lcp->my_reject |= (1 << opt->hdr.id); 98994894Sbrian fsm_rej(dec, opt); 99094894Sbrian } 99194894Sbrian break; 9926059Samurai case MODE_NAK: 99394894Sbrian log_Printf(LogLCP, " Magic 0x%08lx is NAKed!\n", (u_long)magic); 99494894Sbrian lcp->want_magic = GenerateMagic(); 99594894Sbrian break; 9966059Samurai case MODE_REJ: 99794894Sbrian log_Printf(LogLCP, " Magic 0x%08x is REJected!\n", magic); 99894894Sbrian lcp->want_magic = 0; 99994894Sbrian lcp->his_reject |= (1 << opt->hdr.id); 100094894Sbrian break; 10016059Samurai } 10026059Samurai break; 100331514Sbrian 10046059Samurai case TY_PROTOCOMP: 100536285Sbrian log_Printf(LogLCP, "%s\n", request); 10066059Samurai 100731034Sbrian switch (mode_type) { 10086059Samurai case MODE_REQ: 100994894Sbrian if (IsAccepted(lcp->cfg.protocomp)) { 101094894Sbrian lcp->his_protocomp = 1; 101194894Sbrian fsm_ack(dec, opt); 101294894Sbrian } else { 10136059Samurai#ifdef OLDMST 101494894Sbrian /* MorningStar before v1.3 needs NAK */ 101594894Sbrian fsm_nak(dec, opt); 10166059Samurai#else 101794894Sbrian fsm_rej(dec, opt); 101894894Sbrian lcp->my_reject |= (1 << opt->hdr.id); 10196059Samurai#endif 102094894Sbrian } 102194894Sbrian break; 10226059Samurai case MODE_NAK: 10236059Samurai case MODE_REJ: 102494894Sbrian lcp->want_protocomp = 0; 102594894Sbrian lcp->his_reject |= (1 << opt->hdr.id); 102694894Sbrian break; 10276059Samurai } 10286059Samurai break; 102931514Sbrian 10306059Samurai case TY_ACFCOMP: 103136285Sbrian log_Printf(LogLCP, "%s\n", request); 103231034Sbrian switch (mode_type) { 10336059Samurai case MODE_REQ: 103494894Sbrian if (IsAccepted(lcp->cfg.acfcomp)) { 103594894Sbrian lcp->his_acfcomp = 1; 103694894Sbrian fsm_ack(dec, opt); 103794894Sbrian } else { 10386059Samurai#ifdef OLDMST 103994894Sbrian /* MorningStar before v1.3 needs NAK */ 104094894Sbrian fsm_nak(dec, opt); 10416059Samurai#else 104294894Sbrian fsm_rej(dec, opt); 104394894Sbrian lcp->my_reject |= (1 << opt->hdr.id); 10446059Samurai#endif 104594894Sbrian } 104694894Sbrian break; 10476059Samurai case MODE_NAK: 10486059Samurai case MODE_REJ: 104994894Sbrian lcp->want_acfcomp = 0; 105094894Sbrian lcp->his_reject |= (1 << opt->hdr.id); 105194894Sbrian break; 10526059Samurai } 10536059Samurai break; 105431514Sbrian 10556059Samurai case TY_SDP: 105636285Sbrian log_Printf(LogLCP, "%s\n", request); 105731034Sbrian switch (mode_type) { 10586059Samurai case MODE_REQ: 10596059Samurai case MODE_NAK: 10606059Samurai case MODE_REJ: 106194894Sbrian break; 10626059Samurai } 10636059Samurai break; 106431514Sbrian 106538174Sbrian case TY_CALLBACK: 1066134789Sbrian if (opt->hdr.len == 2) { 106738174Sbrian op = CALLBACK_NONE; 1068134789Sbrian sz = 0; 1069134789Sbrian } else { 107094894Sbrian op = (int)opt->data[0]; 1071134789Sbrian sz = opt->hdr.len - 3; 1072134789Sbrian } 107338174Sbrian switch (op) { 107438174Sbrian case CALLBACK_AUTH: 107538174Sbrian log_Printf(LogLCP, "%s Auth\n", request); 107638174Sbrian break; 107738174Sbrian case CALLBACK_DIALSTRING: 1078134833Smarcel log_Printf(LogLCP, "%s Dialstring %.*s\n", request, (int)sz, 107994894Sbrian opt->data + 1); 108038174Sbrian break; 108138174Sbrian case CALLBACK_LOCATION: 1082134833Smarcel log_Printf(LogLCP, "%s Location %.*s\n", request, (int)sz, 1083134833Smarcel opt->data + 1); 108438174Sbrian break; 108538174Sbrian case CALLBACK_E164: 1086134833Smarcel log_Printf(LogLCP, "%s E.164 (%.*s)\n", request, (int)sz, 1087134833Smarcel opt->data + 1); 108838174Sbrian break; 108938174Sbrian case CALLBACK_NAME: 1090134833Smarcel log_Printf(LogLCP, "%s Name %.*s\n", request, (int)sz, 1091134833Smarcel opt->data + 1); 109238174Sbrian break; 109338174Sbrian case CALLBACK_CBCP: 109438174Sbrian log_Printf(LogLCP, "%s CBCP\n", request); 109538174Sbrian break; 109638174Sbrian default: 109738174Sbrian log_Printf(LogLCP, "%s ???\n", request); 109838174Sbrian break; 109938174Sbrian } 110038174Sbrian 110138174Sbrian switch (mode_type) { 110238174Sbrian case MODE_REQ: 110338174Sbrian callback_req = 1; 110494894Sbrian if (p->type != PHYS_DIRECT) { 110594894Sbrian fsm_rej(dec, opt); 110694894Sbrian lcp->my_reject |= (1 << opt->hdr.id); 110794894Sbrian } 110894894Sbrian nak.hdr.id = opt->hdr.id; 110994894Sbrian nak.hdr.len = 3; 111038174Sbrian if ((p->dl->cfg.callback.opmask & CALLBACK_BIT(op)) && 111185095Sbrian (op != CALLBACK_AUTH || p->link.lcp.want_auth) && 111238174Sbrian (op != CALLBACK_E164 || 111394894Sbrian E164ok(&p->dl->cfg.callback, opt->data + 1, sz))) { 111494894Sbrian lcp->his_callback.opmask = CALLBACK_BIT(op); 111538174Sbrian if (sz > sizeof lcp->his_callback.msg - 1) { 111638174Sbrian sz = sizeof lcp->his_callback.msg - 1; 1117134833Smarcel log_Printf(LogWARN, "Truncating option arg to %zu octets\n", sz); 111838174Sbrian } 111994894Sbrian memcpy(lcp->his_callback.msg, opt->data + 1, sz); 112094894Sbrian lcp->his_callback.msg[sz] = '\0'; 112194894Sbrian fsm_ack(dec, opt); 112238174Sbrian } else if ((p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) && 112338174Sbrian p->link.lcp.auth_ineed) { 112494894Sbrian nak.data[0] = CALLBACK_AUTH; 112594894Sbrian fsm_nak(dec, &nak); 112638174Sbrian } else if (p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_CBCP)) { 112794894Sbrian nak.data[0] = CALLBACK_CBCP; 112894894Sbrian fsm_nak(dec, &nak); 112938174Sbrian } else if (p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_E164)) { 113094894Sbrian nak.data[0] = CALLBACK_E164; 113194894Sbrian fsm_nak(dec, &nak); 113238174Sbrian } else if (p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) { 113338174Sbrian log_Printf(LogWARN, "Cannot insist on auth callback without" 113438174Sbrian " PAP or CHAP enabled !\n"); 113594894Sbrian nak.data[0] = 2; 113694894Sbrian fsm_nak(dec, &nak); 113794894Sbrian } else { 113894894Sbrian lcp->my_reject |= (1 << opt->hdr.id); 113994894Sbrian fsm_rej(dec, opt); 114094894Sbrian } 114138174Sbrian break; 114238174Sbrian case MODE_NAK: 114342600Sbrian /* We don't do what he NAKs with, we do things in our preferred order */ 114438174Sbrian if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) 114538174Sbrian lcp->want_callback.opmask &= ~CALLBACK_BIT(CALLBACK_AUTH); 114638174Sbrian else if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_CBCP)) 114738174Sbrian lcp->want_callback.opmask &= ~CALLBACK_BIT(CALLBACK_CBCP); 114838174Sbrian else if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_E164)) 114938174Sbrian lcp->want_callback.opmask &= ~CALLBACK_BIT(CALLBACK_E164); 115038174Sbrian if (lcp->want_callback.opmask == CALLBACK_BIT(CALLBACK_NONE)) { 115138174Sbrian log_Printf(LogPHASE, "Peer NAKd all callbacks, trying none\n"); 115238174Sbrian lcp->want_callback.opmask = 0; 115338174Sbrian } else if (!lcp->want_callback.opmask) { 115438174Sbrian log_Printf(LogPHASE, "Peer NAKd last configured callback\n"); 115538174Sbrian fsm_Close(&lcp->fsm); 115638174Sbrian } 115738174Sbrian break; 115838174Sbrian case MODE_REJ: 115938174Sbrian if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_NONE)) { 116094894Sbrian lcp->his_reject |= (1 << opt->hdr.id); 116138174Sbrian lcp->want_callback.opmask = 0; 116238174Sbrian } else { 116338174Sbrian log_Printf(LogPHASE, "Peer rejected *required* callback\n"); 116438174Sbrian fsm_Close(&lcp->fsm); 116538174Sbrian } 116694894Sbrian break; 116738174Sbrian } 116838174Sbrian break; 116938174Sbrian 117036285Sbrian case TY_SHORTSEQ: 117136285Sbrian mp = &lcp->fsm.bundle->ncp.mp; 117236285Sbrian log_Printf(LogLCP, "%s\n", request); 117336285Sbrian 117436285Sbrian switch (mode_type) { 117536285Sbrian case MODE_REQ: 117636285Sbrian if (lcp->want_mrru && IsAccepted(mp->cfg.shortseq)) { 117736285Sbrian lcp->his_shortseq = 1; 117894894Sbrian fsm_ack(dec, opt); 117994894Sbrian } else { 118094894Sbrian fsm_rej(dec, opt); 118194894Sbrian lcp->my_reject |= (1 << opt->hdr.id); 118294894Sbrian } 118336285Sbrian break; 118436285Sbrian case MODE_NAK: 118536285Sbrian /* 118636285Sbrian * He's trying to get us to ask for short sequence numbers. 118736285Sbrian * We ignore the NAK and honour our configuration file instead. 118836285Sbrian */ 118936285Sbrian break; 119036285Sbrian case MODE_REJ: 119194894Sbrian lcp->his_reject |= (1 << opt->hdr.id); 119236285Sbrian lcp->want_shortseq = 0; /* For when we hit MP */ 119394894Sbrian break; 119436285Sbrian } 119536285Sbrian break; 119636285Sbrian 119736285Sbrian case TY_ENDDISC: 119847859Sbrian mp = &lcp->fsm.bundle->ncp.mp; 119936285Sbrian log_Printf(LogLCP, "%s %s\n", request, 120094894Sbrian mp_Enddisc(opt->data[0], opt->data + 1, opt->hdr.len - 3)); 120136285Sbrian switch (mode_type) { 120236285Sbrian case MODE_REQ: 120336285Sbrian if (!p) { 120436285Sbrian log_Printf(LogLCP, " ENDDISC rejected - not a physical link\n"); 120594894Sbrian fsm_rej(dec, opt); 120694894Sbrian lcp->my_reject |= (1 << opt->hdr.id); 120794894Sbrian } else if (!IsAccepted(mp->cfg.negenddisc)) { 120894894Sbrian lcp->my_reject |= (1 << opt->hdr.id); 120994894Sbrian fsm_rej(dec, opt); 1210134789Sbrian } else if (opt->hdr.len < sizeof p->dl->peer.enddisc.address + 3 && 121194894Sbrian opt->data[0] <= MAX_ENDDISC_CLASS) { 121294894Sbrian p->dl->peer.enddisc.class = opt->data[0]; 121394894Sbrian p->dl->peer.enddisc.len = opt->hdr.len - 3; 121494894Sbrian memcpy(p->dl->peer.enddisc.address, opt->data + 1, opt->hdr.len - 3); 121594894Sbrian p->dl->peer.enddisc.address[opt->hdr.len - 3] = '\0'; 121636285Sbrian /* XXX: If mp->active, compare and NAK with mp->peer ? */ 121794894Sbrian fsm_ack(dec, opt); 121836285Sbrian } else { 121994894Sbrian if (opt->data[0] > MAX_ENDDISC_CLASS) 122036285Sbrian log_Printf(LogLCP, " ENDDISC rejected - unrecognised class %d\n", 122194894Sbrian opt->data[0]); 122236285Sbrian else 122337210Sbrian log_Printf(LogLCP, " ENDDISC rejected - local max length is %ld\n", 122437210Sbrian (long)(sizeof p->dl->peer.enddisc.address - 1)); 122594894Sbrian fsm_rej(dec, opt); 122694894Sbrian lcp->my_reject |= (1 << opt->hdr.id); 122736285Sbrian } 122894894Sbrian break; 122936285Sbrian 123047858Sbrian case MODE_NAK: /* Treat this as a REJ, we don't vary our disc (yet) */ 123136285Sbrian case MODE_REJ: 123294894Sbrian lcp->his_reject |= (1 << opt->hdr.id); 123394894Sbrian break; 123436285Sbrian } 123536285Sbrian break; 123698243Sbrian 12376059Samurai default: 123831962Sbrian sz = (sizeof desc - 2) / 2; 1239134789Sbrian if (sz + 2 > opt->hdr.len) 124094894Sbrian sz = opt->hdr.len - 2; 124131514Sbrian pos = 0; 124231514Sbrian desc[0] = sz ? ' ' : '\0'; 124331514Sbrian for (pos = 0; sz--; pos++) 124494894Sbrian sprintf(desc+(pos<<1)+1, "%02x", opt->data[pos]); 124531514Sbrian 124636285Sbrian log_Printf(LogLCP, "%s%s\n", request, desc); 124731514Sbrian 124831034Sbrian if (mode_type == MODE_REQ) { 124994894Sbrian fsm_rej(dec, opt); 125094894Sbrian lcp->my_reject |= (1 << opt->hdr.id); 12516735Samurai } 12526059Samurai break; 12536059Samurai } 12546059Samurai } 125536285Sbrian 125636285Sbrian if (mode_type != MODE_NOP) { 125738174Sbrian if (mode_type == MODE_REQ && p && p->type == PHYS_DIRECT && 125838174Sbrian p->dl->cfg.callback.opmask && !callback_req && 125938174Sbrian !(p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_NONE))) { 126038174Sbrian /* We *REQUIRE* that the peer requests callback */ 126194894Sbrian nak.hdr.id = TY_CALLBACK; 126294894Sbrian nak.hdr.len = 3; 126338174Sbrian if ((p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) && 126485095Sbrian p->link.lcp.want_auth) 126594894Sbrian nak.data[0] = CALLBACK_AUTH; 126638174Sbrian else if (p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_CBCP)) 126794894Sbrian nak.data[0] = CALLBACK_CBCP; 126838174Sbrian else if (p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_E164)) 126994894Sbrian nak.data[0] = CALLBACK_E164; 127038174Sbrian else { 127138174Sbrian log_Printf(LogWARN, "Cannot insist on auth callback without" 127238174Sbrian " PAP or CHAP enabled !\n"); 127394894Sbrian nak.hdr.len = 2; /* XXX: Silly ! */ 127438174Sbrian } 127594894Sbrian fsm_nak(dec, &nak); 127638174Sbrian } 127785094Sbrian if (mode_type == MODE_REQ && !lcp->mru_req) { 127878410Sbrian mru = DEF_MRU; 127978410Sbrian phmtu = p ? physical_DeviceMTU(p) : 0; 128078410Sbrian if (phmtu && mru > phmtu) 128178410Sbrian mru = phmtu; 128278410Sbrian if (mru > lcp->cfg.max_mtu) 128378410Sbrian mru = lcp->cfg.max_mtu; 128478410Sbrian if (mru < DEF_MRU) { 128578410Sbrian /* Don't let the peer use the default MRU */ 128678410Sbrian lcp->his_mru = lcp->cfg.mtu && lcp->cfg.mtu < mru ? lcp->cfg.mtu : mru; 128794894Sbrian nak.hdr.id = TY_MRU; 128894894Sbrian nak.hdr.len = 4; 128994894Sbrian ua_htons(&lcp->his_mru, nak.data); 129094894Sbrian fsm_nak(dec, &nak); 129185094Sbrian lcp->mru_req = 1; /* Don't keep NAK'ing this */ 129278410Sbrian } 129378410Sbrian } 129494894Sbrian fsm_opt_normalise(dec); 129536285Sbrian } 12966059Samurai} 12976059Samurai 129846686Sbrianextern struct mbuf * 1299134789Sbrianlcp_Input(struct bundle *bundle __unused, struct link *l, struct mbuf *bp) 13006059Samurai{ 130136285Sbrian /* Got PROTO_LCP from link */ 130254912Sbrian m_settype(bp, MB_LCPIN); 130346686Sbrian fsm_Input(&l->lcp.fsm, bp); 130446686Sbrian return NULL; 13056059Samurai} 1306