in net/ip/lwip_base/src/netif/ppp/lcp.c [1127:1577]
static int lcp_nakci(fsm *f, u_char *p, int len, int treat_as_reject) {
ppp_pcb *pcb = f->pcb;
lcp_options *go = &pcb->lcp_gotoptions;
lcp_options *wo = &pcb->lcp_wantoptions;
u_char citype, cichar, *next;
u_short cishort;
u32_t cilong;
lcp_options no; /* options we've seen Naks for */
lcp_options try_; /* options to request next time */
int looped_back = 0;
int cilen;
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 NAKCIVOID(opt, neg) \
if (go->neg && \
len >= CILEN_VOID && \
p[1] == CILEN_VOID && \
p[0] == opt) { \
len -= CILEN_VOID; \
INCPTR(CILEN_VOID, p); \
no.neg = 1; \
try_.neg = 0; \
}
#if CHAP_SUPPORT
#define NAKCICHAP(opt, neg, code) \
if (go->neg && \
len >= CILEN_CHAP && \
p[1] == CILEN_CHAP && \
p[0] == opt) { \
len -= CILEN_CHAP; \
INCPTR(2, p); \
GETSHORT(cishort, p); \
GETCHAR(cichar, p); \
no.neg = 1; \
code \
}
#endif /* CHAP_SUPPORT */
#define NAKCICHAR(opt, neg, code) \
if (go->neg && \
len >= CILEN_CHAR && \
p[1] == CILEN_CHAR && \
p[0] == opt) { \
len -= CILEN_CHAR; \
INCPTR(2, p); \
GETCHAR(cichar, p); \
no.neg = 1; \
code \
}
#define NAKCISHORT(opt, neg, code) \
if (go->neg && \
len >= CILEN_SHORT && \
p[1] == CILEN_SHORT && \
p[0] == opt) { \
len -= CILEN_SHORT; \
INCPTR(2, p); \
GETSHORT(cishort, p); \
no.neg = 1; \
code \
}
#define NAKCILONG(opt, neg, code) \
if (go->neg && \
len >= CILEN_LONG && \
p[1] == CILEN_LONG && \
p[0] == opt) { \
len -= CILEN_LONG; \
INCPTR(2, p); \
GETLONG(cilong, p); \
no.neg = 1; \
code \
}
#if LQR_SUPPORT
#define NAKCILQR(opt, neg, code) \
if (go->neg && \
len >= CILEN_LQR && \
p[1] == CILEN_LQR && \
p[0] == opt) { \
len -= CILEN_LQR; \
INCPTR(2, p); \
GETSHORT(cishort, p); \
GETLONG(cilong, p); \
no.neg = 1; \
code \
}
#endif /* LQR_SUPPORT */
#define NAKCIENDP(opt, neg) \
if (go->neg && \
len >= CILEN_CHAR && \
p[0] == opt && \
p[1] >= CILEN_CHAR && \
p[1] <= len) { \
len -= p[1]; \
INCPTR(p[1], p); \
no.neg = 1; \
try_.neg = 0; \
}
/*
* NOTE! There must be no assignments to individual fields of *go in
* the code below. Any such assignment is a BUG!
*/
/*
* We don't care if they want to send us smaller packets than
* we want. Therefore, accept any MRU less than what we asked for,
* but then ignore the new value when setting the MRU in the kernel.
* If they send us a bigger MRU than what we asked, accept it, up to
* the limit of the default MRU we'd get if we didn't negotiate.
*/
if (go->neg_mru && go->mru != PPP_DEFMRU) {
NAKCISHORT(CI_MRU, neg_mru,
if (cishort <= wo->mru || cishort <= PPP_DEFMRU)
try_.mru = cishort;
);
}
/*
* Add any characters they want to our (receive-side) asyncmap.
*/
if (go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF) {
NAKCILONG(CI_ASYNCMAP, neg_asyncmap,
try_.asyncmap = go->asyncmap | cilong;
);
}
/*
* If they've nak'd our authentication-protocol, check whether
* they are proposing a different protocol, or a different
* hash algorithm for CHAP.
*/
if ((0
#if CHAP_SUPPORT
|| go->neg_chap
#endif /* CHAP_SUPPORT */
#if PAP_SUPPORT
|| go->neg_upap
#endif /* PAP_SUPPORT */
#if EAP_SUPPORT
|| go->neg_eap
#endif /* EAP_SUPPORT */
)
&& len >= CILEN_SHORT
&& p[0] == CI_AUTHTYPE && p[1] >= CILEN_SHORT && p[1] <= len) {
cilen = p[1];
len -= cilen;
#if CHAP_SUPPORT
no.neg_chap = go->neg_chap;
#endif /* CHAP_SUPPORT */
#if PAP_SUPPORT
no.neg_upap = go->neg_upap;
#endif /* PAP_SUPPORT */
#if EAP_SUPPORT
no.neg_eap = go->neg_eap;
#endif /* EAP_SUPPORT */
INCPTR(2, p);
GETSHORT(cishort, p);
#if PAP_SUPPORT
if (cishort == PPP_PAP && cilen == CILEN_SHORT) {
#if EAP_SUPPORT
/* If we were asking for EAP, then we need to stop that. */
if (go->neg_eap)
try_.neg_eap = 0;
else
#endif /* EAP_SUPPORT */
#if CHAP_SUPPORT
/* If we were asking for CHAP, then we need to stop that. */
if (go->neg_chap)
try_.neg_chap = 0;
else
#endif /* CHAP_SUPPORT */
/*
* If we weren't asking for CHAP or EAP, then we were asking for
* PAP, in which case this Nak is bad.
*/
goto bad;
} else
#endif /* PAP_SUPPORT */
#if CHAP_SUPPORT
if (cishort == PPP_CHAP && cilen == CILEN_CHAP) {
GETCHAR(cichar, p);
#if EAP_SUPPORT
/* Stop asking for EAP, if we were. */
if (go->neg_eap) {
try_.neg_eap = 0;
/* Try to set up to use their suggestion, if possible */
if (CHAP_CANDIGEST(go->chap_mdtype, cichar))
try_.chap_mdtype = CHAP_MDTYPE_D(cichar);
} else
#endif /* EAP_SUPPORT */
if (go->neg_chap) {
/*
* We were asking for our preferred algorithm, they must
* want something different.
*/
if (cichar != CHAP_DIGEST(go->chap_mdtype)) {
if (CHAP_CANDIGEST(go->chap_mdtype, cichar)) {
/* Use their suggestion if we support it ... */
try_.chap_mdtype = CHAP_MDTYPE_D(cichar);
} else {
/* ... otherwise, try our next-preferred algorithm. */
try_.chap_mdtype &= ~(CHAP_MDTYPE(try_.chap_mdtype));
if (try_.chap_mdtype == MDTYPE_NONE) /* out of algos */
try_.neg_chap = 0;
}
} else {
/*
* Whoops, they Nak'd our algorithm of choice
* but then suggested it back to us.
*/
goto bad;
}
} else {
/*
* Stop asking for PAP if we were asking for it.
*/
#if PAP_SUPPORT
try_.neg_upap = 0;
#endif /* PAP_SUPPORT */
}
} else
#endif /* CHAP_SUPPORT */
{
#if EAP_SUPPORT
/*
* If we were asking for EAP, and they're Conf-Naking EAP,
* well, that's just strange. Nobody should do that.
*/
if (cishort == PPP_EAP && cilen == CILEN_SHORT && go->neg_eap)
ppp_dbglog("Unexpected Conf-Nak for EAP");
/*
* We don't recognize what they're suggesting.
* Stop asking for what we were asking for.
*/
if (go->neg_eap)
try_.neg_eap = 0;
else
#endif /* EAP_SUPPORT */
#if CHAP_SUPPORT
if (go->neg_chap)
try_.neg_chap = 0;
else
#endif /* CHAP_SUPPORT */
#if PAP_SUPPORT
if(1)
try_.neg_upap = 0;
else
#endif /* PAP_SUPPORT */
{}
p += cilen - CILEN_SHORT;
}
}
#if LQR_SUPPORT
/*
* If they can't cope with our link quality protocol, we'll have
* to stop asking for LQR. We haven't got any other protocol.
* If they Nak the reporting period, take their value XXX ?
*/
NAKCILQR(CI_QUALITY, neg_lqr,
if (cishort != PPP_LQR)
try_.neg_lqr = 0;
else
try_.lqr_period = cilong;
);
#endif /* LQR_SUPPORT */
/*
* Only implementing CBCP...not the rest of the callback options
*/
NAKCICHAR(CI_CALLBACK, neg_cbcp,
try_.neg_cbcp = 0;
(void)cichar; /* if CHAP support is not compiled, cichar is set but not used, which makes some compilers complaining */
);
/*
* Check for a looped-back line.
*/
NAKCILONG(CI_MAGICNUMBER, neg_magicnumber,
try_.magicnumber = magic();
looped_back = 1;
);
/*
* Peer shouldn't send Nak for protocol compression or
* address/control compression requests; they should send
* a Reject instead. If they send a Nak, treat it as a Reject.
*/
NAKCIVOID(CI_PCOMPRESSION, neg_pcompression);
NAKCIVOID(CI_ACCOMPRESSION, neg_accompression);
#ifdef HAVE_MULTILINK
/*
* Nak for MRRU option - accept their value if it is smaller
* than the one we want.
*/
if (go->neg_mrru) {
NAKCISHORT(CI_MRRU, neg_mrru,
if (treat_as_reject)
try_.neg_mrru = 0;
else if (cishort <= wo->mrru)
try_.mrru = cishort;
);
}
#else /* HAVE_MULTILINK */
LWIP_UNUSED_ARG(treat_as_reject);
#endif /* HAVE_MULTILINK */
/*
* Nak for short sequence numbers shouldn't be sent, treat it
* like a reject.
*/
NAKCIVOID(CI_SSNHF, neg_ssnhf);
/*
* Nak of the endpoint discriminator option is not permitted,
* treat it like a reject.
*/
NAKCIENDP(CI_EPDISC, neg_endpoint);
/*
* There may be remaining CIs, if the peer is requesting negotiation
* on an option that we didn't include in our request packet.
* If we see an option that we requested, or one we've already seen
* in this packet, then this packet is bad.
* If we wanted to respond by starting to negotiate on the requested
* option(s), we could, but we don't, because except for the
* authentication type and quality protocol, if we are not negotiating
* an option, it is because we were told not to.
* For the authentication type, the Nak from the peer means
* `let me authenticate myself with you' which is a bit pointless.
* For the quality protocol, the Nak means `ask me to send you quality
* reports', but if we didn't ask for them, we don't want them.
* An option we don't recognize represents the peer asking to
* negotiate some option we don't support, so ignore it.
*/
while (len >= CILEN_VOID) {
GETCHAR(citype, p);
GETCHAR(cilen, p);
if (cilen < CILEN_VOID || (len -= cilen) < 0)
goto bad;
next = p + cilen - 2;
switch (citype) {
case CI_MRU:
if ((go->neg_mru && go->mru != PPP_DEFMRU)
|| no.neg_mru || cilen != CILEN_SHORT)
goto bad;
GETSHORT(cishort, p);
if (cishort < PPP_DEFMRU) {
try_.neg_mru = 1;
try_.mru = cishort;
}
break;
case CI_ASYNCMAP:
if ((go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF)
|| no.neg_asyncmap || cilen != CILEN_LONG)
goto bad;
break;
case CI_AUTHTYPE:
if (0
#if CHAP_SUPPORT
|| go->neg_chap || no.neg_chap
#endif /* CHAP_SUPPORT */
#if PAP_SUPPORT
|| go->neg_upap || no.neg_upap
#endif /* PAP_SUPPORT */
#if EAP_SUPPORT
|| go->neg_eap || no.neg_eap
#endif /* EAP_SUPPORT */
)
goto bad;
break;
case CI_MAGICNUMBER:
if (go->neg_magicnumber || no.neg_magicnumber ||
cilen != CILEN_LONG)
goto bad;
break;
case CI_PCOMPRESSION:
if (go->neg_pcompression || no.neg_pcompression
|| cilen != CILEN_VOID)
goto bad;
break;
case CI_ACCOMPRESSION:
if (go->neg_accompression || no.neg_accompression
|| cilen != CILEN_VOID)
goto bad;
break;
#if LQR_SUPPORT
case CI_QUALITY:
if (go->neg_lqr || no.neg_lqr || cilen != CILEN_LQR)
goto bad;
break;
#endif /* LQR_SUPPORT */
#ifdef HAVE_MULTILINK
case CI_MRRU:
if (go->neg_mrru || no.neg_mrru || cilen != CILEN_SHORT)
goto bad;
break;
#endif /* HAVE_MULTILINK */
case CI_SSNHF:
if (go->neg_ssnhf || no.neg_ssnhf || cilen != CILEN_VOID)
goto bad;
try_.neg_ssnhf = 1;
break;
case CI_EPDISC:
if (go->neg_endpoint || no.neg_endpoint || cilen < CILEN_CHAR)
goto bad;
break;
default:
break;
}
p = next;
}
/*
* OK, the Nak is good. Now we can update state.
* If there are any options left we ignore them.
*/
if (f->state != PPP_FSM_OPENED) {
if (looped_back) {
if (++try_.numloops >= pcb->settings.lcp_loopbackfail) {
ppp_notice("Serial line is looped back.");
pcb->err_code = PPPERR_LOOPBACK;
lcp_close(f->pcb, "Loopback detected");
}
} else
try_.numloops = 0;
*go = try_;
}
return 1;
bad:
LCPDEBUG(("lcp_nakci: received bad Nak!"));
return 0;
}