?? netipcp.c
字號:
citype != opt) \
goto bad; \
GETSHORT(cishort, p); \
if (cishort != val) \
goto bad; \
if (!old) { \
GETCHAR(cimaxslotindex, p); \
if (cimaxslotindex != maxslotindex) \
goto bad; \
GETCHAR(cicflag, p); \
if (cicflag != cflag) \
goto bad; \
} \
}
#define ACKCIADDR(opt, neg, old, val1, val2) \
if (neg) { \
int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \
u_int32_t l; \
if ((len -= addrlen) < 0) \
goto bad; \
GETCHAR(citype, p); \
GETCHAR(cilen, p); \
if (cilen != addrlen || \
citype != opt) \
goto bad; \
GETLONG(l, p); \
cilong = htonl(l); \
if (val1 != cilong) \
goto bad; \
if (old) { \
GETLONG(l, p); \
cilong = htonl(l); \
if (val2 != cilong) \
goto bad; \
} \
}
ACKCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr,
go->old_addrs, go->ouraddr, go->hisaddr);
ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj,
go->maxslotindex, go->cflag);
/*
* If there are any remaining CIs, then this packet is bad.
*/
if (len != 0)
goto bad;
return (1);
bad:
IPCPDEBUG((LOG_INFO, "ipcp_ackci: received bad Ack!"));
return (0);
}
/*
* ipcp_nakci - Peer has sent a NAK for some of our CIs.
* This should not modify any state if the Nak is bad
* or if IPCP is in the OPENED state.
*
* Returns:
* 0 - Nak was bad.
* 1 - Nak was good.
*/
static int ipcp_nakci(fsm *f, u_char *p, int len)
{
ipcp_options *go = &ipcp_gotoptions[f->unit];
u_char cimaxslotindex, cicflag;
u_char citype, cilen, *next;
u_short cishort;
u_int32_t ciaddr1, ciaddr2, l;
ipcp_options no; /* options we've seen Naks for */
ipcp_options try; /* options to request next time */
BZERO(&no, sizeof(no));
try = *go;
/*
* Any Nak'd CIs must be in exactly the same order that we sent.
* Check packet length and CI length at each step.
* If we find any deviations, then this packet is bad.
*/
#define NAKCIADDR(opt, neg, old, code) \
if (go->neg && \
len >= (cilen = (old? CILEN_ADDRS: CILEN_ADDR)) && \
p[1] == cilen && \
p[0] == opt) { \
len -= cilen; \
INCPTR(2, p); \
GETLONG(l, p); \
ciaddr1 = htonl(l); \
if (old) { \
GETLONG(l, p); \
ciaddr2 = htonl(l); \
no.old_addrs = 1; \
} else \
ciaddr2 = 0; \
no.neg = 1; \
code \
}
#define NAKCIVJ(opt, neg, code) \
if (go->neg && \
((cilen = p[1]) == CILEN_COMPRESS || cilen == CILEN_VJ) && \
len >= cilen && \
p[0] == opt) { \
len -= cilen; \
INCPTR(2, p); \
GETSHORT(cishort, p); \
no.neg = 1; \
code \
}
/*
* Accept the peer's idea of {our,his} address, if different
* from our idea, only if the accept_{local,remote} flag is set.
*/
NAKCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), neg_addr, go->old_addrs,
if (go->accept_local && ciaddr1) { /* Do we know our address? */
try.ouraddr = ciaddr1;
IPCPDEBUG((LOG_INFO, "local IP address %s",
ip_ntoa(ciaddr1)));
}
if (go->accept_remote && ciaddr2) { /* Does he know his? */
try.hisaddr = ciaddr2;
IPCPDEBUG((LOG_INFO, "remote IP address %s",
ip_ntoa(ciaddr2)));
}
);
/*
* Accept the peer's value of maxslotindex provided that it
* is less than what we asked for. Turn off slot-ID compression
* if the peer wants. Send old-style compress-type option if
* the peer wants.
*/
NAKCIVJ(CI_COMPRESSTYPE, neg_vj,
if (cilen == CILEN_VJ) {
GETCHAR(cimaxslotindex, p);
GETCHAR(cicflag, p);
if (cishort == IPCP_VJ_COMP) {
try.old_vj = 0;
if (cimaxslotindex < go->maxslotindex)
try.maxslotindex = cimaxslotindex;
if (!cicflag)
try.cflag = 0;
} else {
try.neg_vj = 0;
}
} else {
if (cishort == IPCP_VJ_COMP || cishort == IPCP_VJ_COMP_OLD) {
try.old_vj = 1;
try.vj_protocol = cishort;
} else {
try.neg_vj = 0;
}
}
);
/*
* There may be remaining CIs, if the peer is requesting negotiation
* on an option that we didn't include in our request packet.
* If they want to negotiate about IP addresses, we comply.
* If they want us to ask for compression, we refuse.
*/
while (len > CILEN_VOID) {
GETCHAR(citype, p);
GETCHAR(cilen, p);
if( (len -= cilen) < 0 )
goto bad;
next = p + cilen - 2;
switch (citype) {
case CI_COMPRESSTYPE:
if (go->neg_vj || no.neg_vj ||
(cilen != CILEN_VJ && cilen != CILEN_COMPRESS))
goto bad;
no.neg_vj = 1;
break;
case CI_ADDRS:
if ((go->neg_addr && go->old_addrs) || no.old_addrs
|| cilen != CILEN_ADDRS)
goto bad;
try.neg_addr = 1;
try.old_addrs = 1;
GETLONG(l, p);
ciaddr1 = htonl(l);
if (ciaddr1 && go->accept_local)
try.ouraddr = ciaddr1;
GETLONG(l, p);
ciaddr2 = htonl(l);
if (ciaddr2 && go->accept_remote)
try.hisaddr = ciaddr2;
no.old_addrs = 1;
break;
case CI_ADDR:
if (go->neg_addr || no.neg_addr || cilen != CILEN_ADDR)
goto bad;
try.old_addrs = 0;
GETLONG(l, p);
ciaddr1 = htonl(l);
if (ciaddr1 && go->accept_local)
try.ouraddr = ciaddr1;
if (try.ouraddr != 0)
try.neg_addr = 1;
no.neg_addr = 1;
break;
}
p = next;
}
/* If there is still anything left, this packet is bad. */
if (len != 0)
goto bad;
/*
* OK, the Nak is good. Now we can update state.
*/
if (f->state != OPENED)
*go = try;
return 1;
bad:
IPCPDEBUG((LOG_INFO, "ipcp_nakci: received bad Nak!"));
return 0;
}
/*
* ipcp_rejci - Reject some of our CIs.
*/
static int ipcp_rejci(fsm *f, u_char *p, int len)
{
ipcp_options *go = &ipcp_gotoptions[f->unit];
u_char cimaxslotindex, ciflag, cilen;
u_short cishort;
u_int32_t cilong;
ipcp_options try; /* options to request next time */
try = *go;
/*
* Any Rejected CIs must be in exactly the same order that we sent.
* Check packet length and CI length at each step.
* If we find any deviations, then this packet is bad.
*/
#define REJCIADDR(opt, neg, old, val1, val2) \
if (go->neg && \
len >= (cilen = old? CILEN_ADDRS: CILEN_ADDR) && \
p[1] == cilen && \
p[0] == opt) { \
u_int32_t l; \
len -= cilen; \
INCPTR(2, p); \
GETLONG(l, p); \
cilong = htonl(l); \
/* Check rejected value. */ \
if (cilong != val1) \
goto bad; \
if (old) { \
GETLONG(l, p); \
cilong = htonl(l); \
/* Check rejected value. */ \
if (cilong != val2) \
goto bad; \
} \
try.neg = 0; \
}
#define REJCIVJ(opt, neg, val, old, maxslot, cflag) \
if (go->neg && \
p[1] == (old? CILEN_COMPRESS : CILEN_VJ) && \
len >= p[1] && \
p[0] == opt) { \
len -= p[1]; \
INCPTR(2, p); \
GETSHORT(cishort, p); \
/* Check rejected value. */ \
if (cishort != val) \
goto bad; \
if (!old) { \
GETCHAR(cimaxslotindex, p); \
if (cimaxslotindex != maxslot) \
goto bad; \
GETCHAR(ciflag, p); \
if (ciflag != cflag) \
goto bad; \
} \
try.neg = 0; \
}
REJCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), neg_addr,
go->old_addrs, go->ouraddr, go->hisaddr);
REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol, go->old_vj,
go->maxslotindex, go->cflag);
/*
* If there are any remaining CIs, then this packet is bad.
*/
if (len != 0)
goto bad;
/*
* Now we can update state.
*/
if (f->state != OPENED)
*go = try;
return 1;
bad:
IPCPDEBUG((LOG_INFO, "ipcp_rejci: received bad Reject!"));
return 0;
}
/*
* ipcp_reqci - Check the peer's requested CIs and send appropriate response.
*
* Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
* appropriately. If reject_if_disagree is non-zero, doesn't return
* CONFNAK; returns CONFREJ if it can't return CONFACK.
*/
static int ipcp_reqci(
fsm *f,
u_char *inp, /* Requested CIs */
int *len, /* Length of requested CIs */
int reject_if_disagree
)
{
ipcp_options *wo = &ipcp_wantoptions[f->unit];
ipcp_options *ho = &ipcp_hisoptions[f->unit];
ipcp_options *ao = &ipcp_allowoptions[f->unit];
#ifdef OLD_CI_ADDRS
ipcp_options *go = &ipcp_gotoptions[f->unit];
#endif
u_char *cip, *next; /* Pointer to current and next CIs */
u_short cilen, citype; /* Parsed len, type */
u_short cishort; /* Parsed short value */
u_int32_t tl, ciaddr1; /* Parsed address values */
#ifdef OLD_CI_ADDRS
u_int32_t ciaddr2; /* Parsed address values */
#endif
int rc = CONFACK; /* Final packet return code */
int orc; /* Individual option return code */
u_char *p; /* Pointer to next char to parse */
u_char *ucp = inp; /* Pointer to current output char */
int l = *len; /* Length left */
u_char maxslotindex, cflag;
int d;
cis_received[f->unit] = 1;
/*
* Reset all his options.
*/
BZERO(ho, sizeof(*ho));
/*
* Process all his options.
*/
next = inp;
while (l) {
orc = CONFACK; /* Assume success */
cip = p = next; /* Remember begining of CI */
if (l < 2 || /* Not enough data for CI header or */
p[1] < 2 || /* CI length too small or */
p[1] > l) { /* CI length too big? */
IPCPDEBUG((LOG_INFO, "ipcp_reqci: bad CI length!"));
orc = CONFREJ; /* Reject bad CI */
cilen = l; /* Reject till end of packet */
l = 0; /* Don't loop again */
goto endswitch;
}
GETCHAR(citype, p); /* Parse CI type */
GETCHAR(cilen, p); /* Parse CI length */
l -= cilen; /* Adjust remaining length */
next += cilen; /* Step to next CI */
switch (citype) { /* Check CI type */
#ifdef OLD_CI_ADDRS /* Need to save space... */
case CI_ADDRS:
IPCPDEBUG((LOG_INFO, "ipcp_reqci: received ADDRS "));
if (!ao->neg_addr ||
cilen != CILEN_ADDRS) { /* Check CI length */
orc = CONFREJ; /* Reject CI */
break;
}
/*
* If he has no address, or if we both have his address but
* disagree about it, then NAK it with our idea.
* In particular, if we don't know his address, but he does,
* then accept it.
*/
GETLONG(tl, p); /* Parse source address (his) */
ciaddr1 = htonl(tl);
IPCPDEBUG((LOG_INFO, "his addr %s", ip_ntoa(ciaddr1)));
if (ciaddr1 != wo->hisaddr
&& (ciaddr1 == 0 || !wo->accept_remote)) {
orc = CONFNAK;
if (!reject_if_disagree) {
DECPTR(sizeof(u_int32_t), p);
tl = ntohl(wo->hisaddr);
PUTLONG(tl, p);
}
} else if (ciaddr1 == 0 && wo->hisaddr == 0) {
/*
* If neither we nor he knows his address, reject the option.
*/
orc = CONFREJ;
wo->req_addr = 0; /* don't NAK with 0.0.0.0 later */
break;
}
/*
* If he doesn't know our address, or if we both have our address
* but disagree about it, then NAK it with our idea.
*/
GETLONG(tl, p); /* Parse desination address (ours) */
ciaddr2 = htonl(tl);
IPCPDEBUG((LOG_INFO, "our addr %s", ip_ntoa(ciaddr2)));
if (ciaddr2 != wo->ouraddr) {
if (ciaddr2 == 0 || !wo->accept_local) {
orc = CONFNAK;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -