static void lcp_open(fsm *f) { lcp *_this; int peer_auth = 0; LCP_ASSERT(f != NULL); _this = &f->ppp->lcp; if (psm_opt_is_accepted(_this, pap)) peer_auth = PPP_AUTH_PAP; else if (psm_opt_is_accepted(_this, chap)) peer_auth = PPP_AUTH_CHAP_MD5; else if (psm_opt_is_accepted(_this, chapms)) peer_auth = PPP_AUTH_CHAP_MS; else if (psm_opt_is_accepted(_this, chapms_v2)) peer_auth = PPP_AUTH_CHAP_MS_V2; else if (psm_opt_is_accepted(_this, eap)) peer_auth = PPP_AUTH_EAP; else { if (_this->auth_order[0] > 0) { fsm_log(f, LOG_INFO, "failed to negotiate a auth protocol."); fsm_close(f, "Authentication is required"); ppp_set_disconnect_cause(f->ppp, PPP_DISCON_AUTH_PROTOCOL_UNACCEPTABLE, _this->auth_order[0] /* first one */, 1 /* peer refused */, NULL); ppp_stop(f->ppp, "Authentication is required"); return; } } f->ppp->peer_auth = peer_auth; if (_this->xxxmru > 0 && f->ppp->peer_mru <= 0) f->ppp->peer_mru = _this->xxxmru; if (f->ppp->peer_mru <= 0) f->ppp->peer_mru = f->ppp->mru; /* checking the size of ppp->peer_mru. */ LCP_ASSERT(f->ppp->peer_mru > 500); fsm_log(f, LOG_INFO, "logtype=Opened mru=%d/%d auth=%s magic=%08x/%08x" , f->ppp->mru, f->ppp->peer_mru , lcp_auth_string(peer_auth) , f->ppp->lcp.magic_number, f->ppp->lcp.peer_magic_number ); lcp_reset_timeout(_this); ppp_lcp_up(f->ppp); }
/** * Receive the PPP packet. * @param flags Indicate information of received packet by bit flags. * {@link ::PPP_IO_FLAGS_MPPE_ENCRYPTED} and * {@link ::PPP_IO_FLAGS_DELAYED} may be used. * @return return 0 on success. return 1 on failure. */ static int ppp_recv_packet(npppd_ppp *_this, unsigned char *pkt, int lpkt, int flags) { u_char *inp, *inp_proto; uint16_t proto; PPP_ASSERT(_this != NULL); inp = pkt; if (lpkt < 4) { ppp_log(_this, LOG_DEBUG, "%s(): Rcvd short header.", __func__); return 0; } if (_this->has_acf == 0) { /* nothing to do */ } else if (inp[0] == PPP_ALLSTATIONS && inp[1] == PPP_UI) { inp += 2; } else { /* * Address and Control Field Compression */ if (!psm_opt_is_accepted(&_this->lcp, acfc) && _this->logged_no_address == 0) { /* * On packet loss condition, we may receive ACFC'ed * packets before our LCP is opened because the peer's * LCP is opened already. */ ppp_log(_this, LOG_INFO, "%s: Rcvd broken frame. ACFC is not accepted, " "but received ppp frame that has no address.", __func__); /* * Log this once because it may be noisy. * For example, Yahama RTX-1000 refuses to use ACFC * but it send PPP frames without the address field. */ _this->logged_no_address = 1; } } inp_proto = inp; if ((inp[0] & 0x01) != 0) { /* * Protocol Field Compression */ if (!psm_opt_is_accepted(&_this->lcp, pfc)) { ppp_log(_this, LOG_INFO, "%s: Rcvd broken frame. No protocol field: " "%02x %02x", __func__, inp[0], inp[1]); return 1; } GETCHAR(proto, inp); } else { GETSHORT(proto, inp); } /* * if the PPP frame is reordered, drop it * unless proto is reorder-tolerant */ if (flags & PPP_IO_FLAGS_DELAYED && proto != PPP_PROTO_IP) return 1; if (_this->log_dump_in != 0 && debug_get_debugfp() != NULL) { char buf[256]; snprintf(buf, sizeof(buf), "log.%s.in.pktdump", proto_name(proto)); if (ppp_config_str_equal(_this, buf, "true", 0) != 0) { ppp_log(_this, LOG_DEBUG, "PPP input dump proto=%s(%d/%04x)", proto_name(proto), proto, proto); show_hd(debug_get_debugfp(), pkt, lpkt); } } #ifdef USE_NPPPD_PIPEX if (_this->pipex_enabled != 0 && _this->tunnel_type == PPP_TUNNEL_PPPOE) { switch (proto) { case PPP_PROTO_IP: return 2; /* handled by PIPEX */ case PPP_PROTO_NCP | NCP_CCP: if (lpkt - (inp - pkt) < 4) break; /* error but do it on fsm.c */ if (*inp == 0x0e || /* Reset-Request */ *inp == 0x0f /* Reset-Ack */) { return 2; /* handled by PIPEX */ } /* FALLTHROUGH */ default: break; } } #endif /* USE_NPPPD_PIPEX */ switch (proto) { #ifdef USE_NPPPD_MPPE case PPP_PROTO_IP: /* Checks for MPPE */ if ((flags & PPP_IO_FLAGS_MPPE_ENCRYPTED) == 0) { if (MPPE_REQUIRED(_this)) { /* MPPE is required but naked ip */ if (_this->logged_naked_ip == 0) { ppp_log(_this, LOG_INFO, "mppe is required but received " "naked IP."); /* log this once */ _this->logged_naked_ip = 1; } /* * Windows sends naked IP packets in condition * such that MPPE is not opened and IPCP is not * opened(*1). This occurs at a high * probability when the CCP establishment is * delayed because of packet loss etc. If we * call ppp_stop() here, Windows on the packet * loss condition etc cannot not connect us. * So we don't call ppp_stop() here. * (*1) At least Microsof Windows 2000 * Professional SP4 does. */ /*ppp_stop(_this, "Encryption is required.");*/ return 1; } if (MPPE_READY(_this)) { /* MPPE is opened but naked ip packet */ ppp_log(_this, LOG_WARNING, "mppe is available but received naked IP."); } } /* else input from MPPE */ break; case PPP_PROTO_MPPE: #ifdef USE_NPPPD_MPPE if (_this->mppe_started == 0) { #else { #endif ppp_log(_this, LOG_ERR, "mppe packet is received but mppe is stopped."); return 1; } break; #endif } switch (proto) { case PPP_PROTO_IP: npppd_network_output(_this->pppd, _this, AF_INET, inp, lpkt - (inp - pkt)); goto handled; case PPP_PROTO_LCP: fsm_input(&_this->lcp.fsm, inp, lpkt - (inp - pkt)); goto handled; case PPP_PROTO_PAP: pap_input(&_this->pap, inp, lpkt - (inp - pkt)); goto handled; case PPP_PROTO_CHAP: chap_input(&_this->chap, inp, lpkt - (inp - pkt)); goto handled; #ifdef USE_NPPPD_EAP_RADIUS case PPP_PROTO_EAP: eap_input(&_this->eap, inp, lpkt - (inp - pkt)); goto handled; #endif #ifdef USE_NPPPD_MPPE case PPP_PROTO_MPPE: #ifdef USE_NPPPD_PIPEX if (_this->pipex_enabled != 0) return -1; /* silent discard */ #endif /* USE_NPPPD_PIPEX */ mppe_input(&_this->mppe, inp, lpkt - (inp - pkt)); goto handled; #endif default: if ((proto & 0xff00) == PPP_PROTO_NCP) { switch (proto & 0xff) { case NCP_CCP: /* Compression */ #ifdef USE_NPPPD_MPPE if (MPPE_MUST_NEGO(_this)) { fsm_input(&_this->ccp.fsm, inp, lpkt - (inp - pkt)); goto handled; } /* protocol-reject if MPPE is not necessary */ #endif break; case NCP_IPCP: /* IPCP */ fsm_input(&_this->ipcp.fsm, inp, lpkt - (inp - pkt)); goto handled; } } } /* Protocol reject. Log it with protocol number */ ppp_log(_this, LOG_INFO, "unhandled protocol %s, %d(%04x)", proto_name(proto), proto, proto); if ((flags & PPP_IO_FLAGS_MPPE_ENCRYPTED) != 0) { /* * Don't return a protocol-reject for the packet was encrypted, * because lcp protocol-reject is not encrypted by mppe. */ } else { /* * as RFC1661: Rejected-Information MUST be truncated to * comply with the peer's established MRU. */ lcp_send_protrej(&_this->lcp, inp_proto, MIN(lpkt - (inp_proto - pkt), NPPPD_MIN_MRU - 32)); } return 1; handled: return 0; } /** This function is called to output PPP packets */ inline void ppp_output(npppd_ppp *_this, uint16_t proto, u_char code, u_char id, u_char *datap, int ldata) { u_char *outp; int outlen, hlen, is_lcp = 0; outp = _this->outpacket_buf; /* No header compressions for LCP */ is_lcp = (proto == PPP_PROTO_LCP)? 1 : 0; if (_this->has_acf == 0 || (!is_lcp && psm_peer_opt_is_accepted(&_this->lcp, acfc))) { /* * Don't add ACF(Address and Control Field) if ACF is not * needed on this link or ACFC is negotiated. */ } else { PUTCHAR(PPP_ALLSTATIONS, outp); PUTCHAR(PPP_UI, outp); } if (!is_lcp && proto <= 0xff && psm_peer_opt_is_accepted(&_this->lcp, pfc)) { /* * Protocol Field Compression */ PUTCHAR(proto, outp); } else { PUTSHORT(proto, outp); } hlen = outp - _this->outpacket_buf; if (_this->mru > 0) { if (MRU_PKTLEN(_this->mru, proto) < ldata) { PPP_DBG((_this, LOG_ERR, "packet too large %d. mru=%d", ldata , _this->mru)); _this->oerrors++; PPP_ASSERT("NOT REACHED HERE" == NULL); return; } } if (code != 0) { outlen = ldata + HEADERLEN; PUTCHAR(code, outp); PUTCHAR(id, outp); PUTSHORT(outlen, outp); } else { outlen = ldata; } if (outp != datap && ldata > 0) memmove(outp, datap, ldata); if (_this->log_dump_out != 0 && debug_get_debugfp() != NULL) { char buf[256]; snprintf(buf, sizeof(buf), "log.%s.out.pktdump", proto_name(proto)); if (ppp_config_str_equal(_this, buf, "true", 0) != 0) { ppp_log(_this, LOG_DEBUG, "PPP output dump proto=%s(%d/%04x)", proto_name(proto), proto, proto); show_hd(debug_get_debugfp(), _this->outpacket_buf, outlen + hlen); } } _this->send_packet(_this, _this->outpacket_buf, outlen + hlen, 0); }