📄 if_ppp.c
字号:
if (!suser()) return EPERM; if (npi->mode != sc->sc_npmode[npx]) { s = splnet(); sc->sc_npmode[npx] = npi->mode; if (npi->mode != NPMODE_QUEUE) { ppp_requeue(sc); (*sc->sc_start)(sc); } splx(s); } } break; case PPPIOCGIDLE: s = splnet(); t = time.tv_sec; ((struct ppp_idle *)data)->xmit_idle = t - sc->sc_last_sent; ((struct ppp_idle *)data)->recv_idle = t - sc->sc_last_recv; splx(s); break; default: return (-1); } return (0);}/* * Process an ioctl request to the ppp network interface. */intpppsioctl(ifp, cmd, data) register struct ifnet *ifp; int cmd; caddr_t data;{ struct proc *p = u.u_procp; register struct ppp_softc *sc = &ppp_softc[ifp->if_unit]; register struct ifaddr *ifa = (struct ifaddr *)data; register struct ifreq *ifr = (struct ifreq *)data; struct ppp_stats *psp;#ifdef PPP_COMPRESS struct ppp_comp_stats *pcp;#endif int s = splimp(), error = 0; switch (cmd) { case SIOCSIFFLAGS: if ((ifp->if_flags & IFF_RUNNING) == 0) ifp->if_flags &= ~IFF_UP; break; case SIOCSIFADDR: if (ifa->ifa_addr.sa_family != AF_INET) error = EAFNOSUPPORT; break; case SIOCSIFDSTADDR: if (ifa->ifa_addr.sa_family != AF_INET) error = EAFNOSUPPORT; break;/* * Ioctls other than the above don't get through until the * interface has its IP addresses set :-( */#if 0 case SIOCSIFMTU: if (!suser()) return EPERM; sc->sc_if.if_mtu = ifr->ifr_mtu; break; case SIOCGIFMTU: ifr->ifr_mtu = sc->sc_if.if_mtu; break;#endif case SIOCGPPPSTATS: psp = &((struct ifpppstatsreq *) data)->stats; bzero(psp, sizeof(*psp)); psp->p = sc->sc_stats;#if defined(VJC) && !defined(SL_NO_STATS) if (sc->sc_comp) { psp->vj.vjs_packets = sc->sc_comp->sls_packets; psp->vj.vjs_compressed = sc->sc_comp->sls_compressed; psp->vj.vjs_searches = sc->sc_comp->sls_searches; psp->vj.vjs_misses = sc->sc_comp->sls_misses; psp->vj.vjs_uncompressedin = sc->sc_comp->sls_uncompressedin; psp->vj.vjs_compressedin = sc->sc_comp->sls_compressedin; psp->vj.vjs_errorin = sc->sc_comp->sls_errorin; psp->vj.vjs_tossed = sc->sc_comp->sls_tossed; }#endif /* VJC */ break;#ifdef PPP_COMPRESS case SIOCGPPPCSTATS: pcp = &((struct ifpppcstatsreq *) data)->stats; bzero(pcp, sizeof(*pcp)); if (sc->sc_xc_state != NULL) (*sc->sc_xcomp->comp_stat)(sc->sc_xc_state, &pcp->c); if (sc->sc_rc_state != NULL) (*sc->sc_rcomp->decomp_stat)(sc->sc_rc_state, &pcp->d); break;#endif /* PPP_COMPRESS */ default: error = EINVAL; } splx(s); return (error);}/* * Queue a packet. Start transmission if not active. * Packet is placed in Information field of PPP frame. */intpppoutput(ifp, m0, dst) struct ifnet *ifp; struct mbuf *m0; struct sockaddr *dst;{ register struct ppp_softc *sc = &ppp_softc[ifp->if_unit]; int protocol, address, control; u_char *cp; int s, error; struct ip *ip; struct ifqueue *ifq; enum NPmode mode; int len; struct mbuf *m; if (sc->sc_devp == NULL || (ifp->if_flags & IFF_RUNNING) == 0 || ((ifp->if_flags & IFF_UP) == 0 && dst->sa_family != AF_UNSPEC)) { error = ENETDOWN; /* sort of */ goto bad; } /* * Compute PPP header. * We use the m_context field of the mbuf to indicate whether * the packet should go on the fast queue. */ m0->m_context = 0; switch (dst->sa_family) {#ifdef INET case AF_INET: address = PPP_ALLSTATIONS; control = PPP_UI; protocol = PPP_IP; mode = sc->sc_npmode[NP_IP]; /* * If this is a TCP packet to or from an "interactive" port, * put the packet on the fastq instead. */ if ((ip = mtod(m0, struct ip *))->ip_p == IPPROTO_TCP) { register int p = ntohl(((int *)ip)[ip->ip_hl]); if (INTERACTIVE(p & 0xffff) || INTERACTIVE(p >> 16)) m0->m_context = 1; } break;#endif case AF_UNSPEC: address = PPP_ADDRESS(dst->sa_data); control = PPP_CONTROL(dst->sa_data); protocol = PPP_PROTOCOL(dst->sa_data); mode = NPMODE_PASS; break; default: printf("ppp%d: af%d not supported\n", ifp->if_unit, dst->sa_family); error = EAFNOSUPPORT; goto bad; } /* * Drop this packet, or return an error, if necessary. */ if (mode == NPMODE_ERROR) { error = ENETDOWN; goto bad; } if (mode == NPMODE_DROP) { error = 0; goto bad; } /* * Add PPP header. If no space in first mbuf, allocate another. */ if (M_IS_CLUSTER(m0) || m0->m_off < MMINOFF + PPP_HDRLEN) { struct mbuf *m; MGET(m, M_DONTWAIT, MT_DATA); if (m == NULL) { m_freem(m0); return (ENOBUFS); } m->m_len = 0; m->m_next = m0; m0 = m; } else m0->m_off -= PPP_HDRLEN; cp = mtod(m0, u_char *); *cp++ = address; *cp++ = control; *cp++ = protocol >> 8; *cp++ = protocol & 0xff; m0->m_len += PPP_HDRLEN; len = 0; for (m = m0; m != 0; m = m->m_next) len += m->m_len; if (sc->sc_flags & SC_LOG_OUTPKT) { printf("ppp%d output: ", ifp->if_unit); pppdumpm(m0); } if ((protocol & 0x8000) == 0) { /* * Update the time we sent the most recent data packet. */ sc->sc_last_sent = time.tv_sec; }#if NBPFILTER > 0 /* * See if bpf wants to look at the packet. */ if (sc->sc_bpf) bpf_mtap(sc->sc_bpf, m0);#endif /* * Put the packet on the appropriate queue. */ s = splnet(); if (mode == NPMODE_QUEUE) { /* XXX we should limit the number of packets on this queue */ *sc->sc_npqtail = m0; m0->m_act = NULL; sc->sc_npqtail = &m0->m_act; } else { ifq = m0->m_context? &sc->sc_fastq: &ifp->if_snd; if (IF_QFULL(ifq) && dst->sa_family != AF_UNSPEC) { IF_DROP(ifq); splx(s); sc->sc_if.if_oerrors++; sc->sc_stats.ppp_oerrors++; error = ENOBUFS; goto bad; } IF_ENQUEUE(ifq, m0); (*sc->sc_start)(sc); } ifp->if_opackets++; splx(s); return (0);bad: m_freem(m0); return (error);}/* * After a change in the NPmode for some NP, move packets from the * npqueue to the send queue or the fast queue as appropriate. * Should be called at splnet. */static voidppp_requeue(sc) struct ppp_softc *sc;{ struct mbuf *m, **mpp; struct ifqueue *ifq; enum NPmode mode; for (mpp = &sc->sc_npqueue; (m = *mpp) != NULL; ) { switch (PPP_PROTOCOL(mtod(m, u_char *))) { case PPP_IP: mode = sc->sc_npmode[NP_IP]; break; default: mode = NPMODE_PASS; } switch (mode) { case NPMODE_PASS: /* * This packet can now go on one of the queues to be sent. */ *mpp = m->m_act; m->m_act = NULL; ifq = m->m_context? &sc->sc_fastq: &sc->sc_if.if_snd; if (IF_QFULL(ifq)) { IF_DROP(ifq); sc->sc_if.if_oerrors++; sc->sc_stats.ppp_oerrors++; } else IF_ENQUEUE(ifq, m); break; case NPMODE_DROP: case NPMODE_ERROR: *mpp = m->m_act; m_freem(m); break; case NPMODE_QUEUE: mpp = &m->m_act; break; } } sc->sc_npqtail = mpp;}/* * Transmitter has finished outputting some stuff; * remember to call sc->sc_start later at splnet. */voidppp_restart(sc) struct ppp_softc *sc;{ int s = splimp(); sc->sc_flags &= ~SC_TBUSY; schednetisr(NETISR_PPP); splx(s);}/* * Get a packet to send. This procedure is intended to be called at * splnet, since it may involve time-consuming operations such as * applying VJ compression, packet compression, address/control and/or * protocol field compression to the packet. */struct mbuf *ppp_dequeue(sc) struct ppp_softc *sc;{ struct mbuf *m, *mp; u_char *cp; int address, control, protocol; int s; /* * Grab a packet to send: first try the fast queue, then the * normal queue. */ IF_DEQUEUE(&sc->sc_fastq, m); if (m == NULL) IF_DEQUEUE(&sc->sc_if.if_snd, m); 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 = sl_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_off += 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_off; --m->m_len; } return m;}/* * Software interrupt routine, called at splnet.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -