📄 if_ppp.c
字号:
if (sc->sc_pass_filt.bf_insns != 0) { FREE(sc->sc_pass_filt.bf_insns, M_DEVBUF); sc->sc_pass_filt.bf_insns = 0; sc->sc_pass_filt.bf_len = 0; } if (sc->sc_active_filt.bf_insns != 0) { FREE(sc->sc_active_filt.bf_insns, M_DEVBUF); sc->sc_active_filt.bf_insns = 0; sc->sc_active_filt.bf_len = 0; }#endif /* PPP_FILTER */#ifdef VJC if (sc->sc_comp != 0) { FREE(sc->sc_comp, M_DEVBUF); sc->sc_comp = 0; }#endif}/* * Ioctl routine for generic ppp devices. */intpppioctl(sc, cmd, data, flag, p) struct ppp_softc *sc; int cmd; caddr_t data; int flag; struct proc *p;{ int s, flags, mru, npx, taskid; struct npioctl *npi; time_t t;#ifdef PPP_FILTER int error; struct bpf_program *bp, *nbp; struct bpf_insn *newcode, *oldcode; int newcodelen;#endif /* PPP_FILTER */#ifdef PPP_COMPRESS int nb; struct ppp_option_data *odp; struct compressor **cp; u_char ccp_option[CCP_MAX_OPTION_LENGTH];#endif switch (cmd) { case FIONREAD: *(int *)data = sc->sc_inq.ifq_len; break; case PPPIOCSTASK: taskid = *(int *)data; sc->sc_pppdtask = taskid; break; case PPPIOCGUNIT: *(int *)data = sc->sc_if.if_unit; break; case PPPIOCGFLAGS: *(u_int *)data = sc->sc_flags; break; case PPPIOCSFLAGS: flags = *(int *)data & SC_MASK; s = splsoftnet();#ifdef PPP_COMPRESS if (sc->sc_flags & SC_CCP_OPEN && !(flags & SC_CCP_OPEN)) ppp_ccp_closed(sc);#endif s = splimp(); sc->sc_flags = (sc->sc_flags & ~SC_MASK) | flags; splx(s); break; case PPPIOCSMRU: mru = *(int *)data; if ( mru >= MCLBYTES ) { /* error - currently only handle 1 culster sized MRU */ /* if we want to handle up to PPP_MAXMRU then we */ /* need to reallocate all mbufs on the freeq */ /* this can only be done with iterrupts disabled */ return ( -1 ); } else if ( mru >= PPP_MRU ) { /* update the size */ sc->sc_mru = mru; } break; case PPPIOCGMRU: *(int *)data = sc->sc_mru; break;#ifdef VJC case PPPIOCSMAXCID: if (sc->sc_comp) { s = splsoftnet(); vj_compress_init(sc->sc_comp, *(int *)data); splx(s); } break;#endif case PPPIOCXFERUNIT: sc->sc_xfer = 0; /* Always root p->p_pid;*/ break;#ifdef PPP_COMPRESS case PPPIOCSCOMPRESS: odp = (struct ppp_option_data *) data; nb = odp->length; if (nb > sizeof(ccp_option)) nb = sizeof(ccp_option); if ((error = copyin(odp->ptr, ccp_option, nb)) != 0) return (error); if (ccp_option[1] < 2) /* preliminary check on the length byte */ return (EINVAL); for (cp = ppp_compressors; *cp != NULL; ++cp) if ((*cp)->compress_proto == ccp_option[0]) { /* * Found a handler for the protocol - try to allocate * a compressor or decompressor. */ error = 0; if (odp->transmit) { s = splsoftnet(); if (sc->sc_xc_state != NULL) (*sc->sc_xcomp->comp_free)(sc->sc_xc_state); sc->sc_xcomp = *cp; sc->sc_xc_state = (*cp)->comp_alloc(ccp_option, nb); if (sc->sc_xc_state == NULL) { if (sc->sc_flags & SC_DEBUG) printf("ppp%d: comp_alloc failed\n", sc->sc_if.if_unit); error = ENOBUFS; } splimp(); sc->sc_flags &= ~SC_COMP_RUN; splx(s); } else { s = splsoftnet(); if (sc->sc_rc_state != NULL) (*sc->sc_rcomp->decomp_free)(sc->sc_rc_state); sc->sc_rcomp = *cp; sc->sc_rc_state = (*cp)->decomp_alloc(ccp_option, nb); if (sc->sc_rc_state == NULL) { if (sc->sc_flags & SC_DEBUG) printf("ppp%d: decomp_alloc failed\n", sc->sc_if.if_unit); error = ENOBUFS; } splimp(); sc->sc_flags &= ~SC_DECOMP_RUN; splx(s); } return (error); } if (sc->sc_flags & SC_DEBUG) printf("ppp%d: no compressor for [%x %x %x], %x\n", sc->sc_if.if_unit, ccp_option[0], ccp_option[1], ccp_option[2], nb); return (EINVAL); /* no handler found */#endif /* PPP_COMPRESS */ case PPPIOCGNPMODE: case PPPIOCSNPMODE: npi = (struct npioctl *) data; switch (npi->protocol) { case PPP_IP: npx = NP_IP; break; default: return EINVAL; } if (cmd == PPPIOCGNPMODE) { npi->mode = sc->sc_npmode[npx]; } else { if (npi->mode != sc->sc_npmode[npx]) { s = splsoftnet(); sc->sc_npmode[npx] = npi->mode; if (npi->mode != NPMODE_QUEUE) { ppp_requeue(sc); (*sc->sc_start)(sc); } splx(s); } } break; case PPPIOCGIDLE: s = splsoftnet(); microtime(&ppp_time); t = ppp_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;#ifdef PPP_FILTER case PPPIOCSPASS: case PPPIOCSACTIVE: nbp = (struct bpf_program *) data; if ((unsigned) nbp->bf_len > BPF_MAXINSNS) return EINVAL; newcodelen = nbp->bf_len * sizeof(struct bpf_insn); if (newcodelen != 0) { MALLOC(newcode, struct bpf_insn *, newcodelen, M_DEVBUF, M_WAITOK); if (newcode == 0) { return EINVAL; /* or sumpin */ } if ((error = copyin((caddr_t)nbp->bf_insns, (caddr_t)newcode, newcodelen)) != 0) { FREE(newcode, M_DEVBUF); return error; } if (!bpf_validate(newcode, nbp->bf_len)) { FREE(newcode, M_DEVBUF); return EINVAL; } } else newcode = 0; bp = (cmd == PPPIOCSPASS)? &sc->sc_pass_filt: &sc->sc_active_filt; oldcode = bp->bf_insns; s = splimp(); bp->bf_len = nbp->bf_len; bp->bf_insns = newcode; splx(s); if (oldcode != 0) FREE(oldcode, M_DEVBUF); break;#endif default: return (-1); } return (0);}/* * Process an ioctl request to the ppp network interface. */static intpppsioctl(ifp, cmd, data) register struct ifnet *ifp; int cmd; caddr_t data;{ /*struct proc *p = curproc;*/ /* XXX */ 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; case SIOCSIFMTU: sc->sc_if.if_mtu = ifr->ifr_mtu; break; case SIOCGIFMTU: ifr->ifr_mtu = sc->sc_if.if_mtu; break; case SIOCADDMULTI: case SIOCDELMULTI: if (ifr == 0) { error = EAFNOSUPPORT; break; } switch(ifr->ifr_addr.sa_family) {#ifdef INET case AF_INET: break;#endif default: error = EAFNOSUPPORT; break; } break; case SIO_RTEMS_SHOW_STATS: printf(" MRU:%-8u", sc->sc_mru); printf(" Bytes received:%-8u", sc->sc_stats.ppp_ibytes); printf(" Packets received:%-8u", sc->sc_stats.ppp_ipackets); printf(" Receive errors:%-8u\n", sc->sc_stats.ppp_ierrors); printf(" Bytes sent:%-8u", sc->sc_stats.ppp_obytes); printf(" Packets sent:%-8u", sc->sc_stats.ppp_opackets); printf(" Transmit errors:%-8u\n", sc->sc_stats.ppp_oerrors); break; 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, rtp) struct ifnet *ifp; struct mbuf *m0; struct sockaddr *dst; struct rtentry *rtp;{ 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. */ m0->m_flags &= ~M_HIGHPRI; 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 packet has the "low delay" bit set in the IP header, * put it on the fastq instead. */ ip = mtod(m0, struct ip *); if (ip->ip_tos & IPTOS_LOWDELAY) m0->m_flags |= M_HIGHPRI; 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. * (This assumes M_LEADINGSPACE is always 0 for a cluster mbuf.) */ if (M_LEADINGSPACE(m0) < PPP_HDRLEN) { m0 = m_prepend(m0, PPP_HDRLEN, M_DONTWAIT); if (m0 == 0) { error = ENOBUFS; goto bad; } m0->m_len = 0; } else m0->m_data -= 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) {#ifdef PPP_FILTER /* * Apply the pass and active filters to the packet, * but only if it is a data packet. */ *mtod(m0, u_char *) = 1; /* indicates outbound */ if (sc->sc_pass_filt.bf_insns != 0 && bpf_filter(sc->sc_pass_filt.bf_insns, (u_char *) m0, len, 0) == 0) { error = 0; /* drop this packet */ goto bad; } /* * Update the time we sent the most recent packet. */ if (sc->sc_active_filt.bf_insns == 0 || bpf_filter(sc->sc_active_filt.bf_insns, (u_char *) m0, len, 0)) sc->sc_last_sent = time.tv_sec; *mtod(m0, u_char *) = address;#else /* * Update the time we sent the most recent data packet. */ microtime(&ppp_time); sc->sc_last_sent = 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, m0);#endif /* * Put the packet on the appropriate queue. */ s = splsoftnet(); if (mode == NPMODE_QUEUE) { /* XXX we should limit the number of packets on this queue */ *sc->sc_npqtail = m0; m0->m_nextpkt = NULL; sc->sc_npqtail = &m0->m_nextpkt; } else { ifq = (m0->m_flags & M_HIGHPRI)? &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_lastchange = ppp_time; ifp->if_opackets++; ifp->if_obytes += len; 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 splsoftnet. */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_nextpkt; m->m_nextpkt = NULL; ifq = (m->m_flags & M_HIGHPRI)? &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_nextpkt; m_freem(m); break; case NPMODE_QUEUE: mpp = &m->m_nextpkt; break; } } sc->sc_npqtail = mpp;}/* * Get a packet to send. This procedure is intended to be called at * splsoftnet, 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;#ifdef VJC struct mbuf *mp;#endif u_char *cp; int address, control, protocol;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -