/* * PPP.C -- Send and receive datagrams on serial lines with * Point-to-Point Protocol * * This implementation of PPP is declared to be in the public domain. * * Based (in part) upon previous implementations by: * 1989 -- Drew Daniel Perkins (ddp@andrew.cmu.edu) * Carnegie Mellon University * 09-90 -- Katie Stevens (dkstevens@ucdavis.edu) * UC Davis, Computing Services * * Jan 91 Bill_Simpson@um.cc.umich.edu * Computer Systems Consulting Services * * Feb 91 Glenn McGregor (ghm@merit.edu) * Testing and suggestions. * * May 91 Bill Simpson & Glenn McGregor * Update to newest draft RFCs. * Add support for echo and discard message sending. * PAP prompt for password only when fails (allow missing password). */ #include #include #include "global.h" #include "mbuf.h" #include "timer.h" #include "proc.h" #include "iface.h" #include "internet.h" #include "ip.h" #include "slhc.h" #include "8250.h" #include "asy.h" #include "pktdrvr.h" #include "socket.h" #include "devparam.h" #include "ppp.h" #include "pppfsm.h" #include "ppplcp.h" #include "pppipcp.h" #include "ppppap.h" #include "trace.h" /* Routines local to this file */ static struct mbuf *htonppp __ARGS((struct ppp_hdr *ppp, struct mbuf *data)); static void ppp_log __ARGS((struct ppp_s *ppp_p, char *comment)); static void ppp_in_error __ARGS((struct ppp_s *ppp_p, struct mbuf *bp, char *comment)); static void ppp_out_error __ARGS((struct ppp_s *ppp_p, struct mbuf *bp, char *comment)); static void ppp_unknown __ARGS((struct ppp_s *ppp_p, struct mbuf *bp, char *comment)); static int ppp_raw __ARGS((struct iface *iface, struct mbuf *data)); static void ppp_queue __ARGS((struct ppp_s *ppp_p, struct mbuf *bp, int16 negotiated)); static void ppp_recv __ARGS((int dev, void *p1, void *p2)); static int ppp_iostatus __ARGS((struct iface *ifp, int command, int32 value)); static void ppp_machine __ARGS((int dev, void *p1, void *p2)); /* * FCS lookup table as generated by fcsgen.c */ int16 fcstab[256] = { 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 }; #define pppfcs(fcs, c) ((fcs >> 8) ^ fcstab[(fcs ^ c) & 0x00ff]) #define SP_CHAR 0x20 /* actions for incoming bytes */ enum { modeTOSS, modeESCAPED, modeNORMAL }; /****************************************************************************/ /* Convert PPP header in host form to network form */ static struct mbuf * htonppp(ppp, data) struct ppp_hdr *ppp; struct mbuf *data; { struct mbuf *bp; register char *cp; /* Prepend header onto packet data */ if ((bp = pushdown(data, PPP_HDR_LEN)) == NULLBUF) return NULLBUF; /* Load header with proper values */ cp = bp->data; *cp++ = ppp->addr; *cp++ = ppp->control; cp = put16(cp,ppp->protocol); return bp; } /* Extract PPP header from incoming packet */ int ntohppp(ppp, bpp) struct ppp_hdr *ppp; struct mbuf **bpp; { ppp->addr = PULLCHAR(bpp); ppp->control = PULLCHAR(bpp); ppp->protocol = pull16(bpp); return(PPP_HDR_LEN); } /************************************************************************/ /* General log routine */ static void ppp_log( ppp_p, comment ) struct ppp_s *ppp_p; char *comment; { if (ppp_p->trace) log(-1,"%s: PPP %s", ppp_p->iface->name, comment); } /* Bad Input packet */ static void ppp_in_error(ppp_p, bp, comment) struct ppp_s *ppp_p; struct mbuf *bp; char *comment; { ppp_p->InError++; free_p(bp); ppp_log( ppp_p, comment ); } /* Bad output packet */ static void ppp_out_error(ppp_p, bp, comment) struct ppp_s *ppp_p; struct mbuf *bp; char *comment; { ppp_p->OutError++; free_p(bp); ppp_log( ppp_p, comment ); } /* Unknown type input packet */ static void ppp_unknown(ppp_p, bp, comment) struct ppp_s *ppp_p; struct mbuf *bp; char *comment; { struct ipcp_s *ipcp_p; if ( (ipcp_p = ppp_p->fsm[IPcp].pdv) != NULL ) { slhc_toss( ipcp_p->slhcp ); } ppp_in_error( ppp_p, bp, comment ); } /****************************************************************************/ /* Send IP datagram with Point-to-Point Protocol */ int ppp_send(bp,iface,gateway,prec,del,tput,rel) struct mbuf *bp; /* Buffer to send */ struct iface *iface; /* Pointer to interface control block */ int32 gateway; /* Ignored (PPP is point-to-point) */ int prec; int del; int tput; int rel; { struct ppp_s *ppp_p; struct ipcp_s *ipcp_p; int protocol = PPP_IP_PROTOCOL; if (iface == NULLIF || (ppp_p = iface->extension) == NULL) { free_p(bp); return -1; } if (ppp_p->fsm[IPcp].state != fsmOPENED) { ppp_out_error( ppp_p, bp, "not open for IP traffic" ); return -1; } ipcp_p = ppp_p->fsm[IPcp].pdv; if (ipcp_p->remote.work.negotiate & IPCP_N_COMPRESS) { /* Attempt IP/TCP header compression */ switch ( slhc_compress(ipcp_p->slhcp, &bp, ipcp_p->remote.work.slot_compress) ) { case SL_TYPE_IP: protocol = PPP_IP_PROTOCOL; break; case SL_TYPE_COMPRESSED_TCP: protocol = PPP_COMPR_PROTOCOL; break; case SL_TYPE_UNCOMPRESSED_TCP: protocol = PPP_UNCOMP_PROTOCOL; break; default: ppp_out_error( ppp_p, bp, "bad IP packet" ); return -1; }; } ppp_p->OutIP++; return (*iface->output)(iface,NULLCHAR,NULLCHAR,protocol,bp); } /* Send a packet with PPP header */ int ppp_output(iface,dest,source,protocol,data) struct iface *iface; /* Pointer to interface control block */ char *dest; /* Dest addr (ignored; PPP is point-to-point) */ char *source; /* Source addr (ignored; PPP is point-to-point) */ int16 protocol; /* PPP Protocol Type field */ struct mbuf *data; /* Actual data to be sent */ { struct ppp_s *ppp_p; struct mbuf *bp; struct ppp_hdr hdr; if (iface == NULLIF || (ppp_p = iface->extension) == NULL) { free_p(data); return -1; } if (ppp_p->phase == pppDEAD) { ppp_out_error( ppp_p, data, "line not up" ); return -1; } hdr.addr = HDLC_ALL_ADDR; hdr.control = HDLC_UI; hdr.protocol = protocol; if ((bp = htonppp(&hdr, data)) == NULLBUF) { ppp_out_error( ppp_p, data, Nospace ); return -1; } return (*iface->raw)(iface,bp); } /* Encode a raw packet in PPP framing, put on link output queue */ static int ppp_raw(iface,bp) struct iface *iface; struct mbuf *bp; { struct ppp_s *ppp_p = iface->extension; struct lcp_s *lcp_p = ppp_p->fsm[Lcp].pdv; struct mbuf *hbp; struct ppp_hdr hdr; int full_lcp, full_ac, full_p; int16 calc_fcs = HDLC_FCS_START; int32 accm = LCP_ACCM_DEFAULT; int len = PPP_HDR_LEN; register char *cp; register int c; dump(iface,IF_TRACE_OUT,CL_PPP,bp); iface->rawsndcnt++; iface->lastsent = secclock(); /* Get the HDLC/PPP header */ ntohppp(&hdr, &bp); if ( ( full_lcp = (hdr.protocol == PPP_LCP_PROTOCOL) ) == 0 && (lcp_p->remote.work.negotiate & LCP_N_ACCM) ) { accm = lcp_p->remote.work.accm; } if ( ( full_p = ( full_lcp || !(lcp_p->remote.work.negotiate & LCP_N_PFC) || hdr.protocol > 0x00ff ) ) == 0 ) { --len; } /* Discard HDLC address and control fields if possible */ if ( ( full_ac = ( full_lcp || !(lcp_p->remote.work.negotiate & LCP_N_ACFC) || ( !full_p && hdr.protocol == HDLC_ALL_ADDR && *bp->data == HDLC_UI ) ) ) == 0 ) { len -= 2; } /* Prepend header onto packet data */ if ((hbp = pushdown(bp, len)) == NULLBUF) { ppp_out_error( ppp_p, bp, Nospace ); return -1; } /* Load header with proper values */ cp = hbp->data; if ( full_ac ) { *cp++ = hdr.addr; *cp++ = hdr.control; } if ( full_p ) *cp++ = (hdr.protocol >> 8); *cp++ = (hdr.protocol & 0x00ff); /* Allocate output mbuf that's twice as long as the packet. * This is a worst-case guess (consider a packet full of HDLC_FLAGs!) */ if ((bp = alloc_mbuf((int16)(2*len_p(hbp) + HDLC_ENVLEN))) == NULLBUF) { ppp_out_error( ppp_p, hbp, Nospace ); return -1; } cp = bp->data; /* No need to send an opening flag if the previous packet is still * being transmitted. */ if ( Asy[iface->dev].dma.flags == 0 ) { /* Flush out any line garbage */ *cp++ = HDLC_FLAG; ppp_p->OutOpenFlag++; } /* Copy input to output, escaping special characters */ while ((c = PULLCHAR(&hbp)) != -1) { /* Fold char value into FCS calculated so far */ calc_fcs = pppfcs(calc_fcs, c); if ( ((c < SP_CHAR) && (accm & (1L << c))) || (c == HDLC_ESC_ASYNC) || (c == HDLC_FLAG)) { *cp++ = HDLC_ESC_ASYNC; *cp++ = (c ^ HDLC_ESC_COMPL); } else { *cp++ = c; } } /* Final FCS calculation */ calc_fcs ^= 0xffff; c = (calc_fcs & 0x00ff); /* Least significant byte first */ if ( ((c < SP_CHAR) && (accm & (1L << c))) ||(c == HDLC_ESC_ASYNC) ||(c == HDLC_FLAG)) { *cp++ = HDLC_ESC_ASYNC; *cp++ = (c ^ HDLC_ESC_COMPL); } else { *cp++ = c; } c = (calc_fcs >> 8); /* Most significant byte next */ if ( ((c < SP_CHAR) && (accm & (1L << c))) ||(c == HDLC_ESC_ASYNC) ||(c == HDLC_FLAG)) { *cp++ = HDLC_ESC_ASYNC; *cp++ = (c ^ HDLC_ESC_COMPL); } else { *cp++ = c; } /* Tie off the packet */ *cp++ = HDLC_FLAG; bp->cnt = cp - bp->data; if (iface->trace & IF_TRACE_RAW) raw_dump(iface,IF_TRACE_OUT,bp); ppp_p->OutTxPacketCount++; return asy_send(iface->dev,bp); } /****************************************************************************/ /* Queue packet for ppp_proc with full header */ /* (part of ppp_recv) */ static void ppp_queue(ppp_p,bp,negotiated) struct ppp_s *ppp_p; struct mbuf *bp; int16 negotiated; { struct ppp_hdr hdr; struct mbuf *hbp; /* HDLC address and control fields may be compressed out */ if ((byte_t)bp->data[0] != HDLC_ALL_ADDR) { if (!(negotiated & LCP_N_ACFC)) { ppp_unknown( ppp_p, bp, "missing ALL address" ); return; } } else if ((byte_t)bp->data[1] != HDLC_UI) { if (!(negotiated & LCP_N_ACFC) || !(negotiated & LCP_N_PFC)) { ppp_unknown( ppp_p, bp, "missing UI" ); return; } } else { /* skip address/control fields */ pull16(&bp); } /* Initialize the expected header */ hdr.addr = HDLC_ALL_ADDR; hdr.control = HDLC_UI; hdr.protocol = PULLCHAR(&bp); /* First byte of PPP protocol field may be compressed out */ if ( hdr.protocol & 0x01 ) { if (!(negotiated & LCP_N_PFC)) { ppp_unknown( ppp_p, bp, "missing upper protocol byte" ); return; } } else { hdr.protocol = (hdr.protocol << 8) | PULLCHAR(&bp); /* Second byte of PPP protocol field must be odd */ if ( !(hdr.protocol & 0x01) ) { ppp_unknown( ppp_p, bp, "missing lower protocol byte" ); return; } } /* put full-size header on packet for dump routine */ if ((hbp = htonppp(&hdr,bp)) == NULLBUF){ ppp_unknown( ppp_p, bp, Nospace ); return; } if ( net_route( ppp_p->iface, CL_PPP, hbp ) != 0 ) { ppp_unknown( ppp_p, hbp, Nospace ); } } /* Packetize PPP input from device */ /* (process started by ppp_init) */ void ppp_recv(dev,p1,p2) int dev; void *p1; void *p2; { struct iface *ifp = p1; struct ppp_s *ppp_p = ifp->extension; int16 negotiated = FALSE; int32 accm = LCP_ACCM_DEFAULT; int16 calc_fcs = HDLC_FCS_START; struct mbuf *raw_bp = NULLBUF; struct mbuf *head_bp = NULLBUF; register struct mbuf *tail_bp = NULLBUF; char *cp; /* next byte in tail mbuf */ register int mode = modeTOSS; register int c; while ( (c = get_asy(dev)) != -1 ) { #ifdef PPP_DEBUG_RAW if (ifp->trace & IF_TRACE_RAW) { if ( raw_bp != NULLBUF || (raw_bp = alloc_mbuf( LCP_MRU_HI * 2 )) != NULLBUF ) { *raw_bp->data++ = c; raw_bp->cnt++; if ( raw_bp->cnt != 1 && c == HDLC_FLAG ) { raw_bp->data = (char *)(raw_bp + 1); raw_dump( ifp, IF_TRACE_IN, raw_bp ); raw_bp->cnt = 0; } } } #endif if ( c == HDLC_FLAG ) { if (mode == modeESCAPED) { ppp_unknown( ppp_p, head_bp, "deliberate cancellation" ); } else if ( head_bp != NULLBUF ) { if ( calc_fcs != HDLC_FCS_FINAL ) { ppp_unknown( ppp_p, head_bp, "checksum error" ); ppp_p->InChecksum++; } else { ppp_queue(ppp_p, head_bp, negotiated); } } else { ppp_p->InOpenFlag++; } /* setup for next buffer */ mode = modeNORMAL; head_bp = tail_bp = NULLBUF; calc_fcs = HDLC_FCS_START; accm = LCP_ACCM_DEFAULT; /* Use negotiated values if LCP finished */ if (ppp_p->fsm[Lcp].state == fsmOPENED) { struct lcp_s *lcp_p = ppp_p->fsm[Lcp].pdv; negotiated = lcp_p->local.work.negotiate; if (negotiated & LCP_N_ACCM) { accm = lcp_p->local.work.accm; } } #ifdef PPP_DEBUG_RAW if (!(ifp->trace & IF_TRACE_RAW)) { if ( raw_bp != NULLBUF ) { free_p( raw_bp ); raw_bp = NULLBUF; } } #endif continue; } /* We reach here for every byte inside a frame. * (The order of the following tests is important.) * Check for discard. * Discard spurious control characters. * Check for escape sequence. * (Allow escaped escape.) */ if ( mode == modeTOSS ) { continue; } else if ( c < SP_CHAR && (accm & (1L << c)) ) { continue; } else if ( mode == modeESCAPED ) { mode = modeNORMAL; c ^= HDLC_ESC_COMPL; } else if ( c == HDLC_ESC_ASYNC ) { mode = modeESCAPED; continue; } /* We reach here with a byte for the buffer. * Make sure there is room for it. */ if ( tail_bp == NULLBUF ) { if ((tail_bp = alloc_mbuf(PPP_ALLOC)) == NULLBUF) { ppp_unknown( ppp_p, tail_bp, Nospace ); mode = modeTOSS; continue; } head_bp = tail_bp; cp = tail_bp->data; } else if ( tail_bp->cnt >= tail_bp->size ) { /* Current mbuf is full */ if ( (tail_bp->next = alloc_mbuf(PPP_ALLOC)) == NULLBUF ) { /* No memory, drop the whole packet */ ppp_unknown( ppp_p, head_bp, Nospace ); head_bp = NULLBUF; mode = modeTOSS; continue; } tail_bp = tail_bp->next; cp = tail_bp->data; } /* Store the byte, increment counts */ *cp++ = c; tail_bp->cnt++; calc_fcs = pppfcs(calc_fcs, c); } /* clean up afterward */ free_p(raw_bp); free_p(head_bp); ifp->rxproc = NULLPROC; } /*#pragma option -G-*/ /* Process incoming PPP packets */ /* (called from network task) */ void ppp_proc(iface,bp) struct iface *iface; struct mbuf *bp; { struct ppp_s *ppp_p = iface->extension; struct ipcp_s *ipcp_p; struct ppp_hdr hdr; struct mbuf *hbp; if ( bp == NULLBUF ) return; ppp_p->InRxPacketCount++; /* get PPP header */ ntohppp(&hdr, &bp); /* trim off FCS bytes */ trim_mbuf(&bp, len_p(bp)-2); switch(hdr.protocol) { case PPP_IP_PROTOCOL: /* Regular IP */ if ( ppp_p->fsm[IPcp].state != fsmOPENED ) { ppp_in_error( ppp_p, bp, "not open for IP traffic" ); break; } ppp_p->InIP++; ip_route(iface,bp,0); break; case PPP_COMPR_PROTOCOL: /* Van Jacobson Compressed TCP/IP */ if ( ppp_p->fsm[IPcp].state != fsmOPENED ) { ppp_unknown( ppp_p, bp, "not open for Compressed TCP/IP traffic" ); break; } ipcp_p = ppp_p->fsm[IPcp].pdv; if (!(ipcp_p->local.work.negotiate & IPCP_N_COMPRESS)) { ppp_unknown( ppp_p, bp, "Compressed TCP/IP not enabled" ); break; } if ( slhc_uncompress(ipcp_p->slhcp, &bp) <= 0 ) { ppp_in_error( ppp_p, bp, "Compressed TCP/IP packet error" ); break; } ppp_p->InIP++; ip_route(iface,bp,0); break; case PPP_UNCOMP_PROTOCOL: /* Van Jacobson Uncompressed TCP/IP */ if ( ppp_p->fsm[IPcp].state != fsmOPENED ) { ppp_unknown( ppp_p, bp, "not open for Uncompressed TCP/IP traffic" ); break; } ipcp_p = ppp_p->fsm[IPcp].pdv; if (!(ipcp_p->local.work.negotiate & IPCP_N_COMPRESS)) { ppp_unknown( ppp_p, bp, "Uncompressed TCP/IP not enabled" ); break; } if ( slhc_remember(ipcp_p->slhcp, &bp) <= 0 ) { ppp_in_error( ppp_p, bp, "Uncompressed TCP/IP packet error" ); break; } ppp_p->InIP++; ip_route(iface,bp,0); break; case PPP_LCP_PROTOCOL: /* Link Control Protocol */ ppp_p->InNCP[Lcp]++; fsm_proc(&(ppp_p->fsm[Lcp]),bp); break; case PPP_PAP_PROTOCOL: /* Password Authenticate Protocol */ if (ppp_p->phase != pppAP) { ppp_in_error( ppp_p, bp, "not in Authentication phase;" " dropping PAP packet" ); break; } ppp_p->InNCP[Pap]++; pap_proc(&(ppp_p->fsm[Pap]),bp); break; case PPP_IPCP_PROTOCOL: /* IP Control Protocol */ if (ppp_p->phase < pppREADY) { ppp_in_error( ppp_p, bp, "not ready for IPCP traffic" ); break; } ppp_p->InNCP[IPcp]++; fsm_proc(&(ppp_p->fsm[IPcp]),bp); break; default: if ( ppp_p->trace ) log( -1, "%s: PPP Unknown packet protocol: %x;", ppp_p->iface->name, hdr.protocol); ppp_p->InUnknown++; /* Build Protocol Reject packet: * put the header back on ... */ if ((hbp = htonppp(&hdr,bp)) == NULLBUF){ ppp_log( ppp_p, Nospace ); free_p(bp); return; } /* ... then pull off the address and control fields ... */ pull16(&hbp); /* ... and send it as an LCP packet */ fsm_send( &(ppp_p->fsm[Lcp]), PROT_REJ, 0, hbp ); break; }; } /*#pragma option -G */ /****************************************************************************/ /* Keep track of changes in I-O status */ /* (called through iface iostatus vector) */ static int ppp_iostatus( ifp, command, value ) struct iface *ifp; int command; int32 value; { struct ppp_s *ppp_p = ifp->extension; switch ( command ) { case PARAM_UP: ppp_log( ppp_p, "Physical layer up" ); ppp_p->phase = pppLCP; psignal(ppp_p, 0); return 0; case PARAM_DOWN: ppp_log( ppp_p, "Physical layer down" ); fsm_down( &(ppp_p->fsm[Lcp]) ); /* This point is a little tricky. * If LCP was OPEN, it has just set the phase * to TERMINATE. But we don't want to terminate * if a dialer is able to bring us up again. * Otherwise, we got here because of TERMINATE. * In either case, we change TERMINATE to DEAD. */ ppp_p->phase = pppDEAD; psignal(ppp_p, 0); return 0; }; return -1; } /****************************************************************************/ /* PPP Overall Phase Machine * * This machine is controlled by the pwait & psignal at ppp_p, * whenever the overall link phase (as opposed to the LCP state) changes. */ void ppp_machine(dev,p1,p2) int dev; void *p1; void *p2; { struct iface *ifp = p1; struct ppp_s *ppp_p = ifp->extension; struct lcp_s *lcp_p; for (;;) { switch ( ppp_p->phase ) { case pppDEAD: pwait(ppp_p); break; case pppLCP: /* When Physical Line Up */ /* or Open command */ fsm_start( &(ppp_p->fsm[Lcp]) ); pwait(ppp_p); break; case pppAP: /* When LCP complete */ lcp_p = ppp_p->fsm[Lcp].pdv; if (lcp_p->local.work.negotiate & LCP_N_AUTHENT) { ppp_p->flags |= PPP_AP_LOCAL; pap_local(ppp_p); } if (lcp_p->remote.work.negotiate & LCP_N_AUTHENT) { ppp_p->flags |= PPP_AP_REMOTE; if (pap_remote(ppp_p) != 0) { ppp_p->phase = pppTERMINATE; break; } } if (ppp_p->flags & (PPP_AP_LOCAL | PPP_AP_REMOTE)) { pwait(ppp_p); psignal( ppp_p->fsm[Pap].pdv, 0 ); } else { ppp_p->phase = pppREADY; /* no waiting */ } break; case pppREADY: /* When no authentication */ /* or AP authentication success */ ppp_p->upsince = time(0L); fsm_start( &(ppp_p->fsm[IPcp]) ); pwait(ppp_p); break; case pppTERMINATE: /* When LCP terminating */ /* or AP authentication failure */ /* Tell the dialer to shut down */ if ( ifp->supv != NULLPROC ) alert( ifp->supv, EABORT ); /* Close the link, if it isn't already */ fsm_close( &(ppp_p->fsm[Lcp]) ); ppp_p->phase = pppDEAD; break; }; } } /****************************************************************************/ /* Initialize PPP control structures for a Point-to-Point interface */ int ppp_init(ifp) struct iface *ifp; { struct ppp_s *ppp_p; char *ifn; if ((ppp_p = callocw(1,sizeof(struct ppp_s))) == NULL) return -1; ifp->extension = ppp_p; ifp->iostatus = ppp_iostatus; ifp->raw = ppp_raw; ifp->status = ppp_status; ifp->echo = ppp_echo; ifp->discard = ppp_discard; ppp_p->iface = ifp; ppp_p->phase = pppDEAD; ppp_p->machine = newproc( ifn = if_name( ifp, " machine" ), 512, ppp_machine, ifp->dev, ifp, NULL, 0); free(ifn); pwait(NULL); /* give machine a chance to run */ ifp->rxproc = newproc( ifn = if_name( ifp, " receive" ), 320, ppp_recv, ifp->dev, ifp, NULL, 0); free(ifn); return 0; } int ppp_free(ifp) struct iface *ifp; { struct ppp_s *ppp_p = ifp->extension; int fsmi; alert( ifp->rxproc, -1 ); killproc( ppp_p->machine ); for ( fsmi = Lcp; fsmi < fsmi_Size; ) { fsm_free( &(ppp_p->fsm[fsmi++]) ); } free( ppp_p ); return 0; }