home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
HAM Radio 1
/
HamRadio.cdr
/
misc
/
tcpipsrc
/
ppplcp.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-12-09
|
46KB
|
1,840 lines
/*
* PPPLCP.C -- negotiate data link options
*
* REVISIONS:
* 12-89 -- Katie Stevens (dkstevens@ucdavis.edu)
* UC Davis, Computing Services
* PPP.01 01-90 [ks] must echo requested magic# in REJ
* PPP.08 05-90 [ks] improve PPP trace reporting
* PPP.09 05-90 [ks] add auth type negotiation
* PPP.10 07-90 [ks] make ppp open/close/reset work properly
* PPP.14 08-90 [ks] change UPAP to PAP for consistency
* with RFC1172
* make LCP timeout configurable
* PPP.15 09-90 [ks] update to KA9Q NOS v900828
*/
#include <stdio.h>
#include "global.h"
#include "mbuf.h"
#include "proc.h"
#include "iface.h"
#include "slip.h"
#include "ppp.h"
/* Counter for PPP id field */
extern unsigned char Pppid;
/* PPP tracing */
extern int Ppptrace;
static void lcp_open __ARGS((struct slip *sp));
static int lcp_sendreq __ARGS((struct slip *sp));
static struct mbuf *lcp_makereq __ARGS((struct lcpparm *localp));
static void lcp_rcvack __ARGS((struct slip *sp, struct cnfhdr *rcnf,
struct mbuf *data));
static void lcp_rcvnak __ARGS((struct slip *sp, struct cnfhdr *rcnf,
struct mbuf *data));
static void lcp_rcvrej __ARGS((struct slip *sp, struct cnfhdr *rcnf,
struct mbuf *data));
static void lcp_rcvreq __ARGS((struct slip *sp, struct cnfhdr *rcnf,
struct mbuf *data));
static void lcp_rcvtermack __ARGS((struct slip *sp));
static void lcp_rcvtermreq __ARGS((struct slip *sp, struct cnfhdr *rcnf));
static int lcp_chkack __ARGS((struct slip *sp, struct cnfhdr *ackcnf,
struct mbuf *data));
static int lcp_chknak __ARGS((struct slip *sp, struct cnfhdr *nakcnf,
struct mbuf *data));
static int lcp_chkrej __ARGS((struct slip *sp, struct cnfhdr *rejcnf,
struct mbuf *data));
static void lcp_chkreq __ARGS((struct slip *sp, struct cnfhdr *reqcnf,
struct mbuf *data));
static void lcp_timeout __ARGS((void *vp));
static void lcp_timer __ARGS((struct slip *sp));
static int lcp_sendreply __ARGS((struct slip *sp, char code,
unsigned char id, struct mbuf *data));
/* Possible LCP states */
char *LCPStates[] = {
"Closed",
"Listen",
"Req Sent",
"Ack Rcvd",
"Ack Sent",
"Open",
"Terminate"
};
/* Possible LCP/IPCP packet types */
char *LCPCodes[] = {
NULLCHAR,
"Config Req",
"Config Ack",
"Config Nak",
"Config Rej",
"Terminate Req",
"Terminate Ack",
"Code Rej",
"Protocol Rej",
"Echo Req",
"Echo Reply",
"Discard Req",
};
/* LCP default options, local */
/* Attempt: 0=dont negotiate; 1=attempt negotiation */
/* NOTE: this sructure is used to initialize the local parameter side */
/* of PPP connections; options which will not be negotiated must be */
/* initialized to default LCP values specified in the PPP RFC */
static struct lcpparm attempt_parms = {
0, DEF_MRU,
0, DEF_CTL_MAP,
0, DEF_AUTH_TYPE,
0, DEF_ENCR_TYPE,
0, DEF_MAGIC_NUM,
0, DEF_LINK_QUAL,
0, DEF_PROT_COMPR,
0, DEF_AC_COMPR
};
/* LCP default options, remote */
/* Accept: 0=reject negotiation; 1=negotiation okay */
static struct lcpparm accept_parms = {
1, DEF_MRU,
1, DEF_CTL_MAP,
1, DEF_AUTH_TYPE,
0, DEF_ENCR_TYPE,
0, DEF_MAGIC_NUM,
0, DEF_LINK_QUAL,
1, DEF_PROT_COMPR,
1, DEF_AC_COMPR
};
/****************************************************************************/
/* Convert LCP/IPCP header in host form to network form */
struct mbuf *
htoncnf(cnf, data)
struct cnfhdr *cnf;
struct mbuf *data;
{
struct mbuf *bp;
register char *cp;
/* Prepend bytes for LCP/IPCP header */
if ((bp = pushdown(data, CNF_HDRLEN)) == NULLBUF)
return NULLBUF;
/* Load header with proper values */
cp = bp->data;
*cp++ = cnf->code;
*cp++ = cnf->id;
put16(cp, cnf->len);
return bp;
}
/* Extract LCP/IPCP header from incoming packet */
int
ntohcnf(cnf, bpp)
struct cnfhdr *cnf;
struct mbuf **bpp;
{
cnf->code = pullchar(bpp);
cnf->id = pullchar(bpp);
cnf->len = pull16(bpp);
return(CNF_HDRLEN);
}
/*******************************************/
/* Convert LCP/IPCP configuration option header in host form to network mbuf */
struct mbuf *
htonopt(opt)
struct opthdr *opt;
{
struct mbuf *bp;
register char *cp;
if((bp = alloc_mbuf(OPT_HDRLEN)) == NULLBUF)
return NULLBUF;
/* Load data into LCP/IPCP configuration option header */
cp = bp->data;
*cp++ = opt->type;
*cp++ = opt->len;
bp->cnt = cp - bp->data;
return bp;
}
/* Extract LCP/IPCP configuration option header */
int
ntohopt(opt,bpp)
struct opthdr *opt;
struct mbuf **bpp;
{
if (opt== NULLOPTHDR || bpp == NULLBUFP)
return -1;
if (*bpp == NULLBUF)
return -1;
opt->type = pullchar(bpp);
opt->len = pullchar(bpp);
return 0;
}
/****************************************************************************/
/* Initialize Link Control Protocol state machine for config exchange */
int
lcp_start(sp)
struct slip *sp;
{
struct pppctl *pppiop;
struct lcpctl *lcpiop;
pppiop = sp->pppio;
lcpiop = &(pppiop->lcpio);
if (Ppptrace > 5)
log(-1, "lcp_start()");
/* Leave things alone if not strictly closed */
if ((pppiop->state != PPP_CLOSED)&&(lcpiop->lcp_state != LCP_LISTEN)
&&(lcpiop->lcp_state != LCP_CLOSED)) {
return 0;
}
/* Prepare for Link Control negotiations */
lcp_reset(pppiop);
if (lcpiop->active == -1) {
/* We have been strictly closed with 'ppp close' command */
return 0;
}
/* Ready for Link Control negotiations */
pppiop->state = PPP_LCP;
if (lcpiop->active == 0) {
/* Passive open; wait until remote host attempts connection */
lcpiop->lcp_state = LCP_LISTEN;
return 0;
}
/* Active open; begin LCP configuration negotiation */
lcpiop->lcp_state = LCP_CLOSED;
return(lcp_sendreq(sp));
}
/*******************************************/
/* Close the PPP connection from local side */
int
lcp_close(sp)
struct slip *sp;
{
struct pppctl *pppiop;
struct lcpctl *lcpiop;
struct ipcpctl *ipcpiop;
if (Ppptrace > 5)
log(-1,"lcp_close()");
pppiop = sp->pppio;
lcpiop = &(pppiop->lcpio);
ipcpiop = &(pppiop->ipcpio);
if ((lcpiop->lcp_state == LCP_CLOSED) ||
(lcpiop->lcp_state == LCP_LISTEN)) {
/* Already closed */
return 0;
}
/* Need to shutdown PAP session if waiting for password */
psignal(&(lcpiop->pap_user),0);
/* Need to inform upper layers */
if ((ipcpiop->ipcp_state != IPCP_CLOSED) &&
(ipcpiop->ipcp_state != IPCP_LISTEN)) {
/* Wait for the IP layer to close */
ipcp_close(sp);
pwait(ipcpiop);
}
/* Set a timer against our request to shutdown */
lcp_timer(sp);
/* Ask remote host to shutdown */
lcpiop->lcp_state = LCP_TERMINATE;
lcpiop->ack_retry = 0;
if (lcp_sendreply(sp, TERMINATE_REQ, 0, NULLBUF) == 0)
pwait(lcpiop);
pppiop->state = PPP_CLOSED;
return 0;
}
/* Initialize our LCP configuration options to compiled default options */
void
lcp_init(sp)
struct slip *sp;
{
struct pppctl *pppiop;
struct lcpctl *lcpiop;
struct timer *t;
if (Ppptrace > 5)
log(-1, "lcp_init()");
pppiop = sp->pppio;
lcpiop = &(pppiop->lcpio);
t = &(lcpiop->lcp_tm);
/* One time initialization */
lcpiop->lcp_state = LCP_CLOSED;
lcpiop->active = 0;
memcpy(&(lcpiop->initparm), &attempt_parms, sizeof(struct lcpparm));
set_timer(t,LCP_TIMEOUT*1000L);
lcp_timer(sp); /* Set timer strictly OFF */
stop_timer(&(lcpiop->lcp_tm));
/* Initialization for each LCP open/close */
lcp_reset(pppiop);
return;
}
/* Link Control configuration negotiation complete */
static void
lcp_open(sp)
struct slip *sp;
{
struct pppctl *pppiop;
struct lcpctl *lcpiop;
pppiop = sp->pppio;
lcpiop = &(pppiop->lcpio);
/* Check on Auth Protocol */
if (lcpiop->initparm.auth_type != 0x0000) {
/* We require authentication from the remote host */
if (lcpiop->lclparm.auth_type != lcpiop->initparm.auth_type) {
/* Couldnt agree on auth, shut down the link */
if (Ppptrace)
log(-1,"%s: Couldn't negotiate Authenticate Protocol type",sp->iface->name);
lcp_shutdown(sp);
return;
}
}
/* Mark LCP layer as open */
if (Ppptrace)
log(-1,"%s: PPP/LCP Connection Open",sp->iface->name);
lcpiop->lcp_state = LCP_OPEN;
/* Set flags in PPP control struct to reflect accepted LCP options */
if (sp->iface->mtu > lcpiop->remparm.mru) {
/* Set new Max Transmission Unit for outgoing packets */
sp->iface->mtu = lcpiop->remparm.mru;
if (Ppptrace > 1)
log(-1," Set new MTU for outgoing packets: %d",
sp->iface->mtu);
}
/* Update async control character map for outgoing packets */
if (pppiop->ctlmap != lcpiop->remparm.ctl_map) {
pppiop->ctlmap = lcpiop->remparm.ctl_map;
if (Ppptrace > 1)
log(-1," Set new control map for outgoing packets: 0x%08lx",
pppiop->ctlmap);
}
/* Update for protocol compression for outgoing/incoming packets */
if (lcpiop->remparm.prot_compress) {
sp->escaped |= PPP_XMT_PRCOMP;
if (Ppptrace > 1)
log(-1," Begin protocol compression on outgoing packets");
}
if (lcpiop->lclparm.prot_compress) {
sp->escaped |= PPP_RCV_PRCOMP;
if (Ppptrace > 1)
log(-1," Begin protocol compression on incoming packets");
}
/* Update for addr/ctl compression for outgoing/incoming packets */
if (lcpiop->remparm.ac_compress) {
sp->escaped |= PPP_XMT_ACCOMP;
if (Ppptrace > 1)
log(-1," Begin addr/ctl compression on outgoing packets");
}
if (lcpiop->lclparm.ac_compress) {
sp->escaped |= PPP_RCV_ACCOMP;
if (Ppptrace > 1)
log(-1," Begin addr/ctl compression on incoming packets");
}
/* LCP is open; switch to next phase */
if ((lcpiop->lclparm.auth_type == PAP_AUTH_TYPE) ||
(lcpiop->remparm.auth_type == PAP_AUTH_TYPE)) {
/* Startup PAP negotiations (do IPCP when done with PAP) */
pap_start(sp);
} else {
/* Startup IPCP negotiations */
ipcp_start(sp);
}
return;
}
/* Reset LCP configuration options for initial request */
int
lcp_reset(pppiop)
struct pppctl *pppiop;
{
struct lcpctl *lcpiop;
if (Ppptrace > 5)
log(-1, "lcp_reset()");
lcpiop = &(pppiop->lcpio);
pppiop->ctlmap = DEF_CTL_MAP;
if (lcpiop->active == 0)
lcpiop->lcp_state = LCP_LISTEN;
else
lcpiop->lcp_state = LCP_CLOSED;
lcpiop->ack_retry = 0;
/* Reset our config request prarmeters to our preferred values */
memcpy(&(lcpiop->lclparm),&(lcpiop->initparm),
sizeof(struct lcpparm));
memcpy(&(lcpiop->remparm),&accept_parms,
sizeof(struct lcpparm));
/* Need to shutdown PAP session if waiting for password */
psignal(&(lcpiop->pap_user),0);
return 0;
}
/****************************************************************************/
/* Send our LCP configuration request */
static int
lcp_sendreq(sp)
struct slip *sp;
{
struct pppctl *pppiop;
struct lcpctl *lcpiop;
struct mbuf *bp;
if (Ppptrace > 5)
log(-1,"lcp_sendreq()");
pppiop = sp->pppio;
lcpiop = &(pppiop->lcpio);
/* Get a packet with our configuration request */
bp = lcp_makereq(&(lcpiop->lclparm));
/* Start timer against wait for reply to our config request */
lcp_timer(sp);
/* Send LCP configuration request to remote host */
pppiop->state = PPP_LCP;
if (lcpiop->lcp_state != LCP_ACK_SENT)
lcpiop->lcp_state = LCP_REQ_SENT;
return(lcp_sendreply(sp, CONFIG_REQ, 0, bp));
}
/*******************************************/
static struct mbuf *
lcp_makereq(localp)
struct lcpparm *localp;
{
register char *cp;
struct mbuf *bp;
struct mbuf *req_bp = NULLBUF;
if (Ppptrace > 5)
log(-1," lcp_makereq()");
/* Maximum Receive Unit */
if (localp->neg_mru) {
if (Ppptrace > 5)
log(-1," asking for MRU: %d (0x%02x)",
localp->mru,localp->mru);
/* Attempt to negotiate Maximum Receive Unit */
if ((bp = alloc_mbuf(4)) == NULLBUF)
return NULLBUF;
cp = bp->data;
*cp++ = MAX_RCV_UNIT;
*cp++ = 4;
put16(cp, localp->mru);
bp->cnt += 4;
append(&req_bp, bp);
}
/* Async Control Map */
if (localp->neg_ctl_map) {
if (Ppptrace > 5)
log(-1," asking for Async Control Map: 0x%08lx",
localp->ctl_map);
/* Attempt to negotiate Async Control Map */
if ((bp = alloc_mbuf(6)) == NULLBUF)
return NULLBUF;
cp = bp->data;
*cp++ = ASYNC_CTL_MAP;
*cp++ = 6;
put32(cp, localp->ctl_map);
bp->cnt += 6;
append(&req_bp, bp);
}
/* Authentication type */
if ((localp->neg_auth_type)&&(localp->auth_type != 0x0000)) {
if (Ppptrace > 5)
log(-1," asking for Auth Protocol: 0x%04x",
localp->auth_type);
/* Attempt to negotiate Authentication Protocol */
if ((bp = alloc_mbuf(4)) == NULLBUF)
return NULLBUF;
cp = bp->data;
*cp++ = AUTH_TYPE;
*cp++ = 4;
put16(cp, localp->auth_type);
bp->cnt += 4;
append(&req_bp, bp);
}
/* Magic Number */
if (localp->neg_magic_num) {
if (Ppptrace > 5)
log(-1," asking for Magic Number: %0x08lx",
localp->magic_num);
/* Attempt to negotiate Magic Number */
if ((bp = alloc_mbuf(6)) == NULLBUF)
return NULLBUF;
cp = bp->data;
*cp++ = MAGIC_NUMBER;
*cp++ = 6;
put32(cp, localp->magic_num);
bp->cnt += 6;
append(&req_bp, bp);
}
/* Protocol Field Compression */
if (localp->neg_prot_compress) {
if (Ppptrace > 5)
log(-1," asking for Protcol compression");
/* Attempt to negotiate protocol field compression */
if ((bp = alloc_mbuf(2)) == NULLBUF)
return NULLBUF;
cp = bp->data;
*cp++ = PROT_COMPRESS;
*cp++ = 2;
bp->cnt += 2;
append(&req_bp, bp);
}
/* Address and Control Field Compression */
if (localp->neg_ac_compress) {
if (Ppptrace > 5)
log(-1," asking for Addr/Ctl compression");
/* Attempt to negotiate protocol field compression */
if ((bp = alloc_mbuf(2)) == NULLBUF)
return NULLBUF;
cp = bp->data;
*cp++ = AC_COMPRESS;
*cp++ = 2;
bp->cnt += 2;
append(&req_bp, bp);
}
/* Encryption type not implemented */
/* Link Quality Monitoring not implemented */
return(req_bp);
}
/****************************************************************************/
/* Remote host ACKed our configuration request */
static void
lcp_rcvack(sp, rcnf, data)
struct slip *sp;
struct cnfhdr *rcnf;
struct mbuf *data;
{
struct pppctl *pppiop;
struct lcpctl *lcpiop;
if (Ppptrace > 5)
log(-1, "lcp_rcvack()");
pppiop = sp->pppio;
lcpiop = &(pppiop->lcpio);
stop_timer(&lcpiop->lcp_tm);
switch(lcpiop->lcp_state) {
case LCP_REQ_SENT:
/* Make sure ACK is proper */
if (lcp_chkack(sp, rcnf, data) != -1) {
/* Remote host accepted our request */
lcpiop->lcp_state = LCP_ACK_RCVD;
}
/* Still need to settle request from remote host */
lcp_timer(sp);
break;
case LCP_ACK_SENT:
/* Make sure ACK is proper */
if (lcp_chkack(sp, rcnf, data) == -1) {
/* Error in ACK from remote host */
/* Wait for another ACK, then send another request */
lcp_timer(sp);
} else {
/* LCP negotiation complete */
lcp_open(sp);
}
break;
case LCP_ACK_RCVD:
case LCP_OPEN:
/* Something went wrong; restart negotiations */
free_p(data);
lcp_reset(pppiop);
lcp_sendreq(sp);
break;
case LCP_TERMINATE:
/* We are attempting to close connection; wait */
/* for timeout to resend a Terminate Request */
free_p(data);
break;
case LCP_CLOSED:
case LCP_LISTEN:
default:
/* Confusion; shutdown the connection */
free_p(data);
lcp_shutdown(sp);
break;
}
return;
}
/* Remote host NAKed our configuration request */
static void
lcp_rcvnak(sp, rcnf, data)
struct slip *sp;
struct cnfhdr *rcnf;
struct mbuf *data;
{
struct pppctl *pppiop;
struct lcpctl *lcpiop;
if (Ppptrace > 5)
log(-1, "lcp_rcvnak()");
pppiop = sp->pppio;
lcpiop = &(pppiop->lcpio);
stop_timer(&lcpiop->lcp_tm);
switch(lcpiop->lcp_state) {
case LCP_REQ_SENT:
case LCP_ACK_SENT:
/* Update our config request to reflect NAKed options */
if (lcp_chknak(sp, rcnf, data) == -1) {
/* Bad NAK packet */
/* Wait for another; resend request on timeout */
lcp_timer(sp);
} else {
/* Send updated config request */
lcp_sendreq(sp);
}
break;
case LCP_ACK_RCVD:
case LCP_OPEN:
/* Something went wrong; restart negotiations */
free_p(data);
lcp_reset(pppiop);
lcp_sendreq(sp);
break;
case LCP_TERMINATE:
/* We are attempting to close connection; wait */
/* for timeout to resend a Terminate Request */
free_p(data);
break;
case LCP_CLOSED:
case LCP_LISTEN:
default:
/* Confusion; shutdown the connection */
free_p(data);
lcp_shutdown(sp);
break;
}
return;
}
/* Remote host rejected our configuration request */
static void
lcp_rcvrej(sp, rcnf, data)
struct slip *sp;
struct cnfhdr *rcnf;
struct mbuf *data;
{
struct pppctl *pppiop;
struct lcpctl *lcpiop;
if (Ppptrace > 5)
log(-1, "lcp_rcvrej()");
pppiop = sp->pppio;
lcpiop = &(pppiop->lcpio);
stop_timer(&lcpiop->lcp_tm);
switch(lcpiop->lcp_state) {
case LCP_REQ_SENT:
case LCP_ACK_SENT:
/* Update our config request to reflect rejected options */
if (lcp_chkrej(sp, rcnf, data) == -1) {
/* Bad reject packet */
/* Wait for another; resend request on timeout */
lcp_timer(sp);
} else {
/* Send updated config request */
lcp_sendreq(sp);
}
break;
case LCP_ACK_RCVD:
case LCP_OPEN:
/* Something went wrong; restart negotiations */
free_p(data);
lcp_reset(pppiop);
lcp_sendreq(sp);
break;
case LCP_TERMINATE:
/* We are attempting to close connection; wait */
/* for timeout to resend a Terminate Request */
free_p(data);
break;
case LCP_CLOSED:
case LCP_LISTEN:
default:
/* Confusion; shutdown the connection */
free_p(data);
lcp_shutdown(sp);
break;
}
return;
}
/* Process configuration request sent by remote host */
static void
lcp_rcvreq(sp, rcnf, data)
struct slip *sp;
struct cnfhdr *rcnf;
struct mbuf *data;
{
struct pppctl *pppiop;
struct lcpctl *lcpiop;
if (Ppptrace > 5)
log(-1, "lcp_rcvreq()");
pppiop = sp->pppio;
lcpiop = &(pppiop->lcpio);
switch(lcpiop->lcp_state) {
case LCP_LISTEN: /* Normal event */
case LCP_ACK_SENT: /* Unexpected event */
case LCP_OPEN: /* Unexpected event */
/* Reset LCP state machine for configuration negotiation */
lcp_reset(pppiop);
/* Send our configuration request */
lcp_sendreq(sp);
/* Evaluate configuration request from remote host */
lcp_chkreq(sp, rcnf, data);
break;
case LCP_ACK_RCVD:
/* Stop timer against wait for config request */
stop_timer(&(lcpiop->lcp_tm));
case LCP_REQ_SENT:
/* Evaluate configuration request from remote host */
lcp_chkreq(sp, rcnf, data);
break;
case LCP_TERMINATE:
/* We are attempting to close connection; wait */
/* for timeout to resend a Terminate Request */
free_p(data);
break;
case LCP_CLOSED:
default:
/* We are closed; dont accept any connections */
free_p(data);
lcp_shutdown(sp);
break;
}
return;
}
/* Remote host closed connection */
static void
lcp_rcvtermack(sp)
struct slip *sp;
{
struct pppctl *pppiop;
struct lcpctl *lcpiop;
if (Ppptrace > 5)
log(-1,"lcp_rcvtermack()");
pppiop = sp->pppio;
lcpiop = &(pppiop->lcpio);
stop_timer(&(lcpiop->lcp_tm));
switch(lcpiop->lcp_state) {
case LCP_OPEN:
/* Remote host has abruptly closed connection */
/* Need to inform upper levels */
case LCP_TERMINATE:
/* Remote host has responded to our terminate request */
if (Ppptrace)
log(-1,"%s: PPP/LCP Connection Closed",sp->iface->name);
pppiop->state = PPP_CLOSED;
if (lcpiop->active == 0)
lcpiop->lcp_state = LCP_LISTEN;
else
lcpiop->lcp_state = LCP_CLOSED;
/* Prepare for next open */
lcp_reset(pppiop);
psignal(lcpiop,0);
break;
case LCP_REQ_SENT:
/* Wait for timeout to restart attempt */
break;
case LCP_ACK_SENT:
case LCP_ACK_RCVD:
/* Something went wrong; restart negotiations */
lcp_reset(pppiop);
lcp_sendreq(sp);
break;
case LCP_CLOSED:
case LCP_LISTEN:
default:
/* Unexpected, but no action needed */
break;
}
return;
}
/* Remote peer requested that we close the PPP connection */
void
lcp_rcvtermreq(sp, rcnf)
struct slip *sp;
struct cnfhdr *rcnf;
{
struct pppctl *pppiop;
struct lcpctl *lcpiop;
if (Ppptrace > 5)
log(-1, "lcp_termreq()");
pppiop = sp->pppio;
lcpiop = &(pppiop->lcpio);
if (Ppptrace)
log(-1,"%s: PPP/LCP Peer requested close",sp->iface->name);
lcpiop->active = 0;
lcpiop->lcp_state = LCP_LISTEN;
/* Need to inform upper layers */
lcp_sendreply(sp, TERMINATE_ACK, rcnf->id, NULLBUF);
lcp_reset(pppiop);
pppiop->state = PPP_CLOSED;
return;
}
/* Shutdown the LCP connection */
void
lcp_shutdown(sp)
struct slip *sp;
{
struct pppctl *pppiop;
struct lcpctl *lcpiop;
if (Ppptrace > 5)
log(-1, "lcp_shutdown()");
pppiop = sp->pppio;
lcpiop = &(pppiop->lcpio);
if (Ppptrace)
log(-1,"%s: PPP/LCP Connection Shutdown",sp->iface->name);
if (lcpiop->active == 0)
lcpiop->lcp_state = LCP_LISTEN;
else
lcpiop->lcp_state = LCP_CLOSED;
/* Need to inform upper layers */
lcp_sendreply(sp,TERMINATE_ACK,0,NULLBUF);
lcp_reset(pppiop);
pppiop->state = PPP_CLOSED;
return;
}
/*******************************************/
/* Process configuration ACK send by remote host */
static int
lcp_chkack(sp, ackcnf, data)
struct slip *sp;
struct cnfhdr *ackcnf;
struct mbuf *data;
{
int ackerr = 0;
struct pppctl *pppiop;
struct lcpctl *lcpiop;
struct mbuf *req_bp;
struct opthdr reqopt;
struct opthdr ackopt;
int16 reqi16, acki16;
int32 reqi32, acki32;
if (Ppptrace > 5)
log(-1,"lcp_chkack()");
pppiop = sp->pppio;
lcpiop = &(pppiop->lcpio);
/* LCP ID field must match last request we sent */
if (ackcnf->id != lcpiop->lastid) {
if (Ppptrace > 1)
log(-1,"improper LCP ACK; bad ID");
free_p(data);
return -1;
}
/* Get a copy of last request we sent */
req_bp = lcp_makereq(&(lcpiop->lclparm));
/* Overall buffer length should match */
if (ackcnf->len != len_p(req_bp)) {
ackerr = 1;
}
/* ACK must echo all options we requested in the order requested */
while ((ntohopt(&reqopt, &req_bp) != -1) && (!ackerr)) {
/* Get config option from ACK packet */
if (ntohopt(&ackopt, &data) == -1) {
/* Must have as many acked options as requested */
ackerr = 1;
break;
}
/* Config option headers must match */
if ((ackopt.type != reqopt.type)
||(ackopt.len != reqopt.len)) {
ackerr = 1;
break;
}
/* Config option values must match */
switch(reqopt.type) {
case MAX_RCV_UNIT: /* Maximum Receive Unit */
case AUTH_TYPE: /* Authentication Protocol Type */
acki16 = pull16(&data);
reqi16 = pull16(&req_bp);
if (acki16 != reqi16) {
ackerr = 1;
}
break;
case MAGIC_NUMBER: /* Magic Number */
case ASYNC_CTL_MAP: /* Async Control Map */
acki32 = pull32(&data);
reqi32 = pull32(&req_bp);
if (acki32 != reqi32) {
ackerr = 1;
}
break;
case PROT_COMPRESS: /* Protocol Compression */
case AC_COMPRESS: /* Addr/Control Compression */
/* Option ON if requested */
break;
case ENCR_TYPE: /* Encryption type not implemented */
case LINK_QUALITY: /* Link Qual Monitor not implemented */
default: /* Shouldnt happen */
ackerr = 1;
break;
}
}
free_p(req_bp);
free_p(data);
if (ackerr) {
/* Error in configuration ACK */
if (Ppptrace > 5)
log(-1,"improper LCP ACK echo");
return -1;
}
/* ACK matches last request we made */
if (Ppptrace > 5)
log(-1,"valid LCP ACK echo");
return 0;
}
/* Process configuration NAK send by remote host */
static int
lcp_chknak(sp, nakcnf, data)
struct slip *sp;
struct cnfhdr *nakcnf;
struct mbuf *data;
{
int nakerr = 0;
struct pppctl *pppiop;
struct lcpctl *lcpiop;
struct lcpparm *localp;
struct mbuf *req_bp;
struct opthdr reqopt;
struct opthdr nakopt;
int16 naki16;
int32 naki32;
if (Ppptrace > 5)
log(-1,"lcp_chknak()");
pppiop = sp->pppio;
lcpiop = &(pppiop->lcpio);
localp = &(lcpiop->lclparm);
/* LCP ID field must match last request we sent */
if (nakcnf->id != lcpiop->lastid) {
if (Ppptrace > 1)
log(-1,"improper LCP NAK; bad ID");
free_p(data);
return -1;
}
/* Get a copy of last request we sent */
req_bp = lcp_makereq(&(lcpiop->lclparm));
/* Check overall buffer length */
if (nakcnf->len > len_p(req_bp)) {
/* Remote cant NAK more options than we requested */
nakerr = 1;
}
/* NAKed options must be same order as our original request */
while ((ntohopt(&nakopt, &data) != -1) && (!nakerr)) {
/* Get config option from our request */
if (ntohopt(&reqopt, &req_bp) == -1) {
/* Must find match to each NAKed option */
nakerr = 1;
break;
}
/* Maybe not all options were NAKed; look */
/* for matching option in our request */
while (reqopt.type != nakopt.type) {
/* This option not NAKed; eat rest */
/* of option from the request packet */
reqopt.len -= 2;
while (reqopt.len--)
pullchar(&req_bp);
/* Get next config option from our request */
if (ntohopt(&reqopt, &req_bp) == -1) {
/* Must find match to each NAKed option */
reqopt.type = 0;
nakerr = 1;
break;
}
}
/* Config option headers must match */
if ((nakopt.type != reqopt.type)
||(nakopt.len != reqopt.len)) {
nakerr = 1;
break;
}
/* Remote host replaced our request with new suggestion */
switch(reqopt.type) {
case MAX_RCV_UNIT: /* Maximum Receive Unit */
/* Get suggested MRU */
naki16 = pull16(&data);
/* Eat MRU from our request packet */
pull16(&req_bp);
if ((naki16 < MIN_MRU)||(naki16 > DEF_MRU))
naki16 = DEF_MRU;
/* Save new request value */
localp->mru = naki16;
break;
case ASYNC_CTL_MAP: /* Async Control Map */
/* Get suggested control map */
naki32 = pull32(&data);
/* Eat control map from our request packet */
pull32(&req_bp);
/* Remote host may ask to escape more control */
/* characters than we require, but must escape */
/* at least the control chars that we require. */
if (naki32 != (naki32 | lcpiop->initparm.ctl_map))
naki32 = lcpiop->initparm.ctl_map;
/* Save new request value */
localp->ctl_map = naki32;
break;
case AUTH_TYPE: /* Authentication Protocol Type */
/* Get suggested Auth Protocol */
naki16 = pull16(&data);
/* Eat auth type from our request packet */
pull16(&req_bp);
/* Can only accept auth protocols we know */
if (naki16 != PAP_AUTH_TYPE) {
/* Abandon request for auth type */
/* Wont open LCP layer without auth protocol */
naki16 = DEF_AUTH_TYPE;
}
/* Save new request value */
localp->mru = naki16;
break;
case MAGIC_NUMBER: /* Magic Number */
/* Get suggested magic number */
naki32 = pull32(&data);
/* Eat magic number from our request packet */
pull32(&req_bp);
/* Try to prevent matching magic numbers */
/* Save new request value */
localp->magic_num = naki32;
break;
case PROT_COMPRESS:
/* Remote host says no protocol compression */
localp->neg_prot_compress = 0;
localp->prot_compress = DEF_PROT_COMPR;
break;
case AC_COMPRESS:
/* Remote host says no addr/ctl compression */
localp->neg_ac_compress = 0;
localp->ac_compress = DEF_AC_COMPR;
break;
case ENCR_TYPE: /* Encryption type not implemented */
case LINK_QUALITY: /* Link Qual Monitor not implemented */
default: /* Shouldnt happen */
nakerr = 1;
break;
}
}
free_p(req_bp);
free_p(data);
if (nakerr) {
/* Error in configuration NAK */
if (Ppptrace > 5)
log(-1,"improper LCP NAK echo");
return -1;
}
/* NAK matches last request we made */
if (Ppptrace > 5)
log(-1,"valid LCP NAK echo");
return 0;
}
/* Process configuration reject send by remote host */
static int
lcp_chkrej(sp, rejcnf, data)
struct slip *sp;
struct cnfhdr *rejcnf;
struct mbuf *data;
{
int rejerr = 0;
struct pppctl *pppiop;
struct lcpctl *lcpiop;
struct lcpparm *localp;
struct mbuf *req_bp;
struct opthdr reqopt;
struct opthdr rejopt;
if (Ppptrace > 5)
log(-1,"lcp_chkrej()");
pppiop = sp->pppio;
lcpiop = &(pppiop->lcpio);
localp = &(lcpiop->lclparm);
/* LCP ID field must match last request we sent */
if (rejcnf->id != lcpiop->lastid) {
if (Ppptrace > 1)
log(-1,"improper LCP REJ; bad ID");
free_p(data);
return -1;
}
/* Get a copy of last request we sent */
req_bp = lcp_makereq(&(lcpiop->lclparm));
/* Check overall buffer length */
if (rejcnf->len > len_p(req_bp)) {
/* Remote cant NAK more options than we requested */
rejerr = 1;
}
/* Rejected options must be same order as our original request */
while ((ntohopt(&rejopt, &data) != -1) && (!rejerr)) {
/* Get config option from our request */
if (ntohopt(&reqopt, &req_bp) == -1) {
/* Must find match to each NAKed option */
rejerr = 1;
break;
}
/* Maybe not all options were NAKed; look */
/* for matching option in our request */
while (reqopt.type != rejopt.type) {
/* This option not NAKed; eat rest */
/* of option from the request packet */
reqopt.len -= 2;
while (reqopt.len--)
pullchar(&req_bp);
/* Get next config option from our request */
if (ntohopt(&reqopt, &req_bp) == -1) {
/* Must find match to each NAKed option */
reqopt.type = 0;
rejerr = 1;
break;
}
}
/* Config option headers must match */
if ((rejopt.type != reqopt.type)
||(rejopt.len != reqopt.len)) {
rejerr = 1;
break;
}
/* Remote host wont negotiate this option */
switch(reqopt.type) {
case MAX_RCV_UNIT: /* Maximum Receive Unit */
/* Eat MRU value from config packets */
pull16(&data);
pull16(&req_bp);
/* Dont attempt to negotiate MRU */
localp->neg_mru = 0;
localp->mru = DEF_MRU;
break;
case ASYNC_CTL_MAP: /* Async Control Map */
/* Eat control map value from config packets */
pull32(&data);
pull32(&req_bp);
/* Dont attempt to negotiate control map */
localp->neg_ctl_map = 0;
localp->ctl_map = DEF_CTL_MAP;
break;
case AUTH_TYPE: /* Authentication Protocol Type */
/* Eat auth type value from config packets */
pull16(&data);
pull16(&req_bp);
/* Dont attempt to negotiate auth type */
/* Wont open LCP layer without auth protocol */
localp->neg_auth_type = 0;
localp->auth_type = DEF_AUTH_TYPE;
break;
case MAGIC_NUMBER: /* Magic Number */
/* Eat magic number value from config packets */
pull32(&data);
pull32(&req_bp);
/* Dont attempt to negotiate control map */
localp->neg_magic_num = 0;
localp->magic_num = DEF_MAGIC_NUM;
break;
case PROT_COMPRESS: /* Protocol Compression */
/* Abandon attempt to use protocol compression */
localp->neg_prot_compress = 0;
localp->prot_compress = DEF_PROT_COMPR;
break;
case AC_COMPRESS: /* Addr/Ctl Compression */
/* Abandon attempt to use addr/ctl compression */
localp->neg_ac_compress = 0;
localp->ac_compress = DEF_AC_COMPR;
break;
case ENCR_TYPE: /* Encryption type not implemented */
case LINK_QUALITY: /* Link Qual Monitor not implemented */
default: /* Shouldnt happen */
rejerr = 1;
break;
}
}
free_p(req_bp);
free_p(data);
if (rejerr) {
/* Error in configuration reject */
if (Ppptrace > 5)
log(-1,"improper LCP REJ echo");
return -1;
}
/* Reject matches last request we made */
if (Ppptrace > 5)
log(-1,"valid LCP REJ echo");
return 0;
}
/* Check Link Control options requested by the remote host */
static void
lcp_chkreq(sp, reqcnf, data)
struct slip *sp;
struct cnfhdr *reqcnf;
struct mbuf *data;
{
struct pppctl *pppiop;
struct lcpctl *lcpiop;
int ilen;
int16 i16;
int32 i32;
register char *cp;
char cnf_accept = CONFIG_ACK; /* Overall reply to request */
char opt_accept; /* Per option reply */
struct opthdr reqopt; /* Per option header storage */
struct opthdr replyopt; /* For building reply */
struct lcpparm *remotep; /* Ptr to remote options */
struct lcpparm *initp; /* Ptr to initial lcl opts */
struct mbuf *bp; /* Ptr for building reply */
struct mbuf *reply_bp = NULLBUF; /* Actual reply packet */
if (Ppptrace > 5)
log(-1, "lcp_chkreq()");
pppiop = sp->pppio;
lcpiop = &(pppiop->lcpio);
remotep = &(lcpiop->remparm);
initp = &(lcpiop->initparm);
/* Make sure length in LCP config header is realistic */
i16 = len_p(data);
if (i16 < reqcnf->len)
reqcnf->len = i16;
/* Process options requested by remote host */
while (reqcnf->len > 0) {
/* Get header for next option */
if (ntohopt(&reqopt, &data) == -1)
break;
reqcnf->len -= reqopt.len; /* Count bytes this option */
reqopt.len -= 2; /* Get data len this option */
opt_accept = CONFIG_ACK; /* Assume will accept option */
switch(reqopt.type) {
case MAX_RCV_UNIT:
if (Ppptrace > 5)
log(-1, "remote asking for MRU");
/* Max Receive Unit is a 16bit field */
ilen = 2;
if (reqopt.len < ilen) {
/* Short option data; reject packet */
opt_accept = CONFIG_REJ;
i16 = DEF_MRU;
break;
}
/* Get proposed value from packet */
i16 = pull16(&data);
if ((remotep->neg_mru == 0) && (i16 != DEF_MRU)) {
/* Not open for negotiation */
opt_accept = CONFIG_REJ;
break;
}
/* Check if new value is appropriate */
if (i16 < MIN_MRU) {
/* Too small, ask for minimum instead */
opt_accept = CONFIG_NAK;
i16 = MIN_MRU;
} else if (i16 > DEF_MRU) {
/* Too big, tell largest value we can use */
opt_accept = CONFIG_NAK;
i16 = DEF_MRU;
} else {
/* Value is acceptable */
opt_accept = CONFIG_ACK;
}
remotep->mru = i16;
break;
case ASYNC_CTL_MAP: /* Async Control Map */
if (Ppptrace > 5)
log(-1, "remote asking for async control map");
/* Async control map is a 32bit field */
ilen = 4;
if (reqopt.len < ilen) {
/* Short option data; reject packet */
opt_accept = CONFIG_REJ;
i32 = DEF_CTL_MAP;
break;
}
/* Get proposed value from packet */
i32 = pull32(&data);
if ((remotep->neg_ctl_map == 0)
&& (i32 != DEF_CTL_MAP)) {
/* Not open for negotiation */
opt_accept = CONFIG_REJ;
break;
}
/* Record new async control character map */
opt_accept = CONFIG_ACK;
remotep->ctl_map = i32;
break;
case AUTH_TYPE:
if (Ppptrace > 5)
log(-1, "remote asking for Auth Protocol type");
/* Auth Protocol Type is a 16bit field */
ilen = 2;
if (reqopt.len < ilen) {
/* Short option data; reject packet */
opt_accept = CONFIG_REJ;
i16 = DEF_MRU;
break;
}
/* Get proposed value from packet */
i16 = pull16(&data);
if ((initp->neg_auth_type == 1)
&& (initp->auth_type != DEF_AUTH_TYPE)) {
/* We are requesting auth too; */
/* we only know PAP auth protocol */
/* PAP is a one-way authentication protocol */
opt_accept = CONFIG_REJ;
break;
}
if ((remotep->neg_auth_type == 0)
&& (i16 != DEF_AUTH_TYPE)) {
/* Not open for negotiation */
opt_accept = CONFIG_REJ;
break;
}
/* Check if new value is appropriate */
if (i16 == PAP_AUTH_TYPE) {
/* Yes, we know Password Auth Protocol */
opt_accept = CONFIG_ACK;
} else {
/* We dont know this protocol */
opt_accept = CONFIG_NAK;
i16 = PAP_AUTH_TYPE;
}
remotep->auth_type = i16;
break;
case MAGIC_NUMBER: /* Magic Number */
if (Ppptrace > 5)
log(-1, "remote asking for magic number");
/* Magic number is a 32bit field */
ilen = 4;
if (reqopt.len < ilen) {
/* Short option data; reject packet */
opt_accept = CONFIG_REJ;
i32 = 0L;
break;
}
/* Get proposed value from packet */
i32 = pull32(&data);
if ((remotep->neg_magic_num == 0)
|| (i32 == 0L)) {
/* Not open for negotiation */
opt_accept = CONFIG_REJ;
break;
}
/* Remote host cant use same magic number as us */
if (i32 == lcpiop->lclparm.magic_num) {
opt_accept = CONFIG_NAK;
++i32;
break;
}
/* Record new async control character map */
opt_accept = CONFIG_ACK;
remotep->magic_num = i32;
break;
case PROT_COMPRESS:
if (Ppptrace > 5)
log(-1, "remote asking for protocol compression");
/* Presence of option means do protcol compression */
ilen = 0;
if ((remotep->neg_prot_compress == 0)
&& (!DEF_PROT_COMPR)) {
/* We wont do protocol compression */
opt_accept = CONFIG_REJ;
break;
}
/* Accept request for protocol compression */
opt_accept = CONFIG_ACK;
remotep->prot_compress = 1;
break;
case AC_COMPRESS:
if (Ppptrace > 5)
log(-1, "remote asking for addr/ctl compression");
/* Presence of option means do addr/ctl compression */
ilen = 0;
if ((remotep->neg_ac_compress == 0)
&& (!DEF_AC_COMPR)) {
/* We wont do addr/ctl compression */
opt_accept = CONFIG_REJ;
break;
}
/* Accept request for addr/ctl compression */
opt_accept = CONFIG_ACK;
remotep->ac_compress = 1;
break;
case ENCR_TYPE: /* Encryption type not implemented */
case LINK_QUALITY: /* Link Qual Monitor not implemented */
default: /* Unknown option */
if (Ppptrace > 5)
log(-1, "remote asking for unimplemented option: %x len: %d",
reqopt.type, reqopt.len);
opt_accept = CONFIG_REJ;
ilen = reqopt.len;
if (len_p(data) < ilen)
ilen = len_p(data);
/* Look for standard sizes */
if (ilen == 2)
i16 = pull16(&data);
else if (ilen == 4) {
i32 = pull32(&data);
}
/* Other lengths dequeued at echo time */
break;
}
if ((opt_accept == CONFIG_ACK) &&
(cnf_accept != CONFIG_ACK))
/* This option was good, but a previous */
/* option was not. Return only those options */
/* which are being nacked/rejected. */
continue;
if (opt_accept == CONFIG_NAK) {
if (cnf_accept == CONFIG_REJ)
/* Return only those options */
/* which are being rejected. */
continue;
if (cnf_accept == CONFIG_ACK) {
/* Discard current list of good options */
free_p(reply_bp);
reply_bp = NULLBUF;
/* Send a list of nacked options */
cnf_accept = CONFIG_NAK;
}
}
if (opt_accept == CONFIG_REJ) {
if (cnf_accept != CONFIG_REJ) {
/* Discard current list of good options */
free_p(reply_bp);
reply_bp = NULLBUF;
/* Send a list of rejected options */
cnf_accept = CONFIG_REJ;
}
}
/* Add option response to the return list */
replyopt.type = reqopt.type;
replyopt.len = ilen + OPT_HDRLEN;
if ((bp = htonopt(&replyopt)) == NULLBUF)
break;
append(&reply_bp,bp);
if (ilen) {
if ((bp = alloc_mbuf(ilen)) == NULLBUF)
break;
cp = bp->data;
switch(ilen) {
case 2:
put16(cp,i16);
bp->cnt += 2;
break;
case 4:
put32(cp,i32);
bp->cnt += 4;
break;
default:
while (ilen--)
bp->data[bp->cnt++] = pullchar(&data);
}
append(&reply_bp,bp);
}
}
/* Send ACK/NAK/REJ to remote host */
if (cnf_accept == CONFIG_ACK) {
if (Ppptrace > 1)
log(-1, "accept all options requested by remote peer");
/* Accept configuration requested by remote host */
lcp_sendreply(sp, CONFIG_ACK, reqcnf->id, reply_bp);
if (lcpiop->lcp_state == LCP_REQ_SENT) {
lcpiop->lcp_state = LCP_ACK_SENT;
} else {
/* LCP link now open */
lcp_open(sp);
}
} else {
if (Ppptrace > 1)
log(-1,"options requested by remote peer not accepted: %s",
((cnf_accept==CONFIG_NAK) ? "NAK" : "REJ"));
/* NAK/REJ config request made by remote host */
lcp_sendreply(sp, cnf_accept, reqcnf->id, reply_bp);
/* Start timer against wait for amended config request */
if (lcpiop->lcp_state == LCP_ACK_RCVD)
lcp_timer(sp);
}
free_p(data);
return;
}
/****************************************************************************/
/* Timeout while waiting for reply from remote host */
static void
lcp_timeout(vp)
void *vp;
{
struct slip *sp;
struct pppctl *pppiop;
struct lcpctl *lcpiop;
if (Ppptrace > 1)
log(-1, "lcp_timeout()");
/* Load pointers to interface that timed-out */
sp = (struct slip *)vp;
pppiop = sp->pppio;
lcpiop = &(pppiop->lcpio);
/* Attempt to get things going again */
switch(lcpiop->lcp_state) {
case LCP_ACK_SENT:
/* Remote host isnt listening to our request */
lcp_reset(pppiop);
case LCP_REQ_SENT:
case LCP_ACK_RCVD:
if (lcpiop->active == 0) {
/* If passive open, we got a CONFIG_REQ from remote */
/* host but no ACK in response to our CONFIG_REQ */
if (++lcpiop->ack_retry > LCP_RETRY_MAX) {
/* Remote host doesnt seem to be listening */
lcp_shutdown(sp);
break;
}
}
/* Timeout waiting for ACK to our request, */
/* or timeout waiting for request from remote host */
lcp_sendreq(sp);
break;
case LCP_TERMINATE:
/* Timeout waiting for terminate ACK; send another request */
if (++lcpiop->ack_retry > LCP_TERM_RETRY) {
/* No response to our polite request; give it up */
if (Ppptrace)
log(-1,"%s: PPP/LCP Connection Closed without reply from remote peer",sp->iface->name);
if (lcpiop->active == 0)
lcpiop->lcp_state = LCP_LISTEN;
else
lcpiop->lcp_state = LCP_CLOSED;
lcp_sendreply(sp,TERMINATE_ACK,0,NULLBUF);
lcp_reset(pppiop);
tprintf("Still no response; marking LCP layer as closed\n");
pppiop->state = PPP_CLOSED;
psignal(lcpiop,0);
} else {
/* Request remote host to close data link */
tprintf("Timeout waiting for response to our LCP terminate request\n");
lcp_timer(sp);
lcp_sendreply(sp, TERMINATE_REQ, 0, NULLBUF);
}
break;
case LCP_CLOSED:
case LCP_LISTEN:
case LCP_OPEN:
default:
/* Confusion; shutdown the connection */
lcp_shutdown(sp);
break;
}
return;
}
/* Set a timer in case an expected event does not occur */
static void
lcp_timer(sp)
struct slip *sp;
{
struct pppctl *pppiop;
struct lcpctl *lcpiop;
struct timer *t;
if (Ppptrace > 5)
log(-1,"lcp_timer()");
pppiop = sp->pppio;
lcpiop = &(pppiop->lcpio);
t = &(lcpiop->lcp_tm);
t->func = (void (*)())lcp_timeout;
t->arg = (void *)sp;
start_timer(t);
return;
}
/****************************************************************************/
/* Send an LCP packet to the remote host */
static int
lcp_sendreply(sp,code,id,data)
struct slip *sp;
char code;
unsigned char id;
struct mbuf *data;
{
struct iface *iface;
struct cnfhdr hdr;
/* Load LCP header values */
hdr.code = code;
switch(code) {
case CONFIG_REQ:
case TERMINATE_REQ:
case ECHO_REQ:
/* Save ID field for match aginst replies from remote host */
sp->pppio->lcpio.lastid = Pppid;
case PROT_REJ:
case DISCARD_REQ:
/* Use a unique ID field value */
hdr.id = Pppid++;
break;
case CONFIG_ACK:
case CONFIG_NAK:
case CONFIG_REJ:
case TERMINATE_ACK:
case CODE_REJ:
case ECHO_REPLY:
/* Use ID sent by remote host */
hdr.id = id;
break;
default:
/* Shouldnt happen */
if (Ppptrace)
log(-1, "bogus code: %x", code);
return -1;
}
hdr.len = len_p(data) + CNF_HDRLEN;
if (Ppptrace > 1) {
log(-1, "%s: PPP/LCP Send: current state: %s LCP option: %s id: %d len: %d",
sp->iface->name,
LCPStates[sp->pppio->lcpio.lcp_state],
LCPCodes[code],hdr.id,hdr.len);
}
/* Prepend LCP header to packet data */
if ((data = htoncnf(&hdr,data)) == NULLBUF)
return -1;
/* Send LCP packet to remote host */
sp->pppio->sndlcp++;
iface = sp->iface;
return( (*iface->output)
(iface, NULLCHAR, NULLCHAR, PPP_LCP_TYPE, data) );
}
/* Process incoming LCP packet */
void
lcpproc(iface,bp)
struct iface *iface;
struct mbuf *bp;
{
struct slip *sp;
struct cnfhdr hdr;
sp = &Slip[iface->xdev];
/* Extract LCP header */
ntohcnf(&hdr, &bp);
hdr.len -= CNF_HDRLEN; /* Length includes envelope */
trim_mbuf(&bp, hdr.len); /* Trim off FCS bytes */
if (Ppptrace > 1)
log(-1, "%s: PPP/LCP Recv: current state: %s: LCP option: %s id: %d len: %d",
iface->name,
LCPStates[sp->pppio->lcpio.lcp_state],
LCPCodes[hdr.code], hdr.id, hdr.len);
/* Process LCP packet data */
switch(hdr.code) {
case CONFIG_REQ: /* Request of remote host */
lcp_rcvreq(sp, &hdr, bp);
break;
case CONFIG_ACK: /* Remote accepted our req */
lcp_rcvack(sp, &hdr, bp);
break;
case CONFIG_NAK: /* Remote adjusted our req */
lcp_rcvnak(sp, &hdr, bp);
break;
case CONFIG_REJ: /* Remote rejected our req */
lcp_rcvrej(sp, &hdr, bp);
break;
case TERMINATE_REQ: /* Remote request to close */
lcp_rcvtermreq(sp, &hdr);
break;
case TERMINATE_ACK: /* Remote closed on request */
lcp_rcvtermack(sp);
break;
case CODE_REJ:
case PROT_REJ:
case ECHO_REQ:
case ECHO_REPLY:
case DISCARD_REQ:
if (Ppptrace)
log(-1,"Unimplemented LCP packet type: %x; dropping packet",hdr.code);
free_p(bp);
break;
default:
if (Ppptrace)
log(-1,"Unknown LCP packet type: %x; dropping packet",hdr.code);
free_p(bp);
break;
}
return;
}