diff options
Diffstat (limited to 'usr.sbin/ppp/lcp.c')
-rw-r--r-- | usr.sbin/ppp/lcp.c | 1305 |
1 files changed, 0 insertions, 1305 deletions
diff --git a/usr.sbin/ppp/lcp.c b/usr.sbin/ppp/lcp.c deleted file mode 100644 index cf75718..0000000 --- a/usr.sbin/ppp/lcp.c +++ /dev/null @@ -1,1305 +0,0 @@ -/*- - * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org> - * based on work by Toshiharu OHNO <tony-o@iij.ad.jp> - * Internet Initiative Japan, Inc (IIJ) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include <sys/param.h> -#include <netinet/in.h> -#include <netinet/in_systm.h> -#include <netinet/ip.h> -#include <sys/socket.h> -#include <sys/un.h> - -#include <signal.h> -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <termios.h> -#include <unistd.h> - -#include "layer.h" -#include "ua.h" -#include "defs.h" -#include "command.h" -#include "mbuf.h" -#include "log.h" -#include "timer.h" -#include "fsm.h" -#include "iplist.h" -#include "throughput.h" -#include "proto.h" -#include "descriptor.h" -#include "lqr.h" -#include "hdlc.h" -#include "lcp.h" -#include "ccp.h" -#include "async.h" -#include "link.h" -#include "physical.h" -#include "prompt.h" -#include "slcompress.h" -#include "ncpaddr.h" -#include "ipcp.h" -#include "filter.h" -#include "mp.h" -#include "chat.h" -#include "auth.h" -#include "chap.h" -#include "cbcp.h" -#include "datalink.h" -#ifndef NORADIUS -#include "radius.h" -#endif -#include "ipv6cp.h" -#include "ncp.h" -#include "bundle.h" - -/* for received LQRs */ -struct lqrreq { - struct fsm_opt_hdr hdr; - u_short proto; /* Quality protocol */ - u_int32_t period; /* Reporting interval */ -}; - -static int LcpLayerUp(struct fsm *); -static void LcpLayerDown(struct fsm *); -static void LcpLayerStart(struct fsm *); -static void LcpLayerFinish(struct fsm *); -static void LcpInitRestartCounter(struct fsm *, int); -static void LcpSendConfigReq(struct fsm *); -static void LcpSentTerminateReq(struct fsm *); -static void LcpSendTerminateAck(struct fsm *, u_char); -static void LcpDecodeConfig(struct fsm *, u_char *, u_char *, int, - struct fsm_decode *); - -static struct fsm_callbacks lcp_Callbacks = { - LcpLayerUp, - LcpLayerDown, - LcpLayerStart, - LcpLayerFinish, - LcpInitRestartCounter, - LcpSendConfigReq, - LcpSentTerminateReq, - LcpSendTerminateAck, - LcpDecodeConfig, - fsm_NullRecvResetReq, - fsm_NullRecvResetAck -}; - -static const char * const lcp_TimerNames[] = - {"LCP restart", "LCP openmode", "LCP stopped"}; - -static const char * -protoname(unsigned proto) -{ - static const char * const cftypes[] = { - /* Check out the latest ``Assigned numbers'' rfc (1700) */ - NULL, - "MRU", /* 1: Maximum-Receive-Unit */ - "ACCMAP", /* 2: Async-Control-Character-Map */ - "AUTHPROTO", /* 3: Authentication-Protocol */ - "QUALPROTO", /* 4: Quality-Protocol */ - "MAGICNUM", /* 5: Magic-Number */ - "RESERVED", /* 6: RESERVED */ - "PROTOCOMP", /* 7: Protocol-Field-Compression */ - "ACFCOMP", /* 8: Address-and-Control-Field-Compression */ - "FCSALT", /* 9: FCS-Alternatives */ - "SDP", /* 10: Self-Describing-Pad */ - "NUMMODE", /* 11: Numbered-Mode */ - "MULTIPROC", /* 12: Multi-Link-Procedure */ - "CALLBACK", /* 13: Callback */ - "CONTIME", /* 14: Connect-Time */ - "COMPFRAME", /* 15: Compound-Frames */ - "NDE", /* 16: Nominal-Data-Encapsulation */ - "MRRU", /* 17: Multilink-MRRU */ - "SHORTSEQ", /* 18: Multilink-Short-Sequence-Number-Header */ - "ENDDISC", /* 19: Multilink-Endpoint-Discriminator */ - "PROPRIETRY", /* 20: Proprietary */ - "DCEID", /* 21: DCE-Identifier */ - "MULTIPP", /* 22: Multi-Link-Plus-Procedure */ - "LDBACP", /* 23: Link Discriminator for BACP */ - }; - - if (proto > sizeof cftypes / sizeof *cftypes || cftypes[proto] == NULL) - return HexStr(proto, NULL, 0); - - return cftypes[proto]; -} - -int -lcp_ReportStatus(struct cmdargs const *arg) -{ - struct link *l; - struct lcp *lcp; - - l = command_ChooseLink(arg); - lcp = &l->lcp; - - prompt_Printf(arg->prompt, "%s: %s [%s]\n", l->name, lcp->fsm.name, - State2Nam(lcp->fsm.state)); - prompt_Printf(arg->prompt, - " his side: MRU %d, ACCMAP %08lx, PROTOCOMP %s, ACFCOMP %s,\n" - " MAGIC %08lx, MRRU %u, SHORTSEQ %s, REJECT %04x\n", - lcp->his_mru, (u_long)lcp->his_accmap, - lcp->his_protocomp ? "on" : "off", - lcp->his_acfcomp ? "on" : "off", - (u_long)lcp->his_magic, lcp->his_mrru, - lcp->his_shortseq ? "on" : "off", lcp->his_reject); - prompt_Printf(arg->prompt, - " my side: MRU %d, ACCMAP %08lx, PROTOCOMP %s, ACFCOMP %s,\n" - " MAGIC %08lx, MRRU %u, SHORTSEQ %s, REJECT %04x\n", - lcp->want_mru, (u_long)lcp->want_accmap, - lcp->want_protocomp ? "on" : "off", - lcp->want_acfcomp ? "on" : "off", - (u_long)lcp->want_magic, lcp->want_mrru, - lcp->want_shortseq ? "on" : "off", lcp->my_reject); - - if (lcp->cfg.mru) - prompt_Printf(arg->prompt, "\n Defaults: MRU = %d (max %d), ", - lcp->cfg.mru, lcp->cfg.max_mru); - else - prompt_Printf(arg->prompt, "\n Defaults: MRU = any (max %d), ", - lcp->cfg.max_mru); - if (lcp->cfg.mtu) - prompt_Printf(arg->prompt, "MTU = %d (max %d), ", - lcp->cfg.mtu, lcp->cfg.max_mtu); - else - prompt_Printf(arg->prompt, "MTU = any (max %d), ", lcp->cfg.max_mtu); - prompt_Printf(arg->prompt, "ACCMAP = %08lx\n", (u_long)lcp->cfg.accmap); - prompt_Printf(arg->prompt, " LQR period = %us, ", - lcp->cfg.lqrperiod); - prompt_Printf(arg->prompt, "Open Mode = %s", - lcp->cfg.openmode == OPEN_PASSIVE ? "passive" : "active"); - if (lcp->cfg.openmode > 0) - prompt_Printf(arg->prompt, " (delay %ds)", lcp->cfg.openmode); - prompt_Printf(arg->prompt, "\n FSM retry = %us, max %u Config" - " REQ%s, %u Term REQ%s\n", lcp->cfg.fsm.timeout, - lcp->cfg.fsm.maxreq, lcp->cfg.fsm.maxreq == 1 ? "" : "s", - lcp->cfg.fsm.maxtrm, lcp->cfg.fsm.maxtrm == 1 ? "" : "s"); - prompt_Printf(arg->prompt, " Ident: %s\n", lcp->cfg.ident); - prompt_Printf(arg->prompt, "\n Negotiation:\n"); - prompt_Printf(arg->prompt, " ACFCOMP = %s\n", - command_ShowNegval(lcp->cfg.acfcomp)); - prompt_Printf(arg->prompt, " CHAP = %s\n", - command_ShowNegval(lcp->cfg.chap05)); -#ifndef NODES - prompt_Printf(arg->prompt, " CHAP80 = %s\n", - command_ShowNegval(lcp->cfg.chap80nt)); - prompt_Printf(arg->prompt, " LANMan = %s\n", - command_ShowNegval(lcp->cfg.chap80lm)); - prompt_Printf(arg->prompt, " CHAP81 = %s\n", - command_ShowNegval(lcp->cfg.chap81)); -#endif - prompt_Printf(arg->prompt, " LQR = %s\n", - command_ShowNegval(lcp->cfg.lqr)); - prompt_Printf(arg->prompt, " LCP ECHO = %s\n", - lcp->cfg.echo ? "enabled" : "disabled"); - prompt_Printf(arg->prompt, " PAP = %s\n", - command_ShowNegval(lcp->cfg.pap)); - prompt_Printf(arg->prompt, " PROTOCOMP = %s\n", - command_ShowNegval(lcp->cfg.protocomp)); - - return 0; -} - -static u_int32_t -GenerateMagic(void) -{ - /* Generate random number which will be used as magic number */ - randinit(); - return random(); -} - -void -lcp_SetupCallbacks(struct lcp *lcp) -{ - lcp->fsm.fn = &lcp_Callbacks; - lcp->fsm.FsmTimer.name = lcp_TimerNames[0]; - lcp->fsm.OpenTimer.name = lcp_TimerNames[1]; - lcp->fsm.StoppedTimer.name = lcp_TimerNames[2]; -} - -void -lcp_Init(struct lcp *lcp, struct bundle *bundle, struct link *l, - const struct fsm_parent *parent) -{ - /* Initialise ourselves */ - int mincode = parent ? 1 : LCP_MINMPCODE; - - fsm_Init(&lcp->fsm, "LCP", PROTO_LCP, mincode, LCP_MAXCODE, LogLCP, - bundle, l, parent, &lcp_Callbacks, lcp_TimerNames); - - lcp->cfg.mru = 0; - lcp->cfg.max_mru = MAX_MRU; - lcp->cfg.mtu = 0; - lcp->cfg.max_mtu = MAX_MTU; - lcp->cfg.accmap = 0; - lcp->cfg.openmode = 1; - lcp->cfg.lqrperiod = DEF_LQRPERIOD; - lcp->cfg.fsm.timeout = DEF_FSMRETRY; - lcp->cfg.fsm.maxreq = DEF_FSMTRIES; - lcp->cfg.fsm.maxtrm = DEF_FSMTRIES; - - lcp->cfg.acfcomp = NEG_ENABLED|NEG_ACCEPTED; - lcp->cfg.chap05 = NEG_ACCEPTED; -#ifndef NODES - lcp->cfg.chap80nt = NEG_ACCEPTED; - lcp->cfg.chap80lm = 0; - lcp->cfg.chap81 = NEG_ACCEPTED; -#endif - lcp->cfg.lqr = NEG_ACCEPTED; - lcp->cfg.echo = 0; - lcp->cfg.pap = NEG_ACCEPTED; - lcp->cfg.protocomp = NEG_ENABLED|NEG_ACCEPTED; - *lcp->cfg.ident = '\0'; - - lcp_Setup(lcp, lcp->cfg.openmode); -} - -void -lcp_Setup(struct lcp *lcp, int openmode) -{ - struct physical *p = link2physical(lcp->fsm.link); - - lcp->fsm.open_mode = openmode; - - lcp->his_mru = DEF_MRU; - lcp->his_mrru = 0; - lcp->his_magic = 0; - lcp->his_lqrperiod = 0; - lcp->his_acfcomp = 0; - lcp->his_auth = 0; - lcp->his_authtype = 0; - lcp->his_callback.opmask = 0; - lcp->his_shortseq = 0; - lcp->mru_req = 0; - - if ((lcp->want_mru = lcp->cfg.mru) == 0) - lcp->want_mru = DEF_MRU; - lcp->want_mrru = lcp->fsm.bundle->ncp.mp.cfg.mrru; - lcp->want_shortseq = IsEnabled(lcp->fsm.bundle->ncp.mp.cfg.shortseq) ? 1 : 0; - lcp->want_acfcomp = IsEnabled(lcp->cfg.acfcomp) ? 1 : 0; - - if (lcp->fsm.parent) { - lcp->his_accmap = 0xffffffff; - lcp->want_accmap = lcp->cfg.accmap; - lcp->his_protocomp = 0; - lcp->want_protocomp = IsEnabled(lcp->cfg.protocomp) ? 1 : 0; - lcp->want_magic = GenerateMagic(); - - if (IsEnabled(lcp->cfg.chap05)) { - lcp->want_auth = PROTO_CHAP; - lcp->want_authtype = 0x05; -#ifndef NODES - } else if (IsEnabled(lcp->cfg.chap80nt) || - IsEnabled(lcp->cfg.chap80lm)) { - lcp->want_auth = PROTO_CHAP; - lcp->want_authtype = 0x80; - } else if (IsEnabled(lcp->cfg.chap81)) { - lcp->want_auth = PROTO_CHAP; - lcp->want_authtype = 0x81; -#endif - } else if (IsEnabled(lcp->cfg.pap)) { - lcp->want_auth = PROTO_PAP; - lcp->want_authtype = 0; - } else { - lcp->want_auth = 0; - lcp->want_authtype = 0; - } - - if (p->type != PHYS_DIRECT) - memcpy(&lcp->want_callback, &p->dl->cfg.callback, - sizeof(struct callback)); - else - lcp->want_callback.opmask = 0; - lcp->want_lqrperiod = IsEnabled(lcp->cfg.lqr) ? - lcp->cfg.lqrperiod * 100 : 0; - } else { - lcp->his_accmap = lcp->want_accmap = 0; - lcp->his_protocomp = lcp->want_protocomp = 1; - lcp->want_magic = 0; - lcp->want_auth = 0; - lcp->want_authtype = 0; - lcp->want_callback.opmask = 0; - lcp->want_lqrperiod = 0; - } - - lcp->his_reject = lcp->my_reject = 0; - lcp->auth_iwait = lcp->auth_ineed = 0; - lcp->LcpFailedMagic = 0; -} - -static void -LcpInitRestartCounter(struct fsm *fp, int what) -{ - /* Set fsm timer load */ - struct lcp *lcp = fsm2lcp(fp); - - fp->FsmTimer.load = lcp->cfg.fsm.timeout * SECTICKS; - switch (what) { - case FSM_REQ_TIMER: - fp->restart = lcp->cfg.fsm.maxreq; - break; - case FSM_TRM_TIMER: - fp->restart = lcp->cfg.fsm.maxtrm; - break; - default: - fp->restart = 1; - break; - } -} - -static void -LcpSendConfigReq(struct fsm *fp) -{ - /* Send config REQ please */ - struct physical *p = link2physical(fp->link); - struct lcp *lcp = fsm2lcp(fp); - u_char buff[200]; - struct fsm_opt *o; - struct mp *mp; - u_int16_t proto; - u_short maxmru; - - if (!p) { - log_Printf(LogERROR, "%s: LcpSendConfigReq: Not a physical link !\n", - fp->link->name); - return; - } - - o = (struct fsm_opt *)buff; - if (!physical_IsSync(p)) { - if (lcp->want_acfcomp && !REJECTED(lcp, TY_ACFCOMP)) - INC_FSM_OPT(TY_ACFCOMP, 2, o); - - if (lcp->want_protocomp && !REJECTED(lcp, TY_PROTOCOMP)) - INC_FSM_OPT(TY_PROTOCOMP, 2, o); - - if (!REJECTED(lcp, TY_ACCMAP)) { - ua_htonl(&lcp->want_accmap, o->data); - INC_FSM_OPT(TY_ACCMAP, 6, o); - } - } - - maxmru = p ? physical_DeviceMTU(p) : 0; - if (lcp->cfg.max_mru && (!maxmru || maxmru > lcp->cfg.max_mru)) - maxmru = lcp->cfg.max_mru; - if (maxmru && lcp->want_mru > maxmru) { - log_Printf(LogWARN, "%s: Reducing configured MRU from %u to %u\n", - fp->link->name, lcp->want_mru, maxmru); - lcp->want_mru = maxmru; - } - if (!REJECTED(lcp, TY_MRU)) { - ua_htons(&lcp->want_mru, o->data); - INC_FSM_OPT(TY_MRU, 4, o); - } - - if (lcp->want_magic && !REJECTED(lcp, TY_MAGICNUM)) { - ua_htonl(&lcp->want_magic, o->data); - INC_FSM_OPT(TY_MAGICNUM, 6, o); - } - - if (lcp->want_lqrperiod && !REJECTED(lcp, TY_QUALPROTO)) { - proto = PROTO_LQR; - ua_htons(&proto, o->data); - ua_htonl(&lcp->want_lqrperiod, o->data + 2); - INC_FSM_OPT(TY_QUALPROTO, 8, o); - } - - switch (lcp->want_auth) { - case PROTO_PAP: - proto = PROTO_PAP; - ua_htons(&proto, o->data); - INC_FSM_OPT(TY_AUTHPROTO, 4, o); - break; - - case PROTO_CHAP: - proto = PROTO_CHAP; - ua_htons(&proto, o->data); - o->data[2] = lcp->want_authtype; - INC_FSM_OPT(TY_AUTHPROTO, 5, o); - break; - } - - if (!REJECTED(lcp, TY_CALLBACK)) { - if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) { - *o->data = CALLBACK_AUTH; - INC_FSM_OPT(TY_CALLBACK, 3, o); - } else if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_CBCP)) { - *o->data = CALLBACK_CBCP; - INC_FSM_OPT(TY_CALLBACK, 3, o); - } else if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_E164)) { - size_t sz = strlen(lcp->want_callback.msg); - - if (sz > sizeof o->data - 1) { - sz = sizeof o->data - 1; - log_Printf(LogWARN, "Truncating E164 data to %zu octets (oops!)\n", - sz); - } - *o->data = CALLBACK_E164; - memcpy(o->data + 1, lcp->want_callback.msg, sz); - INC_FSM_OPT(TY_CALLBACK, sz + 3, o); - } - } - - if (lcp->want_mrru && !REJECTED(lcp, TY_MRRU)) { - ua_htons(&lcp->want_mrru, o->data); - INC_FSM_OPT(TY_MRRU, 4, o); - - if (lcp->want_shortseq && !REJECTED(lcp, TY_SHORTSEQ)) - INC_FSM_OPT(TY_SHORTSEQ, 2, o); - } - - mp = &lcp->fsm.bundle->ncp.mp; - if (mp->cfg.enddisc.class != 0 && IsEnabled(mp->cfg.negenddisc) && - !REJECTED(lcp, TY_ENDDISC)) { - *o->data = mp->cfg.enddisc.class; - memcpy(o->data+1, mp->cfg.enddisc.address, mp->cfg.enddisc.len); - INC_FSM_OPT(TY_ENDDISC, mp->cfg.enddisc.len + 3, o); - } - - fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, (u_char *)o - buff, - MB_LCPOUT); -} - -void -lcp_SendProtoRej(struct lcp *lcp, u_char *option, int count) -{ - /* Don't understand `option' */ - fsm_Output(&lcp->fsm, CODE_PROTOREJ, lcp->fsm.reqid, option, count, - MB_LCPOUT); -} - -int -lcp_SendIdentification(struct lcp *lcp) -{ - static u_char id; /* Use a private id */ - u_char msg[DEF_MRU - 3]; - const char *argv[2]; - char *exp[2]; - - if (*lcp->cfg.ident == '\0') - return 0; - - argv[0] = lcp->cfg.ident; - argv[1] = NULL; - - command_Expand(exp, 1, argv, lcp->fsm.bundle, 1, getpid()); - - ua_htonl(&lcp->want_magic, msg); - strncpy(msg + 4, exp[0], sizeof msg - 5); - msg[sizeof msg - 1] = '\0'; - - fsm_Output(&lcp->fsm, CODE_IDENT, id++, msg, 4 + strlen(msg + 4), MB_LCPOUT); - log_Printf(LogLCP, " MAGICNUM %08x\n", lcp->want_magic); - log_Printf(LogLCP, " TEXT %s\n", msg + 4); - - command_Free(1, exp); - return 1; -} - -void -lcp_RecvIdentification(struct lcp *lcp, char *data) -{ - log_Printf(LogLCP, " MAGICNUM %08x\n", lcp->his_magic); - log_Printf(LogLCP, " TEXT %s\n", data); -} - -static void -LcpSentTerminateReq(struct fsm *fp __unused) -{ - /* Term REQ just sent by FSM */ -} - -static void -LcpSendTerminateAck(struct fsm *fp, u_char id) -{ - /* Send Term ACK please */ - struct physical *p = link2physical(fp->link); - - if (p && p->dl->state == DATALINK_CBCP) - cbcp_ReceiveTerminateReq(p); - - fsm_Output(fp, CODE_TERMACK, id, NULL, 0, MB_LCPOUT); -} - -static void -LcpLayerStart(struct fsm *fp) -{ - /* We're about to start up ! */ - struct lcp *lcp = fsm2lcp(fp); - - log_Printf(LogLCP, "%s: LayerStart\n", fp->link->name); - lcp->LcpFailedMagic = 0; - fp->more.reqs = fp->more.naks = fp->more.rejs = lcp->cfg.fsm.maxreq * 3; - lcp->mru_req = 0; -} - -static void -LcpLayerFinish(struct fsm *fp) -{ - /* We're now down */ - log_Printf(LogLCP, "%s: LayerFinish\n", fp->link->name); -} - -static int -LcpLayerUp(struct fsm *fp) -{ - /* We're now up */ - struct physical *p = link2physical(fp->link); - struct lcp *lcp = fsm2lcp(fp); - - log_Printf(LogLCP, "%s: LayerUp\n", fp->link->name); - physical_SetAsyncParams(p, lcp->want_accmap, lcp->his_accmap); - lqr_Start(lcp); - hdlc_StartTimer(&p->hdlc); - fp->more.reqs = fp->more.naks = fp->more.rejs = lcp->cfg.fsm.maxreq * 3; - - lcp_SendIdentification(lcp); - - return 1; -} - -static void -LcpLayerDown(struct fsm *fp) -{ - /* About to come down */ - struct physical *p = link2physical(fp->link); - - log_Printf(LogLCP, "%s: LayerDown\n", fp->link->name); - hdlc_StopTimer(&p->hdlc); - lqr_StopTimer(p); - lcp_Setup(fsm2lcp(fp), 0); -} - -static int -E164ok(struct callback *cb, char *req, int sz) -{ - char list[sizeof cb->msg], *next; - int len; - - if (!strcmp(cb->msg, "*")) - return 1; - - strncpy(list, cb->msg, sizeof list - 1); - list[sizeof list - 1] = '\0'; - for (next = strtok(list, ","); next; next = strtok(NULL, ",")) { - len = strlen(next); - if (sz == len && !memcmp(list, req, sz)) - return 1; - } - return 0; -} - -static int -lcp_auth_nak(struct lcp *lcp, struct fsm_decode *dec) -{ - struct fsm_opt nak; - - nak.hdr.id = TY_AUTHPROTO; - - if (IsAccepted(lcp->cfg.pap)) { - nak.hdr.len = 4; - nak.data[0] = (unsigned char)(PROTO_PAP >> 8); - nak.data[1] = (unsigned char)PROTO_PAP; - fsm_nak(dec, &nak); - return 1; - } - - nak.hdr.len = 5; - nak.data[0] = (unsigned char)(PROTO_CHAP >> 8); - nak.data[1] = (unsigned char)PROTO_CHAP; - - if (IsAccepted(lcp->cfg.chap05)) { - nak.data[2] = 0x05; - fsm_nak(dec, &nak); -#ifndef NODES - } else if (IsAccepted(lcp->cfg.chap80nt) || - IsAccepted(lcp->cfg.chap80lm)) { - nak.data[2] = 0x80; - fsm_nak(dec, &nak); - } else if (IsAccepted(lcp->cfg.chap81)) { - nak.data[2] = 0x81; - fsm_nak(dec, &nak); -#endif - } else { - return 0; - } - - return 1; -} - -static void -LcpDecodeConfig(struct fsm *fp, u_char *cp, u_char *end, int mode_type, - struct fsm_decode *dec) -{ - /* Deal with incoming PROTO_LCP */ - struct lcp *lcp = fsm2lcp(fp); - int pos, op, callback_req, chap_type; - size_t sz; - u_int32_t magic, accmap; - u_short mru, phmtu, maxmtu, maxmru, wantmtu, wantmru, proto; - struct lqrreq req; - char request[20], desc[22]; - struct mp *mp; - struct physical *p = link2physical(fp->link); - struct fsm_opt *opt, nak; - - sz = 0; - op = callback_req = 0; - - while (end - cp >= (int)sizeof(opt->hdr)) { - if ((opt = fsm_readopt(&cp)) == NULL) - break; - - snprintf(request, sizeof request, " %s[%d]", protoname(opt->hdr.id), - opt->hdr.len); - - switch (opt->hdr.id) { - case TY_MRRU: - mp = &lcp->fsm.bundle->ncp.mp; - ua_ntohs(opt->data, &mru); - log_Printf(LogLCP, "%s %u\n", request, mru); - - switch (mode_type) { - case MODE_REQ: - if (mp->cfg.mrru) { - if (REJECTED(lcp, TY_MRRU)) - /* Ignore his previous reject so that we REQ next time */ - lcp->his_reject &= ~(1 << opt->hdr.id); - - if (mru > MAX_MRU) { - /* Push him down to MAX_MRU */ - lcp->his_mrru = MAX_MRU; - nak.hdr.id = TY_MRRU; - nak.hdr.len = 4; - ua_htons(&lcp->his_mrru, nak.data); - fsm_nak(dec, &nak); - } else if (mru < MIN_MRU) { - /* Push him up to MIN_MRU */ - lcp->his_mrru = MIN_MRU; - nak.hdr.id = TY_MRRU; - nak.hdr.len = 4; - ua_htons(&lcp->his_mrru, nak.data); - fsm_nak(dec, &nak); - } else { - lcp->his_mrru = mru; - fsm_ack(dec, opt); - } - break; - } else { - fsm_rej(dec, opt); - lcp->my_reject |= (1 << opt->hdr.id); - } - break; - case MODE_NAK: - if (mp->cfg.mrru) { - if (REJECTED(lcp, TY_MRRU)) - /* Must have changed his mind ! */ - lcp->his_reject &= ~(1 << opt->hdr.id); - - if (mru > MAX_MRU) - lcp->want_mrru = MAX_MRU; - else if (mru < MIN_MRU) - lcp->want_mrru = MIN_MRU; - else - lcp->want_mrru = mru; - } - /* else we honour our config and don't send the suggested REQ */ - break; - case MODE_REJ: - lcp->his_reject |= (1 << opt->hdr.id); - lcp->want_mrru = 0; /* Ah well, no multilink :-( */ - break; - } - break; - - case TY_MRU: - lcp->mru_req = 1; - ua_ntohs(opt->data, &mru); - log_Printf(LogLCP, "%s %d\n", request, mru); - - switch (mode_type) { - case MODE_REQ: - maxmtu = p ? physical_DeviceMTU(p) : 0; - if (lcp->cfg.max_mtu && (!maxmtu || maxmtu > lcp->cfg.max_mtu)) - maxmtu = lcp->cfg.max_mtu; - wantmtu = lcp->cfg.mtu; - if (maxmtu && wantmtu > maxmtu) { - log_Printf(LogWARN, "%s: Reducing configured MTU from %u to %u\n", - fp->link->name, wantmtu, maxmtu); - wantmtu = maxmtu; - } - - if (maxmtu && mru > maxmtu) { - lcp->his_mru = maxmtu; - nak.hdr.id = TY_MRU; - nak.hdr.len = 4; - ua_htons(&lcp->his_mru, nak.data); - fsm_nak(dec, &nak); - } else if (wantmtu && mru < wantmtu) { - /* Push him up to MTU or MIN_MRU */ - lcp->his_mru = wantmtu; - nak.hdr.id = TY_MRU; - nak.hdr.len = 4; - ua_htons(&lcp->his_mru, nak.data); - fsm_nak(dec, &nak); - } else { - lcp->his_mru = mru; - fsm_ack(dec, opt); - } - break; - case MODE_NAK: - maxmru = p ? physical_DeviceMTU(p) : 0; - if (lcp->cfg.max_mru && (!maxmru || maxmru > lcp->cfg.max_mru)) - maxmru = lcp->cfg.max_mru; - wantmru = lcp->cfg.mru > maxmru ? maxmru : lcp->cfg.mru; - - if (wantmru && mru > wantmru) - lcp->want_mru = wantmru; - else if (mru > maxmru) - lcp->want_mru = maxmru; - else if (mru < MIN_MRU) - lcp->want_mru = MIN_MRU; - else - lcp->want_mru = mru; - break; - case MODE_REJ: - lcp->his_reject |= (1 << opt->hdr.id); - /* Set the MTU to what we want anyway - the peer won't care! */ - if (lcp->his_mru > lcp->want_mru) - lcp->his_mru = lcp->want_mru; - break; - } - break; - - case TY_ACCMAP: - ua_ntohl(opt->data, &accmap); - log_Printf(LogLCP, "%s 0x%08lx\n", request, (u_long)accmap); - - switch (mode_type) { - case MODE_REQ: - lcp->his_accmap = accmap; - fsm_ack(dec, opt); - break; - case MODE_NAK: - lcp->want_accmap = accmap; - break; - case MODE_REJ: - lcp->his_reject |= (1 << opt->hdr.id); - break; - } - break; - - case TY_AUTHPROTO: - ua_ntohs(opt->data, &proto); - chap_type = opt->hdr.len == 5 ? opt->data[2] : 0; - - log_Printf(LogLCP, "%s 0x%04x (%s)\n", request, proto, - Auth2Nam(proto, chap_type)); - - switch (mode_type) { - case MODE_REQ: - switch (proto) { - case PROTO_PAP: - if (opt->hdr.len == 4 && IsAccepted(lcp->cfg.pap)) { - lcp->his_auth = proto; - lcp->his_authtype = 0; - fsm_ack(dec, opt); - } else if (!lcp_auth_nak(lcp, dec)) { - lcp->my_reject |= (1 << opt->hdr.id); - fsm_rej(dec, opt); - } - break; - - case PROTO_CHAP: - if ((chap_type == 0x05 && IsAccepted(lcp->cfg.chap05)) -#ifndef NODES - || (chap_type == 0x80 && (IsAccepted(lcp->cfg.chap80nt) || - (IsAccepted(lcp->cfg.chap80lm)))) - || (chap_type == 0x81 && IsAccepted(lcp->cfg.chap81)) -#endif - ) { - lcp->his_auth = proto; - lcp->his_authtype = chap_type; - fsm_ack(dec, opt); - } else { -#ifdef NODES - if (chap_type == 0x80) { - log_Printf(LogWARN, "CHAP 0x80 not available without DES\n"); - } else if (chap_type == 0x81) { - log_Printf(LogWARN, "CHAP 0x81 not available without DES\n"); - } else -#endif - if (chap_type != 0x05) - log_Printf(LogWARN, "%s not supported\n", - Auth2Nam(PROTO_CHAP, chap_type)); - - if (!lcp_auth_nak(lcp, dec)) { - lcp->my_reject |= (1 << opt->hdr.id); - fsm_rej(dec, opt); - } - } - break; - - default: - log_Printf(LogLCP, "%s 0x%04x - not recognised\n", - request, proto); - if (!lcp_auth_nak(lcp, dec)) { - lcp->my_reject |= (1 << opt->hdr.id); - fsm_rej(dec, opt); - } - break; - } - break; - - case MODE_NAK: - switch (proto) { - case PROTO_PAP: - if (IsEnabled(lcp->cfg.pap)) { - lcp->want_auth = PROTO_PAP; - lcp->want_authtype = 0; - } else { - log_Printf(LogLCP, "Peer will only send PAP (not enabled)\n"); - lcp->his_reject |= (1 << opt->hdr.id); - } - break; - case PROTO_CHAP: - if (chap_type == 0x05 && IsEnabled(lcp->cfg.chap05)) { - lcp->want_auth = PROTO_CHAP; - lcp->want_authtype = 0x05; -#ifndef NODES - } else if (chap_type == 0x80 && (IsEnabled(lcp->cfg.chap80nt) || - IsEnabled(lcp->cfg.chap80lm))) { - lcp->want_auth = PROTO_CHAP; - lcp->want_authtype = 0x80; - } else if (chap_type == 0x81 && IsEnabled(lcp->cfg.chap81)) { - lcp->want_auth = PROTO_CHAP; - lcp->want_authtype = 0x81; -#endif - } else { -#ifdef NODES - if (chap_type == 0x80) { - log_Printf(LogLCP, "Peer will only send MSCHAP (not available" - " without DES)\n"); - } else if (chap_type == 0x81) { - log_Printf(LogLCP, "Peer will only send MSCHAPV2 (not available" - " without DES)\n"); - } else -#endif - log_Printf(LogLCP, "Peer will only send %s (not %s)\n", - Auth2Nam(PROTO_CHAP, chap_type), -#ifndef NODES - (chap_type == 0x80 || chap_type == 0x81) ? "configured" : -#endif - "supported"); - lcp->his_reject |= (1 << opt->hdr.id); - } - break; - default: - /* We've been NAK'd with something we don't understand :-( */ - lcp->his_reject |= (1 << opt->hdr.id); - break; - } - break; - - case MODE_REJ: - lcp->his_reject |= (1 << opt->hdr.id); - break; - } - break; - - case TY_QUALPROTO: - memcpy(&req, opt, sizeof req); - log_Printf(LogLCP, "%s proto %x, interval %lums\n", - request, ntohs(req.proto), (u_long)ntohl(req.period) * 10); - switch (mode_type) { - case MODE_REQ: - if (ntohs(req.proto) != PROTO_LQR || !IsAccepted(lcp->cfg.lqr)) { - fsm_rej(dec, opt); - lcp->my_reject |= (1 << opt->hdr.id); - } else { - lcp->his_lqrperiod = ntohl(req.period); - if (lcp->his_lqrperiod < MIN_LQRPERIOD * 100) - lcp->his_lqrperiod = MIN_LQRPERIOD * 100; - req.period = htonl(lcp->his_lqrperiod); - fsm_ack(dec, opt); - } - break; - case MODE_NAK: - lcp->want_lqrperiod = ntohl(req.period); - break; - case MODE_REJ: - lcp->his_reject |= (1 << opt->hdr.id); - break; - } - break; - - case TY_MAGICNUM: - ua_ntohl(opt->data, &magic); - log_Printf(LogLCP, "%s 0x%08lx\n", request, (u_long)magic); - - switch (mode_type) { - case MODE_REQ: - if (lcp->want_magic) { - /* Validate magic number */ - if (magic == lcp->want_magic) { - sigset_t emptyset; - - log_Printf(LogLCP, "Magic is same (%08lx) - %d times\n", - (u_long)magic, ++lcp->LcpFailedMagic); - lcp->want_magic = GenerateMagic(); - fsm_nak(dec, opt); - ualarm(TICKUNIT * (4 + 4 * lcp->LcpFailedMagic), 0); - sigemptyset(&emptyset); - sigsuspend(&emptyset); - } else { - lcp->his_magic = magic; - lcp->LcpFailedMagic = 0; - fsm_ack(dec, opt); - } - } else { - lcp->my_reject |= (1 << opt->hdr.id); - fsm_rej(dec, opt); - } - break; - case MODE_NAK: - log_Printf(LogLCP, " Magic 0x%08lx is NAKed!\n", (u_long)magic); - lcp->want_magic = GenerateMagic(); - break; - case MODE_REJ: - log_Printf(LogLCP, " Magic 0x%08x is REJected!\n", magic); - lcp->want_magic = 0; - lcp->his_reject |= (1 << opt->hdr.id); - break; - } - break; - - case TY_PROTOCOMP: - log_Printf(LogLCP, "%s\n", request); - - switch (mode_type) { - case MODE_REQ: - if (IsAccepted(lcp->cfg.protocomp)) { - lcp->his_protocomp = 1; - fsm_ack(dec, opt); - } else { -#ifdef OLDMST - /* MorningStar before v1.3 needs NAK */ - fsm_nak(dec, opt); -#else - fsm_rej(dec, opt); - lcp->my_reject |= (1 << opt->hdr.id); -#endif - } - break; - case MODE_NAK: - case MODE_REJ: - lcp->want_protocomp = 0; - lcp->his_reject |= (1 << opt->hdr.id); - break; - } - break; - - case TY_ACFCOMP: - log_Printf(LogLCP, "%s\n", request); - switch (mode_type) { - case MODE_REQ: - if (IsAccepted(lcp->cfg.acfcomp)) { - lcp->his_acfcomp = 1; - fsm_ack(dec, opt); - } else { -#ifdef OLDMST - /* MorningStar before v1.3 needs NAK */ - fsm_nak(dec, opt); -#else - fsm_rej(dec, opt); - lcp->my_reject |= (1 << opt->hdr.id); -#endif - } - break; - case MODE_NAK: - case MODE_REJ: - lcp->want_acfcomp = 0; - lcp->his_reject |= (1 << opt->hdr.id); - break; - } - break; - - case TY_SDP: - log_Printf(LogLCP, "%s\n", request); - switch (mode_type) { - case MODE_REQ: - case MODE_NAK: - case MODE_REJ: - break; - } - break; - - case TY_CALLBACK: - if (opt->hdr.len == 2) { - op = CALLBACK_NONE; - sz = 0; - } else { - op = (int)opt->data[0]; - sz = opt->hdr.len - 3; - } - switch (op) { - case CALLBACK_AUTH: - log_Printf(LogLCP, "%s Auth\n", request); - break; - case CALLBACK_DIALSTRING: - log_Printf(LogLCP, "%s Dialstring %.*s\n", request, (int)sz, - opt->data + 1); - break; - case CALLBACK_LOCATION: - log_Printf(LogLCP, "%s Location %.*s\n", request, (int)sz, - opt->data + 1); - break; - case CALLBACK_E164: - log_Printf(LogLCP, "%s E.164 (%.*s)\n", request, (int)sz, - opt->data + 1); - break; - case CALLBACK_NAME: - log_Printf(LogLCP, "%s Name %.*s\n", request, (int)sz, - opt->data + 1); - break; - case CALLBACK_CBCP: - log_Printf(LogLCP, "%s CBCP\n", request); - break; - default: - log_Printf(LogLCP, "%s ???\n", request); - break; - } - - switch (mode_type) { - case MODE_REQ: - callback_req = 1; - if (p->type != PHYS_DIRECT) { - fsm_rej(dec, opt); - lcp->my_reject |= (1 << opt->hdr.id); - } - nak.hdr.id = opt->hdr.id; - nak.hdr.len = 3; - if ((p->dl->cfg.callback.opmask & CALLBACK_BIT(op)) && - (op != CALLBACK_AUTH || p->link.lcp.want_auth) && - (op != CALLBACK_E164 || - E164ok(&p->dl->cfg.callback, opt->data + 1, sz))) { - lcp->his_callback.opmask = CALLBACK_BIT(op); - if (sz > sizeof lcp->his_callback.msg - 1) { - sz = sizeof lcp->his_callback.msg - 1; - log_Printf(LogWARN, "Truncating option arg to %zu octets\n", sz); - } - memcpy(lcp->his_callback.msg, opt->data + 1, sz); - lcp->his_callback.msg[sz] = '\0'; - fsm_ack(dec, opt); - } else if ((p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) && - p->link.lcp.auth_ineed) { - nak.data[0] = CALLBACK_AUTH; - fsm_nak(dec, &nak); - } else if (p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_CBCP)) { - nak.data[0] = CALLBACK_CBCP; - fsm_nak(dec, &nak); - } else if (p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_E164)) { - nak.data[0] = CALLBACK_E164; - fsm_nak(dec, &nak); - } else if (p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) { - log_Printf(LogWARN, "Cannot insist on auth callback without" - " PAP or CHAP enabled !\n"); - nak.data[0] = 2; - fsm_nak(dec, &nak); - } else { - lcp->my_reject |= (1 << opt->hdr.id); - fsm_rej(dec, opt); - } - break; - case MODE_NAK: - /* We don't do what he NAKs with, we do things in our preferred order */ - if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) - lcp->want_callback.opmask &= ~CALLBACK_BIT(CALLBACK_AUTH); - else if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_CBCP)) - lcp->want_callback.opmask &= ~CALLBACK_BIT(CALLBACK_CBCP); - else if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_E164)) - lcp->want_callback.opmask &= ~CALLBACK_BIT(CALLBACK_E164); - if (lcp->want_callback.opmask == CALLBACK_BIT(CALLBACK_NONE)) { - log_Printf(LogPHASE, "Peer NAKd all callbacks, trying none\n"); - lcp->want_callback.opmask = 0; - } else if (!lcp->want_callback.opmask) { - log_Printf(LogPHASE, "Peer NAKd last configured callback\n"); - fsm_Close(&lcp->fsm); - } - break; - case MODE_REJ: - if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_NONE)) { - lcp->his_reject |= (1 << opt->hdr.id); - lcp->want_callback.opmask = 0; - } else { - log_Printf(LogPHASE, "Peer rejected *required* callback\n"); - fsm_Close(&lcp->fsm); - } - break; - } - break; - - case TY_SHORTSEQ: - mp = &lcp->fsm.bundle->ncp.mp; - log_Printf(LogLCP, "%s\n", request); - - switch (mode_type) { - case MODE_REQ: - if (lcp->want_mrru && IsAccepted(mp->cfg.shortseq)) { - lcp->his_shortseq = 1; - fsm_ack(dec, opt); - } else { - fsm_rej(dec, opt); - lcp->my_reject |= (1 << opt->hdr.id); - } - break; - case MODE_NAK: - /* - * He's trying to get us to ask for short sequence numbers. - * We ignore the NAK and honour our configuration file instead. - */ - break; - case MODE_REJ: - lcp->his_reject |= (1 << opt->hdr.id); - lcp->want_shortseq = 0; /* For when we hit MP */ - break; - } - break; - - case TY_ENDDISC: - mp = &lcp->fsm.bundle->ncp.mp; - log_Printf(LogLCP, "%s %s\n", request, - mp_Enddisc(opt->data[0], opt->data + 1, opt->hdr.len - 3)); - switch (mode_type) { - case MODE_REQ: - if (!p) { - log_Printf(LogLCP, " ENDDISC rejected - not a physical link\n"); - fsm_rej(dec, opt); - lcp->my_reject |= (1 << opt->hdr.id); - } else if (!IsAccepted(mp->cfg.negenddisc)) { - lcp->my_reject |= (1 << opt->hdr.id); - fsm_rej(dec, opt); - } else if (opt->hdr.len < sizeof p->dl->peer.enddisc.address + 3 && - opt->data[0] <= MAX_ENDDISC_CLASS) { - p->dl->peer.enddisc.class = opt->data[0]; - p->dl->peer.enddisc.len = opt->hdr.len - 3; - memcpy(p->dl->peer.enddisc.address, opt->data + 1, opt->hdr.len - 3); - p->dl->peer.enddisc.address[opt->hdr.len - 3] = '\0'; - /* XXX: If mp->active, compare and NAK with mp->peer ? */ - fsm_ack(dec, opt); - } else { - if (opt->data[0] > MAX_ENDDISC_CLASS) - log_Printf(LogLCP, " ENDDISC rejected - unrecognised class %d\n", - opt->data[0]); - else - log_Printf(LogLCP, " ENDDISC rejected - local max length is %ld\n", - (long)(sizeof p->dl->peer.enddisc.address - 1)); - fsm_rej(dec, opt); - lcp->my_reject |= (1 << opt->hdr.id); - } - break; - - case MODE_NAK: /* Treat this as a REJ, we don't vary our disc (yet) */ - case MODE_REJ: - lcp->his_reject |= (1 << opt->hdr.id); - break; - } - break; - - default: - sz = (sizeof desc - 2) / 2; - if (sz + 2 > opt->hdr.len) - sz = opt->hdr.len - 2; - pos = 0; - desc[0] = sz ? ' ' : '\0'; - for (pos = 0; sz--; pos++) - sprintf(desc+(pos<<1)+1, "%02x", opt->data[pos]); - - log_Printf(LogLCP, "%s%s\n", request, desc); - - if (mode_type == MODE_REQ) { - fsm_rej(dec, opt); - lcp->my_reject |= (1 << opt->hdr.id); - } - break; - } - } - - if (mode_type != MODE_NOP) { - if (mode_type == MODE_REQ && p && p->type == PHYS_DIRECT && - p->dl->cfg.callback.opmask && !callback_req && - !(p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_NONE))) { - /* We *REQUIRE* that the peer requests callback */ - nak.hdr.id = TY_CALLBACK; - nak.hdr.len = 3; - if ((p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) && - p->link.lcp.want_auth) - nak.data[0] = CALLBACK_AUTH; - else if (p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_CBCP)) - nak.data[0] = CALLBACK_CBCP; - else if (p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_E164)) - nak.data[0] = CALLBACK_E164; - else { - log_Printf(LogWARN, "Cannot insist on auth callback without" - " PAP or CHAP enabled !\n"); - nak.hdr.len = 2; /* XXX: Silly ! */ - } - fsm_nak(dec, &nak); - } - if (mode_type == MODE_REQ && !lcp->mru_req) { - mru = DEF_MRU; - phmtu = p ? physical_DeviceMTU(p) : 0; - if (phmtu && mru > phmtu) - mru = phmtu; - if (mru > lcp->cfg.max_mtu) - mru = lcp->cfg.max_mtu; - if (mru < DEF_MRU) { - /* Don't let the peer use the default MRU */ - lcp->his_mru = lcp->cfg.mtu && lcp->cfg.mtu < mru ? lcp->cfg.mtu : mru; - nak.hdr.id = TY_MRU; - nak.hdr.len = 4; - ua_htons(&lcp->his_mru, nak.data); - fsm_nak(dec, &nak); - lcp->mru_req = 1; /* Don't keep NAK'ing this */ - } - } - fsm_opt_normalise(dec); - } -} - -extern struct mbuf * -lcp_Input(struct bundle *bundle __unused, struct link *l, struct mbuf *bp) -{ - /* Got PROTO_LCP from link */ - m_settype(bp, MB_LCPIN); - fsm_Input(&l->lcp.fsm, bp); - return NULL; -} |