/* * 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; }
/* * Function: send_packet * Purpose: * Send the request directly on the interface, bypassing the routing code. */ static int send_packet(struct ifnet * ifp, struct dhcp_packet * pkt, int pkt_size) { struct mbuf * m; struct sockaddr_in dest; dest = blank_sin; dest.sin_port = htons(IPPORT_BOOTPS); dest.sin_addr.s_addr = INADDR_BROADCAST; m = ip_pkt_to_mbuf((caddr_t)pkt, pkt_size); return dlil_output(ifp, PF_INET, m, 0, (struct sockaddr *)&dest, 0); }
int bpfwrite(dev_t dev, struct uio *uio, __unused int ioflag) { struct bpf_d *d; struct ifnet *ifp; struct mbuf *m = NULL; int error; char dst_buf[SOCKADDR_HDR_LEN + MAX_DATALINK_HDR_LEN]; int datlen = 0; lck_mtx_lock(bpf_mlock); d = bpf_dtab[minor(dev)]; if (d == 0 || d == (void *)1) { lck_mtx_unlock(bpf_mlock); return (ENXIO); } if (d->bd_bif == 0) { lck_mtx_unlock(bpf_mlock); return (ENXIO); } ifp = d->bd_bif->bif_ifp; if (uio_resid(uio) == 0) { lck_mtx_unlock(bpf_mlock); return (0); } ((struct sockaddr *)dst_buf)->sa_len = sizeof(dst_buf); error = bpf_movein(uio, (int)d->bd_bif->bif_dlt, &m, d->bd_hdrcmplt ? NULL : (struct sockaddr *)dst_buf, &datlen); if (error) { lck_mtx_unlock(bpf_mlock); return (error); } if ((unsigned)datlen > ifp->if_mtu) { lck_mtx_unlock(bpf_mlock); m_freem(m); return (EMSGSIZE); } if ((error = ifp_use(ifp, kIfNetUseCount_MustNotBeZero)) != 0) { lck_mtx_unlock(bpf_mlock); m_freem(m); return (error); } #if CONFIG_MACF_NET mac_mbuf_label_associate_bpfdesc(d, m); #endif lck_mtx_unlock(bpf_mlock); if (d->bd_hdrcmplt) { if (d->bd_bif->bif_send) error = d->bd_bif->bif_send(ifp, d->bd_bif->bif_dlt, m); else error = dlil_output(ifp, 0, m, NULL, NULL, 1); } else { error = dlil_output(ifp, PF_INET, m, NULL, (struct sockaddr *)dst_buf, 0); } if (ifp_unuse(ifp) != 0) ifp_use_reached_zero(ifp); /* * The driver frees the mbuf. */ return (error); }