📄 pppfsm.c
字号:
/*
* FILENAME: pppfsm.c
*
* Copyright 2000 By InterNiche Technologies Inc. All rights reserved
*
* PPP Finite state machine logic for LCP, IPCP, etc.
*
* MODULE: PPP
*
* ROUTINES: ppp_inpkt(), ppp_fsm(), ppp_fsm_tmo(),
* ROUTINES: ppp_fsm_init(), ppp_sendctl(), ppp_allpktsend(),
* ROUTINES: ppp_lower_send(), ppp_lowerup(), ppp_lowerdown(), ppp_open(),
* ROUTINES: ppp_close(), ppp_hexdump()
*
* PORTABLE: yes
*/
#include "ipport.h"
#ifdef USE_PPP
#include "ppp_port.h"
#include "mppp.h"
#include "ip.h"
#include "minip.h"
#define PPPFSM_DEBUG 0
#if PPPFSM_DEBUG > 0
#include "ZPrint.h"
#endif
M_PPP ppp_list = NULL; /* master list of PPP links */
extern int modem_hangup(LINEP); /* in modem code */
extern void ppp_set_ipaddr(PACKET pkt); /* in ifppp.c */
/* externally overridable PPP globals */
unsigned ppp_mru = PPP_MRU;
unsigned ppp_mtu = PPP_MTU;
int ppp_maxnaks = 10;
int ppp_retry_secs = 3; /* seconds between retrys */
/* asyncmap is an LCP option for "escaping" bytes with values <32 which
* might be used for line control (eg. XON/XOFF). A character is escaped if
* it's bit is set, eg. a map of 0x00000010 means bytes with the value 4
* will be escaped since the 4th bit is set (01 is the zero-th bit). This mask
* is used by our LCP to negotiate to force the indicated chars to be
* escaped.
*/
u_long allow_asyncmap = 0;
/* PPP received "ECHO" callback routine */
void (* mppp_echo_callback)(M_PPP mppp, u_char * inp, unsigned plen);
/* FSM table - corrosponds to RFC 1661, pages 11 & 12. Each entry
* is an x/y coordinate for a particular state and event. The data
* is a 16 bit value with the state we should transition to in the
* low nibble and up to three actions to perform in the upper
* three nibbles. FFFF means no event or no action.
*/
unshort fsm_table[160] = /* 10 states times 16 events */
{
/* state 0 (INITIAL) */
/* Up */ 2,
/* Down */ 0xFFFF,
/* Open */ (AC_TLS << 4) | 1,
/* Close, */ 0,
/* TOP */ 0xFFFF,
/* TOX */ 0xFFFF,
/* RCROK */ 0xFFFF,
/* RCRBAD, */ 0xFFFF,
/* RCA */ 0xFFFF,
/* RCN */ 0xFFFF,
/* RTR */ 0xFFFF,
/* RTA */ 0xFFFF,
/* RUC */ 0xFFFF,
/* RXJP */ 0xFFFF,
/* RXJC */ 0xFFFF,
/* RXR */ 0xFFFF,
/* state 1 (STARTING) */
/* Up */ (AC_IRC << 8) | (AC_SCR << 4) | 6,
/* Down */ 0xFFFF,
/* Open */ 1,
/* Close, */ (AC_TLF << 4) | 0,
/* TOP */ 0xFFFF,
/* TOX */ 0xFFFF,
/* RCROK */ 0xFFFF,
/* RCRBAD, */ 0xFFFF,
/* RCA */ 0xFFFF,
/* RCN */ 0xFFFF,
/* RTR */ 0xFFFF,
/* RTA */ 0xFFFF,
/* RUC */ 0xFFFF,
/* RXJP */ 0xFFFF,
/* RXJC */ 0xFFFF,
/* RXR */ 0xFFFF,
/* state 2 (CLOSED) */
/* Up */ 0xFFFF,
/* Down */ 0,
/* Open */ (AC_IRC << 8) | (AC_SCR << 4) | 6,
/* Close, */ 2,
/* TOP */ 0xFFFF,
/* TOX */ 0xFFFF,
/* RCROK */ (AC_STA << 4) | 2,
/* RCRBAD, */ (AC_STA << 4) | 2,
/* RCA */ (AC_STA << 4) | 2,
/* RCN */ (AC_STA << 4) | 2,
/* RTR */ (AC_STA << 4) | 2,
/* RTA */ 2,
/* RUC */ (AC_SCJ << 4) | 2,
/* RXJP */ 2,
/* RXJC */ (AC_TLF << 4) | 2,
/* RXR */ 2,
/* state 3 (STOPPED) */
/* Up */ 0xFFFF,
/* Down */ (AC_TLF << 4) | 1, /* RFC1661 says tls/1...typo??? */
/* Open */ 3,
/* Close, */ 2,
/* TOP */ 0xFFFF,
/* TOX */ 0xFFFF,
/* RCROK */ (AC_IRC << 12) | (AC_SCR << 8) | (AC_SCA << 4) | 8,
/* RCRBAD, */ (AC_IRC << 12) | (AC_SCR << 8) | (AC_SCN << 4) | 6,
/* RCA */ (AC_STA << 4) | 3,
/* RCN */ (AC_STA << 4) | 3,
/* RTR */ (AC_STA << 4) | 3,
/* RTA */ 3,
/* RUC */ (AC_SCJ << 4) | 3,
/* RXJP */ 3,
/* RXJC */ (AC_TLF << 4) | 3,
/* RXR */ 3,
/* state 4 (Closing) */
/* Up */ 0xFFFF,
/* Down */ 0,
/* Open */ 5,
/* Close, */ 4,
/* TOP */ (AC_STR << 4) | 4,
/* TOX */ (AC_TLF << 4) | 2,
/* RCROK */ 4,
/* RCRBAD, */ 4,
/* RCA */ 4,
/* RCN */ 4,
/* RTR */ (AC_STA << 4) | 4,
/* RTA */ (AC_TLF << 4) | 2,
/* RUC */ (AC_SCJ << 4) | 4,
/* RXJP */ 4,
/* RXJC */ (AC_TLF << 4) | 2,
/* RXR */ 4,
/* state 5 (Stopping) */
/* Up */ 0xFFFF,
/* Down */ 1,
/* Open */ 5,
/* Close, */ 4,
/* TOP */ (AC_STR << 4) | 5,
/* TOX */ (AC_TLF << 4) | 3,
/* RCROK */ 5,
/* RCRBAD, */ 5,
/* RCA */ 5,
/* RCN */ 5,
/* RTR */ (AC_STA << 4) | 5,
/* RTA */ (AC_TLF << 4) | 3,
/* RUC */ (AC_SCJ << 4) | 5,
/* RXJP */ 5,
/* RXJC */ (AC_TLF << 4) | 3,
/* RXR */ 5,
/* state 6 (REQ-SENT) */
/* Up */ 0xFFFF,
/* Down */ 1,
/* Open */ 6,
/* Close, */ (AC_IRC << 8) | (AC_STR << 4) | 4,
/* TOP */ (AC_SCR << 4) | 6,
/* TOX */ (AC_TLF << 4) | 3,
/* RCROK */ (AC_SCA << 4) | 8,
/* RCRBAD, */ (AC_SCN << 4) | 6,
/* RCA */ (AC_IRC << 4) | 7,
/* RCN */ (AC_IRC << 8) | (AC_SCR << 4) | 6,
/* RTR */ (AC_STA << 4) | 6,
/* RTA */ 6,
/* RUC */ (AC_SCJ << 4) | 6,
/* RXJP */ 6,
/* RXJC */ (AC_TLF << 4) | 3,
/* RXR */ 6,
/* state 7 (ACK_RCVD) */
/* Up */ 0xFFFF,
/* Down */ 1,
/* Open */ 7,
/* Close, */ (AC_IRC << 8) | (AC_STR << 4) | 4,
/* TOP */ (AC_SCR << 4) | 6,
/* TOX */ (AC_TLF << 4) | 3,
/* RCROK */ (AC_SCA << 8) | (AC_TLU << 4) | 9,
/* RCRBAD, */ (AC_SCN << 4) | 7,
/* RCA */ (AC_SCR << 4) | 6,
/* RCN */ (AC_SCR << 4) | 6,
/* RTR */ (AC_STA << 4) | 6,
/* RTA */ 6,
/* RUC */ (AC_SCJ << 4) | 7,
/* RXJP */ 6,
/* RXJC */ (AC_TLF << 4) | 3,
/* RXR */ 7,
/* state 8 ACK_SENT) */
/* Up */ 0xFFFF,
/* Down */ 1,
/* Open */ 8,
/* Close, */ (AC_IRC << 8) | (AC_STR << 4) | 4,
/* TOP */ (AC_SCR << 4) | 8,
/* TOX */ (AC_TLF << 4) | 3,
/* RCROK */ (AC_SCA << 4) | 8,
/* RCRBAD, */ (AC_SCN << 4) | 6,
/* RCA */ (AC_IRC << 8) | (AC_TLU << 4) | 9,
/* RCN */ (AC_IRC << 8) | (AC_SCR << 4) | 8,
/* RTR */ (AC_STA << 4) | 6,
/* RTA */ 8,
/* RUC */ (AC_SCJ << 4) | 8,
/* RXJP */ 8,
/* RXJC */ (AC_TLF << 4) | 3,
/* RXR */ 8,
/* state 9 (OPENED) */
/* Up */ 0xFFFF,
/* Down */ (AC_TLD << 4) | 1,
/* Open */ 9,
/* Close, */ (AC_TLD << 12) | (AC_IRC << 8) | (AC_STR << 4) | 4,
/* TOP */ 0xFFFF,
/* TOX */ 0xFFFF,
/* RCROK */ (AC_TLD << 12) | (AC_SCR << 8) | (AC_SCA << 4) | 8,
/* RCRBAD, */ (AC_TLD << 12) | (AC_SCR << 8) | (AC_SCN << 4) | 6,
/* RCA */ (AC_TLD << 8) | (AC_SCR << 4) | 6,
/* RCN */ (AC_TLD << 8) | (AC_SCR << 4) | 6,
/* RTR */ (AC_TLD << 12) | (AC_ZRC << 8) | (AC_STA << 4)| 5,
/* RTA */ 9,
/* RUC */ (AC_SCJ << 4) | 9,
/* RXJP */ 9,
/* RXJC */ (AC_TLD << 12) | (AC_IRC << 8) | (AC_STR << 4) | 5,
/* RXR */ (AC_SER << 4) | 9,
};
prot_funcs prot_func_tabs[MAX_PPP_PROTS] = {
{
lcp_resetci, /* Reset our Configuration Information */
lcp_addci, /* Add our Configuration Information */
lcp_ackci, /* ACK our Configuration Information */
lcp_nakci, /* NAK our Configuration Information */
lcp_rejci, /* Reject our Configuration Information */
lcp_reqci, /* Request peer's Configuration Information */
lcp_extcode, /* Called to handle LCP-specific codes */
lcp_up, /* Called when fsm reaches OPENED state */
lcp_down, /* Called when fsm leaves OPENED state */
lcp_starting, /* Called when we want the lower layer up */
lcp_finished, /* Called when we want the lower layer down */
"LCP" /* String name of protocol */
},
{
ipcp_resetci, /* Reset our Configuration Information */
ipcp_addci, /* Add our Configuration Information */
ipcp_ackci, /* ACK our Configuration Information */
ipcp_nakci, /* NAK our Configuration Information */
ipcp_rejci, /* Reject our Configuration Information */
ipcp_reqci, /* Request peer's Configuration Information */
NULL, /* Called to handle protocol-specific codes */
ipcp_up, /* Called when fsm reaches OPENED state */
ipcp_down, /* Called when fsm leaves OPENED state */
ipcp_started, /* Called when we want the lower layer up */
ipcp_finished, /* Called when we want the lower layer down */
"IPCP" /* String name of protocol */
},
};
#ifndef NO_CONPRINTF
char * fsmstate[] =
{
"INITIAL",
"STARTING",
"CLOSED",
"STOPPED",
"CLOSING",
"STOPPING",
"REQSENT",
"ACKRCVD",
"ACKSENT",
"OPENED",
};
char * codes[] =
{
"FOO", /* code 0 not used */
"CONFREQ", /* code 1... */
"CONFACK", /* 2 */
"CONFNAK", /* 3 */
"CONFREJ", /* 4 */
"TERMREQ", /* 5 */
"TERMACK", /* 6 */
"CODEREJ", /* 7 */
"PROTREJ", /* 8 */
"PECHOREQ", /* 9 */
"PECHOREP", /* 10 */
"DISCREQ", /* 11 */
"IDENTITY", /* 12 - was "KEEPALIVE" in old RFC */
};
char * prots[] =
{
"LCP",
"IPCP",
"AUTH",
};
#endif /* notdef NO_CONPRINTF */
/* FUNCTION: ppp_inpkt()
*
* input routine for PPP packets. PPP header is pointed to by
* pkt->nb_prot, length is pkt->nb_plen. This packet is already
* unescaped and stripped of any HDLC-like stuffed bytes and
* headers.
*
* PARAM1: M_PPP mppp
* PARAM2: PACKET pkt
*
* RETURNS: void
*/
void
ppp_inpkt(M_PPP mppp, PACKET pkt)
{
u_char * inp; /* data from received packet */
u_char code; /* FSM packet type */
int plen; /* length of received packet */
int hlen; /* length from PPP header */
int err; /* error holder */
int event; /* event for state machine lookup */
unsigned pcode; /* states[] index, 0 for LCP */
int reject;
unshort proto; /* protocol of received pkt */
prot_funcs * pfuncs; /* pointer to protocol function table */
mppp->bytes_in += pkt->nb_plen;
mppp->pkts_in++;
/* see if we need to hexdump received PPP packet */
//ConPrintf("ppp link %p rcvd:", mppp);
ppp_hexdump((u_char*)pkt->nb_prot, pkt->nb_plen);
/* set pointer and length of PPP packet data */
plen = pkt->nb_plen - 2; /* Strip 2 byte prot code */
inp = (u_char*)pkt->nb_prot + 2;
/* Switch based on the received protocol. Get a protocol
* table index for control protocols (LCP, IPCP), or
* pass data to data protocol handlers (IP, VJ)
*/
proto = ppp_getshort((u_char*)pkt->nb_prot);
switch (proto)
{
case PPP_LCP:
#if PPPFSM_DEBUG
Printu("PPP_LCP\r\n");
#endif
pcode = LCP_STATE;
break;
case PPP_IPCP:
#if PPPFSM_DEBUG
Printu("PPP_IPCP\r\n");
#endif
pcode = IPCP_STATE;
break;
#ifdef PPP_VJC
case PPP_VJC_COMP:
#if PPPFSM_DEBUG
Printu("PPP_VJC_COMP\r\n");
#endif
/* Make room for VJ routines in front of the received buffer. */
{
PACKET bigpkt;
LOCK_NET_RESOURCE(FREEQ_RESID);
bigpkt = pk_alloc(pkt->nb_plen + VJC_HDR_OFFSET);
UNLOCK_NET_RESOURCE(FREEQ_RESID);
if(!bigpkt)
{
//ConPrintf("(%p) pkalloc failed for VJ pkt len %d\n",
//mppp, pkt->nb_plen);
mppp->io_errors++;
goto drop;
}
bigpkt->nb_prot += VJC_HDR_OFFSET; /* prepend VJ space */
bigpkt->nb_plen = pkt->nb_plen;
MEMCPY((u_char*)bigpkt->nb_prot, (u_char*)pkt->nb_prot, pkt->nb_plen);
bigpkt->net = pkt->net;
LOCK_NET_RESOURCE(FREEQ_RESID);
pk_free(pkt);
UNLOCK_NET_RESOURCE(FREEQ_RESID);
pkt = bigpkt;
inp = (u_char*)pkt->nb_prot + 2; /* reset input pointer */
plen = pkt->nb_plen - 2; /* Strip 2 byte prot code */
}
case PPP_VJC_UNCOMP:
#if PPPFSM_DEBUG
Printu("PPP_VJC_UNCOMP\r\n");
#endif
err = vj_uncompress_tcp(&inp, plen, proto, &mppp->sc_comp);
if(err == 0)
{
// ConPrintf("(%p) vj_uncompress failed on type %x\n",
// mppp, proto);
mppp->io_errors++;
LOCK_NET_RESOURCE(FREEQ_RESID);
pk_free(pkt);
UNLOCK_NET_RESOURCE(FREEQ_RESID);
return;
}
/* set NEW pointer and length of uncompressed packet. We adjust the
* pointer and length down by two bytes to compensate for the logic
* in PPP_IKP case below.
*/
pkt->nb_plen = err + 2; /* returned new length */
pkt->nb_prot = (char*)inp - 2;
/* fall into PPP_IP code to deliver packet */
#endif /* PPP_VJC */
case PPP_IP:
#if PPPFSM_DEBUG
Printu("PPP_IP\r\n");
#endif
mppp->ifp->mib.ifInOctets += pkt->nb_plen;
pkt->type = htons(0x0800);
pkt->nb_prot += 2; /* bump past type to IP header */
pkt->nb_plen -= 2;
#ifdef NPDEBUG
if (*(pkt->nb_buff - ALIGN_TYPE) != 'M' ||
*(pkt->nb_buff + pkt->nb_blen) != 'M')
{
dtrap("pppfsm 0\n");
panic("pktdemux: corrupt pkt");
}
#endif /* NPDEBUG */
#ifdef USE_MODEM
/* On modem lines check the IP addresses and ID of the last
* IP packet against those of the last IP packet we sent. If
* they all match it means a hung-up modem or looped-back UART.
*/
if(mppp->line.lower_type == LN_ATMODEM)
{
/* (yaxon del) */
#if 0
struct ip * pip = (struct ip *)(pkt->nb_prot);
if((pip->ip_src == mppp->last_ip_src) &&
(pip->ip_dest == mppp->last_ip_dest) &&
(pip->ip_id == mppp->last_ip_id))
{
// ConPrintf("ppp_inpkt: modem hung up\n");
#if PPPFSM_DEBUG
Printu("ppp_inpkt: modem hung up\r\n");
#endif
modem_hangup(&mppp->line); /* clean this up */
}
#endif
}
#endif /* PPP_CHARIO */
LOCK_NET_RESOURCE(RXQ_RESID);
putq(&rcvdq, (qp)pkt);
UNLOCK_NET_RESOURCE(RXQ_RESID);
SignalPktDemux();
return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -