예제 #1
0
static bool
npf_log(npf_cache_t *npc, nbuf_t *nbuf, void *meta, int *decision)
{
	struct mbuf *m = nbuf_head_mbuf(nbuf);
	const npf_ext_log_t *log = meta;
	ifnet_t *ifp;
	int family;

	/* Set the address family. */
	if (npf_iscached(npc, NPC_IP4)) {
		family = AF_INET;
	} else if (npf_iscached(npc, NPC_IP6)) {
		family = AF_INET6;
	} else {
		family = AF_UNSPEC;
	}

	KERNEL_LOCK(1, NULL);

	/* Find a pseudo-interface to log. */
	ifp = if_byindex(log->if_idx);
	if (ifp == NULL) {
		/* No interface. */
		KERNEL_UNLOCK_ONE(NULL);
		return true;
	}

	/* Pass through BPF. */
	ifp->if_opackets++;
	ifp->if_obytes += m->m_pkthdr.len;
	bpf_mtap_af(ifp, family, m);
	KERNEL_UNLOCK_ONE(NULL);

	return true;
}
예제 #2
0
/*
 * Start output on the mpe interface.
 */
void
mpestart(struct ifnet *ifp)
{
	struct mbuf 		*m;
	struct sockaddr		*sa = (struct sockaddr *)&mpedst;
	int			 s;
	sa_family_t		 af;
	struct rtentry		*rt;

	for (;;) {
		s = splnet();
		IFQ_DEQUEUE(&ifp->if_snd, m);
		splx(s);

		if (m == NULL)
			return;

		af = *mtod(m, sa_family_t *);
		m_adj(m, sizeof(af));
		switch (af) {
		case AF_INET:
			bzero(sa, sizeof(struct sockaddr_in));
			satosin(sa)->sin_family = af;
			satosin(sa)->sin_len = sizeof(struct sockaddr_in);
			bcopy(mtod(m, caddr_t), &satosin(sa)->sin_addr,
			    sizeof(in_addr_t));
			m_adj(m, sizeof(in_addr_t));
			break;
		default:
			m_freem(m);
			continue;
		}

		rt = rtalloc1(sa, RT_REPORT, 0);
		if (rt == NULL) {
			/* no route give up */
			m_freem(m);
			continue;
		}

#if NBPFILTER > 0
		if (ifp->if_bpf) {
			/* remove MPLS label before passing packet to bpf */
			m->m_data += sizeof(struct shim_hdr);
			m->m_len -= sizeof(struct shim_hdr);
			m->m_pkthdr.len -= sizeof(struct shim_hdr);
			bpf_mtap_af(ifp->if_bpf, af, m, BPF_DIRECTION_OUT);
			m->m_data -= sizeof(struct shim_hdr);
			m->m_len += sizeof(struct shim_hdr);
			m->m_pkthdr.len += sizeof(struct shim_hdr);
		}
#endif
		/* XXX lie, but mpls_output will only look at sa_family */
		sa->sa_family = AF_MPLS;

		mpls_output(rt->rt_ifp, m, sa, rt);
		RTFREE(rt);
	}
}
예제 #3
0
static void
mpls_input(struct ifnet *ifp, struct mbuf *m)
{
#if 0
	/*
	 * TODO - kefren
	 * I'd love to unshim the packet, guess family
	 * and pass it to bpf
	 */
	bpf_mtap_af(ifp, AF_MPLS, m);
#endif

	mpls_lse(m);
}
예제 #4
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);
}
예제 #5
0
/*
 * prepend shim and deliver
 */
static int
mpls_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, struct rtentry *rt)
{
	union mpls_shim mh, *pms;
	struct rtentry *rt1;
	int err;
	uint psize = sizeof(struct sockaddr_mpls);

	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
		m_freem(m);
		return ENETDOWN;
	}

	if (rt_gettag(rt) == NULL || rt_gettag(rt)->sa_family != AF_MPLS) {
		m_freem(m);
		return EINVAL;
	}

	bpf_mtap_af(ifp, dst->sa_family, m);

	memset(&mh, 0, sizeof(mh));
	mh.s_addr = MPLS_GETSADDR(rt);
	mh.shim.bos = 1;
	mh.shim.exp = 0;
	mh.shim.ttl = mpls_defttl;

	pms = &((struct sockaddr_mpls*)rt_gettag(rt))->smpls_addr;

	while (psize <= rt_gettag(rt)->sa_len - sizeof(mh)) {
		pms++;
		if (mh.shim.label != MPLS_LABEL_IMPLNULL &&
		    ((m = mpls_prepend_shim(m, &mh)) == NULL))
			return ENOBUFS;
		memset(&mh, 0, sizeof(mh));
		mh.s_addr = ntohl(pms->s_addr);
		mh.shim.bos = mh.shim.exp = 0;
		mh.shim.ttl = mpls_defttl;
		psize += sizeof(mh);
	}

	switch(dst->sa_family) {
#ifdef INET
	case AF_INET:
		m = mpls_label_inet(m, &mh, psize - sizeof(struct sockaddr_mpls));
		break;
#endif
#ifdef INET6
	case AF_INET6:
		m = mpls_label_inet6(m, &mh, psize - sizeof(struct sockaddr_mpls));
		break;
#endif
	default:
		m = mpls_prepend_shim(m, &mh);
		break;
	}

	if (m == NULL) {
		IF_DROP(&ifp->if_snd);
		ifp->if_oerrors++;
		return ENOBUFS;
	}

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

	if ((rt1=rtalloc1(rt->rt_gateway, 1)) == NULL) {
		m_freem(m);
		return EHOSTUNREACH;
	}

	err = mpls_send_frame(m, rt1->rt_ifp, rt);
	RTFREE(rt1);
	return err;
}
예제 #6
0
int
gre_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
	   struct rtentry *rt)
{
	int error = 0;
	struct gre_softc *sc = (struct gre_softc *) (ifp->if_softc);
	struct greip *gh = NULL;
	struct ip *inp = NULL;
	u_int8_t ip_tos = 0;
	u_int16_t etype = 0;
	struct mobile_h mob_h;
	struct m_tag *mtag;

	if ((ifp->if_flags & IFF_UP) == 0 ||
	    sc->g_src.s_addr == INADDR_ANY || sc->g_dst.s_addr == INADDR_ANY) {
		m_freem(m);
		error = ENETDOWN;
		goto end;
	}

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

	/* Try to limit infinite recursion through misconfiguration. */
	for (mtag = m_tag_find(m, PACKET_TAG_GRE, NULL); mtag;
	     mtag = m_tag_find(m, PACKET_TAG_GRE, mtag)) {
		if (!bcmp((caddr_t)(mtag + 1), &ifp, sizeof(struct ifnet *))) {
			IF_DROP(&ifp->if_snd);
			m_freem(m);
			error = EIO;
			goto end;
		}
	}

	mtag = m_tag_get(PACKET_TAG_GRE, sizeof(struct ifnet *), M_NOWAIT);
	if (mtag == NULL) {
		IF_DROP(&ifp->if_snd);
		m_freem(m);
		error = ENOBUFS;
		goto end;
	}
	bcopy(&ifp, (caddr_t)(mtag + 1), sizeof(struct ifnet *));
	m_tag_prepend(m, mtag);

	m->m_flags &= ~(M_BCAST|M_MCAST);

#if NBPFILTER > 0
	if (ifp->if_bpf)
		bpf_mtap_af(ifp->if_bpf, dst->sa_family, m, BPF_DIRECTION_OUT);
#endif

	if (sc->g_proto == IPPROTO_MOBILE) {
		if (ip_mobile_allow == 0) {
			IF_DROP(&ifp->if_snd);
			m_freem(m);
			error = EACCES;
			goto end;
		}

		if (dst->sa_family == AF_INET) {
			struct mbuf *m0;
			int msiz;

			/*
			 * Make sure the complete IP header (with options)
			 * is in the first mbuf.
			 */
			if (m->m_len < sizeof(struct ip)) {
				m = m_pullup(m, sizeof(struct ip));
				if (m == NULL) {
					IF_DROP(&ifp->if_snd);
					error = ENOBUFS;
					goto end;
				} else
					inp = mtod(m, struct ip *);

				if (m->m_len < inp->ip_hl << 2) {
					m = m_pullup(m, inp->ip_hl << 2);
					if (m == NULL) {
						IF_DROP(&ifp->if_snd);
						error = ENOBUFS;
						goto end;
					}
				}
			}

			inp = mtod(m, struct ip *);

			bzero(&mob_h, MOB_H_SIZ_L);
			mob_h.proto = (inp->ip_p) << 8;
			mob_h.odst = inp->ip_dst.s_addr;
			inp->ip_dst.s_addr = sc->g_dst.s_addr;

			/*
			 * If the packet comes from our host, we only change
			 * the destination address in the IP header.
			 * Otherwise we need to save and change the source.
			 */
			if (inp->ip_src.s_addr == sc->g_src.s_addr) {
				msiz = MOB_H_SIZ_S;
			} else {
				mob_h.proto |= MOB_H_SBIT;
				mob_h.osrc = inp->ip_src.s_addr;
				inp->ip_src.s_addr = sc->g_src.s_addr;
				msiz = MOB_H_SIZ_L;
			}

			HTONS(mob_h.proto);
			mob_h.hcrc = gre_in_cksum((u_int16_t *) &mob_h, msiz);

			/* Squeeze in the mobility header */
			if ((m->m_data - msiz) < m->m_pktdat) {
				/* Need new mbuf */
				MGETHDR(m0, M_DONTWAIT, MT_HEADER);
				if (m0 == NULL) {
					IF_DROP(&ifp->if_snd);
					m_freem(m);
					error = ENOBUFS;
					goto end;
				}
				M_MOVE_HDR(m0, m);

				m0->m_len = msiz + (inp->ip_hl << 2);
				m0->m_data += max_linkhdr;
				m0->m_pkthdr.len = m->m_pkthdr.len + msiz;
				m->m_data += inp->ip_hl << 2;
				m->m_len -= inp->ip_hl << 2;

				bcopy((caddr_t) inp, mtod(m0, caddr_t),
				    sizeof(struct ip));

				m0->m_next = m;
				m = m0;
			} else {  /* we have some space left in the old one */
				m->m_data -= msiz;
				m->m_len += msiz;
				m->m_pkthdr.len += msiz;
				bcopy(inp, mtod(m, caddr_t),
				    inp->ip_hl << 2);
			}

			/* Copy Mobility header */
			inp = mtod(m, struct ip *);
			bcopy(&mob_h, (caddr_t)(inp + 1), (unsigned) msiz);
			inp->ip_len = htons(ntohs(inp->ip_len) + msiz);
		} else {  /* AF_INET */
예제 #7
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);
}
예제 #8
0
파일: if_gif.c 프로젝트: sofuture/bitrig
void
gif_start(struct ifnet *ifp)
{
	struct gif_softc *sc = (struct gif_softc*)ifp;
	struct mbuf *m;
	int s;
	sa_family_t family;

	while (1) {
		s = splnet();
		IFQ_DEQUEUE(&ifp->if_snd, m);
		splx(s);

		if (m == NULL)
			break;

		/* is interface up and usable? */
		if ((ifp->if_flags & (IFF_OACTIVE | IFF_UP)) != IFF_UP ||
		    sc->gif_psrc == NULL || sc->gif_pdst == NULL ||
		    sc->gif_psrc->sa_family != sc->gif_pdst->sa_family) {
			m_freem(m);
			continue;
		}

		/* get tunnel address family */
		family = sc->gif_psrc->sa_family;

		/*
		 * Check if the packet is comming via bridge and needs
		 * etherip encapsulation or not. bridge(4) directly calls
		 * the start function and bypasses the if_output function
		 * so we need to do the encap here.
		 */
		if (ifp->if_bridge && (m->m_flags & M_PROTO1)) {
			int error = 0;
			/*
			 * Remove multicast and broadcast flags or encapsulated
			 * packet ends up as multicast or broadcast packet.
			 */
			m->m_flags &= ~(M_BCAST|M_MCAST);
			switch (sc->gif_psrc->sa_family) {
#ifdef INET
			case AF_INET:
				error = in_gif_output(ifp, AF_LINK, &m);
				break;
#endif
#ifdef INET6
			case AF_INET6:
				error = in6_gif_output(ifp, AF_LINK, &m);
				break;
#endif
			default:
				error = EAFNOSUPPORT;
				m_freem(m);
				break;
			}
			if (error)
				continue;
			if (gif_checkloop(ifp, m))
				continue;
		}

#if NBPFILTER > 0
		if (ifp->if_bpf) {
			int offset;
			sa_family_t family;
			u_int8_t proto;

			/* must decapsulate outer header for bpf */
			switch (sc->gif_psrc->sa_family) {
#ifdef INET
			case AF_INET:
				offset = sizeof(struct ip);
				proto = mtod(m, struct ip *)->ip_p;
				break;
#endif
#ifdef INET6
			case AF_INET6:
				offset = sizeof(struct ip6_hdr);
				proto = mtod(m, struct ip6_hdr *)->ip6_nxt;
				break;
#endif
			default:
				proto = 0;
				break;
			}
			switch (proto) {
			case IPPROTO_IPV4:
				family = AF_INET;
				break;
			case IPPROTO_IPV6:
				family = AF_INET6;
				break;
			case IPPROTO_ETHERIP:
				family = AF_LINK;
				offset += sizeof(struct etherip_header);
				break;
			case IPPROTO_MPLS:
				family = AF_MPLS;
				break;
			default:
				offset = 0;
				family = sc->gif_psrc->sa_family;
				break;
			}
			m->m_data += offset;
			m->m_len -= offset;
			m->m_pkthdr.len -= offset;
			bpf_mtap_af(ifp->if_bpf, family, m, BPF_DIRECTION_OUT);
			m->m_data -= offset;
			m->m_len += offset;
			m->m_pkthdr.len += offset;
		}
#endif
		ifp->if_opackets++;

		/* XXX we should cache the outgoing route */

		switch (sc->gif_psrc->sa_family) {
#ifdef INET
		case AF_INET:
			ip_output(m, (void *)NULL, (void *)NULL, 0,
			    (void *)NULL, (void *)NULL);
			break;
#endif
#ifdef INET6
		case AF_INET6:
			/*
			 * force fragmentation to minimum MTU, to avoid path
			 * MTU discovery. It is too painful to ask for resend
			 * of inner packet, to achieve path MTU discovery for
			 * encapsulated packets.
			 */
			ip6_output(m, 0, NULL, IPV6_MINMTU, 0, NULL,
			     NULL);
			break;
#endif
		default:
			m_freem(m);
			break;
		}
	}
예제 #9
0
int
looutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
    struct rtentry *rt)
{
	int s, isr;
	struct ifqueue *ifq = 0;

	if ((m->m_flags & M_PKTHDR) == 0)
		panic("looutput: no header mbuf");
#if NBPFILTER > 0
	/*
	 * only send packets to bpf if they are real loopback packets;
	 * looutput() is also called for SIMPLEX interfaces to duplicate
	 * packets for local use. But don't dup them to bpf.
	 */
	if (ifp->if_bpf && (ifp->if_flags & IFF_LOOPBACK))
		bpf_mtap_af(ifp->if_bpf, dst->sa_family, m, BPF_DIRECTION_OUT);
#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;
	switch (dst->sa_family) {

#ifdef INET
	case AF_INET:
		ifq = &ipintrq;
		isr = NETISR_IP;
		break;
#endif
#ifdef INET6
	case AF_INET6:
		ifq = &ip6intrq;
		isr = NETISR_IPV6;
		break;
#endif /* INET6 */
#ifdef MPLS
	case AF_MPLS:
		ifq = &mplsintrq;
		isr = NETISR_MPLS;
		break;
#endif /* MPLS */
	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);
}
예제 #10
0
/*
 * tun_output - queue packets from higher level ready to put out.
 */
static int
tun_output(struct ifnet *ifp, struct mbuf *m0, const struct sockaddr *dst,
    struct rtentry *rt)
{
	struct tun_softc *tp = ifp->if_softc;
	int		s;
	int		error;
#if defined(INET) || defined(INET6)
	int		mlen;
	uint32_t	*af;
#endif

	s = splnet();
	mutex_enter(&tp->tun_lock);
	TUNDEBUG ("%s: tun_output\n", ifp->if_xname);

	if ((tp->tun_flags & TUN_READY) != TUN_READY) {
		TUNDEBUG ("%s: not ready 0%o\n", ifp->if_xname,
			  tp->tun_flags);
		error = EHOSTDOWN;
		goto out;
	}

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

	bpf_mtap_af(ifp, dst->sa_family, m0);

	switch(dst->sa_family) {
#ifdef INET6
	case AF_INET6:
#endif
#ifdef INET
	case AF_INET:
#endif
#if defined(INET) || defined(INET6)
		if (tp->tun_flags & TUN_PREPADDR) {
			/* Simple link-layer header */
			M_PREPEND(m0, dst->sa_len, M_DONTWAIT);
			if (m0 == NULL) {
				IF_DROP(&ifp->if_snd);
				error = ENOBUFS;
				goto out;
			}
			bcopy(dst, mtod(m0, char *), dst->sa_len);
		}

		if (tp->tun_flags & TUN_IFHEAD) {
			/* Prepend the address family */
			M_PREPEND(m0, sizeof(*af), M_DONTWAIT);
			if (m0 == NULL) {
				IF_DROP(&ifp->if_snd);
				error = ENOBUFS;
				goto out;
			}
			af = mtod(m0,uint32_t *);
			*af = htonl(dst->sa_family);
		} else {