/************************************************************************/
/* */
/* MODULE: lcp.c */
/* PRODUCT: PPP driver */
/* PURPOSE: lcp module */
/* DATE: 28 February, 1996 */
/* */
/*----------------------------------------------------------------------*/
/* */
/* Copyright 1991 - 1998, Integrated Systems, Inc. */
/* ALL RIGHTS RESERVED */
/* */
/* Permission is hereby granted to licensees of Integrated Systems, */
/* Inc. products to use or abstract this computer program for the */
/* sole purpose of implementing a product based on Integrated */
/* Systems, Inc. products. No other rights to reproduce, use, */
/* or disseminate this computer program, whether in part or in */
/* whole, are granted. */
/* */
/* Integrated Systems, Inc. makes no representation or warranties */
/* with respect to the performance of this computer program, and */
/* specifically disclaims any responsibility for any damages, */
/* special or consequential, connected with the use of this program. */
/* */
/************************************************************************/
/*
* lcp.c - PPP Link Control Protocol.
*
* Copyright (c) 1989 Carnegie Mellon University.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by Carnegie Mellon University. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
/*
* TODO:
*/
#include "syslog.h"
#include "ppp.h"
#include "fsm.h"
#include "lcp.h"
#include "magic.h"
#include "chap.h"
#include "upap.h"
#include "ni_ppp.h"
/* global vars */
fsm lcp_fsm[NUM_PPP]; /* LCP fsm structure (global)*/
lcp_options lcp_wantoptions[NUM_PPP]; /* Options that we want to request */
lcp_options lcp_gotoptions[NUM_PPP]; /* Options that peer ack'd */
lcp_options lcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */
lcp_options lcp_hisoptions[NUM_PPP]; /* Options that we ack'd */
u_int32_t xmit_accm[NUM_PPP][8]; /* extended transmit ACCM */
static u_int32_t lcp_echos_pending = 0; /* Number of outstanding echo msgs */
static u_int32_t lcp_echo_number = 0; /* ID number of next echo frame */
static u_int32_t lcp_echo_timer_running = 0; /* TRUE if a timer is running */
static u_char nak_buffer[PPP_MRU]; /* where we construct a nak packet */
/*
* Callbacks for fsm code. (CI = Configuration Information)
*/
static void lcp_resetci __P((fsm *)); /* Reset our CI */
static int lcp_cilen __P((fsm *)); /* Return length of our CI */
static void lcp_addci __P((fsm *, u_char *, int *)); /* Add our CI to pkt */
static int lcp_ackci __P((fsm *, u_char *, int)); /* Peer ack'd our CI */
static int lcp_nakci __P((fsm *, u_char *, int)); /* Peer nak'd our CI */
static int lcp_rejci __P((fsm *, u_char *, int)); /* Peer rej'd our CI */
static int lcp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv peer CI */
static void lcp_up __P((fsm *)); /* We're UP */
static void lcp_down __P((fsm *)); /* We're DOWN */
static void lcp_starting __P((fsm *)); /* We need lower layer up */
static void lcp_finished __P((fsm *)); /* We need lower layer down */
static int lcp_extcode __P((fsm *, int, int, u_char *, int));
static void lcp_rprotrej __P((fsm *, u_char *, int));
/*
* routines to send LCP echos to peer
*/
static void lcp_echo_lowerup __P((int));
static void lcp_echo_lowerdown __P((int));
static void LcpEchoTimeout __P((caddr_t));
static void lcp_received_echo_reply __P((fsm *, int, u_char *, int));
static void LcpSendEchoRequest __P((fsm *));
static void LcpLinkFailure __P((fsm *));
static void LcpEchoCheck __P((fsm *));
static fsm_callbacks lcp_callbacks = { /* LCP callback routines */
lcp_resetci, /* Reset our Configuration Information */
lcp_cilen, /* Length of our Configuration Information */
lcp_addci, /* Add our Configuration Information */
lcp_ackci, /* ACK our Configuration Information */
lcp_nakci, /* NAK our Configuration Information */
lcp_rejci, /* Reject our Configuration Information */
lcp_reqci, /* Request peer's Configuration Information */
lcp_up, /* Called when fsm reaches OPENED state */
lcp_down, /* Called when fsm leaves OPENED state */
lcp_starting, /* Called when we want the lower layer up */
lcp_finished, /* Called when we want the lower layer down */
NULL, /* Called when Protocol-Reject received */
NULL, /* Retransmission is necessary */
lcp_extcode, /* Called to handle LCP-specific codes */
"LCP" /* String name of protocol */
};
int lcp_loopbackfail = DEFLOOPBACKFAIL;
/*
* Length of each type of configuration option (in octets)
*/
#define CILEN_VOID 2
#define CILEN_SHORT 4 /* CILEN_VOID + sizeof(short) */
#define CILEN_CHAP 5 /* CILEN_VOID + sizeof(short) + 1 */
#define CILEN_LONG 6 /* CILEN_VOID + sizeof(long) */
#define CILEN_LQR 8 /* CILEN_VOID + sizeof(short) + sizeof(long) */
#define CODENAME(x) ((x) == CONFACK ? "ACK" : \
(x) == CONFNAK ? "NAK" : "REJ")
/*
* lcp_init - Initialize LCP.
*/
void
lcp_init(unit)
int unit;
{
fsm *f = &lcp_fsm[unit];
lcp_options *wo = &lcp_wantoptions[unit];
lcp_options *ao = &lcp_allowoptions[unit];
struct ppp_cfg *pcp = &pppcfgtab[unit];
f->unit = unit;
f->protocol = PPP_LCP;
f->callbacks = &lcp_callbacks;
fsm_init(f);
wo->passive = ((pcp->pppmode & 1) ? 0 : 1);
wo->silent = ((pcp->pppmode & 1) ? 0 : 1);
wo->restart = 0; /* Set to 1 in kernels or multi-line
implementations */
wo->neg_mru = ((pcp->lcp_options & NEGMRU) ? 1 : 0);
wo->mru = pcp->mru;
wo->neg_asyncmap = ((pcp->lcp_options & NEGASYNCMAP) ? 1 : 0);
wo->asyncmap = pcp->asyncmap;
#if CHAPNEEDED
wo->neg_chap = ((pcp->auth_options & REQCHAP) ? 1 : 0);
#else
wo->neg_chap = 0;
#endif
#if UPAPNEEDED
wo->neg_upap = ((pcp->auth_options & REQUPAP) ? 1 : 0);
#else
wo->neg_upap = 0;
#endif
wo->chap_mdtype = CHAP_DIGEST_MD5;
wo->neg_magicnumber = ((pcp->lcp_options & NEGMAGIC) ? 1 : 0);
wo->neg_pcompression = ((pcp->lcp_options & NEGPROTOCOMP) ? 1 : 0);
wo->neg_accompression = ((pcp->lcp_options & NEGACCOMP) ? 1 : 0);
wo->neg_lqr = 0; /* no LQR implementation yet */
ao->neg_mru = ((pcp->lcp_options & NEGMRU) ? 1 : 0);
ao->mru = MAXMRU;
ao->neg_asyncmap = ((pcp->lcp_options & NEGASYNCMAP) ? 1 : 0);
ao->asyncmap = 0;
#if CHAPNEEDED
ao->neg_chap = ((pcp->auth_options & NOCHAP) ? 0 : 1);
#else
ao->neg_chap = 0;
#endif
#if UPAPNEEDED
ao->neg_upap = ((pcp->auth_options & NOUPAP) ? 0 : 1);
#else
ao->neg_upap = 0;
#endif
ao->chap_mdtype = CHAP_DIGEST_MD5;
ao->neg_magicnumber = ((pcp->lcp_opt