in net/ip/lwip_base/src/netif/ppp/ipv6cp.c [671:800]
static int ipv6cp_nakci(fsm *f, u_char *p, int len, int treat_as_reject) {
ppp_pcb *pcb = f->pcb;
ipv6cp_options *go = &pcb->ipv6cp_gotoptions;
u_char citype, cilen, *next;
#ifdef IPV6CP_COMP
u_short cishort;
#endif /* IPV6CP_COMP */
eui64_t ifaceid;
ipv6cp_options no; /* options we've seen Naks for */
ipv6cp_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 NAKCIIFACEID(opt, neg, code) \
if (go->neg && \
len >= (cilen = CILEN_IFACEID) && \
p[1] == cilen && \
p[0] == opt) { \
len -= cilen; \
INCPTR(2, p); \
eui64_get(ifaceid, p); \
no.neg = 1; \
code \
}
#ifdef IPV6CP_COMP
#define NAKCIVJ(opt, neg, code) \
if (go->neg && \
((cilen = p[1]) == CILEN_COMPRESS) && \
len >= cilen && \
p[0] == opt) { \
len -= cilen; \
INCPTR(2, p); \
GETSHORT(cishort, p); \
no.neg = 1; \
code \
}
#endif /* IPV6CP_COMP */
/*
* Accept the peer's idea of {our,his} interface identifier, if different
* from our idea, only if the accept_{local,remote} flag is set.
*/
NAKCIIFACEID(CI_IFACEID, neg_ifaceid,
if (treat_as_reject) {
try_.neg_ifaceid = 0;
} else if (go->accept_local) {
while (eui64_iszero(ifaceid) ||
eui64_equals(ifaceid, go->hisid)) /* bad luck */
eui64_magic(ifaceid);
try_.ourid = ifaceid;
IPV6CPDEBUG(("local LL address %s", llv6_ntoa(ifaceid)));
}
);
#ifdef IPV6CP_COMP
NAKCIVJ(CI_COMPRESSTYPE, neg_vj,
{
if (cishort == IPV6CP_COMP && !treat_as_reject) {
try_.vj_protocol = cishort;
} else {
try_.neg_vj = 0;
}
}
);
#endif /* IPV6CP_COMP */
/*
* 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 interface identifier, we comply.
* If they want us to ask for compression, we refuse.
*/
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) {
#ifdef IPV6CP_COMP
case CI_COMPRESSTYPE:
if (go->neg_vj || no.neg_vj ||
(cilen != CILEN_COMPRESS))
goto bad;
no.neg_vj = 1;
break;
#endif /* IPV6CP_COMP */
case CI_IFACEID:
if (go->neg_ifaceid || no.neg_ifaceid || cilen != CILEN_IFACEID)
goto bad;
try_.neg_ifaceid = 1;
eui64_get(ifaceid, p);
if (go->accept_local) {
while (eui64_iszero(ifaceid) ||
eui64_equals(ifaceid, go->hisid)) /* bad luck */
eui64_magic(ifaceid);
try_.ourid = ifaceid;
}
no.neg_ifaceid = 1;
break;
default:
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 != PPP_FSM_OPENED)
*go = try_;
return 1;
bad:
IPV6CPDEBUG(("ipv6cp_nakci: received bad Nak!"));
return 0;
}