예제 #1
0
/*
 * 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;
}
예제 #2
0
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;
}
예제 #3
0
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;
}
예제 #4
0
/*
 * 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();
}
예제 #5
0
/*
 * 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);
}