Esempio n. 1
0
/*
 * FDDI output routine.
 * Encapsulate a packet of type family for the local net.
 * Use trailer local net encapsulation if enough data in first
 * packet leaves a multiple of 512 bytes of data in remainder.
 * Assumes that ifp is actually pointer to arpcom structure.
 */
static int
fddi_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
	struct route *ro)
{
	u_int16_t type;
	int loop_copy = 0, error = 0, hdrcmplt = 0;
 	u_char esrc[FDDI_ADDR_LEN], edst[FDDI_ADDR_LEN];
	struct fddi_header *fh;
#if defined(INET) || defined(INET6)
	struct llentry *lle;
#endif

#ifdef MAC
	error = mac_ifnet_check_transmit(ifp, m);
	if (error)
		senderr(error);
#endif

	if (ifp->if_flags & IFF_MONITOR)
		senderr(ENETDOWN);
	if (!((ifp->if_flags & IFF_UP) &&
	    (ifp->if_drv_flags & IFF_DRV_RUNNING)))
		senderr(ENETDOWN);
	getmicrotime(&ifp->if_lastchange);

	switch (dst->sa_family) {
#ifdef INET
	case AF_INET: {
		struct rtentry *rt0 = NULL;

		if (ro != NULL)
			rt0 = ro->ro_rt;
		error = arpresolve(ifp, rt0, m, dst, edst, &lle);
		if (error)
			return (error == EWOULDBLOCK ? 0 : error);
		type = htons(ETHERTYPE_IP);
		break;
	}
	case AF_ARP:
	{
		struct arphdr *ah;
		ah = mtod(m, struct arphdr *);
		ah->ar_hrd = htons(ARPHRD_ETHER);

		loop_copy = -1; /* if this is for us, don't do it */

		switch (ntohs(ah->ar_op)) {
		case ARPOP_REVREQUEST:
		case ARPOP_REVREPLY:
			type = htons(ETHERTYPE_REVARP);
			break;
		case ARPOP_REQUEST:
		case ARPOP_REPLY:
		default:
			type = htons(ETHERTYPE_ARP);
			break;
		}

		if (m->m_flags & M_BCAST)
			bcopy(ifp->if_broadcastaddr, edst, FDDI_ADDR_LEN);
                else
			bcopy(ar_tha(ah), edst, FDDI_ADDR_LEN);

	}
	break;
#endif /* INET */
#ifdef INET6
	case AF_INET6:
		error = nd6_storelladdr(ifp, m, dst, (u_char *)edst, &lle);
		if (error)
			return (error); /* Something bad happened */
		type = htons(ETHERTYPE_IPV6);
		break;
#endif /* INET6 */
#ifdef IPX
	case AF_IPX:
		type = htons(ETHERTYPE_IPX);
 		bcopy(&((const struct sockaddr_ipx *)dst)->sipx_addr.x_host,
		    edst, FDDI_ADDR_LEN);
		break;
#endif /* IPX */
#ifdef NETATALK
	case AF_APPLETALK: {
	    struct at_ifaddr *aa;
            if (!aarpresolve(ifp, m, (const struct sockaddr_at *)dst, edst))
                return (0);
	    /*
	     * ifaddr is the first thing in at_ifaddr
	     */
	    if ((aa = at_ifawithnet((const struct sockaddr_at *)dst)) == 0)
		goto bad;
	    
	    /*
	     * In the phase 2 case, we need to prepend an mbuf for the llc header.
	     * Since we must preserve the value of m, which is passed to us by
	     * value, we m_copy() the first mbuf, and use it for our llc header.
	     */
	    if (aa->aa_flags & AFA_PHASE2) {
		struct llc llc;

		M_PREPEND(m, LLC_SNAPFRAMELEN, M_WAITOK);
		llc.llc_dsap = llc.llc_ssap = LLC_SNAP_LSAP;
		llc.llc_control = LLC_UI;
		bcopy(at_org_code, llc.llc_snap.org_code, sizeof(at_org_code));
		llc.llc_snap.ether_type = htons(ETHERTYPE_AT);
		bcopy(&llc, mtod(m, caddr_t), LLC_SNAPFRAMELEN);
		type = 0;
	    } else {
		type = htons(ETHERTYPE_AT);
	    }
	    ifa_free(&aa->aa_ifa);
	    break;
	}
#endif /* NETATALK */

	case pseudo_AF_HDRCMPLT:
	{
		const struct ether_header *eh;

		hdrcmplt = 1;
		eh = (const struct ether_header *)dst->sa_data;
		bcopy(eh->ether_shost, esrc, FDDI_ADDR_LEN);
		/* FALLTHROUGH */
	}

	case AF_UNSPEC:
	{
		const struct ether_header *eh;

		loop_copy = -1;
		eh = (const struct ether_header *)dst->sa_data;
		bcopy(eh->ether_dhost, edst, FDDI_ADDR_LEN);
		if (*edst & 1)
			m->m_flags |= (M_BCAST|M_MCAST);
		type = eh->ether_type;
		break;
	}

	case AF_IMPLINK:
	{
		fh = mtod(m, struct fddi_header *);
		error = EPROTONOSUPPORT;
		switch (fh->fddi_fc & (FDDIFC_C|FDDIFC_L|FDDIFC_F)) {
			case FDDIFC_LLC_ASYNC: {
				/* legal priorities are 0 through 7 */
				if ((fh->fddi_fc & FDDIFC_Z) > 7)
			        	goto bad;
				break;
			}
			case FDDIFC_LLC_SYNC: {
				/* FDDIFC_Z bits reserved, must be zero */
				if (fh->fddi_fc & FDDIFC_Z)
					goto bad;
				break;
			}
			case FDDIFC_SMT: {
				/* FDDIFC_Z bits must be non zero */
				if ((fh->fddi_fc & FDDIFC_Z) == 0)
					goto bad;
				break;
			}
			default: {
				/* anything else is too dangerous */
               	 		goto bad;
			}
		}
		error = 0;
		if (fh->fddi_dhost[0] & 1)
			m->m_flags |= (M_BCAST|M_MCAST);
		goto queue_it;
	}
	default:
		if_printf(ifp, "can't handle af%d\n", dst->sa_family);
		senderr(EAFNOSUPPORT);
	}

	/*
	 * Add LLC header.
	 */
	if (type != 0) {
		struct llc *l;
		M_PREPEND(m, LLC_SNAPFRAMELEN, M_NOWAIT);
		if (m == 0)
			senderr(ENOBUFS);
		l = mtod(m, struct llc *);
		l->llc_control = LLC_UI;
		l->llc_dsap = l->llc_ssap = LLC_SNAP_LSAP;
		l->llc_snap.org_code[0] =
			l->llc_snap.org_code[1] =
			l->llc_snap.org_code[2] = 0;
		l->llc_snap.ether_type = htons(type);
	}

	/*
	 * Add local net header.  If no space in first mbuf,
	 * allocate another.
	 */
	M_PREPEND(m, FDDI_HDR_LEN, M_NOWAIT);
	if (m == 0)
		senderr(ENOBUFS);
	fh = mtod(m, struct fddi_header *);
	fh->fddi_fc = FDDIFC_LLC_ASYNC|FDDIFC_LLC_PRIO4;
	bcopy((caddr_t)edst, (caddr_t)fh->fddi_dhost, FDDI_ADDR_LEN);
  queue_it:
	if (hdrcmplt)
		bcopy((caddr_t)esrc, (caddr_t)fh->fddi_shost, FDDI_ADDR_LEN);
	else
		bcopy(IF_LLADDR(ifp), (caddr_t)fh->fddi_shost,
			FDDI_ADDR_LEN);

	/*
	 * If a simplex interface, and the packet is being sent to our
	 * Ethernet address or a broadcast address, loopback a copy.
	 * XXX To make a simplex device behave exactly like a duplex
	 * device, we should copy in the case of sending to our own
	 * ethernet address (thus letting the original actually appear
	 * on the wire). However, we don't do that here for security
	 * reasons and compatibility with the original behavior.
	 */
	if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) {
		if ((m->m_flags & M_BCAST) || (loop_copy > 0)) {
			struct mbuf *n;
			n = m_copy(m, 0, (int)M_COPYALL);
			(void) if_simloop(ifp, n, dst->sa_family,
					  FDDI_HDR_LEN);
	     	} else if (bcmp(fh->fddi_dhost, fh->fddi_shost,
				FDDI_ADDR_LEN) == 0) {
			(void) if_simloop(ifp, m, dst->sa_family,
					  FDDI_HDR_LEN);
			return (0);	/* XXX */
		}
	}

	error = (ifp->if_transmit)(ifp, m);
	if (error)
		ifp->if_oerrors++;

	return (error);

bad:
	ifp->if_oerrors++;
	if (m)
		m_freem(m);
	return (error);
}
Esempio n. 2
0
/*
 * Ethernet output routine.
 * Encapsulate a packet of type family for the local net.
 * Use trailer local net encapsulation if enough data in first
 * packet leaves a multiple of 512 bytes of data in remainder.
 */
int
ether_output(struct ifnet *ifp, struct mbuf *m,
	const struct sockaddr *dst, struct route *ro)
{
	short type;
	int error = 0, hdrcmplt = 0;
	u_char esrc[ETHER_ADDR_LEN], edst[ETHER_ADDR_LEN];
	struct llentry *lle = NULL;
	struct rtentry *rt0 = NULL;
	struct ether_header *eh;
	struct pf_mtag *t;
	int loop_copy = 1;
	int hlen;	/* link layer header length */

	if (ro != NULL) {
		if (!(m->m_flags & (M_BCAST | M_MCAST)))
			lle = ro->ro_lle;
		rt0 = ro->ro_rt;
	}
#ifdef MAC
	error = mac_ifnet_check_transmit(ifp, m);
	if (error)
		senderr(error);
#endif

	M_PROFILE(m);
	if (ifp->if_flags & IFF_MONITOR)
		senderr(ENETDOWN);
	if (!((ifp->if_flags & IFF_UP) &&
	    (ifp->if_drv_flags & IFF_DRV_RUNNING)))
		senderr(ENETDOWN);

	hlen = ETHER_HDR_LEN;
	switch (dst->sa_family) {
#ifdef INET
	case AF_INET:
		if (lle != NULL && (lle->la_flags & LLE_VALID))
			memcpy(edst, &lle->ll_addr.mac16, sizeof(edst));
		else
			error = arpresolve(ifp, rt0, m, dst, edst, &lle);
		if (error)
			return (error == EWOULDBLOCK ? 0 : error);
		type = htons(ETHERTYPE_IP);
		break;
	case AF_ARP:
	{
		struct arphdr *ah;
		ah = mtod(m, struct arphdr *);
		ah->ar_hrd = htons(ARPHRD_ETHER);

		loop_copy = 0; /* if this is for us, don't do it */

		switch(ntohs(ah->ar_op)) {
		case ARPOP_REVREQUEST:
		case ARPOP_REVREPLY:
			type = htons(ETHERTYPE_REVARP);
			break;
		case ARPOP_REQUEST:
		case ARPOP_REPLY:
		default:
			type = htons(ETHERTYPE_ARP);
			break;
		}

		if (m->m_flags & M_BCAST)
			bcopy(ifp->if_broadcastaddr, edst, ETHER_ADDR_LEN);
		else
			bcopy(ar_tha(ah), edst, ETHER_ADDR_LEN);

	}
	break;
#endif
#ifdef INET6
	case AF_INET6:
		if (lle != NULL && (lle->la_flags & LLE_VALID))
			memcpy(edst, &lle->ll_addr.mac16, sizeof(edst));
		else
			error = nd6_storelladdr(ifp, m, dst, (u_char *)edst, &lle);
		if (error)
			return error;
		type = htons(ETHERTYPE_IPV6);
		break;
#endif
#ifdef IPX
	case AF_IPX:
		if (ef_outputp) {
		    error = ef_outputp(ifp, &m, dst, &type, &hlen);
		    if (error)
			goto bad;
		} else
		    type = htons(ETHERTYPE_IPX);
		bcopy(&((const struct sockaddr_ipx *)dst)->sipx_addr.x_host,
		    edst, sizeof (edst));
		break;
#endif
#ifdef NETATALK
	case AF_APPLETALK:
	  {
	    struct at_ifaddr *aa;

	    if ((aa = at_ifawithnet((const struct sockaddr_at *)dst)) == NULL)
		    senderr(EHOSTUNREACH); /* XXX */
	    if (!aarpresolve(ifp, m, (const struct sockaddr_at *)dst, edst)) {
		    ifa_free(&aa->aa_ifa);
		    return (0);
	    }
	    /*
	     * In the phase 2 case, need to prepend an mbuf for the llc header.
	     */
	    if ( aa->aa_flags & AFA_PHASE2 ) {
		struct llc llc;

		ifa_free(&aa->aa_ifa);
		M_PREPEND(m, LLC_SNAPFRAMELEN, M_NOWAIT);
		if (m == NULL)
			senderr(ENOBUFS);
		llc.llc_dsap = llc.llc_ssap = LLC_SNAP_LSAP;
		llc.llc_control = LLC_UI;
		bcopy(at_org_code, llc.llc_snap_org_code, sizeof(at_org_code));
		llc.llc_snap_ether_type = htons( ETHERTYPE_AT );
		bcopy(&llc, mtod(m, caddr_t), LLC_SNAPFRAMELEN);
		type = htons(m->m_pkthdr.len);
		hlen = LLC_SNAPFRAMELEN + ETHER_HDR_LEN;
	    } else {
		ifa_free(&aa->aa_ifa);
		type = htons(ETHERTYPE_AT);
	    }
	    break;
	  }
#endif /* NETATALK */

	case pseudo_AF_HDRCMPLT:
	    {
		const struct ether_header *eh;
		
		hdrcmplt = 1;
		eh = (const struct ether_header *)dst->sa_data;
		(void)memcpy(esrc, eh->ether_shost, sizeof (esrc));
		/* FALLTHROUGH */

	case AF_UNSPEC:
		loop_copy = 0; /* if this is for us, don't do it */
		eh = (const struct ether_header *)dst->sa_data;
		(void)memcpy(edst, eh->ether_dhost, sizeof (edst));
		type = eh->ether_type;
		break;
            }	
#ifdef MPLS
	case AF_MPLS:
		if (lle != NULL && (lle->la_flags & LLE_VALID))
			bcopy(&lle->ll_addr.mac16 , edst, sizeof(edst));
		else 
			error = mpls_arpresolve(ifp, rt0, m, dst, edst, &lle);
		if (error)
			return (error == EWOULDBLOCK ? 0 : error);
		
		if (m->m_flags & (M_BCAST | M_MCAST))
			type = htons(ETHERTYPE_MPLS_MCAST);
		else
			type = htons(ETHERTYPE_MPLS);				
		break;
#endif /* MPLS */	
	default:
		if_printf(ifp, "can't handle af%d\n", dst->sa_family);
		senderr(EAFNOSUPPORT);
	}

	if (lle != NULL && (lle->la_flags & LLE_IFADDR)) {
		update_mbuf_csumflags(m, m);
		return (if_simloop(ifp, m, dst->sa_family, 0));
	}

	/*
	 * Add local net header.  If no space in first mbuf,
	 * allocate another.
	 */
	M_PREPEND(m, ETHER_HDR_LEN, M_NOWAIT);
	if (m == NULL)
		senderr(ENOBUFS);
	eh = mtod(m, struct ether_header *);
	(void)memcpy(&eh->ether_type, &type,
		sizeof(eh->ether_type));
	(void)memcpy(eh->ether_dhost, edst, sizeof (edst));
	if (hdrcmplt)
		(void)memcpy(eh->ether_shost, esrc,
			sizeof(eh->ether_shost));
	else
		(void)memcpy(eh->ether_shost, IF_LLADDR(ifp),
			sizeof(eh->ether_shost));

	/*
	 * If a simplex interface, and the packet is being sent to our
	 * Ethernet address or a broadcast address, loopback a copy.
	 * XXX To make a simplex device behave exactly like a duplex
	 * device, we should copy in the case of sending to our own
	 * ethernet address (thus letting the original actually appear
	 * on the wire). However, we don't do that here for security
	 * reasons and compatibility with the original behavior.
	 */
	if ((ifp->if_flags & IFF_SIMPLEX) && loop_copy &&
	    ((t = pf_find_mtag(m)) == NULL || !t->routed)) {
		if (m->m_flags & M_BCAST) {
			struct mbuf *n;

			/*
			 * Because if_simloop() modifies the packet, we need a
			 * writable copy through m_dup() instead of a readonly
			 * one as m_copy[m] would give us. The alternative would
			 * be to modify if_simloop() to handle the readonly mbuf,
			 * but performancewise it is mostly equivalent (trading
			 * extra data copying vs. extra locking).
			 *
			 * XXX This is a local workaround.  A number of less
			 * often used kernel parts suffer from the same bug.
			 * See PR kern/105943 for a proposed general solution.
			 */
			if ((n = m_dup(m, M_NOWAIT)) != NULL) {
				update_mbuf_csumflags(m, n);
				(void)if_simloop(ifp, n, dst->sa_family, hlen);
			} else
				ifp->if_iqdrops++;
		} else if (bcmp(eh->ether_dhost, eh->ether_shost,
				ETHER_ADDR_LEN) == 0) {
			update_mbuf_csumflags(m, m);
			(void) if_simloop(ifp, m, dst->sa_family, hlen);
			return (0);	/* XXX */
		}
	}

   /*
	* Bridges require special output handling.
	*/
	if (ifp->if_bridge) {
		BRIDGE_OUTPUT(ifp, m, error);
		return (error);
	}

#if defined(INET) || defined(INET6)
	if (ifp->if_carp &&
	    (error = (*carp_output_p)(ifp, m, dst)))
		goto bad;
#endif

	/* Handle ng_ether(4) processing, if any */
	if (IFP2AC(ifp)->ac_netgraph != NULL) {
		KASSERT(ng_ether_output_p != NULL,
		    ("ng_ether_output_p is NULL"));
		if ((error = (*ng_ether_output_p)(ifp, &m)) != 0) {
bad:			if (m != NULL)
				m_freem(m);
			return (error);
		}
		if (m == NULL)
			return (0);
	}

	/* Continue with link-layer output */
	return ether_output_frame(ifp, m);
}
Esempio n. 3
0
/*
 * Ethernet output routine.
 * Encapsulate a packet of type family for the local net.
 * Use trailer local net encapsulation if enough data in first
 * packet leaves a multiple of 512 bytes of data in remainder.
 */
int
ether_output(struct ifnet *ifp, struct mbuf *m,
	const struct sockaddr *dst, struct route *ro)
{
	short type;
	int error = 0, hdrcmplt = 0;
	u_char edst[ETHER_ADDR_LEN];
	struct llentry *lle = NULL;
	struct rtentry *rt0 = NULL;
	struct ether_header *eh;
	struct pf_mtag *t;
	int loop_copy = 1;
	int hlen;	/* link layer header length */
	int is_gw = 0;
	uint32_t pflags = 0;

	if (ro != NULL) {
		if (!(m->m_flags & (M_BCAST | M_MCAST))) {
			lle = ro->ro_lle;
			if (lle != NULL)
				pflags = lle->la_flags;
		}
		rt0 = ro->ro_rt;
		if (rt0 != NULL && (rt0->rt_flags & RTF_GATEWAY) != 0)
			is_gw = 1;
	}
#ifdef MAC
	error = mac_ifnet_check_transmit(ifp, m);
	if (error)
		senderr(error);
#endif

	M_PROFILE(m);
	if (ifp->if_flags & IFF_MONITOR)
		senderr(ENETDOWN);
	if (!((ifp->if_flags & IFF_UP) &&
	    (ifp->if_drv_flags & IFF_DRV_RUNNING)))
		senderr(ENETDOWN);

	hlen = ETHER_HDR_LEN;
	switch (dst->sa_family) {
#ifdef INET
	case AF_INET:
		if (lle != NULL && (pflags & LLE_VALID) != 0)
			memcpy(edst, &lle->ll_addr.mac16, sizeof(edst));
		else
			error = arpresolve(ifp, is_gw, m, dst, edst, &pflags);
		if (error)
			return (error == EWOULDBLOCK ? 0 : error);
		type = htons(ETHERTYPE_IP);
		break;
	case AF_ARP:
	{
		struct arphdr *ah;
		ah = mtod(m, struct arphdr *);
		ah->ar_hrd = htons(ARPHRD_ETHER);

		loop_copy = 0; /* if this is for us, don't do it */

		switch(ntohs(ah->ar_op)) {
		case ARPOP_REVREQUEST:
		case ARPOP_REVREPLY:
			type = htons(ETHERTYPE_REVARP);
			break;
		case ARPOP_REQUEST:
		case ARPOP_REPLY:
		default:
			type = htons(ETHERTYPE_ARP);
			break;
		}

		if (m->m_flags & M_BCAST)
			bcopy(ifp->if_broadcastaddr, edst, ETHER_ADDR_LEN);
		else
			bcopy(ar_tha(ah), edst, ETHER_ADDR_LEN);

	}
	break;
#endif
#ifdef INET6
	case AF_INET6:
		if (lle != NULL && (pflags & LLE_VALID))
			memcpy(edst, &lle->ll_addr.mac16, sizeof(edst));
		else
			error = nd6_resolve(ifp, is_gw, m, dst, (u_char *)edst,
			    &pflags);
		if (error)
			return (error == EWOULDBLOCK ? 0 : error);
		type = htons(ETHERTYPE_IPV6);
		break;
#endif
	case pseudo_AF_HDRCMPLT:
	    {
		const struct ether_header *eh;

		hdrcmplt = 1;
		/* FALLTHROUGH */

	case AF_UNSPEC:
		loop_copy = 0; /* if this is for us, don't do it */
		eh = (const struct ether_header *)dst->sa_data;
		(void)memcpy(edst, eh->ether_dhost, sizeof (edst));
		type = eh->ether_type;
		break;
            }
	default:
		if_printf(ifp, "can't handle af%d\n", dst->sa_family);
		senderr(EAFNOSUPPORT);
	}

	if ((pflags & LLE_IFADDR) != 0) {
		update_mbuf_csumflags(m, m);
		return (if_simloop(ifp, m, dst->sa_family, 0));
	}

	/*
	 * Add local net header.  If no space in first mbuf,
	 * allocate another.
	 */
	M_PREPEND(m, ETHER_HDR_LEN, M_NOWAIT);
	if (m == NULL)
		senderr(ENOBUFS);
	eh = mtod(m, struct ether_header *);
	if (hdrcmplt == 0) {
		memcpy(&eh->ether_type, &type, sizeof(eh->ether_type));
		memcpy(eh->ether_dhost, edst, sizeof (edst));
		memcpy(eh->ether_shost, IF_LLADDR(ifp),sizeof(eh->ether_shost));
	}

	/*
	 * If a simplex interface, and the packet is being sent to our
	 * Ethernet address or a broadcast address, loopback a copy.
	 * XXX To make a simplex device behave exactly like a duplex
	 * device, we should copy in the case of sending to our own
	 * ethernet address (thus letting the original actually appear
	 * on the wire). However, we don't do that here for security
	 * reasons and compatibility with the original behavior.
	 */
	if ((ifp->if_flags & IFF_SIMPLEX) && loop_copy &&
	    ((t = pf_find_mtag(m)) == NULL || !t->routed)) {
		if (m->m_flags & M_BCAST) {
			struct mbuf *n;

			/*
			 * Because if_simloop() modifies the packet, we need a
			 * writable copy through m_dup() instead of a readonly
			 * one as m_copy[m] would give us. The alternative would
			 * be to modify if_simloop() to handle the readonly mbuf,
			 * but performancewise it is mostly equivalent (trading
			 * extra data copying vs. extra locking).
			 *
			 * XXX This is a local workaround.  A number of less
			 * often used kernel parts suffer from the same bug.
			 * See PR kern/105943 for a proposed general solution.
			 */
			if ((n = m_dup(m, M_NOWAIT)) != NULL) {
				update_mbuf_csumflags(m, n);
				(void)if_simloop(ifp, n, dst->sa_family, hlen);
			} else
				if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
		} else if (bcmp(eh->ether_dhost, eh->ether_shost,
				ETHER_ADDR_LEN) == 0) {
			update_mbuf_csumflags(m, m);
			(void) if_simloop(ifp, m, dst->sa_family, hlen);
			return (0);	/* XXX */
		}
	}

       /*
	* Bridges require special output handling.
	*/
	if (ifp->if_bridge) {
		BRIDGE_OUTPUT(ifp, m, error);
		return (error);
	}

#if defined(INET) || defined(INET6)
	if (ifp->if_carp &&
	    (error = (*carp_output_p)(ifp, m, dst)))
		goto bad;
#endif

	/* Handle ng_ether(4) processing, if any */
	if (ifp->if_l2com != NULL) {
		KASSERT(ng_ether_output_p != NULL,
		    ("ng_ether_output_p is NULL"));
		if ((error = (*ng_ether_output_p)(ifp, &m)) != 0) {
bad:			if (m != NULL)
				m_freem(m);
			return (error);
		}
		if (m == NULL)
			return (0);
	}

	/* Continue with link-layer output */
	return ether_output_frame(ifp, m);
}
Esempio n. 4
0
static int
firewire_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
    struct route *ro)
{
	struct fw_com *fc = IFP2FWC(ifp);
	int error, type;
	struct m_tag *mtag;
	union fw_encap *enc;
	struct fw_hwaddr *destfw;
	uint8_t speed;
	uint16_t psize, fsize, dsize;
	struct mbuf *mtail;
	int unicast, dgl, foff;
	static int next_dgl;
#if defined(INET) || defined(INET6)
	struct llentry *lle;
#endif

#ifdef MAC
	error = mac_ifnet_check_transmit(ifp, m);
	if (error)
		goto bad;
#endif

	if (!((ifp->if_flags & IFF_UP) &&
	   (ifp->if_drv_flags & IFF_DRV_RUNNING))) {
		error = ENETDOWN;
		goto bad;
	}

	/*
	 * For unicast, we make a tag to store the lladdr of the
	 * destination. This might not be the first time we have seen
	 * the packet (for instance, the arp code might be trying to
	 * re-send it after receiving an arp reply) so we only
	 * allocate a tag if there isn't one there already. For
	 * multicast, we will eventually use a different tag to store
	 * the channel number.
	 */
	unicast = !(m->m_flags & (M_BCAST | M_MCAST));
	if (unicast) {
		mtag = m_tag_locate(m, MTAG_FIREWIRE, MTAG_FIREWIRE_HWADDR, NULL);
		if (!mtag) {
			mtag = m_tag_alloc(MTAG_FIREWIRE, MTAG_FIREWIRE_HWADDR,
			    sizeof (struct fw_hwaddr), M_NOWAIT);
			if (!mtag) {
				error = ENOMEM;
				goto bad;
			}
			m_tag_prepend(m, mtag);
		}
		destfw = (struct fw_hwaddr *)(mtag + 1);
	} else {
		destfw = 0;
	}

	switch (dst->sa_family) {
#ifdef INET
	case AF_INET:
		/*
		 * Only bother with arp for unicast. Allocation of
		 * channels etc. for firewire is quite different and
		 * doesn't fit into the arp model.
		 */
		if (unicast) {
			error = arpresolve(ifp, ro ? ro->ro_rt : NULL, m, dst, (u_char *) destfw, &lle);
			if (error)
				return (error == EWOULDBLOCK ? 0 : error);
		}
		type = ETHERTYPE_IP;
		break;

	case AF_ARP:
	{
		struct arphdr *ah;
		ah = mtod(m, struct arphdr *);
		ah->ar_hrd = htons(ARPHRD_IEEE1394);
		type = ETHERTYPE_ARP;
		if (unicast)
			*destfw = *(struct fw_hwaddr *) ar_tha(ah);

		/*
		 * The standard arp code leaves a hole for the target
		 * hardware address which we need to close up.
		 */
		bcopy(ar_tpa(ah), ar_tha(ah), ah->ar_pln);
		m_adj(m, -ah->ar_hln);
		break;
	}
#endif

#ifdef INET6
	case AF_INET6:
		if (unicast) {
			error = nd6_storelladdr(fc->fc_ifp, m, dst,
			    (u_char *) destfw, &lle);
			if (error)
				return (error);
		}
		type = ETHERTYPE_IPV6;
		break;
#endif

	default:
		if_printf(ifp, "can't handle af%d\n", dst->sa_family);
		error = EAFNOSUPPORT;
		goto bad;
	}

	/*
	 * Let BPF tap off a copy before we encapsulate.
	 */
	if (bpf_peers_present(ifp->if_bpf)) {
		struct fw_bpfhdr h;
		if (unicast)
			bcopy(destfw, h.firewire_dhost, 8);
		else
			bcopy(&firewire_broadcastaddr, h.firewire_dhost, 8);
		bcopy(&fc->fc_hwaddr, h.firewire_shost, 8);
		h.firewire_type = htons(type);
		bpf_mtap2(ifp->if_bpf, &h, sizeof(h), m);
	}

	/*
	 * Punt on MCAP for now and send all multicast packets on the
	 * broadcast channel.
	 */
	if (m->m_flags & M_MCAST)
		m->m_flags |= M_BCAST;

	/*
	 * Figure out what speed to use and what the largest supported
	 * packet size is. For unicast, this is the minimum of what we
	 * can speak and what they can hear. For broadcast, lets be
	 * conservative and use S100. We could possibly improve that
	 * by examining the bus manager's speed map or similar. We
	 * also reduce the packet size for broadcast to account for
	 * the GASP header.
	 */
	if (unicast) {
		speed = min(fc->fc_speed, destfw->sspd);
		psize = min(512 << speed, 2 << destfw->sender_max_rec);
	} else {
		speed = 0;
		psize = 512 - 2*sizeof(uint32_t);
	}

	/*
	 * Next, we encapsulate, possibly fragmenting the original
	 * datagram if it won't fit into a single packet.
	 */
	if (m->m_pkthdr.len <= psize - sizeof(uint32_t)) {
		/*
		 * No fragmentation is necessary.
		 */
		M_PREPEND(m, sizeof(uint32_t), M_NOWAIT);
		if (!m) {
			error = ENOBUFS;
			goto bad;
		}
		enc = mtod(m, union fw_encap *);
		enc->unfrag.ether_type = type;
		enc->unfrag.lf = FW_ENCAP_UNFRAG;
		enc->unfrag.reserved = 0;

		/*
		 * Byte swap the encapsulation header manually.
		 */
		enc->ul[0] = htonl(enc->ul[0]);

		error = (ifp->if_transmit)(ifp, m);
		return (error);
	} else {
Esempio n. 5
0
/*
 * Ethernet output routine.
 * Encapsulate a packet of type family for the local net.
 * Use trailer local net encapsulation if enough data in first
 * packet leaves a multiple of 512 bytes of data in remainder.
 */
int
ether_output(struct ifnet *ifp, struct mbuf *m,
	const struct sockaddr *dst, struct route *ro)
{
	int error = 0;
	char linkhdr[ETHER_HDR_LEN], *phdr;
	struct ether_header *eh;
	struct pf_mtag *t;
	int loop_copy = 1;
	int hlen;	/* link layer header length */
	uint32_t pflags;
	struct llentry *lle = NULL;
	struct rtentry *rt0 = NULL;
	int addref = 0;

	phdr = NULL;
	pflags = 0;
	if (ro != NULL) {
		/* XXX BPF uses ro_prepend */
		if (ro->ro_prepend != NULL) {
			phdr = ro->ro_prepend;
			hlen = ro->ro_plen;
		} else if (!(m->m_flags & (M_BCAST | M_MCAST))) {
			if ((ro->ro_flags & RT_LLE_CACHE) != 0) {
				lle = ro->ro_lle;
				if (lle != NULL &&
				    (lle->la_flags & LLE_VALID) == 0) {
					LLE_FREE(lle);
					lle = NULL;	/* redundant */
					ro->ro_lle = NULL;
				}
				if (lle == NULL) {
					/* if we lookup, keep cache */
					addref = 1;
				}
			}
			if (lle != NULL) {
				phdr = lle->r_linkdata;
				hlen = lle->r_hdrlen;
				pflags = lle->r_flags;
			}
		}
		rt0 = ro->ro_rt;
	}

#ifdef MAC
	error = mac_ifnet_check_transmit(ifp, m);
	if (error)
		senderr(error);
#endif

	M_PROFILE(m);
	if (ifp->if_flags & IFF_MONITOR)
		senderr(ENETDOWN);
	if (!((ifp->if_flags & IFF_UP) &&
	    (ifp->if_drv_flags & IFF_DRV_RUNNING)))
		senderr(ENETDOWN);

	if (phdr == NULL) {
		/* No prepend data supplied. Try to calculate ourselves. */
		phdr = linkhdr;
		hlen = ETHER_HDR_LEN;
		error = ether_resolve_addr(ifp, m, dst, ro, phdr, &pflags,
		    addref ? &lle : NULL);
		if (addref && lle != NULL)
			ro->ro_lle = lle;
		if (error != 0)
			return (error == EWOULDBLOCK ? 0 : error);
	}

	if ((pflags & RT_L2_ME) != 0) {
		update_mbuf_csumflags(m, m);
		return (if_simloop(ifp, m, dst->sa_family, 0));
	}
	loop_copy = pflags & RT_MAY_LOOP;

	/*
	 * Add local net header.  If no space in first mbuf,
	 * allocate another.
	 *
	 * Note that we do prepend regardless of RT_HAS_HEADER flag.
	 * This is done because BPF code shifts m_data pointer
	 * to the end of ethernet header prior to calling if_output().
	 */
	M_PREPEND(m, hlen, M_NOWAIT);
	if (m == NULL)
		senderr(ENOBUFS);
	if ((pflags & RT_HAS_HEADER) == 0) {
		eh = mtod(m, struct ether_header *);
		memcpy(eh, phdr, hlen);
	}
Esempio n. 6
0
/*
 * atm_output: ATM output routine
 *   inputs:
 *     "ifp" = ATM interface to output to
 *     "m0" = the packet to output
 *     "dst" = the sockaddr to send to (either IP addr, or raw VPI/VCI)
 *     "ro" = the route to use
 *   returns: error code   [0 == ok]
 *
 *   note: special semantic: if (dst == NULL) then we assume "m" already
 *		has an atm_pseudohdr on it and just send it directly.
 *		[for native mode ATM output]   if dst is null, then
 *		ro->ro_rt must also be NULL.
 */
int
atm_output(struct ifnet *ifp, struct mbuf *m0, struct sockaddr *dst,
    struct route *ro)
{
	u_int16_t etype = 0;			/* if using LLC/SNAP */
	int error = 0, sz;
	struct atm_pseudohdr atmdst, *ad;
	struct mbuf *m = m0;
	struct atmllc *atmllc;
	struct atmllc *llc_hdr = NULL;
	u_int32_t atm_flags;

#ifdef MAC
	error = mac_ifnet_check_transmit(ifp, m);
	if (error)
		senderr(error);
#endif

	if (!((ifp->if_flags & IFF_UP) &&
	    (ifp->if_drv_flags & IFF_DRV_RUNNING)))
		senderr(ENETDOWN);

	/*
	 * check for non-native ATM traffic   (dst != NULL)
	 */
	if (dst) {
		switch (dst->sa_family) {

#if defined(INET) || defined(INET6)
		case AF_INET:
		case AF_INET6:
		{
			if (dst->sa_family == AF_INET6)
			        etype = ETHERTYPE_IPV6;
			else
			        etype = ETHERTYPE_IP;
			if (!atmresolve(ro->ro_rt, m, dst, &atmdst)) {
				m = NULL; 
				/* XXX: atmresolve already free'd it */
				senderr(EHOSTUNREACH);
				/* XXX: put ATMARP stuff here */
				/* XXX: watch who frees m on failure */
			}
		}
			break;
#endif /* INET || INET6 */

		case AF_UNSPEC:
			/*
			 * XXX: bpfwrite. assuming dst contains 12 bytes
			 * (atm pseudo header (4) + LLC/SNAP (8))
			 */
			bcopy(dst->sa_data, &atmdst, sizeof(atmdst));
			llc_hdr = (struct atmllc *)(dst->sa_data +
			    sizeof(atmdst));
			break;
			
		default:
			printf("%s: can't handle af%d\n", ifp->if_xname, 
			    dst->sa_family);
			senderr(EAFNOSUPPORT);
		}

		/*
		 * must add atm_pseudohdr to data
		 */
		sz = sizeof(atmdst);
		atm_flags = ATM_PH_FLAGS(&atmdst);
		if (atm_flags & ATM_PH_LLCSNAP)
			sz += 8;	/* sizeof snap == 8 */
		M_PREPEND(m, sz, M_NOWAIT);
		if (m == 0)
			senderr(ENOBUFS);
		ad = mtod(m, struct atm_pseudohdr *);
		*ad = atmdst;
		if (atm_flags & ATM_PH_LLCSNAP) {
			atmllc = (struct atmllc *)(ad + 1);
			if (llc_hdr == NULL) {
			        bcopy(ATMLLC_HDR, atmllc->llchdr, 
				      sizeof(atmllc->llchdr));
				/* note: in host order */
				ATM_LLC_SETTYPE(atmllc, etype); 
			}
			else
			        bcopy(llc_hdr, atmllc, sizeof(struct atmllc));
		}
	}

	if (ng_atm_output_p != NULL) {
		if ((error = (*ng_atm_output_p)(ifp, &m)) != 0) {
			if (m != NULL)
				m_freem(m);
			return (error);
		}
		if (m == NULL)
			return (0);
	}

	/*
	 * Queue message on interface, and start output if interface
	 * not yet active.
	 */
	if (!IF_HANDOFF_ADJ(&ifp->if_snd, m, ifp,
	    -(int)sizeof(struct atm_pseudohdr)))
		return (ENOBUFS);
	return (error);

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