/* ARGSUSED */ static int pfp_setpacket_sockopt(sock_lower_handle_t handle, int option_name, const void *optval, socklen_t optlen) { struct packet_mreq mreq; struct pfpsock *ps; int error = 0; int opt; ps = (struct pfpsock *)handle; if (!ps->ps_bound) return (EPROTO); if ((option_name == PACKET_ADD_MEMBERSHIP) || (option_name == PACKET_DROP_MEMBERSHIP)) { if (!ps->ps_bound) return (EPROTO); bcopy(optval, &mreq, sizeof (mreq)); if (ps->ps_linkid != mreq.mr_ifindex) return (EINVAL); if (mreq.mr_alen != ((struct sockaddr_ll *)&ps->ps_sock)->sll_halen) return (EINVAL); } switch (option_name) { case PACKET_ADD_MEMBERSHIP : switch (mreq.mr_type) { case PACKET_MR_MULTICAST : error = mac_multicast_add(ps->ps_mch, mreq.mr_address); break; case PACKET_MR_PROMISC : error = pfp_set_promisc(ps, MAC_CLIENT_PROMISC_ALL); break; case PACKET_MR_ALLMULTI : error = pfp_set_promisc(ps, MAC_CLIENT_PROMISC_MULTI); break; } break; case PACKET_DROP_MEMBERSHIP : switch (mreq.mr_type) { case PACKET_MR_MULTICAST : mac_multicast_remove(ps->ps_mch, mreq.mr_address); break; case PACKET_MR_PROMISC : if (ps->ps_promisc != MAC_CLIENT_PROMISC_ALL) return (EINVAL); error = pfp_set_promisc(ps, MAC_CLIENT_PROMISC_FILTERED); break; case PACKET_MR_ALLMULTI : if (ps->ps_promisc != MAC_CLIENT_PROMISC_MULTI) return (EINVAL); error = pfp_set_promisc(ps, MAC_CLIENT_PROMISC_FILTERED); break; } break; case PACKET_AUXDATA : if (optlen == sizeof (int)) { opt = *(int *)optval; ps->ps_auxdata = (opt != 0); } else { error = EINVAL; } break; default : error = EINVAL; break; } return (error); }
/* 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); }
/* 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); }