/* * Queue a packet. Start transmission if not active. * Packet is placed in Information field of PPP frame. * Called at splnet as the if->if_output handler. * Called at splnet from pppwrite(). */ static int pppoutput_serialized(struct ifnet *ifp, struct ifaltq_subque *ifsq, struct mbuf *m0, struct sockaddr *dst, struct rtentry *rtp) { struct ppp_softc *sc = &ppp_softc[ifp->if_dunit]; int protocol, address, control; u_char *cp; int error; #ifdef INET struct ip *ip; #endif struct ifqueue *ifq; enum NPmode mode; int len; struct mbuf *m; struct altq_pktattr pktattr; 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; } ifq_classify(&ifp->if_snd, m0, dst->sa_family, &pktattr); /* * 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 #ifdef IPX case AF_IPX: /* * This is pretty bogus.. We dont have an ipxcp module in pppd * yet to configure the link parameters. Sigh. I guess a * manual ifconfig would do.... -Peter */ address = PPP_ALLSTATIONS; control = PPP_UI; protocol = PPP_IPX; mode = NPMODE_PASS; 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: kprintf("%s: af%d not supported\n", ifp->if_xname, 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, MB_DONTWAIT); if (m0 == NULL) { 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 != NULL; m = m->m_next) len += m->m_len; if (sc->sc_flags & SC_LOG_OUTPKT) { kprintf("%s output: ", ifp->if_xname); 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 != NULL && 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 == NULL || bpf_filter(sc->sc_active_filt.bf_insns, (u_char *) m0, len, 0)) sc->sc_last_sent = time_uptime; *mtod(m0, u_char *) = address; #else /* * Update the time we sent the most recent data packet. */ sc->sc_last_sent = time_uptime; #endif /* PPP_FILTER */ } BPF_MTAP(ifp, m0); /* * Put the packet on the appropriate queue. */ crit_enter(); 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 { /* fastq and if_snd are emptied at spl[soft]net now */ if ((m0->m_flags & M_HIGHPRI) && !ifq_is_enabled(&sc->sc_if.if_snd)) { ifq = &sc->sc_fastq; if (IF_QFULL(ifq) && dst->sa_family != AF_UNSPEC) { IF_DROP(ifq); m_freem(m0); error = ENOBUFS; } else { IF_ENQUEUE(ifq, m0); error = 0; } } else { ASSERT_ALTQ_SQ_SERIALIZED_HW(ifsq); error = ifsq_enqueue(ifsq, m0, &pktattr); } if (error) { crit_exit(); IFNET_STAT_INC(&sc->sc_if, oerrors, 1); sc->sc_stats.ppp_oerrors++; return (error); } (*sc->sc_start)(sc); } getmicrotime(&ifp->if_lastchange); IFNET_STAT_INC(ifp, opackets, 1); IFNET_STAT_INC(ifp, obytes, len); crit_exit(); return (0); bad: m_freem(m0); return (error); }
/* * Queue a packet. Start transmission if not active. * Packet is placed in Information field of PPP frame. */ int pppoutput(struct ifnet *ifp, struct mbuf *m0, struct sockaddr *dst, struct rtentry *rtp) { struct ppp_softc *sc = ifp->if_softc; int protocol, address, control; u_char *cp; int s, error; struct ip *ip; struct ifqueue *ifq; enum NPmode mode; int len; 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; } #ifdef DIAGNOSTIC if (ifp->if_rdomain != rtable_l2(m0->m_pkthdr.ph_rtableid)) { printf("%s: trying to send packet on wrong domain. " "if %d vs. mbuf %d, AF %d\n", ifp->if_xname, ifp->if_rdomain, rtable_l2(m0->m_pkthdr.ph_rtableid), dst->sa_family); } #endif /* * 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("%s: af%d not supported\n", ifp->if_xname, 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.) */ M_PREPEND(m0, PPP_HDRLEN, M_DONTWAIT); if (m0 == 0) { error = ENOBUFS; goto bad; } cp = mtod(m0, u_char *); *cp++ = address; *cp++ = control; *cp++ = protocol >> 8; *cp++ = protocol & 0xff; if ((m0->m_flags & M_PKTHDR) == 0) panic("mbuf packet without packet header!"); len = m0->m_pkthdr.len; if (sc->sc_flags & SC_LOG_OUTPKT) { printf("%s output: ", ifp->if_xname); pppdumpm(m0); } if ((protocol & 0x8000) == 0) { #if NBPFILTER > 0 /* * 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_second; *mtod(m0, u_char *) = address; #else /* * Update the time we sent the most recent packet. */ sc->sc_last_sent = time_second; #endif } #if NBPFILTER > 0 /* * See if bpf wants to look at the packet. */ if (sc->sc_bpf) bpf_mtap(sc->sc_bpf, m0, BPF_DIRECTION_OUT); #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 { if (m0->m_flags & M_HIGHPRI) { ifq = &sc->sc_fastq; if (IF_QFULL(ifq) && dst->sa_family != AF_UNSPEC) { IF_DROP(ifq); m_freem(m0); error = ENOBUFS; } else { IF_ENQUEUE(ifq, m0); error = 0; } } else IFQ_ENQUEUE(&sc->sc_if.if_snd, m0, NULL, error); if (error) { splx(s); sc->sc_if.if_oerrors++; sc->sc_stats.ppp_oerrors++; return (error); } (*sc->sc_start)(sc); } ifp->if_opackets++; ifp->if_obytes += len; splx(s); return (0); bad: m_freem(m0); return (error); }