/* * 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 LCP and IPCP draft RFCs. * Add quick installation features. * Add support for echo and discard message sending. * * Jul 91 Glenn McGregor & Bill Simpson * Improve PAP user interface and fix related bugs. * Remove pwaits and "phase machine". */ #include "global.h" #include "mbuf.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 "ppppap.h" #include "pppipcp.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_error __ARGS((struct ppp_s *ppp_p, struct mbuf *bp, char *comment)); static void ppp_skipped __ARGS((struct ppp_s *ppp_p, struct mbuf *bp, char *comment)); static int ppp_raw __ARGS((struct iface *ifp, struct mbuf *data)); static void ppp_recv __ARGS((int dev, void *p1, void *p2)); static int ppp_iostatus __ARGS((struct iface *ifp, int command, int32 value)); static int ppp_discard __ARGS((struct iface *ifp, struct mbuf *bp)); static int ppp_echo __ARGS((struct iface *ifp, struct mbuf *bp)); /* * FCS lookup table as generated by fcsgen.c */ static 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 /****************************************************************************/ /* Convert PPP header in host form to network form */ static struct mbuf * htonppp(ppp, bp) struct ppp_hdr *ppp; struct mbuf *bp; { register char *cp; /* Prepend header onto packet data */ bp = pushdown(bp, PPP_HDR_LEN); /* Load header with proper values */ cp = bp->data; *cp++ = ppp->addr; *cp++ = ppp->control; cp = put16(cp,ppp->protocol); return bp; } /************************************************************************/ /* General log routine */ static void ppp_log( ppp_p, comment ) struct ppp_s *ppp_p; char *comment; { if (ppp_p->trace) trace_log(ppp_p->iface,"%s PPP %s", ppp_p->iface->name, comment); } /* Bad packet */ static void ppp_error(ppp_p, bp, comment) struct ppp_s *ppp_p; struct mbuf *bp; char *comment; { free_p(bp); ppp_log( ppp_p, comment ); } /* Unknown type input packet */ static void ppp_skipped(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_error( ppp_p, bp, comment ); } /****************************************************************************/ /* Send IP datagram with Point-to-Point Protocol */ int ppp_send(bp,ifp,gateway,tos) struct mbuf *bp; /* Buffer to send */ struct iface *ifp; /* Pointer to interface control block */ int32 gateway; /* Ignored (PPP is point-to-point) */ int tos; { struct ppp_s *ppp_p; struct ipcp_s *ipcp_p; int protocol = PPP_IP_PROTOCOL; if (ifp == NULLIF || (ppp_p = ifp->edv) == NULL) { free_p(bp); return -1; } if (ppp_p->fsm[IPcp].state != fsmOPENED) { ppp_error( ppp_p, bp, "not open for IP traffic" ); ppp_p->OutError++; 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_error( ppp_p, bp, "bad IP packet" ); ppp_p->OutError++; return -1; }; } return (*ifp->output)(ifp,NULLCHAR,NULLCHAR,protocol,bp); } /* Send a packet with PPP header */ int ppp_output(ifp,dest,source,protocol,data) struct iface *ifp; /* 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 (ifp == NULLIF || (ppp_p = ifp->edv) == NULL) { free_p(data); return -1; } if (ppp_p->phase == pppDEAD) { ppp_error( ppp_p, data, "line not up" ); ppp_p->OutError++; return -1; } hdr.addr = HDLC_ALL_ADDR; hdr.control = HDLC_UI; hdr.protocol = protocol; if ((bp = htonppp(&hdr, data)) == NULLBUF) { ppp_log( ppp_p, Nospace ); ppp_p->OutMemory++; return -1; } return (*ifp->raw)(ifp,bp); } /* Encode a raw packet in PPP framing, put on link output queue */ static int ppp_raw(ifp,bp) struct iface *ifp; struct mbuf *bp; { struct ppp_s *ppp_p = ifp->edv; struct lcp_s *lcp_p = ppp_p->fsm[Lcp].pdv; int full_lcp, full_ac, full_p; int16 calc_fcs = HDLC_FCS_START; int32 accm = LCP_ACCM_DEFAULT; struct ppp_hdr ph; int len = PPP_HDR_LEN; struct mbuf *vbp; register char *cp; register int c; dump(ifp,IF_TRACE_OUT,CL_PPP,bp); ppp_p->OutTxOctetCount += len_p(bp) + 2; /* count FCS bytes */ ifp->rawsndcnt++; ifp->lastsent = secclock(); /* Get the HDLC/PPP header, without actually pulling mbuf up */ if ( bp == NULLBUF || bp->cnt < PPP_HDR_LEN ) { ppp_error( ppp_p, bp, "link header missing" ); ppp_p->OutError++; return -1; } ph.addr = bp->data[0]; ph.control = bp->data[1]; ph.protocol = get16(&bp->data[2]); if ( ( full_lcp = (ph.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) || ph.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) ) ) == 0 ) { len -= 2; } /* Load header with proper values */ bp->cnt -= PPP_HDR_LEN - len; cp = (bp->data += PPP_HDR_LEN - len); if ( full_ac ) { *cp++ = ph.addr; *cp++ = ph.control; } if ( full_p ) *cp++ = (ph.protocol >> 8); *cp++ = (ph.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 ((vbp = alloc_mbuf((int16)(2*len_p(bp) + HDLC_ENVLEN))) == NULLBUF) { ppp_error( ppp_p, bp, Nospace ); ppp_p->OutMemory++; return -1; } cp = vbp->data; /* No need to send an opening flag if the previous packet is still * being transmitted. */ if ( Asy[ifp->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(&bp)) != -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; vbp->cnt = cp - vbp->data; if (ifp->trace & IF_TRACE_RAW) raw_dump(ifp,IF_TRACE_OUT,vbp); return asy_send(ifp->dev,vbp); } /****************************************************************************/ /* 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->edv; 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 = FALSE; 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 & PPP_ESCAPED ) { ppp_skipped( ppp_p, head_bp, "deliberate cancellation" ); ppp_p->InFrame++; } else if ( mode & PPP_TOSS ) { free_p( head_bp ); } else if ( head_bp != NULLBUF ) { if ( calc_fcs != HDLC_FCS_FINAL ) { ppp_skipped( ppp_p, head_bp, "checksum error" ); ppp_p->InChecksum++; } else { /* trim off FCS bytes */ trim_mbuf(&head_bp, len_p(head_bp)-2); net_route(ifp,CL_PPP,head_bp); /* Especially on slow machines, serial I/O can be quite * compute intensive, so release the machine before we * do the next packet. This will allow this packet to * go on toward its ultimate destination. [Karn] */ pwait(NULL); } } else { ppp_p->InOpenFlag++; } /* setup for next buffer */ mode = FALSE; 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; if (lcp_p->local.work.negotiate & 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.) * Discard spurious control characters. * Check for escape sequence. * (Allow escaped escape.) */ if ( c < SP_CHAR && (accm & (1L << c)) ) { continue; } else if ( mode & PPP_ESCAPED ) { mode &= ~PPP_ESCAPED; c ^= HDLC_ESC_COMPL; } else if ( c == HDLC_ESC_ASYNC ) { mode |= PPP_ESCAPED; 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_skipped( ppp_p, tail_bp, Nospace ); ppp_p->InMemory++; mode |= PPP_TOSS; 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_skipped( ppp_p, head_bp, Nospace ); ppp_p->InMemory++; head_bp = NULLBUF; mode |= PPP_TOSS; 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; } #ifdef TURBOC_SWITCH_BUG #pragma option -G- #endif /* Process incoming PPP packets */ /* (called from network task) */ void ppp_proc(ifp,bp) struct iface *ifp; struct mbuf *bp; { struct ppp_s *ppp_p; struct ipcp_s *ipcp_p; struct ppp_hdr ph; struct mbuf *hbp; int16 negotiated = FALSE; if ( ifp == NULLIF ) { log(-1, "ppp_proc: missing iface" ); return; } if ( bp == NULLBUF ) { trace_log(ifp, "ppp_proc: missing buffer" ); return; } ppp_p = ifp->edv; ppp_p->InRxOctetCount += len_p(bp) + 2; /* count FCS bytes */ /* 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; } /* HDLC address and control fields may be compressed out */ if ((byte_t)bp->data[0] != HDLC_ALL_ADDR) { if (!(negotiated & LCP_N_ACFC)) { ppp_skipped( ppp_p, bp, "missing ALL address" ); ppp_p->InFrame++; return; } } else if ((byte_t)bp->data[1] != HDLC_UI) { if (!(negotiated & LCP_N_ACFC) || !(negotiated & LCP_N_PFC)) { ppp_skipped( ppp_p, bp, "missing UI" ); ppp_p->InFrame++; return; } } else { /* skip address/control fields */ pull16(&bp); } /* Initialize the expected header */ ph.addr = HDLC_ALL_ADDR; ph.control = HDLC_UI; ph.protocol = PULLCHAR(&bp); /* First byte of PPP protocol field may be compressed out */ if ( ph.protocol & 0x01 ) { if (!(negotiated & LCP_N_PFC)) { ppp_skipped( ppp_p, bp, "missing upper protocol byte" ); ppp_p->InFrame++; return; } } else { ph.protocol = (ph.protocol << 8) | PULLCHAR(&bp); /* Second byte of PPP protocol field must be odd */ if ( !(ph.protocol & 0x01) ) { ppp_skipped( ppp_p, bp, "missing lower protocol byte" ); ppp_p->InFrame++; return; } } switch(ph.protocol) { case PPP_IP_PROTOCOL: /* Regular IP */ if ( ppp_p->fsm[IPcp].state != fsmOPENED ) { ppp_error( ppp_p, bp, "not open for IP traffic" ); ppp_p->InError++; break; } ip_route(ifp,bp,0); break; case PPP_COMPR_PROTOCOL: /* Van Jacobson Compressed TCP/IP */ if ( ppp_p->fsm[IPcp].state != fsmOPENED ) { ppp_skipped( ppp_p, bp, "not open for Compressed TCP/IP traffic" ); ppp_p->InError++; break; } ipcp_p = ppp_p->fsm[IPcp].pdv; if (!(ipcp_p->local.work.negotiate & IPCP_N_COMPRESS)) { ppp_skipped( ppp_p, bp, "Compressed TCP/IP not enabled" ); ppp_p->InError++; break; } if ( slhc_uncompress(ipcp_p->slhcp, &bp) <= 0 ) { ppp_error( ppp_p, bp, "Compressed TCP/IP packet error" ); ppp_p->InError++; break; } ip_route(ifp,bp,0); break; case PPP_UNCOMP_PROTOCOL: /* Van Jacobson Uncompressed TCP/IP */ if ( ppp_p->fsm[IPcp].state != fsmOPENED ) { ppp_skipped( ppp_p, bp, "not open for Uncompressed TCP/IP traffic" ); ppp_p->InError++; break; } ipcp_p = ppp_p->fsm[IPcp].pdv; if (!(ipcp_p->local.work.negotiate & IPCP_N_COMPRESS)) { ppp_skipped( ppp_p, bp, "Uncompressed TCP/IP not enabled" ); ppp_p->InError++; break; } if ( slhc_remember(ipcp_p->slhcp, &bp) <= 0 ) { ppp_error( ppp_p, bp, "Uncompressed TCP/IP packet error" ); ppp_p->InError++; break; } ip_route(ifp,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_p->phase != pppREADY) { ppp_error( ppp_p, bp, "not ready for Authentication" ); ppp_p->InError++; 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_error( ppp_p, bp, "not ready for IPCP traffic" ); ppp_p->InError++; break; } ppp_p->InNCP[IPcp]++; fsm_proc(&(ppp_p->fsm[IPcp]),bp); break; default: if ( ppp_p->trace ) trace_log(ppp_p->iface, "%s PPP Unknown packet protocol: %x;", ppp_p->iface->name, ph.protocol); ppp_p->InUnknown++; /* Build Protocol Reject packet: * put the header back on ... */ if ((hbp = htonppp(&ph,bp)) == NULLBUF){ ppp_log( ppp_p, Nospace ); ppp_p->InMemory++; 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; }; } #ifdef TURBOC_SWITCH_BUG #pragma option -G #endif /************************************************************************/ /* 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->edv; switch ( command ) { case PARAM_UP: ppp_log( ppp_p, "Physical layer up" ); if ( ppp_p->phase == pppDEAD ) { ppp_p->phase = pppLCP; } fsm_start( &(ppp_p->fsm[Lcp]) ); return 0; case PARAM_DOWN: ppp_log( ppp_p, "Physical layer down" ); fsm_down( &(ppp_p->fsm[Lcp]) ); ppp_p->phase = pppDEAD; return 0; }; return -1; } static int ppp_discard(ifp,bp) struct iface *ifp; struct mbuf *bp; { struct ppp_s *ppp_p = ifp->edv; return fsm_send(&(ppp_p->fsm[Lcp]), DISCARD_REQ, 0, bp); } static int ppp_echo(ifp,bp) struct iface *ifp; struct mbuf *bp; { struct ppp_s *ppp_p = ifp->edv; return fsm_send(&(ppp_p->fsm[Lcp]), ECHO_REQ, 0, bp); } /****************************************************************************/ /* Initialize PPP control structures for a Point-to-Point interface */ int ppp_init(ifp,vj) struct iface *ifp; int vj; /* Unused */ { struct ppp_s *ppp_p; char *ifn; /* Setup for Point-to-Point Protocol */ setencap(ifp,"PPP"); ifp->ioctl = asy_ioctl; ifp->flags = FALSE; ppp_p = callocw(1,sizeof(struct ppp_s)); ifp->edv = ppp_p; ifp->iostatus = ppp_iostatus; ifp->raw = ppp_raw; ifp->show = ppp_show; ifp->echo = ppp_echo; ifp->discard = ppp_discard; ppp_p->iface = ifp; ppp_p->phase = pppDEAD; lcp_init(ppp_p); pap_init(ppp_p); ipcp_init(ppp_p); 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->edv; int fsmi; alert( ifp->rxproc, -1 ); for ( fsmi = Lcp; fsmi < fsmi_Size; ) { fsm_free( &(ppp_p->fsm[fsmi++]) ); } free( ppp_p->peername ); free( ppp_p ); return 0; }