📄 if_ppp.c
字号:
*/voidpppintr(){ struct ppp_softc *sc; int i, s, s2; struct mbuf *m; sc = ppp_softc; s = splnet(); for (i = 0; i < NPPP; ++i, ++sc) { if (!(sc->sc_flags & SC_TBUSY) && (sc->sc_if.if_snd.ifq_head || sc->sc_fastq.ifq_head)) { s2 = splimp(); sc->sc_flags |= SC_TBUSY; splx(s2); (*sc->sc_start)(sc); } for (;;) { s2 = splimp(); IF_DEQUEUE(&sc->sc_rawq, m); splx(s2); if (m == NULL) break; ppp_inproc(sc, m); } } splx(s);}#ifdef PPP_COMPRESS/* * Handle a CCP packet. `rcvd' is 1 if the packet was received, * 0 if it is about to be transmitted. */static voidppp_ccp(sc, m, rcvd) struct ppp_softc *sc; struct mbuf *m; int rcvd;{ u_char *dp, *ep; struct mbuf *mp; int slen, s; /* * Get a pointer to the data after the PPP header. */ if (m->m_len <= PPP_HDRLEN) { mp = m->m_next; if (mp == NULL) return; dp = (mp != NULL)? mtod(mp, u_char *): NULL; } else { mp = m; dp = mtod(mp, u_char *) + PPP_HDRLEN; } ep = mtod(mp, u_char *) + mp->m_len; if (dp + CCP_HDRLEN > ep) return; slen = CCP_LENGTH(dp); if (dp + slen > ep) { if (sc->sc_flags & SC_DEBUG) printf("if_ppp/ccp: not enough data in mbuf (%x+%x > %x+%x)\n", dp, slen, mtod(mp, u_char *), mp->m_len); return; } switch (CCP_CODE(dp)) { case CCP_CONFREQ: case CCP_TERMREQ: case CCP_TERMACK: /* CCP must be going down - disable compression */ if (sc->sc_flags & SC_CCP_UP) { s = splimp(); sc->sc_flags &= ~(SC_CCP_UP | SC_COMP_RUN | SC_DECOMP_RUN); splx(s); } break; case CCP_CONFACK: if (sc->sc_flags & SC_CCP_OPEN && !(sc->sc_flags & SC_CCP_UP) && slen >= CCP_HDRLEN + CCP_OPT_MINLEN && slen >= CCP_OPT_LENGTH(dp + CCP_HDRLEN) + CCP_HDRLEN) { if (!rcvd) { /* we're agreeing to send compressed packets. */ if (sc->sc_xc_state != NULL && (*sc->sc_xcomp->comp_init) (sc->sc_xc_state, dp + CCP_HDRLEN, slen - CCP_HDRLEN, sc->sc_if.if_unit, 0, sc->sc_flags & SC_DEBUG)) { s = splimp(); sc->sc_flags |= SC_COMP_RUN; splx(s); } } else { /* peer is agreeing to send compressed packets. */ if (sc->sc_rc_state != NULL && (*sc->sc_rcomp->decomp_init) (sc->sc_rc_state, dp + CCP_HDRLEN, slen - CCP_HDRLEN, sc->sc_if.if_unit, 0, sc->sc_mru, sc->sc_flags & SC_DEBUG)) { s = splimp(); sc->sc_flags |= SC_DECOMP_RUN; sc->sc_flags &= ~(SC_DC_ERROR | SC_DC_FERROR); splx(s); } } } break; case CCP_RESETACK: if (sc->sc_flags & SC_CCP_UP) { if (!rcvd) { if (sc->sc_xc_state && (sc->sc_flags & SC_COMP_RUN)) (*sc->sc_xcomp->comp_reset)(sc->sc_xc_state); } else { if (sc->sc_rc_state && (sc->sc_flags & SC_DECOMP_RUN)) { (*sc->sc_rcomp->decomp_reset)(sc->sc_rc_state); s = splimp(); sc->sc_flags &= ~SC_DC_ERROR; splx(s); } } } break; }}/* * CCP is down; free (de)compressor state if necessary. */static voidppp_ccp_closed(sc) struct ppp_softc *sc;{ if (sc->sc_xc_state) { (*sc->sc_xcomp->comp_free)(sc->sc_xc_state); sc->sc_xc_state = NULL; } if (sc->sc_rc_state) { (*sc->sc_rcomp->decomp_free)(sc->sc_rc_state); sc->sc_rc_state = NULL; }}#endif /* PPP_COMPRESS *//* * PPP packet input routine. * The caller has checked and removed the FCS and has inserted * the address/control bytes and the protocol high byte if they * were omitted. */voidppppktin(sc, m, lost) struct ppp_softc *sc; struct mbuf *m; int lost;{ int s = splimp(); m->m_context = lost; IF_ENQUEUE(&sc->sc_rawq, m); schednetisr(NETISR_PPP); splx(s);}/* * Process a received PPP packet, doing decompression as necessary. * Should be called at splnet. */#define COMPTYPE(proto) ((proto) == PPP_VJC_COMP? TYPE_COMPRESSED_TCP: \ TYPE_UNCOMPRESSED_TCP)static voidppp_inproc(sc, m) struct ppp_softc *sc; struct mbuf *m;{ struct ifnet *ifp = &sc->sc_if; struct ifqueue *inq, *lock; int s, ilen, xlen, proto, rv; u_char *cp, adrs, ctrl; struct mbuf *mp, *dmp = NULL, *pc; u_char *iphdr; u_int hlen; sc->sc_stats.ppp_ipackets++; if (sc->sc_flags & SC_LOG_INPKT) { ilen = 0; for (mp = m; mp != NULL; mp = mp->m_next) ilen += mp->m_len; printf("ppp%d: got %d bytes\n", ifp->if_unit, ilen); pppdumpm(m); } cp = mtod(m, u_char *); adrs = PPP_ADDRESS(cp); ctrl = PPP_CONTROL(cp); proto = PPP_PROTOCOL(cp); if (m->m_context) { s = splimp(); sc->sc_flags |= SC_VJ_RESET; splx(s); }#ifdef PPP_COMPRESS /* * Decompress this packet if necessary, update the receiver's * dictionary, or take appropriate action on a CCP packet. */ if (proto == PPP_COMP && sc->sc_rc_state && (sc->sc_flags & SC_DECOMP_RUN) && !(sc->sc_flags & SC_DC_ERROR) && !(sc->sc_flags & SC_DC_FERROR)) { /* decompress this packet */ rv = (*sc->sc_rcomp->decompress)(sc->sc_rc_state, m, &dmp); if (rv == DECOMP_OK) { m_freem(m); if (dmp == NULL) { /* no error, but no decompressed packet produced */ return; } m = dmp; cp = mtod(m, u_char *); proto = PPP_PROTOCOL(cp); } else { /* * An error has occurred in decompression. * Pass the compressed packet up to pppd, which may take * CCP down or issue a Reset-Req. */ if (sc->sc_flags & SC_DEBUG) printf("ppp%d: decompress failed %d\n", ifp->if_unit, rv); s = splimp(); sc->sc_flags |= SC_VJ_RESET; if (rv == DECOMP_ERROR) sc->sc_flags |= SC_DC_ERROR; else sc->sc_flags |= SC_DC_FERROR; splx(s); } } else { if (sc->sc_rc_state && (sc->sc_flags & SC_DECOMP_RUN)) { (*sc->sc_rcomp->incomp)(sc->sc_rc_state, m); } if (proto == PPP_CCP) { ppp_ccp(sc, m, 1); } }#endif ilen = 0; for (mp = m; mp != NULL; mp = mp->m_next) ilen += mp->m_len;#ifdef VJC if (sc->sc_flags & SC_VJ_RESET) { /* * If we've missed a packet, we must toss subsequent compressed * packets which don't have an explicit connection ID. */ if (sc->sc_comp) sl_uncompress_tcp(NULL, 0, TYPE_ERROR, sc->sc_comp); s = splimp(); sc->sc_flags &= ~SC_VJ_RESET; splx(s); } /* * See if we have a VJ-compressed packet to uncompress. */ if (proto == PPP_VJC_COMP) { if ((sc->sc_flags & SC_REJ_COMP_TCP) || sc->sc_comp == 0) goto bad; xlen = sl_uncompress_tcp_core(cp + PPP_HDRLEN, m->m_len - PPP_HDRLEN, ilen - PPP_HDRLEN, TYPE_COMPRESSED_TCP, sc->sc_comp, &iphdr, &hlen); if (xlen <= 0) { if (sc->sc_flags & SC_DEBUG) printf("ppp%d: VJ uncompress failed on type comp\n", ifp->if_unit); goto bad; } /* Copy the PPP and IP headers into a new mbuf. */ MGET(mp, M_DONTWAIT, MT_DATA); if (mp == NULL) goto bad; mp->m_len = 0; mp->m_next = NULL; if (hlen + PPP_HDRLEN > MLEN) { MCLGET(mp, pc); if (M_TRAILINGSPACE(mp) < hlen + PPP_HDRLEN) { m_freem(mp); goto bad; /* lose if big headers and no clusters */ } } cp = mtod(mp, u_char *); cp[0] = adrs; cp[1] = ctrl; cp[2] = 0; cp[3] = PPP_IP; proto = PPP_IP; bcopy(iphdr, cp + PPP_HDRLEN, hlen); mp->m_len = hlen + PPP_HDRLEN; /* * Trim the PPP and VJ headers off the old mbuf * and stick the new and old mbufs together. */ m->m_off += PPP_HDRLEN + xlen; m->m_len -= PPP_HDRLEN + xlen; if (m->m_len <= M_TRAILINGSPACE(mp)) { bcopy(mtod(m, u_char *), mtod(mp, u_char *) + mp->m_len, m->m_len); mp->m_len += m->m_len; MFREE(m, mp->m_next); } else mp->m_next = m; m = mp; ilen += hlen - xlen; } else if (proto == PPP_VJC_UNCOMP) { if ((sc->sc_flags & SC_REJ_COMP_TCP) || sc->sc_comp == 0) goto bad; xlen = sl_uncompress_tcp_core(cp + PPP_HDRLEN, m->m_len - PPP_HDRLEN, ilen - PPP_HDRLEN, TYPE_UNCOMPRESSED_TCP, sc->sc_comp, &iphdr, &hlen); if (xlen < 0) { if (sc->sc_flags & SC_DEBUG) printf("ppp%d: VJ uncompress failed on type uncomp\n", ifp->if_unit); goto bad; } proto = PPP_IP; cp[3] = PPP_IP; }#endif /* VJC */ /* * If the packet will fit in an ordinary mbuf, don't waste a * whole cluster on it. */ if (ilen <= MLEN && M_IS_CLUSTER(m)) { MGET(mp, M_DONTWAIT, MT_DATA); if (mp != NULL) { m_copydata(m, mtod(mp, caddr_t), ilen); m_freem(m); m = mp; m->m_len = ilen; } } /* * Record the time that we received this packet. */ if ((proto & 0x8000) == 0) { sc->sc_last_recv = time.tv_sec; }#if NBPFILTER > 0 /* See if bpf wants to look at the packet. */ if (sc->sc_bpf) bpf_mtap(sc->sc_bpf, m);#endif rv = 0; switch (proto) {#ifdef INET case PPP_IP: /* * IP packet - take off the ppp header and pass it up to IP. */ if ((ifp->if_flags & IFF_UP) == 0 || sc->sc_npmode[NP_IP] != NPMODE_PASS) { /* interface is down - drop the packet. */ m_freem(m); return; } m->m_off += PPP_HDRLEN; m->m_len -= PPP_HDRLEN; schednetisr(NETISR_IP); inq = &ipintrq; break;#endif default: /* * Some other protocol - place on input queue for read(). */ inq = &sc->sc_inq; rv = 1; break; } /* * Put the packet on the appropriate input queue. */ s = splimp(); lock = inq; smp_lock(&lock->lk_ifqueue, LK_RETRY); if (IF_QFULL(inq)) { IF_DROP(inq); smp_unlock(&lock->lk_ifqueue); splx(s); if (sc->sc_flags & SC_DEBUG) printf("ppp%d: input queue full\n", ifp->if_unit); goto bad; } IF_ENQUEUEIF(inq, m, &sc->sc_if); smp_unlock(&lock->lk_ifqueue); splx(s); ifp->if_ipackets++; if (rv) (*sc->sc_ctlp)(sc); return; bad: m_freem(m); sc->sc_if.if_ierrors++; sc->sc_stats.ppp_ierrors++;}#define MAX_DUMP_BYTES 128static voidpppdumpm(m0) struct mbuf *m0;{ char buf[3*MAX_DUMP_BYTES+4]; char *bp = buf; struct mbuf *m; static char digits[] = "0123456789abcdef"; for (m = m0; m; m = m->m_next) { int l = m->m_len; u_char *rptr = mtod(m, u_char *); while (l--) { if (bp > buf + sizeof(buf) - 4) goto done; *bp++ = digits[*rptr >> 4]; /* convert byte to ascii hex */ *bp++ = digits[*rptr++ & 0xf]; } if (m->m_next) { if (bp > buf + sizeof(buf) - 3) goto done; *bp++ = '|'; } else *bp++ = ' '; }done: if (m) *bp++ = '>'; *bp = 0; printf("%s\n", buf);}#endif /* NPPP > 0 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -