+ /* check for VLAN */
+ if ((m->m_pkthdr.csum_flags & CSUM_VLAN_TAG_VALID) != 0) {
+ if (EVL_VLANOFTAG(m->m_pkthdr.vlan_tag) != 0) {
+ *protocol_family = PF_VLAN;
+ return 0;
+ }
+ /* the packet is just priority-tagged, clear the bit */
+ m->m_pkthdr.csum_flags &= ~CSUM_VLAN_TAG_VALID;
+ } else if (ether_type == htons(ETHERTYPE_VLAN)) {
+ struct ether_vlan_header * evl;
+
+ evl = (struct ether_vlan_header *)(void *)frame_header;
+ if (m->m_len < ETHER_VLAN_ENCAP_LEN ||
+ ntohs(evl->evl_proto) == ETHERTYPE_VLAN ||
+ EVL_VLANOFTAG(ntohs(evl->evl_tag)) != 0) {
+ *protocol_family = PF_VLAN;
+ return 0;
+ }
+ /* the packet is just priority-tagged */
+
+ /* make the encapsulated ethertype the actual ethertype */
+ ether_type = evl->evl_encap_proto = evl->evl_proto;
+
+ /* remove the encapsulation header */
+ m->m_len -= ETHER_VLAN_ENCAP_LEN;
+ m->m_data += ETHER_VLAN_ENCAP_LEN;
+ m->m_pkthdr.len -= ETHER_VLAN_ENCAP_LEN;
+ m->m_pkthdr.csum_flags = 0; /* can't trust hardware checksum */
+ } else if (ether_type == htons(ETHERTYPE_ARP)) {
+ m->m_pkthdr.pkt_flags |= PKTF_INET_RESOLVE; /* ARP packet */
+ }
+ 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) {
+ bcopy(data, &extProto1, sizeof(u_int32_t));
+
+ /* SAP or SNAP */
+ if ((extProto1 & htonl(0xFFFFFF00)) == htonl(0xAAAA0300)) {
+ /* SNAP */
+ type = DLIL_DESC_SNAP;
+ bcopy(data + sizeof(u_int32_t), &extProto2,
+ 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;
+}
+
+/*
+ * On embedded, ether_frameout is practicaly ether_frameout_extended.
+ * On non-embedded, ether_frameout has long been exposed as a public KPI,
+ * and therefore its signature must remain the same (without the pre- and
+ * postpend length parameters.)
+ */
+#if KPI_INTERFACE_EMBEDDED
+int
+ether_frameout(struct ifnet *ifp, struct mbuf **m,
+ const struct sockaddr *ndest, const char *edst,
+ const char *ether_type, u_int32_t *prepend_len, u_int32_t *postpend_len)
+#else /* !KPI_INTERFACE_EMBEDDED */
+int
+ether_frameout(struct ifnet *ifp, struct mbuf **m,
+ const struct sockaddr *ndest, const char *edst,
+ const char *ether_type)
+#endif /* KPI_INTERFACE_EMBEDDED */
+{
+#if KPI_INTERFACE_EMBEDDED
+ return ether_frameout_extended(ifp, m, ndest, edst, ether_type,
+ prepend_len, postpend_len);
+#else /* !KPI_INTERFACE_EMBEDDED */
+ return ether_frameout_extended(ifp, m, ndest, edst, ether_type,
+ NULL, NULL);
+#endif /* !KPI_INTERFACE_EMBEDDED */
+}