/* * 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 spl[soft]net. */ static void ppp_requeue(struct ppp_softc *sc) { struct mbuf *m, **mpp; struct ifqueue *ifq; struct ifaltq_subque *ifsq; enum NPmode mode; int error; ifsq = ifq_get_subq_default(&sc->sc_if.if_snd); 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; if ((m->m_flags & M_HIGHPRI) && !ifq_is_enabled(&sc->sc_if.if_snd)) { ifq = &sc->sc_fastq; if (IF_QFULL(ifq)) { IF_DROP(ifq); error = ENOBUFS; } else { IF_ENQUEUE(ifq, m); error = 0; } } else { error = ifsq_enqueue(ifsq, m, NULL); } if (error) { IFNET_STAT_INC(&sc->sc_if, oerrors, 1); sc->sc_stats.ppp_oerrors++; } 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; }
int pppoutput(struct ifnet *ifp, struct mbuf *m0, struct sockaddr *dst, struct rtentry *rtp) { struct ifaltq_subque *ifsq = ifq_get_subq_default(&ifp->if_snd); int error; ifsq_serialize_hw(ifsq); error = pppoutput_serialized(ifp, ifsq, m0, dst, rtp); ifsq_deserialize_hw(ifsq); return error; }
static int ng_iface_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, struct rtentry *rt0) { struct ifaltq_subque *ifsq = ifq_get_subq_default(&ifp->if_snd); int error; ifsq_serialize_hw(ifsq); error = ng_iface_output_serialized(ifp, m, dst, rt0); ifsq_deserialize_hw(ifsq); return error; }
/* * Software interrupt routine, called at spl[soft]net. */ static void pppintr(netmsg_t msg) { struct mbuf *m; struct ppp_softc *sc; struct ifaltq_subque *ifsq; int i; /* * Packets are never sent to this netisr so the message must always * be replied. Interlock processing and notification by replying * the message first. */ lwkt_replymsg(&msg->lmsg, 0); get_mplock(); sc = ppp_softc; ifsq = ifq_get_subq_default(&sc->sc_if.if_snd); for (i = 0; i < NPPP; ++i, ++sc) { ifnet_serialize_all(&sc->sc_if); if (!(sc->sc_flags & SC_TBUSY) && (!ifsq_is_empty(ifsq) || !IF_QEMPTY(&sc->sc_fastq))) { sc->sc_flags |= SC_TBUSY; (*sc->sc_start)(sc); } for (;;) { IF_DEQUEUE(&sc->sc_rawq, m); if (m == NULL) break; ppp_inproc(sc, m); } ifnet_deserialize_all(&sc->sc_if); } rel_mplock(); }
/* * 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(struct ppp_softc *sc) { struct mbuf *m, *mp; u_char *cp; int address, control, protocol; /* * Grab a packet to send: first try the fast queue, then the * normal queue. */ IF_DEQUEUE(&sc->sc_fastq, m); if (m == NULL) m = ifsq_dequeue(ifq_get_subq_default(&sc->sc_if.if_snd)); 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 */ } }
/* * Move frames from the ps q to the vap's send queue * and/or the driver's send queue; and kick the start * method for each, as appropriate. Note we're careful * to preserve packet ordering here. */ static void pwrsave_flushq(struct ieee80211_node *ni) { struct ieee80211_psq *psq = &ni->ni_psq; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211_psq_head *qhead; struct ifnet *parent, *ifp; struct ifaltq_subque *ifp_ifsq, *parent_ifsq; IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni, "flush ps queue, %u packets queued", psq->psq_len); qhead = &psq->psq_head[0]; /* 802.11 frames */ if (qhead->head != NULL) { const struct mbuf *m; int bcnt = 0; for (m = qhead->head; m != NULL; m = m->m_nextpkt) bcnt += m->m_pkthdr.len; /* XXX could dispatch through vap and check M_ENCAP */ parent = vap->iv_ic->ic_ifp; parent_ifsq = ifq_get_subq_default(&parent->if_snd); /* XXX this breaks ALTQ's packet scheduler */ ALTQ_SQ_LOCK(parent_ifsq); /* XXX need different driver interface */ /* XXX bypasses q max and OACTIVE */ IF_PREPEND_LIST(parent_ifsq, qhead->head, qhead->tail, qhead->len, bcnt); ALTQ_SQ_UNLOCK(parent_ifsq); qhead->head = qhead->tail = NULL; qhead->len = 0; } else { parent = NULL; parent_ifsq = NULL; } qhead = &psq->psq_head[1]; /* 802.3 frames */ if (qhead->head != NULL) { const struct mbuf *m; int bcnt = 0; for (m = qhead->head; m != NULL; m = m->m_nextpkt) bcnt += m->m_pkthdr.len; ifp = vap->iv_ifp; ifp_ifsq = ifq_get_subq_default(&ifp->if_snd); /* XXX this breaks ALTQ's packet scheduler */ ALTQ_SQ_LOCK(ifp_ifsq); /* XXX need different driver interface */ /* XXX bypasses q max and OACTIVE */ IF_PREPEND_LIST(ifp_ifsq, qhead->head, qhead->tail, qhead->len, bcnt); ALTQ_SQ_UNLOCK(ifp_ifsq); qhead->head = qhead->tail = NULL; qhead->len = 0; } else { ifp = NULL; ifp_ifsq = NULL; } psq->psq_len = 0; /* NB: do this outside the psq lock */ /* XXX packets might get reordered if parent is OACTIVE */ if (parent != NULL && parent_ifsq != NULL) parent->if_start(parent, parent_ifsq); if (ifp != NULL && ifp_ifsq != NULL) ifp->if_start(ifp, ifp_ifsq); }