home *** CD-ROM | disk | FTP | other *** search
- /*
- * 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;
- }
- }
-