/*
 * 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_frameout(
	struct ifnet			*ifp,
	struct mbuf				**m,
	const struct sockaddr	*ndest,
	const char				*edst,
	const char				*ether_type)
{
	struct ether_header *eh;
	int hlen;	/* link layer header length */

	hlen = ETHER_HDR_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) &&
	    ((*m)->m_flags & M_LOOP)) {
	    if (lo_ifp) {
            if ((*m)->m_flags & M_BCAST) {
                struct mbuf *n = m_copy(*m, 0, (int)M_COPYALL);
                if (n != NULL)
                    dlil_output(lo_ifp, ndest->sa_family, n, NULL, ndest, 0);
            }
            else {
					if (_ether_cmp(edst, ifnet_lladdr(ifp)) == 0) {
                    dlil_output(lo_ifp, ndest->sa_family, *m, NULL, ndest, 0);
                    return EJUSTRETURN;
                }
            }
	    }
	}
    
	/*
	 * Add local net header.  If no space in first mbuf,
	 * allocate another.
	 */
	M_PREPEND(*m, sizeof (struct ether_header), M_DONTWAIT);
	if (*m == 0) {
	    return (EJUSTRETURN);
	}


	eh = mtod(*m, struct ether_header *);
	(void)memcpy(&eh->ether_type, ether_type,
		sizeof(eh->ether_type));
 	(void)memcpy(eh->ether_dhost, edst, ETHER_ADDR_LEN);
 	ifnet_lladdr_copy_bytes(ifp, eh->ether_shost, ETHER_ADDR_LEN);

	return 0;
}
int
ether_demux(
	ifnet_t				ifp,
	mbuf_t				m,
	char				*frame_header,
	protocol_family_t	*protocol_family)
{
	struct ether_header *eh = (struct ether_header *)frame_header;
	u_short			ether_type = eh->ether_type;
	u_int16_t		type;
	u_int8_t		*data;
	u_long			i = 0;
	struct ether_desc_blk_str *desc_blk = (struct ether_desc_blk_str *)ifp->family_cookie;
	u_long			maxd = desc_blk ? desc_blk->n_max_used : 0;
	struct en_desc	*ed = desc_blk ? desc_blk->block_ptr : NULL;
	u_int32_t		extProto1 = 0;
	u_int32_t		extProto2 = 0;

	if (eh->ether_dhost[0] & 1) {
		/* Check for broadcast */
		if (_ether_cmp(etherbroadcastaddr, eh->ether_dhost) == 0)
			m->m_flags |= M_BCAST;
		else
			m->m_flags |= M_MCAST;
	}

	if (ifp->if_eflags & IFEF_BOND) {
		/* if we're bonded, bond "protocol" gets all the packets */
		*protocol_family = PF_BOND;
		return (0);
	}

	if ((eh->ether_dhost[0] & 1) == 0) {
		/*
		 * When the driver is put into promiscuous mode we may receive unicast
		 * frames that are not intended for our interfaces.  They are marked here
		 * as being promiscuous so the caller may dispose of them after passing
		 * the packets to any interface filters.
		 */
		if (_ether_cmp(eh->ether_dhost, ifnet_lladdr(ifp))) {
			m->m_flags |= M_PROMISC;
		}
	}
	
	/* Quick check for VLAN */
	if ((m->m_pkthdr.csum_flags & CSUM_VLAN_TAG_VALID) != 0 ||
		ether_type == htons(ETHERTYPE_VLAN)) {
		*protocol_family = PF_VLAN;
		return 0;
	}
	
	data = mtod(m, u_int8_t*);
	
	/*
	* Determine the packet's protocol type and stuff the protocol into
	* longs for quick compares.
	*/
	
	if (ntohs(ether_type) <= 1500) {
		extProto1 = *(u_int32_t*)data;
		
		// SAP or SNAP
		if ((extProto1 & htonl(0xFFFFFF00)) == htonl(0xAAAA0300)) {
			// SNAP
			type = DLIL_DESC_SNAP;
			extProto2 = *(u_int32_t*)(data + sizeof(u_int32_t));
			extProto1 &= htonl(0x000000FF);
		} else {
			type = DLIL_DESC_SAP;
			extProto1 &= htonl(0xFFFFFF00);
		}
	} else {
		type = DLIL_DESC_ETYPE2;
	}
	
	/* 
	* Search through the connected protocols for a match. 
	*/
	
	switch (type) {
		case DLIL_DESC_ETYPE2:
			for (i = 0; i < maxd; i++) {
				if ((ed[i].type == type) && (ed[i].data[0] == ether_type)) {
					*protocol_family = ed[i].protocol_family;
					return 0;
				}
			}
			break;
		
		case DLIL_DESC_SAP:
			for (i = 0; i < maxd; i++) {
				if ((ed[i].type == type) && (ed[i].data[0] == extProto1)) {
					*protocol_family = ed[i].protocol_family;
					return 0;
				}
			}
			break;
		
		case DLIL_DESC_SNAP:
			for (i = 0; i < maxd; i++) {
				if ((ed[i].type == type) && (ed[i].data[0] == extProto1) &&
					(ed[i].data[1] == extProto2)) {
					*protocol_family = ed[i].protocol_family;
					return 0;
				}
			}
		break;
	}
	
	return ENOENT;
}			
////////////////////////////////////////////////////////////////////////////////
//
// firewire_frameout
//
// IN:	ifnet_t ifp,struct mbuf **m
// IN:  struct sockaddr *ndest - contains the destination IP Address 
// IN:	char *edst - filled by firewire_arpresolve function in if_firewire.c
// IN:  char *fw_type 
//
// Invoked by : 
//  dlil.c for dlil_output, Its called after inet_firewire_pre_output
//
// 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.
//
////////////////////////////////////////////////////////////////////////////////
__private_extern__ int
firewire_frameout(ifnet_t ifp, mbuf_t *m, 
					const struct sockaddr *ndest, const char *edst, const char *fw_type)
{
	register struct firewire_header *fwh;
		
	/*
	 * 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 ((ifnet_flags(ifp) & IFF_SIMPLEX) &&
	    (mbuf_flags(*m) & MBUF_LOOP))
	{
		if (loop_ifp == NULL) {
			ifnet_find_by_name("lo0", &loop_ifp);
			
			/*
			 * We make an assumption here that lo0 will never go away. This
			 * means we don't have to worry about releasing the reference
			 * later and we don't have to worry about leaking a reference
			 * every time we are loaded.
			 */
			ifnet_release(loop_ifp);
		}
		
	    if (loop_ifp) 
		{
            if (mbuf_flags(*m) & MBUF_BCAST)
			{
                mbuf_t n;
                
                if (mbuf_copym(*m, 0, MBUF_COPYALL, MBUF_WAITOK, &n) == 0)
                    ifnet_output(loop_ifp, PF_INET, n, 0, ndest);
            } 
            else 
            {
				if (bcmp(edst, ifnet_lladdr(ifp), FIREWIRE_ADDR_LEN) == 0) 
				{
                    ifnet_output(loop_ifp, PF_INET, *m, 0, ndest);
                    return EJUSTRETURN;
                }
            }
	    }
	}

	//
	// Add local net header.  If no space in first mbuf,
	// allocate another.
	//
	if (mbuf_prepend(m, sizeof(struct firewire_header), MBUF_DONTWAIT) != 0)
	    return (EJUSTRETURN);

	//
	// Lets put this intelligent here into the mbuf 
	// so we can demux on our output path
	//
	fwh = (struct firewire_header*)mbuf_data(*m);
	(void)memcpy(&fwh->fw_type, fw_type,sizeof(fwh->fw_type));
	memcpy(fwh->fw_dhost, edst, FIREWIRE_ADDR_LEN);
	(void)memcpy(fwh->fw_shost, ifnet_lladdr(ifp), sizeof(fwh->fw_shost));
	
	return 0;
}