+
+
+/*
+ * Get a list of available data link type of the interface.
+ */
+static int
+bpf_getdltlist(struct bpf_d *d, caddr_t addr, struct proc *p)
+{
+ u_int n;
+ int error;
+ struct ifnet *ifp;
+ struct bpf_if *bp;
+ user_addr_t dlist;
+ struct bpf_dltlist bfl;
+
+ bcopy(addr, &bfl, sizeof (bfl));
+ if (proc_is64bit(p)) {
+ dlist = (user_addr_t)bfl.bfl_u.bflu_pad;
+ } else {
+ dlist = CAST_USER_ADDR_T(bfl.bfl_u.bflu_list);
+ }
+
+ ifp = d->bd_bif->bif_ifp;
+ n = 0;
+ error = 0;
+
+ for (bp = bpf_iflist; bp; bp = bp->bif_next) {
+ if (bp->bif_ifp != ifp)
+ continue;
+ /*
+ * Return DLT_PKTAP only to processes that know how to handle it
+ */
+ if (bp->bif_dlt == DLT_PKTAP && !(d->bd_flags & BPF_WANT_PKTAP))
+ continue;
+ if (dlist != USER_ADDR_NULL) {
+ if (n >= bfl.bfl_len) {
+ return (ENOMEM);
+ }
+ error = copyout(&bp->bif_dlt, dlist,
+ sizeof (bp->bif_dlt));
+ if (error != 0)
+ break;
+ dlist += sizeof (bp->bif_dlt);
+ }
+ n++;
+ }
+ bfl.bfl_len = n;
+ bcopy(&bfl, addr, sizeof (bfl));
+
+ return (error);
+}
+
+/*
+ * Set the data link type of a BPF instance.
+ */
+static int
+bpf_setdlt(struct bpf_d *d, uint32_t dlt)
+{
+ int error, opromisc;
+ struct ifnet *ifp;
+ struct bpf_if *bp;
+
+ if (d->bd_bif->bif_dlt == dlt)
+ return (0);
+
+ while (d->bd_hbuf_read)
+ msleep((caddr_t)d, bpf_mlock, PRINET, "bpf_reading", NULL);
+
+ if ((d->bd_flags & BPF_CLOSING) != 0)
+ return (ENXIO);
+
+ ifp = d->bd_bif->bif_ifp;
+ for (bp = bpf_iflist; bp; bp = bp->bif_next) {
+ if (bp->bif_ifp == ifp && bp->bif_dlt == dlt)
+ break;
+ }
+ if (bp != NULL) {
+ opromisc = d->bd_promisc;
+ if (bpf_detachd(d, 0) != 0)
+ return (ENXIO);
+ error = bpf_attachd(d, bp);
+ if (error) {
+ printf("bpf_setdlt: bpf_attachd %s%d failed (%d)\n",
+ ifnet_name(bp->bif_ifp), ifnet_unit(bp->bif_ifp), error);
+ return error;
+ }
+ reset_d(d);
+ if (opromisc) {
+ lck_mtx_unlock(bpf_mlock);
+ error = ifnet_set_promiscuous(bp->bif_ifp, 1);
+ lck_mtx_lock(bpf_mlock);
+ if (error) {
+ printf("%s: ifpromisc %s%d failed (%d)\n",
+ __func__, ifnet_name(bp->bif_ifp),
+ ifnet_unit(bp->bif_ifp), error);
+ } else {
+ d->bd_promisc = 1;
+ }
+ }
+ }
+ return (bp == NULL ? EINVAL : 0);
+}
+
+static int
+bpf_set_traffic_class(struct bpf_d *d, int tc)
+{
+ int error = 0;
+
+ if (!SO_VALID_TC(tc))
+ error = EINVAL;
+ else
+ d->bd_traffic_class = tc;
+
+ return (error);
+}
+
+static void
+bpf_set_packet_service_class(struct mbuf *m, int tc)
+{
+ if (!(m->m_flags & M_PKTHDR))
+ return;
+
+ VERIFY(SO_VALID_TC(tc));
+ (void) m_set_service_class(m, so_tc2msc(tc));
+}
+