home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mega CD-ROM 1
/
megacd_rom_1.zip
/
megacd_rom_1
/
NETWORK
/
SRC_0618.ZIP
/
PPPLCP.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-06-07
|
27KB
|
1,075 lines
/*
* PPPLCP.C -- negotiate data link options
*
* This implementation of PPP is declared to be in the public domain.
*
* Jan 91 Bill_Simpson@um.cc.umich.edu
* Computer Systems Consulting Services
*
* Acknowledgements and correction history may be found in PPP.C
*/
#include <stdio.h>
#include "global.h"
#include "mbuf.h"
#include "iface.h"
#include "ppp.h"
#include "pppfsm.h"
#include "ppplcp.h"
#include "ppppap.h"
#include "cmdparse.h"
#include "devparam.h"
/* These defaults are defined in the PPP RFCs, and must not be changed */
static struct lcp_value_s lcp_default = {
FALSE, /* no need to negotiate defaults */
LCP_MRU_DEFAULT,
LCP_ACCM_DEFAULT,
0, /* no authentication */
0, /* no encryption */
0L, /* no magic number */
0L, /* no reporting period */
};
/* for test purposes, accept anything we understand in the NAK */
static int16 lcp_negotiate = LCP_N_MRU | LCP_N_ACCM | LCP_N_AUTHENT
| LCP_N_PFC | LCP_N_ACFC | LCP_N_MAGIC;
static byte_t option_length[] = {
0, /* unused */
4, /* MRU */
6, /* ACCM */
4, /* authentication */
4, /* encryption */
6, /* magic number */
6, /* monitor reporting period */
2, /* Protocol compression */
2 /* Address/Control compression */
};
static int dolcp_local __ARGS((int argc, char *argv[], void *p));
static int dolcp_open __ARGS((int argc, char *argv[], void *p));
static int dolcp_remote __ARGS((int argc, char *argv[], void *p));
static int dolcp_accm __ARGS((int argc, char *argv[], void *p));
static int dolcp_acfc __ARGS((int argc, char *argv[], void *p));
static int dolcp_auth __ARGS((int argc, char *argv[], void *p));
static int dolcp_magic __ARGS((int argc, char *argv[], void *p));
static int dolcp_mru __ARGS((int argc, char *argv[], void *p));
static int dolcp_pfc __ARGS((int argc, char *argv[], void *p));
static int dolcp_default __ARGS((int argc, char *argv[], void *p));
static void lcp_option __ARGS((struct mbuf **bpp,
struct lcp_value_s *value_p,
byte_t o_type,
byte_t o_length,
struct mbuf **copy_bpp ));
static void lcp_makeoptions __ARGS((struct mbuf **bpp,
struct lcp_value_s *value_p,
int16 negotiating));
static struct mbuf *lcp_makereq __ARGS((struct fsm_s *fsm_p));
static int lcp_check __ARGS((struct mbuf **bpp,
struct lcp_s *lcp_p,
struct lcp_side_s *side_p,
struct option_hdr *option_p,
int request));
static int lcp_request __ARGS((struct fsm_s *fsm_p,
struct config_hdr *config,
struct mbuf *data));
static int lcp_ack __ARGS((struct fsm_s *fsm_p,
struct config_hdr *ackcnf,
struct mbuf *data));
static int lcp_nak __ARGS((struct fsm_s *fsm_p,
struct config_hdr *nakcnf,
struct mbuf *data));
static int lcp_reject __ARGS((struct fsm_s *fsm_p,
struct config_hdr *rejcnf,
struct mbuf *data));
static void lcp_reset __ARGS((struct fsm_s *fsm_p));
static void lcp_starting __ARGS((struct fsm_s *fsm_p));
static void lcp_stopping __ARGS((struct fsm_s *fsm_p));
static void lcp_closing __ARGS((struct fsm_s *fsm_p));
static void lcp_opening __ARGS((struct fsm_s *fsm_p));
static void lcp_free __ARGS((struct fsm_s *fsm_p));
static void lcp_init __ARGS((struct ppp_s *ppp_p));
static struct fsm_constant_s lcp_constants = {
"Lcp",
PPP_LCP_PROTOCOL,
0x0FFE, /* codes 1-11 recognized */
Lcp,
LCP_REQ_TRY,
LCP_NAK_TRY,
LCP_TERM_TRY,
LCP_TIMEOUT * 1000L,
lcp_free,
lcp_reset,
lcp_starting,
lcp_opening,
lcp_closing,
lcp_stopping,
lcp_makereq,
lcp_request,
lcp_ack,
lcp_nak,
lcp_reject
};
/************************************************************************/
/* "ppp <iface> lcp" subcommands */
static struct cmds Lcpcmds[] = {
"close", doppp_close, 0, 0, NULLCHAR,
"listen", doppp_passive, 0, 0, NULLCHAR,
"local", dolcp_local, 0, 0, NULLCHAR,
"open", dolcp_open, 0, 0, NULLCHAR,
"remote", dolcp_remote, 0, 0, NULLCHAR,
"timeout", doppp_timeout, 0, 0, NULLCHAR,
"try", doppp_try, 0, 0, NULLCHAR,
NULLCHAR,
};
/* "ppp <iface> lcp [local | remote]" subcommands */
static struct cmds Lcpside_cmds[] = {
"accm", dolcp_accm, 0, 0, NULLCHAR,
"acfc", dolcp_acfc, 0, 0, NULLCHAR,
"authenticate", dolcp_auth, 0, 0, NULLCHAR,
"magic", dolcp_magic, 0, 0, NULLCHAR,
"mru", dolcp_mru, 0, 0, NULLCHAR,
"pfc", dolcp_pfc, 0, 0, NULLCHAR,
"default", dolcp_default, 0, 0, NULLCHAR,
NULLCHAR,
};
int
doppp_lcp(argc,argv,p)
int argc;
char *argv[];
void *p;
{
register struct iface *ifp = p;
register struct ppp_s *ppp_p = ifp->extension;
lcp_init(ppp_p);
return subcmd(Lcpcmds, argc, argv, &(ppp_p->fsm[Lcp]));
}
static int
dolcp_local(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct fsm_s *fsm_p = p;
struct lcp_s *lcp_p = fsm_p->pdv;
return subcmd(Lcpside_cmds, argc, argv, &(lcp_p->local));
}
static int
dolcp_open(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct fsm_s *fsm_p = p;
doppp_active( argc, argv, p );
if ( fsm_p->ppp_p->phase >= pppLCP ) {
fsm_start( fsm_p );
}
return 0;
}
static int
dolcp_remote(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct fsm_s *fsm_p = p;
struct lcp_s *lcp_p = fsm_p->pdv;
return subcmd(Lcpside_cmds, argc, argv, &(lcp_p->remote));
}
/************************************************************************/
static int
dolcp_accm(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct lcp_side_s *side_p = p;
if (argc < 2) {
tprintf("0x%08lx\n",side_p->want.accm);
} else if (stricmp(argv[1],"allow") == 0) {
return bit16cmd(&(side_p->will_negotiate),LCP_N_ACCM,
"Allow ACCM", --argc, &argv[1] );
} else {
side_p->want.accm = strtoul(argv[1], NULLCHARP, 0);
if ( side_p->want.accm != LCP_ACCM_DEFAULT )
side_p->want.negotiate |= LCP_N_ACCM;
else
side_p->want.negotiate &= ~LCP_N_ACCM;
}
return 0;
}
static int
dolcp_acfc(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct lcp_side_s *side_p = p;
if (stricmp(argv[1],"allow") == 0) {
return bit16cmd(&(side_p->will_negotiate),LCP_N_ACFC,
"Allow Address/Control Field Compression", --argc, &argv[1] );
}
return bit16cmd( &(side_p->want.negotiate), LCP_N_ACFC,
"Address/Control Field Compression", argc, argv );
}
static int
dolcp_auth(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct lcp_side_s *side_p = p;
if (argc < 2) {
if ( side_p->want.negotiate & LCP_N_AUTHENT ) {
switch ( side_p->want.authentication ) {
case PPP_PAP_PROTOCOL:
tprintf("Pap\n");
break;
default:
tprintf("0x%04x\n", side_p->want.authentication);
break;
};
} else {
tprintf("None\n");
}
} else if (stricmp(argv[1],"allow") == 0) {
return bit16cmd(&(side_p->will_negotiate),LCP_N_AUTHENT,
"Allow Authentication", --argc, &argv[1] );
} else if (stricmp(argv[1],"pap") == 0) {
side_p->want.negotiate |= LCP_N_AUTHENT;
side_p->want.authentication = PPP_PAP_PROTOCOL;
} else if (stricmp(argv[1],"none") == 0) {
side_p->want.negotiate &= ~LCP_N_AUTHENT;
} else {
tprintf("allow pap none\n");
return 1;
}
return 0;
}
static int
dolcp_magic(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct lcp_side_s *side_p = p;
int result = 0;
if (argc < 2) {
tprintf("%d\n",side_p->want.magic_number);
} else if (stricmp(argv[1],"allow") == 0) {
return bit16cmd(&(side_p->will_negotiate),LCP_N_MAGIC,
"Allow Magic Number", --argc, &argv[1] );
} else {
register int32 x = strtoul(argv[1], NULLCHARP, 0);
if ( !x ) {
int test;
/* Check for keyword */
result = setbool( &test, "Magic Number", argc, argv );
if ( test ) {
/* Make a non-zero random number */
x = Clock | 0x80000000L;
}
}
if ( x ) {
side_p->want.negotiate |= LCP_N_MAGIC;
} else {
side_p->want.negotiate &= ~LCP_N_MAGIC;
}
side_p->want.magic_number = x;
}
return result;
}
static int
dolcp_mru(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct lcp_side_s *side_p = p;
if (argc < 2) {
tprintf("%d\n",side_p->want.mru);
} else if (stricmp(argv[1],"allow") == 0) {
return bit16cmd(&(side_p->will_negotiate),LCP_N_MRU,
"Allow MRU", --argc, &argv[1] );
} else {
register int x = (int)strtol( argv[1], NULLCHARP, 0 );
if (x < LCP_MRU_LO || x > LCP_MRU_HI) {
tprintf("MRU %s (%d) out of range %d thru %d\n",
argv[1], x, LCP_MRU_LO, LCP_MRU_HI);
return -1;
} else if ( x != LCP_MRU_DEFAULT ) {
side_p->want.negotiate |= LCP_N_MRU;
} else {
side_p->want.negotiate &= ~LCP_N_MRU;
}
side_p->want.mru = x;
}
return 0;
}
static int
dolcp_pfc(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct lcp_side_s *side_p = p;
if (stricmp(argv[1],"allow") == 0) {
return bit16cmd(&(side_p->will_negotiate),LCP_N_PFC,
"Allow Protocol Field Compression", --argc, &argv[1] );
}
return bit16cmd( &(side_p->want.negotiate), LCP_N_PFC,
"Protocol Field Compression", argc, argv );
}
static int
dolcp_default(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct lcp_side_s *side_p = p;
ASSIGN( side_p->want, lcp_default );
return 0;
}
/************************************************************************/
/* E V E N T P R O C E S S I N G */
/************************************************************************/
static void
lcp_option( bpp, value_p, o_type, o_length, copy_bpp )
struct mbuf **bpp;
struct lcp_value_s *value_p;
byte_t o_type;
byte_t o_length;
struct mbuf **copy_bpp;
{
struct mbuf *bp;
register char *cp;
register int toss = o_length - OPTION_HDR_LEN;
if ((bp = alloc_mbuf(o_length)) == NULLBUF) {
return;
}
cp = bp->data;
*cp++ = o_type;
*cp++ = o_length;
switch ( o_type ) {
case LCP_MRU:
put16(cp, value_p->mru);
toss -= 2;
#ifdef PPP_DEBUG_OPTIONS
if (PPPtrace & PPP_DEBUG_OPTIONS)
log(-1, " making MRU: 0x%02x", value_p->mru);
#endif
break;
case LCP_ACCM:
put32(cp, value_p->accm);
toss -= 4;
#ifdef PPP_DEBUG_OPTIONS
if (PPPtrace & PPP_DEBUG_OPTIONS)
log(-1, " making ACCM: 0x%08lx", value_p->accm);
#endif
break;
case LCP_AUTHENT:
put16(cp, value_p->authentication);
toss -= 2;
#ifdef PPP_DEBUG_OPTIONS
if (PPPtrace & PPP_DEBUG_OPTIONS)
log(-1, " making Auth Protocol: 0x%04x",
value_p->authentication);
#endif
break;
case LCP_MAGIC:
put32(cp, value_p->magic_number);
toss -= 4;
#ifdef PPP_DEBUG_OPTIONS
if (PPPtrace & PPP_DEBUG_OPTIONS)
log(-1, " making Magic Number: 0x%08lx",
value_p->magic_number);
#endif
break;
case LCP_PFC:
#ifdef PPP_DEBUG_OPTIONS
if (PPPtrace & PPP_DEBUG_OPTIONS)
log(-1, " making Protocol compression");
#endif
break;
case LCP_ACFC:
#ifdef PPP_DEBUG_OPTIONS
if (PPPtrace & PPP_DEBUG_OPTIONS)
log(-1, " making Addr/Ctl compression");
#endif
break;
case LCP_ENCRYPT: /* not implemented */
case LCP_QUALITY: /* not implemented */
default:
#ifdef PPP_DEBUG_OPTIONS
if (PPPtrace & PPP_DEBUG_OPTIONS)
log(-1, " making unimplemented type %d", o_type);
#endif
break;
};
while ( toss-- > 0 ) {
*cp++ = pullchar(copy_bpp);
}
bp->cnt += o_length;
append(bpp, bp);
}
/************************************************************************/
/* Build a list of options */
static void
lcp_makeoptions(bpp, value_p, negotiating)
struct mbuf **bpp;
struct lcp_value_s *value_p;
int16 negotiating;
{
register int o_type;
PPP_DEBUG_ROUTINES("lcp_makeoptions()");
for ( o_type = 1; o_type <= LCP_OPTION_LIMIT; o_type++ ) {
if (negotiating & (1 << o_type)) {
lcp_option( bpp, value_p,
o_type, option_length[ o_type ], NULLBUFP);
}
}
}
/************************************************************************/
/* Build a request to send to remote host */
static struct mbuf *
lcp_makereq(fsm_p)
struct fsm_s *fsm_p;
{
struct lcp_s *lcp_p = fsm_p->pdv;
struct mbuf *req_bp = NULLBUF;
PPP_DEBUG_ROUTINES("lcp_makereq()");
lcp_makeoptions( &req_bp, &(lcp_p->local.work),
lcp_p->local.work.negotiate );
return(req_bp);
}
/************************************************************************/
/* Check the options, updating the working values.
* Returns -1 if ran out of data, ACK/NAK/REJ as appropriate.
*/
static int
lcp_check( bpp, lcp_p, side_p, option_p, request )
struct mbuf **bpp;
struct lcp_s *lcp_p;
struct lcp_side_s *side_p;
struct option_hdr *option_p;
int request;
{
int toss = option_p->len - OPTION_HDR_LEN;
int option_result = CONFIG_ACK; /* Assume good values */
switch(option_p->type) {
case LCP_MRU:
side_p->work.mru = pull16(bpp);
toss -= 2;
#ifdef PPP_DEBUG_OPTIONS
if (PPPtrace & PPP_DEBUG_OPTIONS)
log(-1, " checking MRU: 0x%02x", side_p->work.mru);
#endif
/* Check if new value is appropriate */
if (side_p->work.mru < LCP_MRU_LO) {
side_p->work.mru = LCP_MRU_LO;
option_result = CONFIG_NAK;
} else if (side_p->work.mru > LCP_MRU_HI) {
side_p->work.mru = LCP_MRU_HI;
option_result = CONFIG_NAK;
}
if ( request && (side_p->want.negotiate & LCP_N_MRU)
&& side_p->work.mru > side_p->want.mru ) {
side_p->work.mru = side_p->want.mru;
option_result = side_p->want.mru;
}
break;
case LCP_ACCM:
side_p->work.accm = pull32(bpp);
toss -= 4;
#ifdef PPP_DEBUG_OPTIONS
if (PPPtrace & PPP_DEBUG_OPTIONS)
log(-1, " checking ACCM: 0x%08lx", side_p->work.accm);
#endif
/* Remote host may ask to escape more control */
/* characters than we require, but must escape */
/* at least the control chars that we require. */
if ( (!request || (side_p->want.negotiate & LCP_N_ACCM))
&& side_p->work.accm !=
(side_p->work.accm | side_p->want.accm) ) {
side_p->work.accm |= side_p->want.accm;
option_result = CONFIG_NAK;
}
break;
case LCP_AUTHENT:
side_p->work.authentication = pull16(bpp);
toss -= 2;
#ifdef PPP_DEBUG_OPTIONS
if (PPPtrace & PPP_DEBUG_OPTIONS)
log(-1, " checking Auth Protocol: 0x%04x",
side_p->work.authentication);
#endif
/* Check if new value is appropriate */
switch ( side_p->work.authentication ) {
case PPP_PAP_PROTOCOL:
/* Yes */
break;
default:
side_p->work.authentication = PPP_PAP_PROTOCOL;
option_result = CONFIG_NAK;
break;
};
break;
case LCP_MAGIC:
side_p->work.magic_number = pull32(bpp);
toss -= 4;
#ifdef PPP_DEBUG_OPTIONS
if (PPPtrace & PPP_DEBUG_OPTIONS)
log(-1, " checking Magic Number: 0x%08lx",
side_p->work.magic_number);
#endif
/* Ensure that magic numbers are different */
if (side_p->work.magic_number == 0L
|| lcp_p->remote.work.magic_number == lcp_p->local.work.magic_number) {
side_p->work.magic_number += Clock;
option_result = CONFIG_NAK;
}
break;
case LCP_PFC:
#ifdef PPP_DEBUG_OPTIONS
if (PPPtrace & PPP_DEBUG_OPTIONS)
log(-1, " checking Protocol compression");
#endif
break;
case LCP_ACFC:
#ifdef PPP_DEBUG_OPTIONS
if (PPPtrace & PPP_DEBUG_OPTIONS)
log(-1, " checking Addr/Ctl compression");
#endif
break;
case LCP_ENCRYPT: /* not implemented */
case LCP_QUALITY: /* not implemented */
default:
option_result = CONFIG_REJ;
break;
};
if (option_p->type > LCP_OPTION_LIMIT
|| !(side_p->will_negotiate & (1 << option_p->type))) {
option_result = CONFIG_REJ;
}
if ( toss < 0 )
return -1;
if ( !request && toss > 0 ) {
/* toss extra bytes in option */
while( toss-- > 0 ) {
if ( pullchar(bpp) == -1 )
return -1;
}
}
return (option_result);
}
/************************************************************************/
/* Check Link Control options requested by the remote host */
static int
lcp_request(fsm_p, config, data)
struct fsm_s *fsm_p;
struct config_hdr *config;
struct mbuf *data;
{
struct lcp_s *lcp_p = fsm_p->pdv;
int32 signed_length = config->len;
struct mbuf *reply_bp = NULLBUF; /* reply packet */
int reply_result = CONFIG_ACK; /* reply to request */
int16 desired; /* desired to negotiate */
struct option_hdr option; /* option header storage */
int option_result; /* option reply */
PPP_DEBUG_ROUTINES("lcp_request()");
lcp_p->remote.work.negotiate = FALSE; /* clear flags */
/* Process options requested by remote host */
while (signed_length > 0 && ntohopt(&option, &data) != -1) {
if ((signed_length -= option.len) < 0) {
PPP_DEBUG_CHECKS("LCP REQ: bad header length");
free_p(data);
free_p(reply_bp);
return -1;
}
if ( ( option_result = lcp_check( &data, lcp_p,
&(lcp_p->remote), &option, TRUE ) ) == -1 ) {
PPP_DEBUG_CHECKS("LCP REQ: ran out of data");
free_p(data);
free_p(reply_bp);
return -1;
}
#ifdef PPP_DEBUG_OPTIONS
if (PPPtrace & PPP_DEBUG_OPTIONS) {
log(-1, "LCP REQ: result %s, option %d, length %d",
fsmCodes[option_result],
option.type,
option.len);
}
#endif
if ( option_result < reply_result ) {
continue;
} else if ( option_result > reply_result ) {
/* Discard current list of replies */
free_p(reply_bp);
reply_bp = NULLBUF;
reply_result = option_result;
}
/* remember that we processed option */
if ( option_result != CONFIG_REJ
&& option.type <= LCP_OPTION_LIMIT ) {
lcp_p->remote.work.negotiate |= (1 << option.type);
}
/* Add option response to the return list */
lcp_option( &reply_bp, &(lcp_p->remote.work),
option.type, option.len, &data );
}
/* Now check for any missing options which are desired */
if ( fsm_p->retry_nak > 0
&& (desired = lcp_p->remote.want.negotiate
& ~lcp_p->remote.work.negotiate) != 0 ) {
switch ( reply_result ) {
case CONFIG_ACK:
free_p(reply_bp);
reply_bp = NULLBUF;
reply_result = CONFIG_NAK;
/* fallthru */
case CONFIG_NAK:
lcp_makeoptions( &reply_bp, &(lcp_p->remote.want),
desired );
fsm_p->retry_nak--;
break;
case CONFIG_REJ:
/* do nothing */
break;
};
} else if ( reply_result == CONFIG_NAK ) {
/* if too many NAKs, reject instead */
if ( fsm_p->retry_nak > 0 )
fsm_p->retry_nak--;
else
reply_result = CONFIG_REJ;
}
/* Send ACK/NAK/REJ to remote host */
fsm_send(fsm_p, reply_result, config->id, reply_bp);
free_p(data);
return (reply_result != CONFIG_ACK);
}
/************************************************************************/
/* Process configuration ACK sent by remote host */
static int
lcp_ack(fsm_p, config, data)
struct fsm_s *fsm_p;
struct config_hdr *config;
struct mbuf *data;
{
struct mbuf *req_bp;
int error = FALSE;
PPP_DEBUG_ROUTINES("lcp_ack()");
/* ID field must match last request we sent */
if (config->id != fsm_p->lastid) {
PPP_DEBUG_CHECKS("LCP ACK: wrong ID");
free_p(data);
return -1;
}
/* Get a copy of last request we sent */
req_bp = lcp_makereq(fsm_p);
/* Overall buffer length should match */
if (config->len != len_p(req_bp)) {
PPP_DEBUG_CHECKS("LCP ACK: buffer length mismatch");
error = TRUE;
} else {
register int req_char;
register int ack_char;
/* Each byte should match */
while ((req_char = pullchar(&req_bp)) != -1) {
if ((ack_char = pullchar(&data)) == -1
|| ack_char != req_char ) {
PPP_DEBUG_CHECKS("LCP ACK: data mismatch");
log (-1, "req=%02X, ack=%02X", req_char, ack_char);
error = TRUE;
break;
}
}
}
free_p(req_bp);
free_p(data);
if (error) {
return -1;
}
PPP_DEBUG_CHECKS("LCP ACK: valid");
return 0;
}
/************************************************************************/
/* Process configuration NAK sent by remote host */
static int
lcp_nak(fsm_p, config, data)
struct fsm_s *fsm_p;
struct config_hdr *config;
struct mbuf *data;
{
struct lcp_s *lcp_p = fsm_p->pdv;
struct lcp_side_s *local_p = &(lcp_p->local);
int32 signed_length = config->len;
struct option_hdr option;
int last_option = 0;
int result;
PPP_DEBUG_ROUTINES("lcp_nak()");
/* ID field must match last request we sent */
if (config->id != fsm_p->lastid) {
PPP_DEBUG_CHECKS("LCP NAK: wrong ID");
free_p(data);
return -1;
}
/* First, process in order. Then, process extra "important" options */
while (signed_length > 0 && ntohopt(&option, &data) != -1) {
if ((signed_length -= option.len) < 0) {
PPP_DEBUG_CHECKS("LCP NAK: bad header length");
free_p(data);
return -1;
}
if ( option.type > LCP_OPTION_LIMIT ) {
PPP_DEBUG_CHECKS("LCP NAK: option out of range");
} else if ( option.type < last_option
|| !(local_p->work.negotiate & (1 << option.type)) ) {
if (local_p->work.negotiate & (1 << option.type)) {
PPP_DEBUG_CHECKS("LCP NAK: option out of order");
free_p(data);
return -1; /* was requested */
}
local_p->work.negotiate |= (1 << option.type);
last_option = LCP_OPTION_LIMIT + 1;
} else {
last_option = option.type;
}
if ( ( result = lcp_check( &data, lcp_p,
local_p, &option, FALSE ) ) == -1 ) {
PPP_DEBUG_CHECKS("LCP NAK: ran out of data");
free_p(data);
return -1;
}
/* update the negotiation status */
if ( result == CONFIG_REJ
&& option.type <= LCP_OPTION_LIMIT ) {
local_p->work.negotiate &= ~(1 << option.type);
}
}
PPP_DEBUG_CHECKS("LCP NAK: valid");
free_p(data);
return 0;
}
/************************************************************************/
/* Process configuration reject sent by remote host */
static int
lcp_reject(fsm_p, config, data)
struct fsm_s *fsm_p;
struct config_hdr *config;
struct mbuf *data;
{
struct lcp_s *lcp_p = fsm_p->pdv;
struct lcp_side_s *local_p = &(lcp_p->local);
int32 signed_length = config->len;
struct option_hdr option;
int last_option = 0;
PPP_DEBUG_ROUTINES("lcp_reject()");
/* ID field must match last request we sent */
if (config->id != fsm_p->lastid) {
PPP_DEBUG_CHECKS("LCP REJ: wrong ID");
free_p(data);
return -1;
}
/* Process in order, checking for errors */
while (signed_length > 0 && ntohopt(&option, &data) != -1) {
register int k;
if ((signed_length -= option.len) < 0) {
PPP_DEBUG_CHECKS("LCP REJ: bad header length");
free_p(data);
return -1;
}
if ( option.type > LCP_OPTION_LIMIT ) {
PPP_DEBUG_CHECKS("LCP REJ: option out of range");
} else if ( option.type < last_option
|| !(local_p->work.negotiate & (1 << option.type))) {
PPP_DEBUG_CHECKS("LCP REJ: option out of order");
free_p(data);
return -1;
}
for ( k = option.len - OPTION_HDR_LEN; k-- > 0; ) {
if ( pullchar(&data) == -1 ) {
PPP_DEBUG_CHECKS("LCP REJ: ran out of data");
free_p(data);
return -1;
}
}
last_option = option.type;
if ( option.type <= LCP_OPTION_LIMIT ) {
local_p->work.negotiate &= ~(1 << option.type);
}
}
PPP_DEBUG_CHECKS("LCP REJ: valid");
free_p(data);
return 0;
}
/************************************************************************/
/* I N I T I A L I Z A T I O N */
/************************************************************************/
/* Reset configuration options before request */
static void
lcp_reset(fsm_p)
struct fsm_s *fsm_p;
{
struct lcp_s *lcp_p = fsm_p->pdv;
PPP_DEBUG_ROUTINES("lcp_reset()");
if ( lcp_p->local.want.negotiate & LCP_N_MAGIC ) {
lcp_p->local.want.magic_number += Clock;
}
ASSIGN( lcp_p->local.work, lcp_p->local.want );
lcp_p->local.will_negotiate |= lcp_p->local.want.negotiate;
lcp_p->remote.work.negotiate = FALSE;
lcp_p->remote.will_negotiate |= lcp_p->remote.want.negotiate;
}
/************************************************************************/
/* Prepare to begin configuration exchange */
static void
lcp_starting(fsm_p)
struct fsm_s *fsm_p;
{
PPP_DEBUG_ROUTINES("lcp_starting()");
}
/************************************************************************/
/* After termination */
static void
lcp_stopping(fsm_p)
struct fsm_s *fsm_p;
{
struct iface *ifp = fsm_p->ppp_p->iface;
PPP_DEBUG_ROUTINES("lcp_stopping()");
/* Now, tell the device to go down.
* In turn, it should tell our IO status
* when it has gone down.
*/
ifp->ioctl(ifp,PARAM_DOWN,TRUE,0L);
}
/************************************************************************/
/* Close higher levels in preparation for link shutdown */
static void
lcp_closing(fsm_p)
struct fsm_s *fsm_p;
{
struct ppp_s *ppp_p = fsm_p->ppp_p;
switch ( ppp_p->phase ) {
case pppREADY:
fsm_down( &(ppp_p->fsm[IPcp]) );
break;
case pppAP:
pap_down( &(ppp_p->fsm[Pap]) );
break;
default:
/* nothing to do */
break;
};
ppp_p->phase = pppTERMINATE;
psignal(ppp_p, 0);
}
/************************************************************************/
/* configuration negotiation complete */
static void
lcp_opening(fsm_p)
struct fsm_s *fsm_p;
{
struct lcp_s *lcp_p = fsm_p->pdv;
struct iface *ifp = fsm_p->ppp_p->iface;
if (ifp->mtu > lcp_p->remote.work.mru) {
/* Set new Max Transmission Unit for outgoing packets */
ifp->mtu = lcp_p->remote.work.mru;
if (PPPtrace > 1)
log(-1," Set new MTU for outgoing packets: %d",
ifp->mtu);
}
fsm_p->ppp_p->phase = pppAP;
psignal(fsm_p->ppp_p, 0);
}
/************************************************************************/
static void
lcp_free(fsm_p)
struct fsm_s *fsm_p;
{
/* nothing to do */
}
/* Initialize configuration structure */
static void
lcp_init(ppp_p)
struct ppp_s *ppp_p;
{
struct fsm_s *fsm_p;
struct lcp_s *lcp_p;
PPPtrace = ppp_p->trace;
PPP_DEBUG_ROUTINES("lcp_init()");
if (ppp_p->fsm[Lcp].pdv != NULL)
return; /* already initialized */
fsm_p = &(ppp_p->fsm[Lcp]);
fsm_p->ppp_p = ppp_p;
fsm_p->pdc = &lcp_constants;
fsm_p->pdv =
lcp_p = callocw(1,sizeof(struct lcp_s));
/* Set option parameters to first request defaults */
ASSIGN( lcp_p->local.want, lcp_default );
lcp_p->local.will_negotiate = lcp_negotiate;
ASSIGN( lcp_p->remote.want, lcp_default );
ASSIGN( lcp_p->remote.work, lcp_default );
lcp_p->remote.will_negotiate = lcp_negotiate;
fsm_init(fsm_p);
}