📄 if_ppp.c
字号:
/* * Grab a packet to send: first try the fast queue, then the * normal queue. */ rtems_bsdnet_semaphore_obtain(); IF_DEQUEUE(&sc->sc_fastq, m); if (m == NULL) IF_DEQUEUE(&sc->sc_if.if_snd, m); rtems_bsdnet_semaphore_release(); if (m == NULL) return NULL; ++sc->sc_stats.ppp_opackets; /* * Extract the ppp header of the new packet. * The ppp header will be in one mbuf. */ cp = mtod(m, u_char *); address = PPP_ADDRESS(cp); control = PPP_CONTROL(cp); protocol = PPP_PROTOCOL(cp); switch (protocol) { case PPP_IP:#ifdef VJC /* * If the packet is a TCP/IP packet, see if we can compress it. */ if ((sc->sc_flags & SC_COMP_TCP) && sc->sc_comp != NULL) { struct ip *ip; int type; mp = m; ip = (struct ip *) (cp + PPP_HDRLEN); if (mp->m_len <= PPP_HDRLEN) { mp = mp->m_next; if (mp == NULL) break; ip = mtod(mp, struct ip *); } /* this code assumes the IP/TCP header is in one non-shared mbuf */ if (ip->ip_p == IPPROTO_TCP) { type = vj_compress_tcp(mp, ip, sc->sc_comp, !(sc->sc_flags & SC_NO_TCP_CCID)); switch (type) { case TYPE_UNCOMPRESSED_TCP: protocol = PPP_VJC_UNCOMP; break; case TYPE_COMPRESSED_TCP: protocol = PPP_VJC_COMP; cp = mtod(m, u_char *); cp[0] = address; /* header has moved */ cp[1] = control; cp[2] = 0; break; } cp[3] = protocol; /* update protocol in PPP header */ } }#endif /* VJC */ break;#ifdef PPP_COMPRESS case PPP_CCP: ppp_ccp(sc, m, 0); break;#endif /* PPP_COMPRESS */ }#ifdef PPP_COMPRESS if (protocol != PPP_LCP && protocol != PPP_CCP && sc->sc_xc_state && (sc->sc_flags & SC_COMP_RUN)) { struct mbuf *mcomp = NULL; int slen, clen; slen = 0; for (mp = m; mp != NULL; mp = mp->m_next) slen += mp->m_len; clen = (*sc->sc_xcomp->compress) (sc->sc_xc_state, &mcomp, m, slen, sc->sc_if.if_mtu + PPP_HDRLEN); if (mcomp != NULL) { if (sc->sc_flags & SC_CCP_UP) { /* Send the compressed packet instead of the original. */ m_freem(m); m = mcomp; cp = mtod(m, u_char *); protocol = cp[3]; } else { /* Can't transmit compressed packets until CCP is up. */ m_freem(mcomp); } } }#endif /* PPP_COMPRESS */ /* * Compress the address/control and protocol, if possible. */ if (sc->sc_flags & SC_COMP_AC && address == PPP_ALLSTATIONS && control == PPP_UI && protocol != PPP_ALLSTATIONS && protocol != PPP_LCP) { /* can compress address/control */ m->m_data += 2; m->m_len -= 2; } if (sc->sc_flags & SC_COMP_PROT && protocol < 0xFF) { /* can compress protocol */ if (mtod(m, u_char *) == cp) { cp[2] = cp[1]; /* move address/control up */ cp[1] = cp[0]; } ++m->m_data; --m->m_len; } return m;}/* * Software interrupt routine, called at splsoftnet. */voidpppintr(void){}#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 (%p+%x > %p+%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 *//* * Process a received PPP packet, doing decompression as necessary. * Should be called at splsoftnet. */#define COMPTYPE(proto) ((proto) == PPP_VJC_COMP? TYPE_COMPRESSED_TCP: \ TYPE_UNCOMPRESSED_TCP)static struct mbuf *ppp_inproc(sc, m) struct ppp_softc *sc; struct mbuf *m;{ struct mbuf *mf = (struct mbuf *)0; struct ifnet *ifp = &sc->sc_if; struct ifqueue *inq; int s, ilen, proto, rv; u_char *cp, adrs, ctrl; struct mbuf *mp;#ifdef PPP_COMPRESS struct mbuf *dmp = NULL;#endif#ifdef VJC u_char *iphdr; u_int hlen; int xlen;#endif 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_flags & M_ERRMARK) { m->m_flags &= ~M_ERRMARK; 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 mf; } 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) vj_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 = vj_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. */ MGETHDR(mp, M_DONTWAIT, MT_DATA); if (mp == NULL) goto bad; mp->m_len = 0; mp->m_next = NULL; if (hlen + PPP_HDRLEN > MHLEN) { MCLGET(mp, M_DONTWAIT); 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_data += 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 = vj_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 a header mbuf, don't waste a * whole cluster on it. */ if (ilen <= MHLEN && M_IS_CLUSTER(m)) { MGETHDR(mp, M_DONTWAIT, MT_DATA); if (mp != NULL) { m_copydata(m, 0, ilen, mtod(mp, caddr_t)); /* instead of freeing - return cluster mbuf so it can be reused */ /* m_freem(m); */ mf = m; m = mp; m->m_len = ilen; } } m->m_pkthdr.len = ilen; m->m_pkthdr.rcvif = ifp; if ((proto & 0x8000) == 0) {#ifdef PPP_FILTER /* * See whether we want to pass this packet, and * if it counts as link activity. */ adrs = *mtod(m, u_char *); /* save address field */ *mtod(m, u_char *) = 0; /* indicate inbound */ if (sc->sc_pass_filt.bf_insns != 0 && bpf_filter(sc->sc_pass_filt.bf_insns, (u_char *) m, ilen, 0) == 0) { /* drop this packet */ m_freem(m); return mf; } if (sc->sc_active_filt.bf_insns == 0 || bpf_filter(sc->sc_active_filt.bf_insns, (u_char *) m, ilen, 0)) sc->sc_last_recv = time.tv_sec; *mtod(m, u_char *) = adrs;#else /* * Record the time that we received this packet. */ microtime(&ppp_time); sc->sc_last_recv = ppp_time.tv_sec;#endif /* PPP_FILTER */ }#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 mf; } m->m_pkthdr.len -= PPP_HDRLEN; m->m_data += 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(); if (IF_QFULL(inq)) { IF_DROP(inq); splx(s); if (sc->sc_flags & SC_DEBUG) printf("ppp%d: input queue full\n", ifp->if_unit); ifp->if_iqdrops++; goto bad; } IF_ENQUEUE(inq, m); splx(s); ifp->if_ipackets++; ifp->if_ibytes += ilen; microtime(&ppp_time); ifp->if_lastchange = ppp_time; if (rv) { (*sc->sc_ctlp)(sc); } return mf; bad: m_freem(m); sc->sc_if.if_ierrors++; sc->sc_stats.ppp_ierrors++; return mf;}#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 = (u_char *)m->m_data; 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 + -