📄 pppfsm.c
字号:
#ifdef PAP_SUPPORT
case PPP_UPAP:
#if PPPFSM_DEBUG
Printu("PPP_UPAP\r\n");
#endif
upap_input(mppp, inp, plen);
goto drop;
#endif
#ifdef CHAP_SUPPORT
case PPP_CHAP:
#if PPPFSM_DEBUG
Printu("PPP_CHAP\r\n");
#endif
ChapInput(mppp, inp, plen);
goto drop;
#endif
#ifdef PPP_MULTILINK
case PPP_ML:
pppml_rcv(mppp, pkt);
return;
#endif /* PPP_MULTILINK */
default:
// ConPrintf("ppp_inpkt: (link %p): unsupported prot %x\n", mppp, proto);
/* send protocol reject packet */
ppp_sendctl(mppp, LCP_STATE, PROTREJ, (u_char*)pkt->nb_prot,
pkt->nb_plen, mppp->in_ids[LCP_STATE]);
LOCK_NET_RESOURCE(FREEQ_RESID);
pk_free(pkt);
UNLOCK_NET_RESOURCE(FREEQ_RESID);
return;
}
/* Fall to here if it's one of the FSM control protocols.
* get the protocol header and do length error checking
*/
code = *inp; /* FSM op-code */
mppp->in_ids[pcode] = *(inp + 1); /* save Id for possible reply */
hlen = (int)ppp_getshort(inp + 2);
/* verify packet is not truncated & plen is OK */
if((hlen > plen) || (plen < 4))
{
// ConPrintf("(link %p) truncated packet, lengths: hdr:%d, actual:%d\n", mppp, hlen, plen);
goto drop;
}
/* set pointer & length to CI list after header */
inp += 4;
plen -= 4;
//ConPrintf("ppp_inpkt (link %p); prot: %s, code %s, state %s, len %d\n",
//mppp, prots[pcode], codes[code], fsmstate[mppp->states[pcode]], plen );
/* We shouldn't be getting packets in states INITIAL and STARTING */
if(mppp->states[pcode] < ST_CLOSED)
{
// ConPrintf("(link %p) got pkt in state %s\n", mppp,
// fsmstate[mppp->states[pcode]]);
goto drop;
}
/* Call the receive routine and map the FSM packet type code
* to an event type for the state table.
*/
pfuncs = &prot_func_tabs[pcode];
err = -1;
hlen -= 4; /* deduct header size before passing to routines */
reject = (mppp->naks_received[pcode] >= ppp_maxnaks) ? TRUE : FALSE;
event = EV_NOEVENT; /* stifle compiler warnings */
mppp->rxcode = code; /* save last code received */
switch (code)
{
case CONFREQ: /* Configuration Request */
if(pfuncs->reqci)
err = pfuncs->reqci(mppp, inp, &hlen, reject);
if(err == CONFACK)
event = EV_RCROK;
else
event = EV_RCRBAD; /* NAK, REJ, or bad pkt */
break;
case CONFACK: /* Configuration Ack */
if(pfuncs->ackci)
err = pfuncs->ackci(mppp, inp, hlen);
if(err == 0)
event = EV_RCA;
else
event = EV_NOEVENT;
break;
case CONFNAK: /* Configuration Nak */
if(pfuncs->nakci)
err = pfuncs->nakci(mppp, inp, hlen);
if(err == 0)
event = EV_RCN;
else
event = EV_NOEVENT;
break;
case CONFREJ: /* Configuration Reject */
if(pfuncs->rejci)
event = pfuncs->rejci(mppp, inp, hlen);
break;
case TERMREQ: /* Termination Request */
event = EV_RTR;
break;
case TERMACK: /* Termination Ack */
event = EV_RTA;
break;
case CODEREJ: /* Code Reject */
event = EV_RXJP;
break;
case PROTREJ: /* Protocol Reject */
if(pcode == PPP_IPCP)
{
/* This is pretty serious, log it */
// ConPrintf("(link %p) Prot-Reject for IPCP, closing\n", mppp);
/* signal FSM as though lowest layer went down */
ppp_lowerdown(mppp, LCP_STATE);
event = EV_RXJC; /* set event for TLF later */
}
else
{
// ConPrintf("(link %p) Prot-Reject for %x\n", mppp, proto);
event = EV_RXJP; /* almost a no-op */
}
break;
case PECHOREQ: /* Echo Request */
/* To prepare ECHOREP we have to insert our magic number */
ppp_putlong(inp, mppp->lcp_gotoptions.magicnumber);
/* No break; fall into RXR event code */
case DISCREQ: /* Discard Request */
event = EV_RXR;
break;
case PECHOREP: /* Echo Reply */
if(mppp_echo_callback)
mppp_echo_callback(mppp, inp, hlen);
LOCK_NET_RESOURCE(FREEQ_RESID);
pk_free(pkt);
UNLOCK_NET_RESOURCE(FREEQ_RESID);
return;
#ifdef PPP_IDENTIFY
case IDENTITY: /* LCP Indentity request */
if(proto == PPP_LCP) /* verify this is LCP code */
{
int idlen; /* length of received ID info */
/* Technically this is an LCP pkt, however it's more
* efficeint to just handle it in-line here.
* Save Identity string in mppp and null-terminate for
* printf()ing. Make sure we don;t overrun mppp->identity
* buffer. At this point inp points to a 4 byte "magic number"
* field, which we skip.
*/
idlen = min((hlen - 4), (PPP_MAX_IDENTITY - 1));
MEMCPY(mppp->identity, (inp + 4), idlen);
mppp->identity[idlen] = 0; /* null-term */
/* RFC-1570 suggests we should both log this and print to user */
// ConPrintf("rcvd IDENTITY: %s\n", mppp->identity);
dprintf("rcvd IDENTITY: %s\n", mppp->identity);
LOCK_NET_RESOURCE(FREEQ_RESID);
pk_free(pkt);
UNLOCK_NET_RESOURCE(FREEQ_RESID);
return;
}
/* else fall into "unknown code" logic */
#endif /* PPP_IDENTIFY */
default:
//ConPrintf("(link %p) unknown code: %x", mppp, code);
if(pfuncs->extcode)
pfuncs->extcode(mppp, code, CODEREJ, inp, hlen);
LOCK_NET_RESOURCE(FREEQ_RESID);
pk_free(pkt);
UNLOCK_NET_RESOURCE(FREEQ_RESID);
return;
}
/* do the FSM actions indicated in the table */
ppp_fsm(mppp, pcode, event, inp, hlen);
drop:
LOCK_NET_RESOURCE(FREEQ_RESID);
pk_free(pkt);
UNLOCK_NET_RESOURCE(FREEQ_RESID);
return;
}
/* FUNCTION: ppp_fsm()
*
* Perform the FSM transition and actions for the passed mppp to handle
* the passed code and event.
*
* PARAM1: M_PPP mppp - session
* PARAM2: unsigned pcode - protocol code (LCP, IPCP, etc.)
* PARAM3: int event - one of the EV_ event codes
* PARAM4: u_char * inp - packet data for received packet events
* PARAM5: int inlen - length of inp
*
* RETURNS: void
*/
void
ppp_fsm(M_PPP mppp, unsigned pcode, int event, u_char * inp, int inlen)
{
unshort cmd; /* series of 4-bit actions code from FSM table */
u_char newstate; /* state we end up in after FSM change */
u_char oldstate; /* state before FSM change */
int i; /* index */
int state; /* state of this mppp */
int action; /* next 4-bit action code from cmd */
prot_funcs * pfuncs; /* pointer to protocol function table */
u_char replytype; /* code for reply */
u_char * outp; /* pointer to reply send data */
int outlen; /* length of reply to send, if any */
u_char reply_id; /* PPP header ID to put in output pkt, if any */
if(event == EV_NOEVENT)
return;
#ifdef NPDEBUG
if((event > NUM_PPPEVENTS) || (pcode > IPCP_STATE))
{
dtrap("pppfsm 1\n"); /* PARAMETER OUT OF RANGE */
return;
}
#endif /* NPDEBUG */
pfuncs = &prot_func_tabs[pcode];
state = mppp->states[pcode];
/* Take action and fix state machine based on state table */
cmd = fsm_table[(state * NUM_PPPEVENTS) + event];
if(cmd == 0xFFFF)
{
//ConPrintf("fsm_input (link %p): bad state: %d, event:%d.",
//mppp, state, event);
ppp_cleartimer(mppp);
return;
}
newstate = (u_char)(cmd & 0x000F); /* extract new state */
oldstate = mppp->states[pcode]; /* remember current state */
cmd &= 0xFFF0; /* mask out state nibble */
// ConPrintf("ppp_fsm (link %p): %s state: %s -> %s\n",
// mppp, prots[pcode], fsmstate[oldstate], fsmstate[newstate]);
/* if this is the beginning of a new session we need to reset the
* lines options to defaults. New sessions are begun by UP in the LCP
* layer or OPEN in the IPCP layer
*/
if((oldstate == ST_INITIAL) &&
(((event == EV_UP) && (pcode == LCP_STATE)) ||
((event == EV_OPEN) && (pcode == IPCP_STATE))))
{
ppp_fsm_init(mppp);
}
/* If this line just came up without a prior open call then
* we are the PPP server:
*/
if((event == EV_UP) && (oldstate == ST_INITIAL))
mppp->pppflags |= PPP_SERVER;
#ifdef PPP_MULTILINK
/* if this is a multilink bundle member and it is leaving the
* OPENED state then we need to clean up the ML flags.
*/
if((oldstate == ST_OPENED) && (newstate != ST_OPENED))
mppp->pppflags &= ~(ML_IPCP|ML_LCP);
#endif
/* For down or close events clear any running retry timers */
if((event == EV_DOWN) || (event == EV_CLOSE))
ppp_cleartimer(mppp);
/* RFC 1661 seems to imply we should set the state after these
* actions are performed, but it seems more robust here.
*/
mppp->states[pcode] = newstate;
/* If we are exiting a timed state to an untimed one
* we need to clear the timer.
*/
if((newstate <= ST_STOPPED) || (newstate >= ST_OPENED))
{
/* Old state had a timer? */
if((oldstate > ST_STOPPED) && (oldstate < ST_OPENED))
ppp_cleartimer(mppp);
}
/* rotate through the three action nibbles, performing the
* indicated action if it's non-zero
*/
for(i = 0; i < 3; i++)
{
if(cmd == 0) /* no (more) actions? */
break;
replytype = 0xFF; /* signal for no reply */
reply_id = mppp->in_ids[pcode]; /* default to reply, may be changed */
outp = inp; /* set default reply CI data */
outlen = inlen; /* and default send CI length */
action = cmd >> 12; /* get next 4-bit action code */
switch(action)
{
case AC_TLU: /* This-Layer-Up */
if(pfuncs->up)
pfuncs->up(mppp);
break;
case AC_TLD: /* This-Layer-Down */
if(pfuncs->down)
pfuncs->down(mppp);
break;
case AC_TLS: /* This-Layer-Started */
if(pfuncs->starting)
pfuncs->starting(mppp);
break;
case AC_TLF: /* This-Layer-Finished */
if(pfuncs->finished)
pfuncs->finished(mppp);
break;
case AC_IRC: /* Initialize-Restart-Count (and timer) */
mppp->retrys = PPP_FSMTRYS;
if(mppp->tmo_tick)
mppp->tmo_tick = cticks + (ppp_retry_secs * (u_long)TPS);
break;
case AC_ZRC: /* Zero-Restart-Count */
ppp_cleartimer(mppp);
break;
case AC_SCR: /* Send-Configure-Request */
replytype = CONFREQ;
reply_id = mppp->out_ids[pcode]++;
if((state != ST_REQSENT) &&
(state != ST_ACKRCVD) &&
(state != ST_ACKSENT ))
{
/* Not currently negotiating - reset options */
if(pfuncs->resetci)
(pfuncs->resetci)(mppp);
mppp->nakloops = 0;
}
if(pfuncs->addci)
{
outlen = pfuncs->addci(mppp); /* build the confreq in mppp->lastci */
outp = mppp->lastci; /* set send pointer */
}
break;
case AC_SCA: /* Send-Configure-Ack */
replytype = CONFACK;
break;
case AC_SCN: /* Send-Configure-Nak/Rej */
/* inp should already have NAK packet, and reject bit should be set */
if(mppp->pppflags & SEND_REJECT)
{
mppp->pppflags &= ~SEND_REJECT; /* clear flag */
replytype = CONFREJ; /* send reject, not NAK */
}
else
replytype = CONFNAK;
break;
case AC_STR: /* Send-Terminate-Request */
replytype = TERMREQ;
reply_id = mppp->out_ids[pcode]++;
outlen = 0; /* no data, TERMREQ is all header */
break;
case AC_STA: /* Send-Terminate-Ack */
replytype = TERMACK;
break;
case AC_SCJ: /* Send-Code-Reject */
dtrap("pppfsm 2\n");
replytype = CODEREJ;
break;
case AC_SER: /* Send-Echo-Reply (or similar) */
switch(mppp->rxcode)
{
case PECHOREQ:
replytype = PECHOREP;
break;
default: /* ECHOREP, DISCARD are noop */
break;
}
case 0: /* noop, just loop back for next action */
break;
default:
dtrap("pppfsm 3\n");
break;
}
cmd <<= 4; /* shift in next nibble */
/* See if we need to send a reply type packet */
if(replytype != 0xFF)
{
// ConPrintf("ppp_fsm (link %p) sending %s, len:%d\n",
// mppp, codes[replytype], outlen);
ppp_sendctl(mppp, pcode, replytype, outp, outlen, reply_id);
}
}
/* If we're entering one of the timed states from an untimed state
* then start a retry timer. The retry count itself was set
* in the IRC and ZRC actions above.
*/
if((newstate > ST_STOPPED) && (newstate < ST_OPENED))
{
/* old state didn't have a timer? */
if((oldstate <= ST_STOPPED) || (oldstate >= ST_OPENED))
ppp_settimer(mppp, ppp_fsm_tmo, ppp_retry_secs, (long)pcode);
}
/* If LCP has just gone from CLOSED state to INITIAL it probably
* means the line failed to connect - our modem code signals this
* with a ppp_lowerdown() call. Do a close now on IPCP so it
* doesn't linger in STARTING state. It's a bit off the spec., but
* it makes things work better.
*/
if((newstate == ST_INITIAL) &&
(pcode == LCP_STATE))
{
//ConPrintf("LCP (%p) failed, closing IPCP\n", mppp);
ppp_close(mppp, IPCP_STATE);
}
return;
}
/* FUNCTION: ppp_fsm_tmo()
*
* Handle a PPP FSM timer expiration.
*
* PARAM1: M_PPP mppp
* PARAM2: long parm
*
* RETURNS: void
*/
void
ppp_fsm_tmo(M_PPP mppp, long parm)
{
if(mppp->retrys-- > 1) /* do we have more retrys? */
{
ppp_fsm(mppp, (int)parm, EV_TOP, NULL, 0); /* another try */
mppp->tmo_tick = cticks + (ppp_retry_secs * (u_long)TPS); /* reset timer */
mppp->tmr_sets++; /* count this as a set */
}
else /* timed out, clean up */
ppp_fsm(mppp, (int)parm, EV_TOX, NULL, 0);
}
/* FUNCTION: ppp_fsm_init()
*
* Initialize an mppp structure for a new connect
*
* PARAM1: M_PPP mppp
*
* RETURNS: void
*/
void
ppp_fsm_init(M_PPP mppp)
{
lcp_options * lcp_ho = &mppp->lcp_hisoptions;
//ConPrintf("ppp_fsm_init (link %p)\n", mppp);
/* Reset peer's options structure. */
MEMSET(lcp_ho, 0, sizeof(*lcp_ho));
/* reset our options */
lcp_resetci(mppp);
ipcp_resetci(mppp);
/* Per RFC1662, Default initial asyncmaps to escape all 32 control
* chars. These are usually renegotiated and modified by LCP negotiation.
* Frame oriented links like PPPOE should simply ignore then.
*/
mppp->his_asyncmap = 0xFFFFFFFF;
mppp->my_asyncmap = 0xFFFFFFFF;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -