📄 pppfsm.c
字号:
/*
* PPPFSM.C -- PPP Finite State Machine
*
* This implementation of PPP is declared to be in the public domain.
*
* Acknowledgements and correction history may be found in PPP.C
*/
#include <stdio.h>
#include <ctype.h>
#include "global.h"
#include "mbuf.h"
#include "iface.h"
#include "ppp.h"
#include "pppfsm.h"
#include "ppplcp.h"
#include "trace.h"
char *fsmStates[] = {
"Closed",
"Listen",
"Req Sent",
"Ack Rcvd",
"Ack Sent",
"Opened",
"TermSent"
};
char *fsmCodes[] = {
NULL,
"Config Req",
"Config Ack",
"Config Nak",
"Config Reject",
"Termin Req",
"Termin Ack",
"Code Reject",
"Protocol Reject",
"Echo Request",
"Echo Reply",
"Discard Request",
};
static int fsm_sendtermreq(struct fsm_s *fsm_p);
static int fsm_sendtermack(struct fsm_s *fsm_p, byte_t id);
static void fsm_timeout(void *vp);
static void fsm_reset(struct fsm_s *fsm_p);
static void fsm_opening(struct fsm_s *fsm_p);
/************************************************************************/
/* Convert header in host form to network form */
void
htoncnf(
struct config_hdr *cnf,
struct mbuf **bpp
){
register uint8 *cp;
/* Prepend bytes for LCP/IPCP header */
pushdown(bpp, NULL,CONFIG_HDR_LEN);
/* Load header with proper values */
cp = (*bpp)->data;
*cp++ = cnf->code;
*cp++ = cnf->id;
put16(cp, cnf->len);
}
/* Extract header from incoming packet */
int
ntohcnf(cnf, bpp)
struct config_hdr *cnf;
struct mbuf **bpp;
{
uint8 cnfb[CONFIG_HDR_LEN];
if ( cnf == NULL )
return -1;
if ( pullup( bpp, cnfb, CONFIG_HDR_LEN ) < CONFIG_HDR_LEN )
return -1;
cnf->code = cnfb[0];
cnf->id = cnfb[1];
cnf->len = get16(&cnfb[2]);
return 0;
}
/***************************************/
/* Extract configuration option header */
int
ntohopt(opt,bpp)
struct option_hdr *opt;
struct mbuf **bpp;
{
uint8 optb[OPTION_HDR_LEN];
if ( opt == NULL )
return -1;
if ( pullup( bpp, optb, OPTION_HDR_LEN ) < OPTION_HDR_LEN )
return -1;
opt->type = optb[0];
opt->len = optb[1];
return 0;
}
/************************************************************************/
void
fsm_no_action(fsm_p)
struct fsm_s *fsm_p;
{
PPP_DEBUG_ROUTINES("fsm_no_action()");
}
int
fsm_no_check(
struct fsm_s *fsm_p,
struct config_hdr *hdr,
struct mbuf **bpp
){
PPP_DEBUG_ROUTINES("fsm_no_check()");
return 0;
}
/************************************************************************/
/* General log routine */
void
fsm_log(fsm_p, comment)
struct fsm_s *fsm_p;
char *comment;
{
if (PPPtrace > 1)
trace_log(PPPiface,"%s PPP/%s %-8s; %s",
fsm_p->ppp_p->iface->name,
fsm_p->pdc->name,
fsmStates[fsm_p->state],
comment);
}
/************************************************************************/
/* Set a timer in case an expected event does not occur */
void
fsm_timer(fsm_p)
struct fsm_s *fsm_p;
{
PPP_DEBUG_ROUTINES("fsm_timer()");
start_timer( &(fsm_p->timer) );
}
/************************************************************************/
/* Send a packet to the remote host */
int
fsm_send(
struct fsm_s *fsm_p,
byte_t code,
byte_t id,
struct mbuf **data
){
struct ppp_s *ppp_p = fsm_p->ppp_p;
struct iface *iface = ppp_p->iface;
struct config_hdr hdr;
struct mbuf *bp;
switch( hdr.code = code ) {
case CONFIG_REQ:
case TERM_REQ:
case ECHO_REQ:
/* Save ID field for match against replies from remote host */
fsm_p->lastid = ppp_p->id;
/* fallthru */
case PROT_REJ:
case DISCARD_REQ:
/* Use a unique ID field value */
hdr.id = ppp_p->id++;
break;
case CONFIG_ACK:
case CONFIG_NAK:
case CONFIG_REJ:
case TERM_ACK:
case CODE_REJ:
case ECHO_REPLY:
/* Use ID sent by remote host */
hdr.id = id;
break;
default:
/* we're in trouble */
trace_log(PPPiface, "%s PPP/%s %-8s;"
" Send with bogus code: %d",
iface->name,
fsm_p->pdc->name,
fsmStates[fsm_p->state],
code);
return -1;
};
switch( code ) {
case ECHO_REQ:
case ECHO_REPLY:
case DISCARD_REQ:
{
struct lcp_s *lcp_p = fsm_p->pdv;
bp = ambufw(4);
put32(bp->data, lcp_p->local.work.magic_number);
*data = bp;
}
};
hdr.len = len_p(*data) + CONFIG_HDR_LEN;
/* Prepend header to packet data */
htoncnf(&hdr,data);
if (PPPtrace > 1) {
trace_log(PPPiface, "%s PPP/%s %-8s;"
" Sending %s, id: %d, len: %d",
iface->name,
fsm_p->pdc->name,
fsmStates[fsm_p->state],
fsmCodes[code],
hdr.id,hdr.len);
}
ppp_p->OutNCP[fsm_p->pdc->fsmi]++;
return( (*iface->output)
(iface, NULL, NULL, fsm_p->pdc->protocol, data) );
}
/************************************************************************/
/* Send a configuration request */
int
fsm_sendreq(fsm_p)
struct fsm_s *fsm_p;
{
struct mbuf *bp;
PPP_DEBUG_ROUTINES("fsm_sendreq()");
if ( fsm_p->retry <= 0 )
return -1;
fsm_p->retry--;
fsm_timer(fsm_p);
bp = (*fsm_p->pdc->makereq)(fsm_p);
return( fsm_send(fsm_p, CONFIG_REQ, 0, &bp) );
}
/************************************************************************/
/* Send a termination request */
static int
fsm_sendtermreq(fsm_p)
struct fsm_s *fsm_p;
{
PPP_DEBUG_ROUTINES("fsm_sendtermreq()");
if ( fsm_p->retry <= 0 )
return -1;
fsm_p->retry--;
fsm_timer(fsm_p);
return( fsm_send(fsm_p, TERM_REQ, 0, NULL) );
}
/************************************************************************/
/* Send Terminate Ack */
static int
fsm_sendtermack(fsm_p,id)
struct fsm_s *fsm_p;
byte_t id;
{
PPP_DEBUG_ROUTINES("fsm_sendtermack()");
return( fsm_send(fsm_p, TERM_ACK, id, NULL) );
}
/************************************************************************/
/* Reset state machine */
static void
fsm_reset(fsm_p)
struct fsm_s *fsm_p;
{
PPP_DEBUG_ROUTINES("fsm_reset()");
fsm_p->state = (fsm_p->flags & (FSM_ACTIVE | FSM_PASSIVE))
? fsmLISTEN : fsmCLOSED;
fsm_p->retry = fsm_p->try_req;
fsm_p->retry_nak = fsm_p->try_nak;
(*fsm_p->pdc->reset)(fsm_p);
}
/************************************************************************/
/* Configuration negotiation complete */
static void
fsm_opening(fsm_p)
struct fsm_s *fsm_p;
{
fsm_log(fsm_p, "Opened");
stop_timer(&(fsm_p->timer));
(*fsm_p->pdc->opening)(fsm_p);
fsm_p->state = fsmOPENED;
}
/************************************************************************/
/* E V E N T P R O C E S S I N G */
/************************************************************************/
/* Process incoming packet */
void
fsm_proc(
struct fsm_s *fsm_p,
struct mbuf **bpp
){
struct config_hdr hdr;
PPPtrace = fsm_p->ppp_p->trace;
PPPiface = fsm_p->ppp_p->iface;
if ( ntohcnf(&hdr, bpp) == -1 )
fsm_log( fsm_p, "short configuration packet" );
if (PPPtrace > 1)
trace_log(PPPiface, "%s PPP/%s %-8s;"
" Processing %s, id: %d, len: %d",
fsm_p->ppp_p->iface->name,
fsm_p->pdc->name,
fsmStates[fsm_p->state],
fsmCodes[hdr.code],
hdr.id, hdr.len);
hdr.len -= CONFIG_HDR_LEN; /* Length includes envelope */
trim_mbuf(bpp, hdr.len); /* Trim off padding */
switch(hdr.code) {
case CONFIG_REQ:
switch(fsm_p->state) {
case fsmOPENED: /* Unexpected event? */
(*fsm_p->pdc->closing)(fsm_p);
fsm_reset(fsm_p);
/* fallthru */
case fsmLISTEN:
(*fsm_p->pdc->starting)(fsm_p);
fsm_sendreq(fsm_p);
/* fallthru */
case fsmREQ_Sent:
case fsmACK_Sent: /* Unexpected event? */
fsm_p->state =
((*fsm_p->pdc->request)(fsm_p, &hdr, bpp) == 0)
? fsmACK_Sent : fsmREQ_Sent;
break;
case fsmACK_Rcvd:
if ((*fsm_p->pdc->request)(fsm_p, &hdr, bpp) == 0) {
fsm_opening(fsm_p);
} else {
/* give peer time to respond */
fsm_timer(fsm_p);
}
break;
case fsmCLOSED:
/* Don't accept any connections */
fsm_sendtermack(fsm_p, hdr.id);
/* fallthru */
case fsmTERM_Sent:
/* We are attempting to close connection; */
/* wait for timeout to resend a Terminate Request */
free_p(bpp);
break;
};
break;
case CONFIG_ACK:
switch(fsm_p->state) {
case fsmREQ_Sent:
if ((*fsm_p->pdc->ack)(fsm_p, &hdr, bpp) == 0) {
fsm_p->state = fsmACK_Rcvd;
}
break;
case fsmACK_Sent:
if ((*fsm_p->pdc->ack)(fsm_p, &hdr, bpp) == 0) {
fsm_opening(fsm_p);
}
break;
case fsmOPENED: /* Unexpected event? */
(*fsm_p->pdc->closing)(fsm_p);
(*fsm_p->pdc->starting)(fsm_p);
fsm_reset(fsm_p);
/* fallthru */
case fsmACK_Rcvd: /* Unexpected event? */
free_p(bpp);
fsm_sendreq(fsm_p);
fsm_p->state = fsmREQ_Sent;
break;
case fsmCLOSED:
case fsmLISTEN:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -