in net/ip/lwip_base/src/netif/ppp/ccp.c [541:738]
static void ccp_resetci(fsm *f) {
ppp_pcb *pcb = f->pcb;
ccp_options *go = &pcb->ccp_gotoptions;
ccp_options *wo = &pcb->ccp_wantoptions;
#if MPPE_SUPPORT
ccp_options *ao = &pcb->ccp_allowoptions;
#endif /* MPPE_SUPPORT */
#if DEFLATE_SUPPORT || BSDCOMPRESS_SUPPORT || PREDICTOR_SUPPORT
u_char opt_buf[CCP_MAX_OPTION_LENGTH];
#endif /* DEFLATE_SUPPORT || BSDCOMPRESS_SUPPORT || PREDICTOR_SUPPORT */
#if DEFLATE_SUPPORT || BSDCOMPRESS_SUPPORT
int res;
#endif /* DEFLATE_SUPPORT || BSDCOMPRESS_SUPPORT */
#if MPPE_SUPPORT
if (pcb->settings.require_mppe) {
wo->mppe = ao->mppe =
(pcb->settings.refuse_mppe_40 ? 0 : MPPE_OPT_40)
| (pcb->settings.refuse_mppe_128 ? 0 : MPPE_OPT_128);
}
#endif /* MPPE_SUPPORT */
*go = *wo;
pcb->ccp_all_rejected = 0;
#if MPPE_SUPPORT
if (go->mppe) {
int auth_mschap_bits = pcb->auth_done;
int numbits;
/*
* Start with a basic sanity check: mschap[v2] auth must be in
* exactly one direction. RFC 3079 says that the keys are
* 'derived from the credentials of the peer that initiated the call',
* however the PPP protocol doesn't have such a concept, and pppd
* cannot get this info externally. Instead we do the best we can.
* NB: If MPPE is required, all other compression opts are invalid.
* So, we return right away if we can't do it.
*/
/* Leave only the mschap auth bits set */
auth_mschap_bits &= (CHAP_MS_WITHPEER | CHAP_MS_PEER |
CHAP_MS2_WITHPEER | CHAP_MS2_PEER);
/* Count the mschap auths */
auth_mschap_bits >>= CHAP_MS_SHIFT;
numbits = 0;
do {
numbits += auth_mschap_bits & 1;
auth_mschap_bits >>= 1;
} while (auth_mschap_bits);
if (numbits > 1) {
ppp_error("MPPE required, but auth done in both directions.");
lcp_close(pcb, "MPPE required but not available");
return;
}
if (!numbits) {
ppp_error("MPPE required, but MS-CHAP[v2] auth not performed.");
lcp_close(pcb, "MPPE required but not available");
return;
}
/* A plugin (eg radius) may not have obtained key material. */
if (!pcb->mppe_keys_set) {
ppp_error("MPPE required, but keys are not available. "
"Possible plugin problem?");
lcp_close(pcb, "MPPE required but not available");
return;
}
/* LM auth not supported for MPPE */
if (pcb->auth_done & (CHAP_MS_WITHPEER | CHAP_MS_PEER)) {
/* This might be noise */
if (go->mppe & MPPE_OPT_40) {
ppp_notice("Disabling 40-bit MPPE; MS-CHAP LM not supported");
go->mppe &= ~MPPE_OPT_40;
wo->mppe &= ~MPPE_OPT_40;
}
}
/* Last check: can we actually negotiate something? */
if (!(go->mppe & (MPPE_OPT_40 | MPPE_OPT_128))) {
/* Could be misconfig, could be 40-bit disabled above. */
ppp_error("MPPE required, but both 40-bit and 128-bit disabled.");
lcp_close(pcb, "MPPE required but not available");
return;
}
/* sync options */
ao->mppe = go->mppe;
/* MPPE is not compatible with other compression types */
#if BSDCOMPRESS_SUPPORT
ao->bsd_compress = go->bsd_compress = 0;
#endif /* BSDCOMPRESS_SUPPORT */
#if PREDICTOR_SUPPORT
ao->predictor_1 = go->predictor_1 = 0;
ao->predictor_2 = go->predictor_2 = 0;
#endif /* PREDICTOR_SUPPORT */
#if DEFLATE_SUPPORT
ao->deflate = go->deflate = 0;
#endif /* DEFLATE_SUPPORT */
}
#endif /* MPPE_SUPPORT */
/*
* Check whether the kernel knows about the various
* compression methods we might request.
*/
#if BSDCOMPRESS_SUPPORT
/* FIXME: we don't need to test if BSD compress is available
* if BSDCOMPRESS_SUPPORT is set, it is.
*/
if (go->bsd_compress) {
opt_buf[0] = CI_BSD_COMPRESS;
opt_buf[1] = CILEN_BSD_COMPRESS;
for (;;) {
if (go->bsd_bits < BSD_MIN_BITS) {
go->bsd_compress = 0;
break;
}
opt_buf[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits);
res = ccp_test(pcb, opt_buf, CILEN_BSD_COMPRESS, 0);
if (res > 0) {
break;
} else if (res < 0) {
go->bsd_compress = 0;
break;
}
go->bsd_bits--;
}
}
#endif /* BSDCOMPRESS_SUPPORT */
#if DEFLATE_SUPPORT
/* FIXME: we don't need to test if deflate is available
* if DEFLATE_SUPPORT is set, it is.
*/
if (go->deflate) {
if (go->deflate_correct) {
opt_buf[0] = CI_DEFLATE;
opt_buf[1] = CILEN_DEFLATE;
opt_buf[3] = DEFLATE_CHK_SEQUENCE;
for (;;) {
if (go->deflate_size < DEFLATE_MIN_WORKS) {
go->deflate_correct = 0;
break;
}
opt_buf[2] = DEFLATE_MAKE_OPT(go->deflate_size);
res = ccp_test(pcb, opt_buf, CILEN_DEFLATE, 0);
if (res > 0) {
break;
} else if (res < 0) {
go->deflate_correct = 0;
break;
}
go->deflate_size--;
}
}
if (go->deflate_draft) {
opt_buf[0] = CI_DEFLATE_DRAFT;
opt_buf[1] = CILEN_DEFLATE;
opt_buf[3] = DEFLATE_CHK_SEQUENCE;
for (;;) {
if (go->deflate_size < DEFLATE_MIN_WORKS) {
go->deflate_draft = 0;
break;
}
opt_buf[2] = DEFLATE_MAKE_OPT(go->deflate_size);
res = ccp_test(pcb, opt_buf, CILEN_DEFLATE, 0);
if (res > 0) {
break;
} else if (res < 0) {
go->deflate_draft = 0;
break;
}
go->deflate_size--;
}
}
if (!go->deflate_correct && !go->deflate_draft)
go->deflate = 0;
}
#endif /* DEFLATE_SUPPORT */
#if PREDICTOR_SUPPORT
/* FIXME: we don't need to test if predictor is available,
* if PREDICTOR_SUPPORT is set, it is.
*/
if (go->predictor_1) {
opt_buf[0] = CI_PREDICTOR_1;
opt_buf[1] = CILEN_PREDICTOR_1;
if (ccp_test(pcb, opt_buf, CILEN_PREDICTOR_1, 0) <= 0)
go->predictor_1 = 0;
}
if (go->predictor_2) {
opt_buf[0] = CI_PREDICTOR_2;
opt_buf[1] = CILEN_PREDICTOR_2;
if (ccp_test(pcb, opt_buf, CILEN_PREDICTOR_2, 0) <= 0)
go->predictor_2 = 0;
}
#endif /* PREDICTOR_SUPPORT */
}