/* * Bind a PF_PACKET socket to a network interface. * * The default operation of this bind() is to place the socket (and thus the * network interface) into promiscuous mode. It is then up to the application * to turn that down by issuing the relevant ioctls, if desired. */ static int sdpfp_bind(sock_lower_handle_t handle, struct sockaddr *addr, socklen_t addrlen, struct cred *cred) { struct sockaddr_ll *addr_ll, *sol; mac_client_handle_t mch; struct pfpsock *ps; mac_handle_t mh; int error; ps = (struct pfpsock *)handle; if (ps->ps_bound) return (EINVAL); if (addrlen < sizeof (struct sockaddr_ll) || addr == NULL) return (EINVAL); addr_ll = (struct sockaddr_ll *)addr; error = pfp_open_index(addr_ll->sll_ifindex, &mh, &mch, cred); if (error != 0) return (error); /* * Ensure that each socket is only bound once. */ mutex_enter(&ps->ps_lock); if (ps->ps_mh != 0) { mutex_exit(&ps->ps_lock); pfp_close(mh, mch); return (EADDRINUSE); } ps->ps_mh = mh; ps->ps_mch = mch; mutex_exit(&ps->ps_lock); /* * Cache all of the information from bind so that it's in an easy * place to get at when packets are received. */ sol = &ps->ps_sock; sol->sll_family = AF_PACKET; sol->sll_ifindex = addr_ll->sll_ifindex; sol->sll_protocol = addr_ll->sll_protocol; sol->sll_halen = mac_addr_len(ps->ps_mh); mac_unicast_primary_get(ps->ps_mh, sol->sll_addr); mac_sdu_get(ps->ps_mh, NULL, &ps->ps_max_sdu); ps->ps_linkid = addr_ll->sll_ifindex; error = mac_promisc_add(ps->ps_mch, MAC_CLIENT_PROMISC_ALL, pfp_packet, ps, &ps->ps_phd, MAC_PROMISC_FLAGS_VLAN_TAG_STRIP); if (error == 0) { ps->ps_promisc = MAC_CLIENT_PROMISC_ALL; ps->ps_bound = B_TRUE; } return (error); }
/* * DL_PHYS_ADDR_REQ */ static void proto_physaddr_req(dld_str_t *dsp, mblk_t *mp) { dl_phys_addr_req_t *dlp = (dl_phys_addr_req_t *)mp->b_rptr; queue_t *q = dsp->ds_wq; t_uscalar_t dl_err = 0; char *addr = NULL; uint_t addr_length; if (MBLKL(mp) < sizeof (dl_phys_addr_req_t)) { dl_err = DL_BADPRIM; goto done; } if (dsp->ds_dlstate == DL_UNATTACHED || DL_ACK_PENDING(dsp->ds_dlstate)) { dl_err = DL_OUTSTATE; goto done; } addr_length = dsp->ds_mip->mi_addr_length; if (addr_length > 0) { addr = kmem_alloc(addr_length, KM_SLEEP); switch (dlp->dl_addr_type) { case DL_CURR_PHYS_ADDR: mac_unicast_primary_get(dsp->ds_mh, (uint8_t *)addr); break; case DL_FACT_PHYS_ADDR: bcopy(dsp->ds_mip->mi_unicst_addr, addr, addr_length); break; case DL_CURR_DEST_ADDR: if (!mac_dst_get(dsp->ds_mh, (uint8_t *)addr)) dl_err = DL_NOTSUPPORTED; break; default: dl_err = DL_UNSUPPORTED; } } done: if (dl_err == 0) dlphysaddrack(q, mp, addr, (t_uscalar_t)addr_length); else dlerrorack(q, mp, DL_PHYS_ADDR_REQ, dl_err, 0); if (addr != NULL) kmem_free(addr, addr_length); }
static void vnic_notify_cb(void *arg, mac_notify_type_t type) { vnic_t *vnic = arg; /* * Do not deliver notifications if the vnic is not fully initialized * or is in process of being torn down. */ if (!vnic->vn_enabled) return; switch (type) { case MAC_NOTE_UNICST: /* * Only the VLAN VNIC needs to be notified with primary MAC * address change. */ if (vnic->vn_addr_type != VNIC_MAC_ADDR_TYPE_PRIMARY) return; /* the unicast MAC address value */ mac_unicast_primary_get(vnic->vn_lower_mh, vnic->vn_addr); /* notify its upper layer MAC about MAC address change */ mac_unicst_update(vnic->vn_mh, (const uint8_t *)vnic->vn_addr); break; case MAC_NOTE_LINK: mac_link_update(vnic->vn_mh, mac_client_stat_get(vnic->vn_mch, MAC_STAT_LINK_STATE)); break; default: break; } }
/* ARGSUSED */ static int sdpfp_ioctl(sock_lower_handle_t handle, int cmd, intptr_t arg, int mod, int32_t *rval, struct cred *cr) { #if defined(_SYSCALL32) struct timeval32 tival; #else struct timeval tival; #endif mac_client_promisc_type_t mtype; datalink_id_t linkid; struct lifreq lifreq; struct ifreq ifreq; struct pfpsock *ps; mac_handle_t mh; timespec_t tv; int error; switch (cmd) { /* * ioctls that work on "struct lifreq" */ case SIOCSLIFFLAGS : case SIOCGLIFINDEX : case SIOCGLIFFLAGS : case SIOCGLIFMTU : error = pfp_lifreq_getlinkid(arg, &lifreq, &linkid); if (error != 0) return (error); break; /* * ioctls that work on "struct ifreq". * Not all of these have a "struct lifreq" partner, for example * SIOCGIFHWADDR, for the simple reason that the logical interface * does not have a hardware address. */ case SIOCSIFFLAGS : case SIOCGIFINDEX : case SIOCGIFFLAGS : case SIOCGIFMTU : case SIOCGIFHWADDR : error = pfp_ifreq_getlinkid(arg, &ifreq, &linkid); if (error != 0) return (error); break; } error = mac_open_by_linkid(linkid, &mh); if (error != 0) return (error); ps = (struct pfpsock *)handle; switch (cmd) { case SIOCGLIFINDEX : lifreq.lifr_index = linkid; break; case SIOCGIFINDEX : ifreq.ifr_index = linkid; break; case SIOCGIFFLAGS : ifreq.ifr_flags = IFF_RUNNING; if (ps->ps_promisc == MAC_CLIENT_PROMISC_ALL) ifreq.ifr_flags |= IFF_PROMISC; break; case SIOCGLIFFLAGS : lifreq.lifr_flags = IFF_RUNNING; if (ps->ps_promisc == MAC_CLIENT_PROMISC_ALL) lifreq.lifr_flags |= IFF_PROMISC; break; case SIOCSIFFLAGS : if (linkid != ps->ps_linkid) { error = EINVAL; } else { if ((ifreq.ifr_flags & IFF_PROMISC) != 0) mtype = MAC_CLIENT_PROMISC_ALL; else mtype = MAC_CLIENT_PROMISC_FILTERED; error = pfp_set_promisc(ps, mtype); } break; case SIOCSLIFFLAGS : if (linkid != ps->ps_linkid) { error = EINVAL; } else { if ((lifreq.lifr_flags & IFF_PROMISC) != 0) mtype = MAC_CLIENT_PROMISC_ALL; else mtype = MAC_CLIENT_PROMISC_FILTERED; error = pfp_set_promisc(ps, mtype); } break; case SIOCGIFMTU : mac_sdu_get(mh, NULL, &ifreq.ifr_mtu); break; case SIOCGLIFMTU : mac_sdu_get(mh, NULL, &lifreq.lifr_mtu); break; case SIOCGIFHWADDR : mac_unicast_primary_get(mh, (uint8_t *)ifreq.ifr_addr.sa_data); ifreq.ifr_addr.sa_family = pfp_dl_to_arphrd(mac_type(mh)); break; case SIOCGSTAMP : (void) gethrestime(&tv); tival.tv_sec = (time_t)tv.tv_sec; tival.tv_usec = tv.tv_nsec / 1000; error = ddi_copyout(&tival, (void *)arg, sizeof (tival), 0); break; default : break; } mac_close(mh); if (error == 0) { /* * Only the "GET" ioctls need to copy data back to userace. */ switch (cmd) { case SIOCGLIFINDEX : case SIOCGLIFFLAGS : case SIOCGLIFMTU : error = ddi_copyout(&lifreq, (void *)arg, sizeof (lifreq), 0); break; case SIOCGIFINDEX : case SIOCGIFFLAGS : case SIOCGIFMTU : case SIOCGIFHWADDR : error = ddi_copyout(&ifreq, (void *)arg, sizeof (ifreq), 0); break; default : break; } } return (error); }
/* * Program the macaddress and vlans of a port. * * Returns 0 on sucess, 1 on failure. */ static int vsw_set_if_hw_addr(vsw_t *vswp) { mac_diag_t diag; uint8_t *macaddr; uint8_t primary_addr[ETHERADDRL]; uint16_t vid = VLAN_ID_NONE; int rv; uint16_t mac_flags = MAC_UNICAST_TAG_DISABLE | MAC_UNICAST_STRIP_DISABLE; D1(vswp, "%s: enter", __func__); ASSERT(RW_WRITE_HELD(&vswp->maccl_rwlock)); if (vswp->mch == NULL) return (0); macaddr = (uint8_t *)vswp->if_addr.ether_addr_octet; /* check if it is the primary macaddr of the card. */ mac_unicast_primary_get(vswp->mh, primary_addr); if (ether_cmp((void *)primary_addr, (void*)macaddr) == 0) { mac_flags |= MAC_UNICAST_PRIMARY; } /* * If the interface has a specific 'pvid', then * register with that vlan-id, otherwise register * with VLAN_ID_NONE. */ if (vswp->pvid != vswp->default_vlan_id) { vid = vswp->pvid; } if (!(vswp->smode & VSW_LAYER2_PROMISC)) { mac_flags |= MAC_UNICAST_HW; } if (vswp->addr_set == B_FALSE) { vswp->muh = NULL; rv = mac_unicast_add(vswp->mch, macaddr, mac_flags, &vswp->muh, vid, &diag); if (rv != 0) { cmn_err(CE_WARN, "vsw%d: Failed to program" "macaddr,vid(%s, %d) err=%d", vswp->instance, ether_sprintf((void *)macaddr), vid, rv); return (rv); } vswp->addr_set = B_TRUE; D2(vswp, "%s:programmed macaddr(%s) vid(%d) into device %s", __func__, ether_sprintf((void *)macaddr), vid, vswp->physname); } vsw_mac_add_vlans(vswp, vswp->mch, macaddr, mac_flags, vswp->vids, vswp->nvids); vsw_maccl_set_bandwidth(vswp, NULL, VSW_LOCALDEV, vswp->bandwidth); mac_rx_set(vswp->mch, vsw_if_rx_cb, (void *)vswp); D1(vswp, "%s: exit", __func__); return (rv); }
static int vnic_unicast_add(vnic_t *vnic, vnic_mac_addr_type_t vnic_addr_type, int *addr_slot, uint_t prefix_len, int *addr_len_ptr_arg, uint8_t *mac_addr_arg, uint16_t flags, vnic_ioc_diag_t *diag, uint16_t vid, boolean_t req_hwgrp_flag) { mac_diag_t mac_diag; uint16_t mac_flags = 0; int err; uint_t addr_len; if (flags & VNIC_IOC_CREATE_NODUPCHECK) mac_flags |= MAC_UNICAST_NODUPCHECK; switch (vnic_addr_type) { case VNIC_MAC_ADDR_TYPE_FIXED: case VNIC_MAC_ADDR_TYPE_VRID: /* * The MAC address value to assign to the VNIC * is already provided in mac_addr_arg. addr_len_ptr_arg * already contains the MAC address length. */ break; case VNIC_MAC_ADDR_TYPE_RANDOM: /* * Random MAC address. There are two sub-cases: * * 1 - If mac_len == 0, a new MAC address is generated. * The length of the MAC address to generated depends * on the type of MAC used. The prefix to use for the MAC * address is stored in the most significant bytes * of the mac_addr argument, and its length is specified * by the mac_prefix_len argument. This prefix can * correspond to a IEEE OUI in the case of Ethernet, * for example. * * 2 - If mac_len > 0, the address was already picked * randomly, and is now passed back during VNIC * re-creation. The mac_addr argument contains the MAC * address that was generated. We distinguish this * case from the fixed MAC address case, since we * want the user consumers to know, when they query * the list of VNICs, that a VNIC was assigned a * random MAC address vs assigned a fixed address * specified by the user. */ /* * If it's a pre-generated address, we're done. mac_addr_arg * and addr_len_ptr_arg already contain the MAC address * value and length. */ if (*addr_len_ptr_arg > 0) break; /* generate a new random MAC address */ if ((err = mac_addr_random(vnic->vn_mch, prefix_len, mac_addr_arg, &mac_diag)) != 0) { *diag = vnic_mac2vnic_diag(mac_diag); return (err); } *addr_len_ptr_arg = mac_addr_len(vnic->vn_lower_mh); break; case VNIC_MAC_ADDR_TYPE_FACTORY: err = mac_addr_factory_reserve(vnic->vn_mch, addr_slot); if (err != 0) { if (err == EINVAL) *diag = VNIC_IOC_DIAG_MACFACTORYSLOTINVALID; if (err == EBUSY) *diag = VNIC_IOC_DIAG_MACFACTORYSLOTUSED; if (err == ENOSPC) *diag = VNIC_IOC_DIAG_MACFACTORYSLOTALLUSED; return (err); } mac_addr_factory_value(vnic->vn_lower_mh, *addr_slot, mac_addr_arg, &addr_len, NULL, NULL); *addr_len_ptr_arg = addr_len; break; case VNIC_MAC_ADDR_TYPE_AUTO: /* first try to allocate a factory MAC address */ err = mac_addr_factory_reserve(vnic->vn_mch, addr_slot); if (err == 0) { mac_addr_factory_value(vnic->vn_lower_mh, *addr_slot, mac_addr_arg, &addr_len, NULL, NULL); vnic_addr_type = VNIC_MAC_ADDR_TYPE_FACTORY; *addr_len_ptr_arg = addr_len; break; } /* * Allocating a factory MAC address failed, generate a * random MAC address instead. */ if ((err = mac_addr_random(vnic->vn_mch, prefix_len, mac_addr_arg, &mac_diag)) != 0) { *diag = vnic_mac2vnic_diag(mac_diag); return (err); } *addr_len_ptr_arg = mac_addr_len(vnic->vn_lower_mh); vnic_addr_type = VNIC_MAC_ADDR_TYPE_RANDOM; break; case VNIC_MAC_ADDR_TYPE_PRIMARY: /* * We get the address here since we copy it in the * vnic's vn_addr. * We can't ask for hardware resources since we * don't currently support hardware classification * for these MAC clients. */ if (req_hwgrp_flag) { *diag = VNIC_IOC_DIAG_NO_HWRINGS; return (ENOTSUP); } mac_unicast_primary_get(vnic->vn_lower_mh, mac_addr_arg); *addr_len_ptr_arg = mac_addr_len(vnic->vn_lower_mh); mac_flags |= MAC_UNICAST_VNIC_PRIMARY; break; } vnic->vn_addr_type = vnic_addr_type; err = mac_unicast_add(vnic->vn_mch, mac_addr_arg, mac_flags, &vnic->vn_muh, vid, &mac_diag); if (err != 0) { if (vnic_addr_type == VNIC_MAC_ADDR_TYPE_FACTORY) { /* release factory MAC address */ mac_addr_factory_release(vnic->vn_mch, *addr_slot); } *diag = vnic_mac2vnic_diag(mac_diag); } return (err); }
/* * DL_BIND_REQ */ static void proto_bind_req(dld_str_t *dsp, mblk_t *mp) { dl_bind_req_t *dlp = (dl_bind_req_t *)mp->b_rptr; int err = 0; uint8_t dlsap_addr[MAXMACADDRLEN + sizeof (uint16_t)]; uint_t dlsap_addr_length; t_uscalar_t dl_err; t_scalar_t sap; queue_t *q = dsp->ds_wq; mac_perim_handle_t mph; void *mdip; int32_t intr_cpu; if (MBLKL(mp) < sizeof (dl_bind_req_t)) { dl_err = DL_BADPRIM; goto failed; } if (dlp->dl_xidtest_flg != 0) { dl_err = DL_NOAUTO; goto failed; } if (dlp->dl_service_mode != DL_CLDLS) { dl_err = DL_UNSUPPORTED; goto failed; } if (dsp->ds_dlstate != DL_UNBOUND) { dl_err = DL_OUTSTATE; goto failed; } mac_perim_enter_by_mh(dsp->ds_mh, &mph); if ((err = dls_active_set(dsp)) != 0) { dl_err = DL_SYSERR; goto failed2; } dsp->ds_dlstate = DL_BIND_PENDING; /* * Set the receive callback. */ dls_rx_set(dsp, (dsp->ds_mode == DLD_RAW) ? dld_str_rx_raw : dld_str_rx_unitdata, dsp); /* * Bind the channel such that it can receive packets. */ sap = dlp->dl_sap; dsp->ds_nonip = !check_mod_above(dsp->ds_rq, "ip") && !check_mod_above(dsp->ds_rq, "arp"); err = dls_bind(dsp, sap); if (err != 0) { switch (err) { case EINVAL: dl_err = DL_BADADDR; err = 0; break; default: dl_err = DL_SYSERR; break; } dsp->ds_dlstate = DL_UNBOUND; dls_active_clear(dsp, B_FALSE); goto failed2; } intr_cpu = mac_client_intr_cpu(dsp->ds_mch); mdip = mac_get_devinfo(dsp->ds_mh); mac_perim_exit(mph); /* * We do this after we get out of the perim to avoid deadlocks * etc. since part of mac_client_retarget_intr is to walk the * device tree in order to find and retarget the interrupts. */ if (intr_cpu != -1) mac_client_set_intr_cpu(mdip, dsp->ds_mch, intr_cpu); /* * Copy in MAC address. */ dlsap_addr_length = dsp->ds_mip->mi_addr_length; mac_unicast_primary_get(dsp->ds_mh, dlsap_addr); /* * Copy in the SAP. */ *(uint16_t *)(dlsap_addr + dlsap_addr_length) = sap; dlsap_addr_length += sizeof (uint16_t); dsp->ds_dlstate = DL_IDLE; dlbindack(q, mp, sap, dlsap_addr, dlsap_addr_length, 0, 0); return; failed2: mac_perim_exit(mph); failed: dlerrorack(q, mp, DL_BIND_REQ, dl_err, (t_uscalar_t)err); }
/* * DL_INFO_REQ */ static void proto_info_req(dld_str_t *dsp, mblk_t *mp) { dl_info_ack_wrapper_t *dlwp; dl_info_ack_t *dlp; dl_qos_cl_sel1_t *selp; dl_qos_cl_range1_t *rangep; uint8_t *addr; uint8_t *brdcst_addr; uint_t addr_length; uint_t sap_length; mac_info_t minfo; mac_info_t *minfop; queue_t *q = dsp->ds_wq; /* * Swap the request message for one large enough to contain the * wrapper structure defined above. */ if ((mp = mexchange(q, mp, sizeof (dl_info_ack_wrapper_t), M_PCPROTO, 0)) == NULL) return; bzero(mp->b_rptr, sizeof (dl_info_ack_wrapper_t)); dlwp = (dl_info_ack_wrapper_t *)mp->b_rptr; dlp = &(dlwp->dl_info); ASSERT(dlp == (dl_info_ack_t *)mp->b_rptr); dlp->dl_primitive = DL_INFO_ACK; /* * Set up the sub-structure pointers. */ addr = dlwp->dl_addr; brdcst_addr = dlwp->dl_brdcst_addr; rangep = &(dlwp->dl_qos_range1); selp = &(dlwp->dl_qos_sel1); /* * This driver supports only version 2 connectionless DLPI provider * nodes. */ dlp->dl_service_mode = DL_CLDLS; dlp->dl_version = DL_VERSION_2; /* * Set the style of the provider */ dlp->dl_provider_style = dsp->ds_style; ASSERT(dlp->dl_provider_style == DL_STYLE1 || dlp->dl_provider_style == DL_STYLE2); /* * Set the current DLPI state. */ dlp->dl_current_state = dsp->ds_dlstate; /* * Gratuitously set the media type. This is to deal with modules * that assume the media type is known prior to DL_ATTACH_REQ * being completed. */ dlp->dl_mac_type = DL_ETHER; /* * If the stream is not at least attached we try to retrieve the * mac_info using mac_info_get() */ if (dsp->ds_dlstate == DL_UNATTACHED || dsp->ds_dlstate == DL_ATTACH_PENDING || dsp->ds_dlstate == DL_DETACH_PENDING) { if (!mac_info_get(ddi_major_to_name(dsp->ds_major), &minfo)) { /* * Cannot find mac_info. giving up. */ goto done; } minfop = &minfo; } else { minfop = (mac_info_t *)dsp->ds_mip; /* We can only get the sdu if we're attached. */ mac_sdu_get(dsp->ds_mh, &dlp->dl_min_sdu, &dlp->dl_max_sdu); } /* * Set the media type (properly this time). */ if (dsp->ds_native) dlp->dl_mac_type = minfop->mi_nativemedia; else dlp->dl_mac_type = minfop->mi_media; /* * Set the DLSAP length. We only support 16 bit values and they * appear after the MAC address portion of DLSAP addresses. */ sap_length = sizeof (uint16_t); dlp->dl_sap_length = NEG(sap_length); addr_length = minfop->mi_addr_length; /* * Copy in the media broadcast address. */ if (minfop->mi_brdcst_addr != NULL) { dlp->dl_brdcst_addr_offset = (uintptr_t)brdcst_addr - (uintptr_t)dlp; bcopy(minfop->mi_brdcst_addr, brdcst_addr, addr_length); dlp->dl_brdcst_addr_length = addr_length; } /* Only VLAN links and links that have a normal tag mode support QOS. */ if ((dsp->ds_mch != NULL && mac_client_vid(dsp->ds_mch) != VLAN_ID_NONE) || (dsp->ds_dlp != NULL && dsp->ds_dlp->dl_tagmode == LINK_TAGMODE_NORMAL)) { dlp->dl_qos_range_offset = (uintptr_t)rangep - (uintptr_t)dlp; dlp->dl_qos_range_length = sizeof (dl_qos_cl_range1_t); rangep->dl_qos_type = DL_QOS_CL_RANGE1; rangep->dl_trans_delay.dl_target_value = DL_UNKNOWN; rangep->dl_trans_delay.dl_accept_value = DL_UNKNOWN; rangep->dl_protection.dl_min = DL_UNKNOWN; rangep->dl_protection.dl_max = DL_UNKNOWN; rangep->dl_residual_error = DL_UNKNOWN; /* * Specify the supported range of priorities. */ rangep->dl_priority.dl_min = 0; rangep->dl_priority.dl_max = (1 << VLAN_PRI_SIZE) - 1; dlp->dl_qos_offset = (uintptr_t)selp - (uintptr_t)dlp; dlp->dl_qos_length = sizeof (dl_qos_cl_sel1_t); selp->dl_qos_type = DL_QOS_CL_SEL1; selp->dl_trans_delay = DL_UNKNOWN; selp->dl_protection = DL_UNKNOWN; selp->dl_residual_error = DL_UNKNOWN; /* * Specify the current priority (which can be changed by * the DL_UDQOS_REQ primitive). */ selp->dl_priority = dsp->ds_pri; } dlp->dl_addr_length = addr_length + sizeof (uint16_t); if (dsp->ds_dlstate == DL_IDLE) { /* * The stream is bound. Therefore we can formulate a valid * DLSAP address. */ dlp->dl_addr_offset = (uintptr_t)addr - (uintptr_t)dlp; if (addr_length > 0) mac_unicast_primary_get(dsp->ds_mh, addr); *(uint16_t *)(addr + addr_length) = dsp->ds_sap; } done: IMPLY(dlp->dl_qos_offset != 0, dlp->dl_qos_length != 0); IMPLY(dlp->dl_qos_range_offset != 0, dlp->dl_qos_range_length != 0); IMPLY(dlp->dl_addr_offset != 0, dlp->dl_addr_length != 0); IMPLY(dlp->dl_brdcst_addr_offset != 0, dlp->dl_brdcst_addr_length != 0); qreply(q, mp); }
/* ARGSUSED */ static int sdpfp_ioctl(sock_lower_handle_t handle, int cmd, intptr_t arg, int mod, int32_t *rval, struct cred *cr) { struct timeval tival; mac_client_promisc_type_t mtype; struct sockaddr_dl *sock; datalink_id_t linkid; struct lifreq lifreq; struct ifreq ifreq; struct pfpsock *ps; mac_handle_t mh; int error; ps = (struct pfpsock *)handle; switch (cmd) { /* * ioctls that work on "struct lifreq" */ case SIOCSLIFFLAGS : case SIOCGLIFINDEX : case SIOCGLIFFLAGS : case SIOCGLIFMTU : case SIOCGLIFHWADDR : error = pfp_lifreq_getlinkid(arg, &lifreq, &linkid, mod); if (error != 0) return (error); break; /* * ioctls that work on "struct ifreq". * Not all of these have a "struct lifreq" partner, for example * SIOCGIFHWADDR, for the simple reason that the logical interface * does not have a hardware address. */ case SIOCSIFFLAGS : case SIOCGIFINDEX : case SIOCGIFFLAGS : case SIOCGIFMTU : case SIOCGIFHWADDR : error = pfp_ifreq_getlinkid(arg, &ifreq, &linkid, mod); if (error != 0) return (error); break; case SIOCGSTAMP : tival.tv_sec = (time_t)ps->ps_timestamp.tv_sec; tival.tv_usec = ps->ps_timestamp.tv_nsec / 1000; if (get_udatamodel() == DATAMODEL_NATIVE) { error = ddi_copyout(&tival, (void *)arg, sizeof (tival), mod); } #ifdef _SYSCALL32_IMPL else { struct timeval32 tv32; TIMEVAL_TO_TIMEVAL32(&tv32, &tival); error = ddi_copyout(&tv32, (void *)arg, sizeof (tv32), mod); } #endif return (error); } error = mac_open_by_linkid(linkid, &mh); if (error != 0) return (error); switch (cmd) { case SIOCGLIFINDEX : lifreq.lifr_index = linkid; break; case SIOCGIFINDEX : ifreq.ifr_index = linkid; break; case SIOCGIFFLAGS : ifreq.ifr_flags = IFF_RUNNING; if (ps->ps_promisc == MAC_CLIENT_PROMISC_ALL) ifreq.ifr_flags |= IFF_PROMISC; break; case SIOCGLIFFLAGS : lifreq.lifr_flags = IFF_RUNNING; if (ps->ps_promisc == MAC_CLIENT_PROMISC_ALL) lifreq.lifr_flags |= IFF_PROMISC; break; case SIOCSIFFLAGS : if (linkid != ps->ps_linkid) { error = EINVAL; } else { if ((ifreq.ifr_flags & IFF_PROMISC) != 0) mtype = MAC_CLIENT_PROMISC_ALL; else mtype = MAC_CLIENT_PROMISC_FILTERED; error = pfp_set_promisc(ps, mtype); } break; case SIOCSLIFFLAGS : if (linkid != ps->ps_linkid) { error = EINVAL; } else { if ((lifreq.lifr_flags & IFF_PROMISC) != 0) mtype = MAC_CLIENT_PROMISC_ALL; else mtype = MAC_CLIENT_PROMISC_FILTERED; error = pfp_set_promisc(ps, mtype); } break; case SIOCGIFMTU : mac_sdu_get(mh, NULL, &ifreq.ifr_mtu); break; case SIOCGLIFMTU : mac_sdu_get(mh, NULL, &lifreq.lifr_mtu); break; case SIOCGIFHWADDR : if (mac_addr_len(mh) > sizeof (ifreq.ifr_addr.sa_data)) { error = EPFNOSUPPORT; break; } if (mac_addr_len(mh) == 0) { (void) memset(ifreq.ifr_addr.sa_data, 0, sizeof (ifreq.ifr_addr.sa_data)); } else { mac_unicast_primary_get(mh, (uint8_t *)ifreq.ifr_addr.sa_data); } /* * The behaviour here in setting sa_family is consistent * with what applications such as tcpdump would expect * for a Linux PF_PACKET socket. */ ifreq.ifr_addr.sa_family = pfp_dl_to_arphrd(mac_type(mh)); break; case SIOCGLIFHWADDR : lifreq.lifr_type = 0; sock = (struct sockaddr_dl *)&lifreq.lifr_addr; if (mac_addr_len(mh) > sizeof (sock->sdl_data)) { error = EPFNOSUPPORT; break; } /* * Fill in the sockaddr_dl with link layer details. Of note, * the index is returned as 0 for a couple of reasons: * (1) there is no public API that uses or requires it * (2) the MAC index is currently 32bits and sdl_index is 16. */ sock->sdl_family = AF_LINK; sock->sdl_index = 0; sock->sdl_type = mac_type(mh); sock->sdl_nlen = 0; sock->sdl_alen = mac_addr_len(mh); sock->sdl_slen = 0; if (mac_addr_len(mh) == 0) { (void) memset(sock->sdl_data, 0, sizeof (sock->sdl_data)); } else { mac_unicast_primary_get(mh, (uint8_t *)sock->sdl_data); } break; default : break; } mac_close(mh); if (error == 0) { /* * Only the "GET" ioctls need to copy data back to userace. */ switch (cmd) { case SIOCGLIFINDEX : case SIOCGLIFFLAGS : case SIOCGLIFMTU : case SIOCGLIFHWADDR : error = ddi_copyout(&lifreq, (void *)arg, sizeof (lifreq), mod); break; case SIOCGIFINDEX : case SIOCGIFFLAGS : case SIOCGIFMTU : case SIOCGIFHWADDR : error = ddi_copyout(&ifreq, (void *)arg, sizeof (ifreq), mod); break; default : break; } } return (error); }