📄 netppp.c
字号:
/***********************************/
/*** PUBLIC FUNCTION DEFINITIONS ***/
/***********************************/
/* Initialize the PPP subsystem. */
/*
void pppInit(Interface* pInterface)
{
}
*/
void pppInit(void)
{
struct protent *protp;
int i, j;
for (i = 0; i < NUM_PPP; i++) {
pppControl[i].openFlag = 0;
sprintf(pppControl[i].ifname, "ppp%d", i);
/*
* Initialize to the standard option set.
*/
for (j = 0; (protp = protocols[j]) != NULL; ++j)
(*protp->init)(i);
}
#if STATS_SUPPORT > 0
/* Clear the statistics. */
memset(&pppStats, 0, sizeof(pppStats));
pppStats.headLine.fmtStr = "\t\tPPP STATISTICS\r\n";
pppStats.ppp_ibytes.fmtStr = "\tBYTES IN : %5lu\r\n";
pppStats.ppp_ipackets.fmtStr = "\tPACKETS IN : %5lu\r\n";
pppStats.ppp_ierrors.fmtStr = "\tIN ERRORS : %5lu\r\n";
pppStats.ppp_derrors.fmtStr = "\tDISPATCH ERR: %5lu\r\n";
pppStats.ppp_obytes.fmtStr = "\tBYTES OUT : %5lu\r\n";
pppStats.ppp_opackets.fmtStr = "\tPACKETS OUT : %5lu\r\n";
pppStats.ppp_oerrors.fmtStr = "\tOUT ERRORS : %5lu\r\n";
#endif
}
/* Open a new PPP connection using the given I/O device.
* This initializes the PPP control block but does not
* attempt to negotiate the LCP session. If this port
* connects to a modem, the modem connection must be
* established before calling this.
* Return a new PPP connection descriptor on success or
* an error code (negative) on failure. */
int pppOpen(int fd)
{
PPPControl *pc;
char c;
int pd;
/* XXX
* Ensure that fd is not already used for PPP
*/
/* Find a free PPP session descriptor. */
OS_ENTER_CRITICAL();
for (pd = 0; pd < NUM_PPP && pppControl[pd].openFlag != 0; pd++);
if (pd >= NUM_PPP)
pd = PPPERR_OPEN;
else
pppControl[pd].openFlag = !0;
OS_EXIT_CRITICAL();
/*
* Save the old line discipline of fd, and set it to PPP.
* (For the Accu-Vote, save and set the framing character).
* Set the user name and password in case we need PAP
* authentication.
*/
if (pd >= 0) {
c = PPP_FLAG;
#ifdef OS_DEPENDENT
if (ioctl(fd, GETFRAME, &pppControl[pd].oldFrame) < 0
|| ioctl(fd, SETFRAME, &c) < 0) {
pd = PPPERR_DEVICE;
pppControl[pd].openFlag = 0;
}
#else
pppControl[pd].openFlag = 1;
#endif
upap_setloginpasswd(pd, user, passwd);
}
/* Launch a deamon thread. */
if (pd >= 0) {
lcp_init(pd);
pc = &pppControl[pd];
pc->fd = fd;
pc->kill_link = 0;
pc->if_up = 0;
pc->errCode = 0;
pc->inState = PDIDLE;
pc->inHead = NULL;
pc->inTail = NULL;
pc->inEscaped = 0;
pc->lastXMit = mtime() - MAXIDLEFLAG;
pc->traceOffset = 0;
#if VJ_SUPPORT > 0
pc->vjEnabled = 0;
vj_compress_init(&pc->vjComp);
#endif
/*
* Default the in and out accm so that escape and flag characters
* are always escaped.
*/
memset(pc->inACCM, 0, sizeof(ext_accm));
pc->inACCM[15] = 0x60;
memset(pc->outACCM, 0, sizeof(ext_accm));
pc->outACCM[15] = 0x60;
//#ifdef OS_DEPENDENT
OSTaskCreate(pppMain, (void*)pd, pc->pppStack + STACK_SIZE, (UBYTE)(PRI_PPP0 + pd));
//#endif
while(pd >= 0 && !pc->if_up) {
msleep(500);
if (lcp_phase[pd] == PHASE_DEAD) {
pppClose(pd);
if (pc->errCode)
pd = pc->errCode;
else
pd = PPPERR_CONNECT;
}
// else if (buttonStatus() == YESNOBUTTON) {
// pppClose(pd);
// pd = PPPERR_USER;
// }
}
pc->traceOffset = 2;
}
return pd;
}
/* Close a PPP connection and release the descriptor.
* Any outstanding packets in the queues are dropped.
* Return 0 on success, an error code on failure. */
int pppClose(int pd)
{
PPPControl *pc = &pppControl[pd];
int st = 0;
/* Disconnect */
pc->kill_link = !0;
pc->traceOffset = 0;
while(st >= 0 && lcp_phase[pd] != PHASE_DEAD) {
msleep(500);
// if (buttonStatus() == YESNOBUTTON)
// st = PPPERR_USER;
break;
}
#ifdef OS_DEPENDENT
/* Reset fd line discipline. In our case, the framing character. */
if (ioctl(pc->fd, SETFRAME, &pppControl[pd].oldFrame) < 0)
st = PPPERR_DEVICE;
#endif
pc->openFlag = 0;
return st;
}
/* Send a packet on the given connection.
* Return 0 on success, an error code on failure. */
#pragma argsused
int pppOutput(int pd, u_short protocol, NBuf *nb)
{
PPPControl *pc = &pppControl[pd];
u_int fcsOut = PPP_INITFCS;
NBuf *headMB = NULL, *tailMB = NULL, *tnb;
int st = 0;
u_char c = 0;
int n;
u_char *sPtr;
/* Grab an output buffer. */
nGET(headMB);
if (headMB == NULL) {
st = PPPERR_ALLOC;
PPPDEBUG((LOG_WARNING, TL_PPP, "pppOutput[%d]: first alloc fail", pd));
#if STATS_SUPPORT > 0
pppStats.PPPoerrors++;
#endif
/* Validate parameters. */
/* We let any protocol value go through - it can't hurt us
* and the peer will just drop it if it's not accepting it. */
} else if (pd < 0 || pd >= NUM_PPP || !pc->openFlag || !nb) {
st = PPPERR_PARAM;
PPPDEBUG((LOG_WARNING, TL_PPP, "pppOutput[%d]: bad parms prot=%d nb=%P",
pd, protocol, nb));
#if STATS_SUPPORT > 0
pppStats.PPPoerrors++;
#endif
/* Check that the link is up. */
} else if (lcp_phase[pd] == PHASE_DEAD) {
PPPDEBUG((LOG_ERR, TL_PPP, "pppOutput[%d]: link not up", pd));
#if STATS_SUPPORT > 0
pppStats.PPPderrors++;
#endif
st = PPPERR_OPEN;
} else {
#if VJ_SUPPORT > 0
/*
* Attempt Van Jacobson header compression if VJ is configured and
* this is an IP packet.
*/
if (protocol == PPP_IP && pc->vjEnabled) {
switch (vj_compress_tcp(&pc->vjComp, nb)) {
case TYPE_IP:
/* No change...
protocol = PPP_IP_PROTOCOL;
*/
break;
case TYPE_COMPRESSED_TCP:
protocol = PPP_VJC_COMP;
break;
case TYPE_UNCOMPRESSED_TCP:
protocol = PPP_VJC_UNCOMP;
break;
default:
PPPDEBUG((LOG_WARNING, TL_PPP, "pppOutput[%d]: bad IP packet", pd));
#if STATS_SUPPORT > 0
pppStats.PPPderrors++;
#endif
return PPPERR_PROTOCOL;
}
}
#endif
headMB->len = 0;
tailMB = headMB;
/* Build the PPP header. */
if (diffTime(pc->lastXMit) <= MAXIDLEFLAG)
tailMB = pppMPutRaw(PPP_FLAG, tailMB);
if (!pc->accomp) {
fcsOut = PPP_FCS(fcsOut, PPP_ALLSTATIONS);
tailMB = pppMPutC(PPP_ALLSTATIONS, &pc->outACCM, tailMB);
fcsOut = PPP_FCS(fcsOut, PPP_UI);
tailMB = pppMPutC(PPP_UI, &pc->outACCM, tailMB);
}
if (!pc->pcomp || protocol > 0xFF) {
c = (protocol >> 8) & 0xFF;
fcsOut = PPP_FCS(fcsOut, c);
tailMB = pppMPutC(c, &pc->outACCM, tailMB);
}
c = protocol & 0xFF;
fcsOut = PPP_FCS(fcsOut, c);
tailMB = pppMPutC(c, &pc->outACCM, tailMB);
/* Load packet. */
while (nb) {
sPtr = nBUFTOPTR(nb, u_char *);
n = nb->len;
while (n-- > 0) {
c = *sPtr++;
/* Update FCS before checking for special characters. */
fcsOut = PPP_FCS(fcsOut, c);
/* Copy to output buffer escaping special characters. */
tailMB = pppMPutC(c, &pc->outACCM, tailMB);
}
nFREE(nb, tnb);
nb = tnb;
}
/* Add FCS and trailing flag. */
c = ~fcsOut & 0xFF;
tailMB = pppMPutC(c, &pc->outACCM, tailMB);
c = (~fcsOut >> 8) & 0xFF;
tailMB = pppMPutC(c, &pc->outACCM, tailMB);
tailMB = pppMPutRaw(PPP_FLAG, tailMB);
/* If we failed to complete the packet, throw it away.
* Otherwise send it. */
if (!tailMB) {
st = PPPERR_ALLOC;
PPPDEBUG((pppControl[pd].traceOffset + LOG_WARNING, TL_PPP,
"pppOutput[%d]: Alloc err - dropping proto=%d",
pd, protocol));
nFreeChain(headMB);
#if STATS_SUPPORT > 0
pppStats.PPPoerrors++;
#endif
}
else {
PPPDEBUG((pppControl[pd].traceOffset + LOG_INFO, TL_PPP,
// "pppOutput[%d]: proto=x%X %d:%.*H", pd, protocol, headMB->chainLen, MIN(headMB->len * 2, 50), headMB->data));
"pppOutput[%d]: proto=x%X len=%d", pd, protocol, headMB->chainLen));
nPut(pc->fd, headMB);
#if STATS_SUPPORT > 0
pppStats.PPPopackets++;
#endif
}
headMB = NULL;
}
/* If we didn't consume the source buffer, drop it. */
if (nb)
nFreeChain(nb);
/* If we didn't send the output buffer, drop it. */
if (headMB) {
nFreeChain(headMB);
#if STATS_SUPPORT > 0
pppStats.PPPoerrors++;
#endif
}
return st;
}
/* Process an nBuf chain received on given connection.
* The nBuf chain is always passed on or freed making the original
* nBuf pointer invalid. Note that this does not check for packet
* chains. This does not require complete packets but if a packet
* spans calls, those calls must be in the correct order. This is
* designed to handle packets received from the serial interface
* but could be used for a loopback interface.
* Return 0 on success, an error code on failure.
*/
int pppInput(int pd, NBuf *nb)
{
NBuf *nextNBuf;
while (nb != NULL) {
/* Consume the buffer. Ideally we could just work on the
* recieved buffer but unless we get the serial driver to
* preprocess the escape sequences, it's easier to just
* work from one buffer to another. */
pppInProc(pd, nb->data, nb->len);
nFREE(nb, nextNBuf);
nb = nextNBuf;
}
return 0;
}
/* Get and set parameters for the given connection.
* Return 0 on success, an error code on failure. */
int pppIOCtl(int pd, int cmd, void *arg)
{
PPPControl *pc = &pppControl[pd];
int st = 0;
if (pd < 0 || pd >= NUM_PPP)
st = PPPERR_PARAM;
else {
switch(cmd) {
case PPPCTLG_UPSTATUS: /* Get the PPP up status. */
if (arg)
*(int *)arg = (int)(pc->if_up);
else
st = PPPERR_PARAM;
break;
case PPPCTLS_ERRCODE: /* Set the PPP error code. */
if (arg)
pc->errCode = *(int *)arg;
else
st = PPPERR_PARAM;
break;
case PPPCTLG_ERRCODE: /* Get the PPP error code. */
if (arg)
*(int *)arg = (int)(pc->errCode);
else
st = PPPERR_PARAM;
break;
case PPPCTLG_FD:
if (arg)
*(int *)arg = (int)(pc->fd);
else
st = PPPERR_PARAM;
break;
default:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -