home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
HAM Radio 1
/
HamRadio.cdr
/
misc
/
src0131
/
pppipcp.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-12-09
|
44KB
|
1,698 lines
/*
* PPPIPCP.C -- negotiate IP parameters
*
* 12-89 -- Katie Stevens (dkstevens@ucdavis.edu)
* UC Davis, Computing Services
* PPP.04 02-90 [ks] make automatic route entry a private route
* PPP.07 04-90 [ks] make IP addr negotiation independent of
* whether host is active or passive open
* thanks to Brad Clements, bkc@omnigate.clarkson.edu
* dont bring up IP unless both addrs are known
* PPP.08 05-90 [ks] IP compr: we request means we want to rcv compr;
* remote requests means we should xmt compr TCP.
* improve PPP trace reporting
* PPP.09 05-90 [ks] add UPAP auth protocol
* PPP.10 07-90 [ks] make ppp open/close/reset work properly
* add peerID-to-IPaddr lookup table
* add peer IP lookup pool
* PPP.13 08-90 [ks] add timestamp on PPP link open
* PPP.14 08-90 [ks] change UPAP to PAP for consistency with RFC1172
* make IPCP timeout configurable
* PPP.15 09-90 [ks] update to KA9Q NOS v900828
*/
#include <stdio.h>
#include <ctype.h>
#include <time.h>
#include "global.h"
#include "files.h"
#include "netuser.h"
#include "mbuf.h"
/*#include "proc.h"*/
#include "iface.h"
#include "pktdrvr.h"
#include "ip.h"
#include "tcp.h"
#include "slcompre.h"
#include "ppp.h"
#include "slip.h"
#include "proc.h"
extern int32 Ip_addr;
/* Counter for PPP id field */
extern unsigned char Pppid;
/* PPP tracing */
extern int Ppptrace;
static void ipcp_open __ARGS((struct slip *sp));
static int ipcp_addr_idle __ARGS((int32 addr));
static int32 ipcp_lookuppeer __ARGS((char *peerid));
static int32 ipcp_poolnext __ARGS((struct ipcppool *poolp));
static void ipcp_reset_tcp __ARGS((struct slip *sp));
static int ipcp_sendreq __ARGS((struct slip *sp));
static struct mbuf *ipcp_makereq __ARGS((struct ipcpctl *ipcpiop));
static void ipcp_rcvack __ARGS((struct slip *sp, struct cnfhdr *rcnf,
struct mbuf *data));
static void ipcp_rcvnak __ARGS((struct slip *sp, struct cnfhdr *rcnf,
struct mbuf *data));
static void ipcp_rcvrej __ARGS((struct slip *sp, struct cnfhdr *rcnf,
struct mbuf *data));
static void ipcp_rcvreq __ARGS((struct slip *sp, struct cnfhdr *rcnf,
struct mbuf *data));
static void ipcp_rcvtermack __ARGS((struct slip *sp));
static void ipcp_rcvtermreq __ARGS((struct slip *sp, struct cnfhdr *rcnf));
static void ipcp_shutdown __ARGS((struct slip *sp));
static int ipcp_chkack __ARGS((struct slip *sp, struct cnfhdr *ackcnf,
struct mbuf *data));
static int ipcp_chknak __ARGS((struct slip *sp, struct cnfhdr *nakcnf,
struct mbuf *data));
static int ipcp_chkrej __ARGS((struct slip *sp, struct cnfhdr *rejcnf,
struct mbuf *data));
static void ipcp_chkreq __ARGS((struct slip *sp, struct cnfhdr *reqcnf,
struct mbuf *data));
static void ipcp_timeout __ARGS((void *vp));
static void ipcp_timer __ARGS((struct slip *sp));
static int ipcp_sendreply __ARGS((struct slip *sp, char code,
unsigned char id, struct mbuf *data));
/* In PPPLCP.C */
/* Possible IPCP states same as possible LCP states */
extern char *LCPStates[];
extern char *LCPCodes[];
/****************************************************************************/
/* Initialize IP Control Protocol state machine for config exchange */
int
ipcp_start(sp)
struct slip *sp;
{
struct pppctl *pppiop;
struct lcpctl *lcpiop;
struct ipcpctl *ipcpiop;
if (Ppptrace > 5)
log(-1, "ipcp_start()");
pppiop = sp->pppio;
lcpiop = &(pppiop->lcpio);
ipcpiop = &(pppiop->ipcpio);
/* Just finished LCP negotiation; prepare for IPCP negotiation */
pppiop->state = PPP_IPCP;
ipcp_reset(sp);
/* Can set peer_addr with 'ppp peer' command */
ipcpiop->attempt_dest = ipcpiop->peer_addr;
/* If not already set, can lookup PAP peer ID in PPPHOSTS file */
if ((ipcpiop->peer_addr == 0L) &&
(lcpiop->lclparm.auth_type == PAP_AUTH_TYPE)) {
ipcpiop->attempt_dest = ipcp_lookuppeer(lcpiop->pap_user);
}
/* If still not set, can get next address from PPP pool */
if ((ipcpiop->peer_addr == 0L) &&
(ipcpiop->peer_pool != NULLPOOL)) {
ipcpiop->attempt_dest = ipcp_poolnext(ipcpiop->peer_pool);
}
if (ipcpiop->attempt_dest == 0L)
ipcpiop->accept_addrs = 1;
if (!ipcpiop->active) {
/* Passive open; wait until remote host attempts connection */
ipcpiop->ipcp_state = IPCP_LISTEN;
return 0;
}
/* Active open; begin IPCP configuration negotiation */
ipcpiop->ipcp_state = IPCP_CLOSED;
return(ipcp_sendreq(sp));
}
/*******************************************/
/* Close the IP connection from local side */
int
ipcp_close(sp)
struct slip *sp;
{
struct pppctl *pppiop;
struct ipcpctl *ipcpiop;
if (Ppptrace > 5)
log(-1,"ipcp_close()");
pppiop = sp->pppio;
ipcpiop = &(pppiop->ipcpio);
if ((ipcpiop->ipcp_state == IPCP_CLOSED) ||
(ipcpiop->ipcp_state == IPCP_LISTEN)) {
/* Already closed */
return 0;
}
if (Ppptrace > 1)
log(-1,"%s: PPP/IPCP IP Closing",sp->iface->name);
/* Reset IP connections on this interface */
ipcp_reset_tcp(sp);
/* Remove routing entry from route table */
rt_drop(ipcpiop->attempt_dest, (unsigned int)32);
/* Set a timer against our request to shutdown */
ipcp_timer(sp);
/* Ask remote host to shutdown */
ipcpiop->ipcp_state = IPCP_TERMINATE;
ipcpiop->ack_retry = 0;
if (ipcp_sendreply(sp, TERMINATE_REQ, 0, NULLBUF) == 0)
pwait(ipcpiop);
return 0;
}
/* Initialize our IPCP configuration options to compiled default options */
void
ipcp_init(sp)
struct slip *sp;
{
struct pppctl *pppiop;
struct ipcpctl *ipcpiop;
struct timer *t;
if (Ppptrace > 5)
log(-1, "ipcp_init()");
pppiop = sp->pppio;
ipcpiop = &(pppiop->ipcpio);
t = &(ipcpiop->ipcp_tm);
ipcpiop->ipcp_state = IPCP_CLOSED;
/* Set option parameters to first request defaults */
ipcpiop->peer_addr = 0L;
ipcpiop->neg_ip_compr = 0;
ipcpiop->ip_compr_type = DEF_IP_COMPR;
/* Initialize timer */
set_timer(t,IPCP_TIMEOUT*1000L);
ipcp_timer(sp);
stop_timer(&(ipcpiop->ipcp_tm));
ipcp_reset(sp);
}
/* IP Control configuration negotiation complete */
static void
ipcp_open(sp)
struct slip *sp;
{
struct pppctl *pppiop;
struct ipcpctl *ipcpiop;
pppiop = sp->pppio;
ipcpiop = &(pppiop->ipcpio);
/* Mark IPCP layer as open */
if (Ppptrace)
log(-1,"%s: PPP/IPCP IP Open",sp->iface->name);
ipcpiop->ipcp_state = IPCP_OPEN;
/* Make sure we found out IP address at each end */
if ((ipcpiop->attempt_src != ipcpiop->accept_dest)
|| (ipcpiop->attempt_src == 0L)) {
if (Ppptrace)
log(-1,"Couldnt negotiate local IP addr for interface %s",
sp->iface->name);
ipcp_shutdown(sp);
return;
}
if ((ipcpiop->attempt_dest != ipcpiop->accept_src)
|| (ipcpiop->attempt_dest == 0L)) {
if (Ppptrace)
log(-1,"Couldnt negotiate remote peer IP addr for interface %s",
sp->iface->name);
ipcp_shutdown(sp);
return;
}
/* Set IP compression to reflect negotiated option */
if (ipcpiop->lcl_ip_compr == IPCP_VJCOMPR) {
sp->escaped |= PPP_RCV_VJCOMPR;
if (Ppptrace > 1)
log(-1," Begin Van Jacobson TCP/IP header compression on incoming packets");
} else {
sp->escaped &= ~PPP_RCV_VJCOMPR;
}
if (ipcpiop->rem_ip_compr == IPCP_VJCOMPR) {
sp->escaped |= PPP_XMT_VJCOMPR;
if (Ppptrace > 1)
log(-1," Begin Van Jacobson TCP/IP header compression on outgoing packets");
} else {
sp->escaped &= ~PPP_XMT_VJCOMPR;
}
if ((sp->escaped & (PPP_RCV_VJCOMPR | PPP_XMT_VJCOMPR)) != 0) {
/* Initialize compression control structure */
sp->slcomp = (struct slcompress *)mallocw(sizeof(struct slcompress));
sl_compress_init(sp->slcomp);
}
/* Set our IP address to reflect negotiated option */
if (ipcpiop->attempt_src != sp->iface->addr) {
if (Ip_addr == 0L)
Ip_addr = ipcpiop->attempt_src;
sp->iface->addr = ipcpiop->attempt_src;
if (Ppptrace > 1)
log(-1," Saving new IP addr for interface %s: %s",
sp->iface->name,inet_ntoa(sp->iface->addr));
}
/* Add point-to-point route to remote PPP host */
rt_add(ipcpiop->attempt_dest, (unsigned int)32, (int32)0,
sp->iface, (int32)1, (int32)0, (char)1);
if (Ppptrace > 1)
log(-1," Add route to peer (%s) on interface %s",
inet_ntoa(ipcpiop->attempt_dest),
sp->iface->name);
/* Allow any queued IP traffic */
pppiop->state = PPP_OPEN;
pppiop->upsince = time(0L);
}
/* Reset IPCP configuration options for initial request */
int
ipcp_reset(sp)
struct slip *sp;
{
struct pppctl *pppiop;
struct ipcpctl *ipcpiop;
if (Ppptrace > 5)
log(-1, "ipcp_reset()");
pppiop = sp->pppio;
ipcpiop = &(pppiop->ipcpio);
ipcpiop->ipcp_state = IPCP_CLOSED;
ipcpiop->ack_retry = 0;
ipcpiop->active = pppiop->lcpio.active;
/* Set up for IP addr exchange; attempt values set in ipcp_start() */
ipcpiop->attempt_addrs = 1;
ipcpiop->attempt_src = Ip_addr;
/* If we dont know our IP address, or if we dont know IP addr */
/* of the remote host, accept address assignment from remote */
if ((ipcpiop->attempt_src == 0L)||(ipcpiop->attempt_dest == 0L)) {
ipcpiop->accept_addrs = 1;
} else {
ipcpiop->accept_addrs = 0;
}
ipcpiop->accept_src = ipcpiop->attempt_dest;
ipcpiop->accept_dest = ipcpiop->attempt_src;
/* Reset IP header compression options to first request defaults */
ipcpiop->attempt_ip_compr = ipcpiop->neg_ip_compr;
ipcpiop->lcl_ip_compr = ipcpiop->ip_compr_type;
ipcpiop->accept_ip_compr = 1;
ipcpiop->rem_ip_compr = DEF_IP_COMPR;
sp->escaped &= ~PPP_RCV_VJCOMPR;
sp->escaped &= ~PPP_XMT_VJCOMPR;
return 0;
}
/*******************************************/
static int
ipcp_addr_idle(addr)
int32 addr;
{
struct iface *ifp;
struct pppctl *pppiop;
/* Check if peer IP address is already in use on another interface */
for (ifp=Ifaces; ifp != NULLIF; ifp = ifp->next) {
if ((Slip[ifp->xdev].iface == ifp) &&
(Slip[ifp->xdev].type == CL_PPP)) {
pppiop = Slip[ifp->xdev].pppio;
if ((pppiop->ipcpio.ipcp_state != IPCP_CLOSED) &&
(pppiop->ipcpio.attempt_dest == addr)) {
return 0;
}
}
}
return 1;
}
/* Check if we have a specific IP address to assign to remote peer host */
static int32
ipcp_lookuppeer(peerid)
char *peerid;
{
FILE *peerfp;
char buf[128];
char *cp;
int32 peer_addr = 0L;
if ((peerfp = fopen(Userfile, READ_TEXT)) == NULLFILE)
return 0L;
while (fgets(buf,128,peerfp) != NULLCHAR) {
if(buf[0] == '#')
continue; /* Comment */
if((cp = strchr(buf,' ')) == NULLCHAR)
/* Bogus entry */
continue;
*cp++ = '\0'; /* Now points to password */
if(stricmp(peerid,buf) == 0) {
++cp;
if ((cp = strrchr(cp,' ')) == NULLCHAR)
/* No IP address given */
break;
++cp;
peer_addr = resolve(cp);
break; /* Found user name */
}
}
fclose(peerfp);
return(peer_addr);
}
static int32
ipcp_poolnext(poolp)
struct ipcppool *poolp;
{
int i;
int32 nextaddr = 0L;
for (i=0; i<=(poolp->peer_max - poolp->peer_min); ++i) {
if (ipcp_addr_idle(poolp->peer_next))
nextaddr = poolp->peer_next;
if (poolp->peer_next == poolp->peer_max)
poolp->peer_next = poolp->peer_min;
else
++poolp->peer_next;
if (nextaddr != 0L)
break;
}
return(nextaddr);
}
/* Close all TCP connections in preparation for PPP link shutdown */
static void
ipcp_reset_tcp(sp)
struct slip *sp;
{
register struct iface *ifp;
register int i;
register struct tcb *tcb;
register struct route *rp;
ifp = sp->iface;
for(i=0;i<NTCB;i++){
for(tcb=Tcbs[i];tcb != NULLTCB;tcb = tcb->next) {
if ((tcb->state == TCP_LISTEN) &&
(tcb->flags.clone == 1)) {
/* Leave servers alone */
continue;
}
rp = rt_lookup(tcb->conn.remote.address);
if (rp->iface == ifp) {
/* Reset active connections */
reset_tcp(tcb);
}
}
}
/* Wait 1sec for any replys or static */
pause(1000L);
}
/****************************************************************************/
/* Send our IPCP configuration request */
static int
ipcp_sendreq(sp)
struct slip *sp;
{
struct pppctl *pppiop;
struct ipcpctl *ipcpiop;
struct mbuf *bp;
if (Ppptrace > 5)
log(-1,"ipcp_sendreq()");
pppiop = sp->pppio;
ipcpiop = &(pppiop->ipcpio);
/* Get a packet with our configuration request */
bp = ipcp_makereq(ipcpiop);
/* Start timer against wait for reply to our config request */
ipcp_timer(sp);
/* Send IPCP configuration request to remote host */
pppiop->state = PPP_IPCP;
if (ipcpiop->ipcp_state != IPCP_ACK_SENT)
ipcpiop->ipcp_state = IPCP_REQ_SENT;
return(ipcp_sendreply(sp, CONFIG_REQ, 0, bp));
}
/*******************************************/
static struct mbuf *
ipcp_makereq(ipcpiop)
struct ipcpctl *ipcpiop;
{
register char *cp;
struct mbuf *bp;
struct mbuf *req_bp = NULLBUF;
if (Ppptrace > 5)
log(-1," ipcp_makereq()");
/* Request our preferred IP control options */
if (ipcpiop->attempt_addrs) {
/* Attempt to negotiate IP addrs */
if (Ppptrace > 5) {
log(-1," asking for src addr: %s",
inet_ntoa(ipcpiop->attempt_src));
log(-1," asking for dest addr: %s",
inet_ntoa(ipcpiop->attempt_dest));
}
if ((bp = alloc_mbuf(10)) == NULLBUF)
return NULLBUF;
cp = bp->data;
*cp++ = IP_ADDRS;
*cp++ = 10;
cp = put32(cp, ipcpiop->attempt_src);
cp = put32(cp, ipcpiop->attempt_dest);
bp->cnt += 10;
append(&req_bp, bp);
}
/* IP header compression */
if (ipcpiop->attempt_ip_compr) {
if (Ppptrace > 5) {
log(-1," asking for IP compression: %x",
ipcpiop->lcl_ip_compr);
}
/* Attempt to negotiate IP compression */
if ((bp = alloc_mbuf(4)) == NULLBUF)
return NULLBUF;
cp = bp->data;
*cp++ = IP_COMPR_TYPE;
*cp++ = 4;
put16(cp, ipcpiop->lcl_ip_compr);
bp->cnt += 4;
append(&req_bp, bp);
}
/* Return our config request */
return(req_bp);
}
/****************************************************************************/
/* Remote host ACKed our configuration request */
static void
ipcp_rcvack(sp, rcnf, data)
struct slip *sp;
struct cnfhdr *rcnf;
struct mbuf *data;
{
struct pppctl *pppiop;
struct ipcpctl *ipcpiop;
if (Ppptrace > 5)
log(-1, "ipcp_rcvack()");
pppiop = sp->pppio;
ipcpiop = &(pppiop->ipcpio);
stop_timer(&ipcpiop->ipcp_tm);
switch(ipcpiop->ipcp_state) {
case IPCP_REQ_SENT:
/* Make sure ACK is proper */
if (ipcp_chkack(sp, rcnf, data) != -1) {
/* Remote host accepted our request */
ipcpiop->ipcp_state = IPCP_ACK_RCVD;
}
/* Still need to settle request from remote host */
ipcp_timer(sp);
break;
case IPCP_ACK_SENT:
/* Make sure ACK is proper */
if (ipcp_chkack(sp, rcnf, data) == -1) {
/* Error in ACK from remote host */
/* Wait for another ACK, then send another request */
ipcp_timer(sp);
} else {
/* IPCP negotiation complete */
ipcp_open(sp);
}
break;
case IPCP_ACK_RCVD:
case IPCP_OPEN:
/* Something went wrong; restart negotiations */
free_p(data);
ipcp_reset(sp);
ipcp_sendreq(sp);
break;
case IPCP_TERMINATE:
/* We are attempting to close connection; wait */
/* for timeout to resend a Terminate Request */
free_p(data);
break;
case IPCP_CLOSED:
case IPCP_LISTEN:
default:
/* Confusion; shutdown the connection */
free_p(data);
ipcp_shutdown(sp);
break;
}
}
/* Remote host NAKed our configuration request */
static void
ipcp_rcvnak(sp, rcnf, data)
struct slip *sp;
struct cnfhdr *rcnf;
struct mbuf *data;
{
struct pppctl *pppiop;
struct ipcpctl *ipcpiop;
if (Ppptrace > 5)
log(-1, "ipcp_rcvnak()");
pppiop = sp->pppio;
ipcpiop = &(pppiop->ipcpio);
stop_timer(&ipcpiop->ipcp_tm);
switch(ipcpiop->ipcp_state) {
case IPCP_REQ_SENT:
case IPCP_ACK_SENT:
/* Update our config request to reflect NAKed options */
if (ipcp_chknak(sp, rcnf, data) == -1) {
/* Bad NAK packet */
/* Wait for another; resend request on timeout */
ipcp_timer(sp);
} else {
/* Send updated config request */
ipcp_sendreq(sp);
}
break;
case IPCP_ACK_RCVD:
case IPCP_OPEN:
/* Something went wrong; restart negotiations */
free_p(data);
ipcp_reset(sp);
ipcp_sendreq(sp);
break;
case IPCP_TERMINATE:
/* We are attempting to close connection; wait */
/* for timeout to resend a Terminate Request */
free_p(data);
break;
case IPCP_CLOSED:
case IPCP_LISTEN:
default:
/* Confusion; shutdown the connection */
free_p(data);
ipcp_shutdown(sp);
break;
}
}
/* Remote host rejected our configuration request */
static void
ipcp_rcvrej(sp, rcnf, data)
struct slip *sp;
struct cnfhdr *rcnf;
struct mbuf *data;
{
struct pppctl *pppiop;
struct ipcpctl *ipcpiop;
if (Ppptrace > 5)
log(-1, "ipcp_rcvrej()");
pppiop = sp->pppio;
ipcpiop = &(pppiop->ipcpio);
stop_timer(&ipcpiop->ipcp_tm);
switch(ipcpiop->ipcp_state) {
case IPCP_REQ_SENT:
case IPCP_ACK_SENT:
/* Update our config request to reflect rejected options */
if (ipcp_chkrej(sp, rcnf, data) == -1) {
/* Bad reject packet */
/* Wait for another; resend request on timeout */
ipcp_timer(sp);
} else {
/* Send updated config request */
ipcp_sendreq(sp);
}
break;
case IPCP_ACK_RCVD:
case IPCP_OPEN:
/* Something went wrong; restart negotiations */
free_p(data);
ipcp_reset(sp);
ipcp_sendreq(sp);
break;
case IPCP_TERMINATE:
/* We are attempting to close connection; wait */
/* for timeout to resend a Terminate Request */
free_p(data);
break;
case IPCP_CLOSED:
case IPCP_LISTEN:
default:
/* Confusion; shutdown the connection */
free_p(data);
ipcp_shutdown(sp);
break;
}
}
/* Process configuration request sent by remote host */
static void
ipcp_rcvreq(sp, rcnf, data)
struct slip *sp;
struct cnfhdr *rcnf;
struct mbuf *data;
{
struct pppctl *pppiop;
struct ipcpctl *ipcpiop;
if (Ppptrace > 5)
log(-1, "ipcp_rcvreq()");
pppiop = sp->pppio;
ipcpiop = &(pppiop->ipcpio);
switch(ipcpiop->ipcp_state) {
case IPCP_LISTEN: /* Normal event */
case IPCP_ACK_SENT: /* Unexpected event */
case IPCP_OPEN: /* Unexpected event */
/* Reset IPCP state machine for configuration negotiation */
ipcp_reset(sp);
/* Send our configuration request */
ipcp_sendreq(sp);
/* Evaluate configuration request from remote host */
ipcp_chkreq(sp, rcnf, data);
break;
case IPCP_ACK_RCVD:
/* Stop timer against wait for config request */
stop_timer(&(ipcpiop->ipcp_tm));
case IPCP_REQ_SENT:
/* Evaluate configuration request from remote host */
ipcp_chkreq(sp, rcnf, data);
break;
case IPCP_TERMINATE:
/* We are attempting to close connection; wait */
/* for timeout to resend a Terminate Request */
free_p(data);
break;
case IPCP_CLOSED:
default:
/* We are closed; dont accept any connections */
free_p(data);
ipcp_shutdown(sp);
break;
}
}
/* Remote host closed connection */
static void
ipcp_rcvtermack(sp)
struct slip *sp;
{
struct pppctl *pppiop;
struct ipcpctl *ipcpiop;
if (Ppptrace > 5)
log(-1,"ipcp_rcvtermack()");
pppiop = sp->pppio;
ipcpiop = &(pppiop->ipcpio);
stop_timer(&(ipcpiop->ipcp_tm));
switch(ipcpiop->ipcp_state) {
case IPCP_OPEN:
/* Remote host has abruptly closed connection */
/* Reset IP connections on this interface */
ipcp_reset_tcp(sp);
/* Remove routing entry from route table */
rt_drop(ipcpiop->attempt_dest, (unsigned int)32);
/* Fall through */
case IPCP_TERMINATE:
/* Remote host has responded to our terminate request */
if (Ppptrace)
log(-1,"%s: PPP/IPCP IP Closed",sp->iface->name);
if (ipcpiop->active)
ipcpiop->ipcp_state = IPCP_CLOSED;
else
ipcpiop->ipcp_state = IPCP_LISTEN;
/* Prepare for next open */
ipcp_reset(sp);
/* We are done; signal anyone waiting for us to close */
psignal(ipcpiop,0);
break;
case IPCP_REQ_SENT:
/* Wait for timeout to restart attempt */
break;
case IPCP_ACK_SENT:
case IPCP_ACK_RCVD:
/* Something went wrong; restart negotiations */
ipcp_reset(sp);
ipcp_sendreq(sp);
break;
case IPCP_CLOSED:
case IPCP_LISTEN:
default:
/* Unexpected, but no action needed */
break;
}
}
/* Remote peer requested that we close the IP layer */
static void
ipcp_rcvtermreq(sp, rcnf)
struct slip *sp;
struct cnfhdr *rcnf;
{
struct pppctl *pppiop;
struct ipcpctl *ipcpiop;
if (Ppptrace > 5)
log(-1, "ipcp_shutdown()");
pppiop = sp->pppio;
ipcpiop = &(pppiop->ipcpio);
/* Reset IP connections on this interface */
ipcp_reset_tcp(sp);
/* Remove routing entry from route table */
rt_drop(ipcpiop->attempt_dest, (unsigned int)32);
if (Ppptrace)
log(-1,"%s: PPP/IPCP Peer requested close",sp->iface->name);
ipcpiop->active = 0;
ipcpiop->ipcp_state = IPCP_LISTEN;
ipcp_sendreply(sp, TERMINATE_ACK, rcnf->id, NULLBUF);
ipcp_reset(sp);
}
/* Shutdown the IPCP connection */
static void
ipcp_shutdown(sp)
struct slip *sp;
{
struct pppctl *pppiop;
struct ipcpctl *ipcpiop;
if (Ppptrace > 5)
log(-1, "ipcp_shutdown()");
pppiop = sp->pppio;
ipcpiop = &(pppiop->ipcpio);
/* Reset IP connections on this interface */
ipcp_reset_tcp(sp);
/* Remove routing entry from route table */
rt_drop(ipcpiop->attempt_dest, (unsigned int)32);
if (Ppptrace)
log(-1,"%s: PPP/IPCP IP Shutdown",sp->iface->name);
if (ipcpiop->active)
ipcpiop->ipcp_state = IPCP_CLOSED;
else
ipcpiop->ipcp_state = IPCP_LISTEN;
ipcp_sendreply(sp,TERMINATE_ACK,0,NULLBUF);
ipcp_reset(sp);
}
/*******************************************/
/* Process configuration ACK send by remote host */
static int
ipcp_chkack(sp, ackcnf, data)
struct slip *sp;
struct cnfhdr *ackcnf;
struct mbuf *data;
{
int ackerr = 0;
struct pppctl *pppiop;
struct ipcpctl *ipcpiop;
struct mbuf *req_bp;
struct opthdr reqopt;
struct opthdr ackopt;
int16 reqi16, acki16;
int32 reqsrc_ip, reqdest_ip, acksrc_ip, ackdest_ip;
if (Ppptrace > 5)
log(-1,"ipcp_chkack()");
pppiop = sp->pppio;
ipcpiop = &(pppiop->ipcpio);
/* IPCP ID field must match last request we sent */
if (ackcnf->id != ipcpiop->lastid) {
if (Ppptrace > 1)
log(-1,"improper IPCP ACK; bad ID");
free_p(data);
return -1;
}
/* Get a copy of last request we sent */
req_bp = ipcp_makereq(ipcpiop);
/* 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 IP_ADDRS: /* IP address */
/* Echoed values must match our request */
reqsrc_ip = pull32(&req_bp);
reqdest_ip = pull32(&req_bp);
acksrc_ip = pull32(&data);
ackdest_ip = pull32(&data);
if (acksrc_ip != reqsrc_ip) {
ackerr = 1;
break;
}
if (ackdest_ip != reqdest_ip) {
ackerr = 1;
break;
}
break;
case IP_COMPR_TYPE: /* IP header compr */
/* Echoed values must match our request */
reqi16 = pull16(&req_bp);
acki16 = pull16(&data);
if (reqi16 != acki16) {
ackerr = 1;
break;
}
break;
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 IPCP ACK echo");
return -1;
}
/* ACK matches last request we made */
if (Ppptrace > 5)
log(-1,"valid IPCP ACK echo");
return 0;
}
/* Process configuration NAK send by remote host */
static int
ipcp_chknak(sp, nakcnf, data)
struct slip *sp;
struct cnfhdr *nakcnf;
struct mbuf *data;
{
int nakerr = 0;
struct pppctl *pppiop;
struct ipcpctl *ipcpiop;
struct mbuf *req_bp;
struct opthdr reqopt;
struct opthdr nakopt;
int16 naki16;
int32 naksrc_ip, nakdest_ip;
if (Ppptrace > 5)
log(-1,"ipcp_chknak()");
pppiop = sp->pppio;
ipcpiop = &(pppiop->ipcpio);
/* IPCP ID field must match last request we sent */
if (nakcnf->id != ipcpiop->lastid) {
if (Ppptrace > 1)
log(-1,"improper IPCP NAK; bad ID");
free_p(data);
return -1;
}
/* Get a copy of last request we sent */
req_bp = ipcp_makereq(ipcpiop);
/* 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 IP_ADDRS: /* IP address */
/* Get replacement value from NAK packet */
naksrc_ip = pull32(&data);
nakdest_ip = pull32(&data);
/* Eat option value from our request packet */
pull32(&req_bp);
pull32(&req_bp);
/* Ignore remote if we want to control addrs */
if (ipcpiop->accept_addrs != 0) {
/* We asked remote for our addresses */
if (ipcpiop->attempt_src == 0L)
ipcpiop->attempt_src = naksrc_ip;
if (ipcpiop->attempt_dest == 0L)
ipcpiop->attempt_dest = nakdest_ip;
}
break;
case IP_COMPR_TYPE: /* IP header compr */
/* Get replacement value from NAK packet */
naki16 = pull16(&data);
/* Eat option value from our request packet */
pull16(&req_bp);
/* See if we can do this type of IP compression */
if (naki16 == IPCP_VJCOMPR) {
/* Ask for Van Jacobson TCP compression */
ipcpiop->lcl_ip_compr = IPCP_VJCOMPR;
} else {
/* Cant do that type of compr, ask for none */
ipcpiop->lcl_ip_compr = DEF_IP_COMPR;
}
break;
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 IPCP NAK echo");
return -1;
}
/* NAK matches last request we made */
if (Ppptrace > 5)
log(-1,"valid IPCP NAK echo");
return 0;
}
/* Process configuration reject send by remote host */
static int
ipcp_chkrej(sp, rejcnf, data)
struct slip *sp;
struct cnfhdr *rejcnf;
struct mbuf *data;
{
int rejerr = 0;
struct pppctl *pppiop;
struct ipcpctl *ipcpiop;
struct mbuf *req_bp;
struct opthdr reqopt;
struct opthdr rejopt;
if (Ppptrace > 5)
log(-1,"ipcp_chkrej()");
pppiop = sp->pppio;
ipcpiop = &(pppiop->ipcpio);
/* IPCP ID field must match last request we sent */
if (rejcnf->id != ipcpiop->lastid) {
if (Ppptrace > 1)
log(-1,"improper IPCP REJ; bad ID");
free_p(data);
return -1;
}
/* Get a copy of last request we sent */
req_bp = ipcp_makereq(ipcpiop);
/* 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 IP_ADDRS: /* IP address */
/* Eat option values from each packet */
pull32(&req_bp);
pull32(&req_bp);
pull32(&data);
pull32(&data);
/* Abandon attempt to negotiate IP addrs */
ipcpiop->attempt_addrs = 0;
break;
case IP_COMPR_TYPE: /* IP header compression */
/* Eat option values from each packet */
pull16(&req_bp);
pull16(&data);
/* Abandon attempt to negotiate IP compression */
ipcpiop->attempt_ip_compr = 0;
ipcpiop->lcl_ip_compr = DEF_IP_COMPR;
break;
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 IPCP REJ echo");
return -1;
}
/* Reject matches last request we made */
if (Ppptrace > 5)
log(-1,"valid IPCP REJ echo");
return 0;
}
/* Check IP Control options requested by the remote host */
static void
ipcp_chkreq(sp, reqcnf, data)
struct slip *sp;
struct cnfhdr *reqcnf;
struct mbuf *data;
{
struct pppctl *pppiop;
struct ipcpctl *ipcpiop;
int ilen;
int16 i16;
int32 reqsrc_ip, reqdest_ip;
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 mbuf *bp; /* Ptr for building reply */
struct mbuf *reply_bp = NULLBUF; /* Actual reply packet */
if (Ppptrace > 5)
log(-1, "ipcp_chkreq()");
pppiop = sp->pppio;
ipcpiop = &(pppiop->ipcpio);
/* Make sure length in IPCP config header is realistic */
ilen = len_p(data);
if (ilen < reqcnf->len)
reqcnf->len = ilen;
/* 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 IP_ADDRS: /* IP address */
if (Ppptrace > 5)
log(-1, "remote asking to negotiate IP addrs");
/* IP Addr is 2 32bit fields */
ilen = 8;
if (reqopt.len < ilen) {
/* Short option data; reject packet */
opt_accept = CONFIG_REJ;
break;
}
/* Get proposed value from packet */
reqsrc_ip = pull32(&data);
reqdest_ip = pull32(&data);
if (Ppptrace > 5) {
log(-1, "src IP addr: %s",
inet_ntoa(reqsrc_ip));
log(-1, "dest IP addr: %s",
inet_ntoa(reqdest_ip));
}
/* Check requested IP addresses */
if (ipcpiop->accept_addrs == 0) {
/* Request okay if it matches what we want */
if ((reqsrc_ip == ipcpiop->attempt_dest)
&& (reqdest_ip == ipcpiop->attempt_src)) {
opt_accept = CONFIG_ACK;
/* Save these values for later */
ipcpiop->accept_src = reqsrc_ip;
ipcpiop->accept_dest = reqdest_ip;
break;
}
if ((reqsrc_ip == ipcpiop->accept_src)
&& (reqdest_ip == ipcpiop->accept_dest)) {
/* We already NAKed these once */
opt_accept = CONFIG_REJ;
break;
}
/* Cant accept suggestion of remote host */
opt_accept = CONFIG_NAK;
/* Save these values in case remote insists */
ipcpiop->accept_src = reqsrc_ip;
ipcpiop->accept_dest = reqdest_ip;
/* Tell remote what to request instead */
reqsrc_ip = ipcpiop->attempt_dest;
reqdest_ip = ipcpiop->attempt_src;
break;
}
/* Make sure remote is not repeating itself */
if ((reqsrc_ip == ipcpiop->accept_src)
&& (reqdest_ip == ipcpiop->accept_dest)) {
/* We already NAKed these once */
opt_accept = CONFIG_REJ;
break;
}
/* Save these values for later */
ipcpiop->accept_src = reqsrc_ip;
ipcpiop->accept_dest = reqdest_ip;
/* Remote host may request IP addrs */
if(reqsrc_ip == 0L) {
/* Remote host request its IP addr */
if (ipcpiop->attempt_dest == 0L) {
/* We dont have an addr for remote */
opt_accept = CONFIG_REJ;
break;
} else {
/* Give IP addr to remote peer */
opt_accept = CONFIG_NAK;
reqsrc_ip = ipcpiop->attempt_dest;
}
} else {
/* Remote host gave us its IP addr */
if (ipcpiop->attempt_dest == 0L) {
/* We need to know peer IP addr */
ipcpiop->attempt_dest = reqsrc_ip;
} else {
/* We already know peer IP addr */
if (reqsrc_ip != ipcpiop->attempt_dest) {
opt_accept = CONFIG_NAK;
reqsrc_ip = ipcpiop->attempt_dest;
}
}
}
if (reqdest_ip == 0L) {
/* Remote host requested our IP addr */
if (ipcpiop->attempt_src == 0L) {
/* We dont know our IP addr */
opt_accept = CONFIG_REJ;
break;
} else {
/* Tell remote what our IP addr is */
opt_accept = CONFIG_NAK;
reqdest_ip = ipcpiop->attempt_src;
}
} else {
/* Remote host gave us our IP addr */
if (ipcpiop->attempt_src == 0L) {
/* We need to know our IP addr */
ipcpiop->attempt_src = reqdest_ip;
} else {
/* We already know our IP addr */
if (reqdest_ip != ipcpiop->attempt_src) {
opt_accept = CONFIG_NAK;
reqdest_ip = ipcpiop->attempt_src;
}
}
}
break;
case IP_COMPR_TYPE: /* IP header compression */
if (Ppptrace > 5) {
log(-1, "remote asking to negotiate IP compression");
}
/* IP compression type is a 16 bit field */
ilen = 2;
if (reqopt.len < ilen) {
/* Short option; reject packet */
opt_accept = CONFIG_REJ;
break;
}
/* Get proposed value from packet */
i16 = pull16(&data);
if ((ipcpiop->accept_ip_compr == 0)
&& (i16 != DEF_IP_COMPR)) {
/* Not open for negotiation */
opt_accept = CONFIG_REJ;
break;
}
/* Check if requested compr type is acceptable */
if (i16 == IPCP_VJCOMPR) {
/* We can do Van Jacobson TCP header compr */
opt_accept = CONFIG_ACK;
} else {
/* Dont know this compr type;
* suggest Van Jacobson TCP header compr
*/
opt_accept = CONFIG_NAK;
i16 = IPCP_VJCOMPR;
}
ipcpiop->rem_ip_compr = i16;
break;
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);
/* Data 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 8:
cp = put32(cp, reqsrc_ip);
cp = put32(cp, reqdest_ip);
bp->cnt += 8;
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 */
ipcp_sendreply(sp, CONFIG_ACK, reqcnf->id, reply_bp);
if (ipcpiop->ipcp_state == IPCP_REQ_SENT) {
ipcpiop->ipcp_state = IPCP_ACK_SENT;
} else {
/* PPP data link now ready for IP traffic */
ipcp_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 */
ipcp_sendreply(sp, cnf_accept, reqcnf->id, reply_bp);
/* Start timer against wait for amended config request */
if (ipcpiop->ipcp_state == IPCP_ACK_RCVD)
ipcp_timer(sp);
}
free_p(data);
}
/****************************************************************************/
/* Timeout while waiting for reply from remote host */
static void
ipcp_timeout(vp)
void *vp;
{
struct slip *sp;
struct pppctl *pppiop;
struct ipcpctl *ipcpiop;
if (Ppptrace > 1)
log(-1, "ipcp_timeout()");
/* Load pointers to interface that timed-out */
sp = (struct slip *)vp;
pppiop = sp->pppio;
ipcpiop = &(pppiop->ipcpio);
/* Attempt to get things going again */
switch(ipcpiop->ipcp_state) {
case IPCP_ACK_SENT:
/* Remote host isnt listening to our request */
ipcp_reset(sp);
case IPCP_REQ_SENT:
case IPCP_ACK_RCVD:
if (!ipcpiop->active) {
/* If passive open, we got a CONFIG_REQ from remote */
/* host but no ACK in response to our CONFIG_REQ */
if (++ipcpiop->ack_retry > IPCP_RETRY_MAX) {
/* Remote host doesnt seem to be listening */
ipcp_shutdown(sp);
break;
}
}
/* Timeout waiting for ACK to our request, */
/* or timeout waiting for request from remote host */
ipcp_sendreq(sp);
break;
case IPCP_TERMINATE:
/* Timeout waiting for terminate ACK; send another request */
if (++ipcpiop->ack_retry > IPCP_TERM_RETRY) {
/* No response to our polite request; give it up */
if (Ppptrace)
log(-1,"%s: PPP/IPCP IP Closed without reply from remote peer",sp->iface->name);
if (ipcpiop->active)
ipcpiop->ipcp_state = IPCP_CLOSED;
else
ipcpiop->ipcp_state = IPCP_LISTEN;
ipcp_sendreply(sp,TERMINATE_ACK,0,NULLBUF);
ipcp_reset(sp);
tprintf("Still no response; marking IPCP layer as closed\n");
psignal(ipcpiop,0);
} else {
/* Request remote host to close IP */
tprintf("Timeout waiting for response to our IPCP terminate request\n");
ipcp_timer(sp);
ipcp_sendreply(sp, TERMINATE_REQ, 0, NULLBUF);
}
break;
case IPCP_CLOSED:
case IPCP_LISTEN:
case IPCP_OPEN:
default:
/* Confusion; shutdown the connection */
ipcp_shutdown(sp);
break;
}
}
/* Set a timer in case an expected event does not occur */
static void
ipcp_timer(sp)
struct slip *sp;
{
struct pppctl *pppiop;
struct ipcpctl *ipcpiop;
struct timer *t;
if (Ppptrace > 5)
log(-1,"ipcp_timer()");
pppiop = sp->pppio;
ipcpiop = &(pppiop->ipcpio);
t = &(ipcpiop->ipcp_tm);
t->func = (void (*)())ipcp_timeout;
t->arg = (void *)sp;
start_timer(t);
}
/****************************************************************************/
/* Send an IPCP packet to the remote host */
static int
ipcp_sendreply(sp,code,id,data)
struct slip *sp;
char code;
unsigned char id;
struct mbuf *data;
{
struct iface *iface;
struct cnfhdr hdr;
/* Load IPCP header values */
hdr.code = code;
switch(code) {
case CONFIG_REQ:
case TERMINATE_REQ:
/* Save ID field for match aginst replies from remote host */
sp->pppio->ipcpio.lastid = Pppid;
/* 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:
/* Use ID sent by remote host */
hdr.id = id;
break;
default:
/* Shouldnt happen */
if (Ppptrace)
log(-1, "bogus code: %x\n", code);
return -1;
}
hdr.len = len_p(data) + CNF_HDRLEN;
/* Prepend IPCP header to packet data */
if ((data = htoncnf(&hdr,data)) == NULLBUF)
return -1;
if (Ppptrace > 1)
log(-1, "%s: PPP/IPCP Send: current state: %s IPCP option: %s id: %d len: %d",
sp->iface->name,
LCPStates[sp->pppio->ipcpio.ipcp_state],
LCPCodes[code],hdr.id,hdr.len);
/* Send IPCP packet to remote host */
sp->pppio->sndipcp++;
iface = sp->iface;
return( (*iface->output)
(iface, NULLCHAR, NULLCHAR, PPP_IPCP_TYPE, data) );
}
/* Process incoming IPCP packet */
void
ipcpproc(iface,bp)
struct iface *iface;
struct mbuf *bp;
{
struct slip *sp;
struct cnfhdr hdr;
sp = &Slip[iface->xdev];
/* Extract IPCP 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/IPCP Recv: current state: %s IPCP option: %s id: %d len: %d",
iface->name,
LCPStates[sp->pppio->ipcpio.ipcp_state],
LCPCodes[hdr.code], hdr.id, hdr.len);
/* Process IPCP packet data */
switch(hdr.code) {
case CONFIG_REQ: /* Request of remote host */
ipcp_rcvreq(sp, &hdr, bp);
break;
case CONFIG_ACK: /* Remote accepted our req */
ipcp_rcvack(sp, &hdr, bp);
break;
case CONFIG_NAK: /* Remote adjusted our req */
ipcp_rcvnak(sp, &hdr, bp);
break;
case CONFIG_REJ: /* Remote rejected our req */
ipcp_rcvrej(sp, &hdr, bp);
break;
case TERMINATE_REQ: /* Remote request to close */
ipcp_rcvtermreq(sp, &hdr);
break;
case TERMINATE_ACK: /* Remote closed on request */
ipcp_rcvtermack(sp);
break;
case CODE_REJ:
if (Ppptrace)
log(-1,"Unimplemented IPCP packet type: %x; dropping packet",hdr.code);
free_p(bp);
break;
default:
if (Ppptrace)
log(-1,"Unknown IPCP packet type: %x; dropping packet",hdr.code);
free_p(bp);
break;
}
}