/* * ccp_input - process a received CCP packet. */ static void ccp_input( int unit, u_char *p, int len) { fsm *f = &ccp_fsm[unit]; int oldstate; /* * Check for a terminate-request so we can print a message. */ oldstate = f->state; fsm_input(f, p, len); if (oldstate == OPENED && p[0] == TERMREQ && f->state != OPENED) notice("Compression disabled by peer."); /* * If we get a terminate-ack and we're not asking for compression, * close CCP. */ if (oldstate == REQSENT && p[0] == TERMACK && !ANY_COMPRESS(ccp_gotoptions[unit])) ccp_close(unit, "No compression negotiated"); }
static void ccp_input (T_NET_BUF *nbuf) { NET_COUNT_PPP_CCP(net_count_ppp_ccp_in_octets, nbuf->len); NET_COUNT_PPP_CCP(net_count_ppp_ccp_in_packets, 1); fsm_input(&ccp_fsm, nbuf); }
/* * ccp_input - process a received CCP packet. */ void ccp_input(PPP_IF_VAR_T *pPppIf, u_char *p, int len) { fsm *f = &pPppIf->ccp_fsm; int oldstate; /* * Check for a terminate-request so we can print a message. */ oldstate = f->state; fsm_input(f, p, len); if (oldstate == OPENED && p[0] == TERMREQ && f->state != OPENED){ syslog(SYS_LOG_NOTICE, "Compression disabled by peer."); diag_printf("Compression disabled by peer.\n"); #ifdef MPPE if (pPppIf->ccp_wantoptions.mppe) { diag_printf("MPPE disabled, closing LCP\n"); lcp_close(pPppIf); } #endif /* MPPE */ } /* * If we get a terminate-ack and we're not asking for compression, * close CCP. */ if (oldstate == REQSENT && p[0] == TERMACK && !ANY_COMPRESS(f->pPppIf->ccp_gotoptions)) ccp_close(pPppIf); }
/* * ipcp_input - Input IPCP packet. */ static void ipcp_input( int unit, u_char *p, int len) { fsm_input(&ipcp_fsm[unit], p, len); }
/* * lcp_input - Input LCP packet. */ static void lcp_input( int unit, u_char *p, int len) { fsm *f = &lcp_fsm[unit]; fsm_input(f, p, len); }
/** * 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); }