示例#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 splsoftnet.
 */
static void
ppp_requeue(struct ppp_softc *sc)
{
    struct mbuf *m, **mpp;
    struct ifqueue *ifq;
    enum NPmode mode;
    int error;

    splsoftassert(IPL_SOFTNET);

    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 = &sc->sc_fastq;
		if (IF_QFULL(ifq)) {
		    IF_DROP(ifq);
		    m_freem(m);
		    error = ENOBUFS;
		}
		else {
		    IF_ENQUEUE(ifq, m);
		    error = 0;
		}
	    } else
		IFQ_ENQUEUE(&sc->sc_if.if_snd, m, NULL, error);
	    if (error) {
		sc->sc_if.if_oerrors++;
		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
looutput(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
         struct rtentry *rt)
{
    pktqueue_t *pktq = NULL;
    struct ifqueue *ifq = NULL;
    int s, isr = -1;
    int csum_flags;
    size_t pktlen;

    MCLAIM(m, ifp->if_mowner);
    KASSERT(KERNEL_LOCKED_P());

    if ((m->m_flags & M_PKTHDR) == 0)
        panic("looutput: no header mbuf");
    if (ifp->if_flags & IFF_LOOPBACK)
        bpf_mtap_af(ifp, dst->sa_family, m);
    m->m_pkthdr.rcvif = ifp;

    if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
        m_freem(m);
        return (rt->rt_flags & RTF_BLACKHOLE ? 0 :
                rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
    }

    pktlen = m->m_pkthdr.len;
    ifp->if_opackets++;
    ifp->if_obytes += pktlen;

#ifdef ALTQ
    /*
     * ALTQ on the loopback interface is just for debugging.  It's
     * used only for loopback interfaces, not for a simplex interface.
     */
    if ((ALTQ_IS_ENABLED(&ifp->if_snd) || TBR_IS_ENABLED(&ifp->if_snd)) &&
            ifp->if_start == lostart) {
        struct altq_pktattr pktattr;
        int error;

        /*
         * If the queueing discipline needs packet classification,
         * do it before prepending the link headers.
         */
        IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family, &pktattr);

        M_PREPEND(m, sizeof(uint32_t), M_DONTWAIT);
        if (m == NULL)
            return (ENOBUFS);
        *(mtod(m, uint32_t *)) = dst->sa_family;

        s = splnet();
        IFQ_ENQUEUE(&ifp->if_snd, m, &pktattr, error);
        (*ifp->if_start)(ifp);
        splx(s);
        return (error);
    }
#endif /* ALTQ */

    m_tag_delete_nonpersistent(m);

#ifdef MPLS
    if (rt != NULL && rt_gettag(rt) != NULL &&
            rt_gettag(rt)->sa_family == AF_MPLS &&
            (m->m_flags & (M_MCAST | M_BCAST)) == 0) {
        union mpls_shim msh;
        msh.s_addr = MPLS_GETSADDR(rt);
        if (msh.shim.label != MPLS_LABEL_IMPLNULL) {
            ifq = &mplsintrq;
            isr = NETISR_MPLS;
        }
    }
    if (isr != NETISR_MPLS)
#endif
        switch (dst->sa_family) {

#ifdef INET
        case AF_INET:
            csum_flags = m->m_pkthdr.csum_flags;
            KASSERT((csum_flags & ~(M_CSUM_IPv4|M_CSUM_UDPv4)) == 0);
            if (csum_flags != 0 && IN_LOOPBACK_NEED_CHECKSUM(csum_flags)) {
                ip_undefer_csum(m, 0, csum_flags);
            }
            m->m_pkthdr.csum_flags = 0;
            pktq = ip_pktq;
            break;
#endif
#ifdef INET6
        case AF_INET6:
            csum_flags = m->m_pkthdr.csum_flags;
            KASSERT((csum_flags & ~M_CSUM_UDPv6) == 0);
            if (csum_flags != 0 &&
                    IN6_LOOPBACK_NEED_CHECKSUM(csum_flags)) {
                ip6_undefer_csum(m, 0, csum_flags);
            }
            m->m_pkthdr.csum_flags = 0;
            m->m_flags |= M_LOOP;
            pktq = ip6_pktq;
            break;
#endif
#ifdef IPX
        case AF_IPX:
            ifq = &ipxintrq;
            isr = NETISR_IPX;
            break;
#endif
#ifdef NETATALK
        case AF_APPLETALK:
            ifq = &atintrq2;
            isr = NETISR_ATALK;
            break;
#endif
        default:
            printf("%s: can't handle af%d\n", ifp->if_xname,
                   dst->sa_family);
            m_freem(m);
            return (EAFNOSUPPORT);
        }

    s = splnet();
    if (__predict_true(pktq)) {
        int error = 0;

        if (__predict_true(pktq_enqueue(pktq, m, 0))) {
            ifp->if_ipackets++;
            ifp->if_ibytes += pktlen;
        } else {
            m_freem(m);
            error = ENOBUFS;
        }
        splx(s);
        return error;
    }
    if (IF_QFULL(ifq)) {
        IF_DROP(ifq);
        m_freem(m);
        splx(s);
        return (ENOBUFS);
    }
    IF_ENQUEUE(ifq, m);
    schednetisr(isr);
    ifp->if_ipackets++;
    ifp->if_ibytes += m->m_pkthdr.len;
    splx(s);
    return (0);
}
示例#3
0
int
looutput(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
    struct rtentry *rt)
{
	int s, isr;
	struct ifqueue *ifq = NULL;

	MCLAIM(m, ifp->if_mowner);
	if ((m->m_flags & M_PKTHDR) == 0)
		panic("looutput: no header mbuf");
#if NBPFILTER > 0
	if (ifp->if_bpf && (ifp->if_flags & IFF_LOOPBACK))
		bpf_mtap_af(ifp->if_bpf, dst->sa_family, m);
#endif
	m->m_pkthdr.rcvif = ifp;

	if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
		m_freem(m);
		return (rt->rt_flags & RTF_BLACKHOLE ? 0 :
			rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
	}

	ifp->if_opackets++;
	ifp->if_obytes += m->m_pkthdr.len;

#ifdef ALTQ
	/*
	 * ALTQ on the loopback interface is just for debugging.  It's
	 * used only for loopback interfaces, not for a simplex interface.
	 */
	if ((ALTQ_IS_ENABLED(&ifp->if_snd) || TBR_IS_ENABLED(&ifp->if_snd)) &&
	    ifp->if_start == lostart) {
		struct altq_pktattr pktattr;
		int error;

		/*
		 * If the queueing discipline needs packet classification,
		 * do it before prepending the link headers.
		 */
		IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family, &pktattr);

		M_PREPEND(m, sizeof(uint32_t), M_DONTWAIT);
		if (m == NULL)
			return (ENOBUFS);
		*(mtod(m, uint32_t *)) = dst->sa_family;

		s = splnet();
		IFQ_ENQUEUE(&ifp->if_snd, m, &pktattr, error);
		(*ifp->if_start)(ifp);
		splx(s);
		return (error);
	}
#endif /* ALTQ */

	m_tag_delete_nonpersistent(m);

	switch (dst->sa_family) {

#ifdef INET
	case AF_INET:
		ifq = &ipintrq;
		isr = NETISR_IP;
		break;
#endif
#ifdef INET6
	case AF_INET6:
		m->m_flags |= M_LOOP;
		ifq = &ip6intrq;
		isr = NETISR_IPV6;
		break;
#endif
#ifdef ISO
	case AF_ISO:
		ifq = &clnlintrq;
		isr = NETISR_ISO;
		break;
#endif
#ifdef IPX
	case AF_IPX:
		ifq = &ipxintrq;
		isr = NETISR_IPX;
		break;
#endif
#ifdef NETATALK
	case AF_APPLETALK:
	        ifq = &atintrq2;
		isr = NETISR_ATALK;
		break;
#endif
	default:
		printf("%s: can't handle af%d\n", ifp->if_xname,
		    dst->sa_family);
		m_freem(m);
		return (EAFNOSUPPORT);
	}
	s = splnet();
	if (IF_QFULL(ifq)) {
		IF_DROP(ifq);
		m_freem(m);
		splx(s);
		return (ENOBUFS);
	}
	IF_ENQUEUE(ifq, m);
	// schednetisr(isr);
	ifp->if_ipackets++;
	ifp->if_ibytes += m->m_pkthdr.len;
	splx(s);
	return (0);
}
/*
 * Send an EAPOL-Key frame to node `ni'.  If MIC or encryption is required,
 * the PTK must be passed (otherwise it can be set to NULL.)
 */
int
ieee80211_send_eapol_key(struct ieee80211com *ic, struct mbuf *m,
    struct ieee80211_node *ni, const struct ieee80211_ptk *ptk)
{
	struct ifnet *ifp = &ic->ic_if;
	struct ether_header *eh;
	struct ieee80211_eapol_key *key;
	u_int16_t info;
	int s, len, error;

	M_PREPEND(m, sizeof(struct ether_header), M_DONTWAIT);
	if (m == NULL)
		return ENOMEM;
	/* no need to m_pullup here (ok by construction) */
	eh = mtod(m, struct ether_header *);
	eh->ether_type = htons(ETHERTYPE_PAE);
	IEEE80211_ADDR_COPY(eh->ether_shost, ic->ic_myaddr);
	IEEE80211_ADDR_COPY(eh->ether_dhost, ni->ni_macaddr);

	key = (struct ieee80211_eapol_key *)&eh[1];
	key->version = EAPOL_VERSION;
	key->type = EAPOL_KEY;
	key->desc = (ni->ni_rsnprotos == IEEE80211_PROTO_RSN) ?
	    EAPOL_KEY_DESC_IEEE80211 : EAPOL_KEY_DESC_WPA;

	info = BE_READ_2(key->info);
	/* use V3 descriptor if KDF is SHA256-based */
	if (ieee80211_is_sha256_akm(ni->ni_rsnakms))
		info |= EAPOL_KEY_DESC_V3;
	/* use V2 descriptor if pairwise or group cipher is CCMP */
	else if (ni->ni_rsncipher == IEEE80211_CIPHER_CCMP ||
	    ni->ni_rsngroupcipher == IEEE80211_CIPHER_CCMP)
		info |= EAPOL_KEY_DESC_V2;
	else
		info |= EAPOL_KEY_DESC_V1;
	BE_WRITE_2(key->info, info);

	len = m->m_len - sizeof(struct ether_header);
	BE_WRITE_2(key->paylen, len - sizeof(*key));
	BE_WRITE_2(key->len, len - 4);

#ifndef IEEE80211_STA_ONLY
	if (info & EAPOL_KEY_ENCRYPTED) {
		if (ni->ni_rsnprotos == IEEE80211_PROTO_WPA) {
			/* clear "Encrypted" bit for WPA */
			info &= ~EAPOL_KEY_ENCRYPTED;
			BE_WRITE_2(key->info, info);
		}
		ieee80211_eapol_key_encrypt(ic, key, ptk->kek);

		if ((info & EAPOL_KEY_VERSION_MASK) != EAPOL_KEY_DESC_V1) {
			/* AES Key Wrap adds 8 bytes + padding */
			m->m_pkthdr.len = m->m_len =
			    sizeof(*eh) + 4 + BE_READ_2(key->len);
		}
	}
#endif
	if (info & EAPOL_KEY_KEYMIC)
		ieee80211_eapol_key_mic(key, ptk->kck);

	len = m->m_pkthdr.len;
	s = splnet();
#ifndef IEEE80211_STA_ONLY
	/* start a 100ms timeout if an answer is expected from supplicant */
	if (info & EAPOL_KEY_KEYACK)
		timeout_add_msec(&ni->ni_eapol_to, 100);
#endif
	IFQ_ENQUEUE(&ifp->if_snd, m, NULL, error);
	if (error == 0) {
		ifp->if_obytes += len;
		if ((ifp->if_flags & IFF_OACTIVE) == 0)
			(*ifp->if_start)(ifp);
	}
	splx(s);

	return error;
}
示例#5
0
/*
 * 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);
}
示例#6
0
/*
 * Ethernet output routine.
 * Encapsulate a packet of type family for the local net.
 * Assumes that ifp is actually pointer to arpcom structure.
 */
int
ether_output(struct ifnet *ifp0, struct mbuf *m0, struct sockaddr *dst,
    struct rtentry *rt0)
{
	u_int16_t etype;
	int s, len, error = 0;
	u_char edst[ETHER_ADDR_LEN];
	u_char *esrc;
	struct mbuf *m = m0;
	struct rtentry *rt;
	struct mbuf *mcopy = NULL;
	struct ether_header *eh;
	struct arpcom *ac = (struct arpcom *)ifp0;
	short mflags;
	struct ifnet *ifp = ifp0;

#ifdef DIAGNOSTIC
	if (ifp->if_rdomain != rtable_l2(m->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(m->m_pkthdr.ph_rtableid),
		    dst->sa_family);
	}
#endif

#if NTRUNK > 0
	/* restrict transmission on trunk members to bpf only */
	if (ifp->if_type == IFT_IEEE8023ADLAG &&
	    (m_tag_find(m, PACKET_TAG_DLT, NULL) == NULL))
		senderr(EBUSY);
#endif

#if NCARP > 0
	if (ifp->if_type == IFT_CARP) {
		ifp = ifp->if_carpdev;
		ac = (struct arpcom *)ifp;

		if ((ifp0->if_flags & (IFF_UP|IFF_RUNNING)) !=
		    (IFF_UP|IFF_RUNNING))
			senderr(ENETDOWN);
	}
#endif /* NCARP > 0 */

	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
		senderr(ENETDOWN);
	if ((rt = rt0) != NULL) {
		if ((rt->rt_flags & RTF_UP) == 0) {
			if ((rt0 = rt = rtalloc1(dst, RT_REPORT,
			    m->m_pkthdr.ph_rtableid)) != NULL)
				rt->rt_refcnt--;
			else
				senderr(EHOSTUNREACH);
		}

		if (rt->rt_flags & RTF_GATEWAY) {
			if (rt->rt_gwroute == NULL)
				goto lookup;
			if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
				rtfree(rt);
				rt = rt0;
			lookup:
				rt->rt_gwroute = rtalloc1(rt->rt_gateway,
				    RT_REPORT, ifp->if_rdomain);
				if ((rt = rt->rt_gwroute) == NULL)
					senderr(EHOSTUNREACH);
			}
		}
		if (rt->rt_flags & RTF_REJECT)
			if (rt->rt_rmx.rmx_expire == 0 ||
			    time_second < rt->rt_rmx.rmx_expire)
				senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
	}
	esrc = ac->ac_enaddr;
	switch (dst->sa_family) {

#ifdef INET
	case AF_INET:
		if (!arpresolve(ac, rt, m, dst, edst))
			return (0);	/* if not yet resolved */
		/* If broadcasting on a simplex interface, loopback a copy */
		if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX) &&
		    !m->m_pkthdr.pf.routed)
			mcopy = m_copy(m, 0, (int)M_COPYALL);
		etype = htons(ETHERTYPE_IP);
		break;
#endif
#ifdef INET6
	case AF_INET6:
		if (!nd6_storelladdr(ifp, rt, m, dst, (u_char *)edst))
			return (0); /* it must be impossible, but... */
		etype = htons(ETHERTYPE_IPV6);
		break;
#endif
#ifdef MPLS
       case AF_MPLS:
		if (rt)
			dst = rt_key(rt);
		else
			senderr(EHOSTUNREACH);

		if (!ISSET(ifp->if_xflags, IFXF_MPLS))
			senderr(ENETUNREACH);

		switch (dst->sa_family) {
			case AF_LINK:
				if (((struct sockaddr_dl *)dst)->sdl_alen <
				    sizeof(edst))
					senderr(EHOSTUNREACH);
				memcpy(edst, LLADDR((struct sockaddr_dl *)dst),
				    sizeof(edst));
				break;
			case AF_INET:
				if (!arpresolve(ac, rt, m, dst, edst))
					return (0); /* if not yet resolved */
				break;
			default:
				senderr(EHOSTUNREACH);
		}
		/* XXX handling for simplex devices in case of M/BCAST ?? */
		if (m->m_flags & (M_BCAST | M_MCAST))
			etype = htons(ETHERTYPE_MPLS_MCAST);
		else
			etype = htons(ETHERTYPE_MPLS);
		break;
#endif /* MPLS */
	case pseudo_AF_HDRCMPLT:
		eh = (struct ether_header *)dst->sa_data;
		esrc = eh->ether_shost;
		/* FALLTHROUGH */

	case AF_UNSPEC:
		eh = (struct ether_header *)dst->sa_data;
		memcpy(edst, eh->ether_dhost, sizeof(edst));
		/* AF_UNSPEC doesn't swap the byte order of the ether_type. */
		etype = eh->ether_type;
		break;

	default:
		printf("%s: can't handle af%d\n", ifp->if_xname,
			dst->sa_family);
		senderr(EAFNOSUPPORT);
	}

	/* XXX Should we feed-back an unencrypted IPsec packet ? */
	if (mcopy)
		(void) looutput(ifp, mcopy, dst, rt);

#if NCARP > 0
	if (ifp0 != ifp && ifp0->if_type == IFT_CARP)
		esrc = carp_get_srclladdr(ifp0, esrc);
#endif

	if (ether_addheader(&m, ifp, etype, esrc, edst) == -1)
		senderr(ENOBUFS);

#if NBRIDGE > 0
	/*
	 * Interfaces that are bridgeports need special handling for output.
	 */
	if (ifp->if_bridgeport) {
		struct m_tag *mtag;

		/*
		 * Check if this packet has already been sent out through
		 * this bridgeport, in which case we simply send it out
		 * without further bridge processing.
		 */
		for (mtag = m_tag_find(m, PACKET_TAG_BRIDGE, NULL); mtag;
		    mtag = m_tag_find(m, PACKET_TAG_BRIDGE, mtag)) {
#ifdef DEBUG
			/* Check that the information is there */
			if (mtag->m_tag_len != sizeof(caddr_t)) {
				error = EINVAL;
				goto bad;
			}
#endif
			if (!memcmp(&ifp->if_bridgeport, mtag + 1,
			    sizeof(caddr_t)))
				break;
		}
		if (mtag == NULL) {
			/* Attach a tag so we can detect loops */
			mtag = m_tag_get(PACKET_TAG_BRIDGE, sizeof(caddr_t),
			    M_NOWAIT);
			if (mtag == NULL) {
				error = ENOBUFS;
				goto bad;
			}
			memcpy(mtag + 1, &ifp->if_bridgeport, sizeof(caddr_t));
			m_tag_prepend(m, mtag);
			error = bridge_output(ifp, m, NULL, NULL);
			return (error);
		}
	}
#endif
	mflags = m->m_flags;
	len = m->m_pkthdr.len;
	s = splnet();
	/*
	 * Queue message on interface, and start output if interface
	 * not yet active.
	 */
	IFQ_ENQUEUE(&ifp->if_snd, m, NULL, error);
	if (error) {
		/* mbuf is already freed */
		splx(s);
		return (error);
	}
	ifp->if_obytes += len;
#if NCARP > 0
	if (ifp != ifp0)
		ifp0->if_obytes += len;
#endif /* NCARP > 0 */
	if (mflags & M_MCAST)
		ifp->if_omcasts++;
	if_start(ifp);
	splx(s);
	return (error);

bad:
	if (m)
		m_freem(m);
	return (error);
}