/* * 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; }