1*10639SDarren.Reed@Sun.COM /* 2*10639SDarren.Reed@Sun.COM * CDDL HEADER START 3*10639SDarren.Reed@Sun.COM * 4*10639SDarren.Reed@Sun.COM * The contents of this file are subject to the terms of the 5*10639SDarren.Reed@Sun.COM * Common Development and Distribution License (the "License"). 6*10639SDarren.Reed@Sun.COM * You may not use this file except in compliance with the License. 7*10639SDarren.Reed@Sun.COM * 8*10639SDarren.Reed@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*10639SDarren.Reed@Sun.COM * or http://www.opensolaris.org/os/licensing. 10*10639SDarren.Reed@Sun.COM * See the License for the specific language governing permissions 11*10639SDarren.Reed@Sun.COM * and limitations under the License. 12*10639SDarren.Reed@Sun.COM * 13*10639SDarren.Reed@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 14*10639SDarren.Reed@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*10639SDarren.Reed@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 16*10639SDarren.Reed@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 17*10639SDarren.Reed@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 18*10639SDarren.Reed@Sun.COM * 19*10639SDarren.Reed@Sun.COM * CDDL HEADER END 20*10639SDarren.Reed@Sun.COM */ 21*10639SDarren.Reed@Sun.COM 22*10639SDarren.Reed@Sun.COM /* 23*10639SDarren.Reed@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24*10639SDarren.Reed@Sun.COM * Use is subject to license terms. 25*10639SDarren.Reed@Sun.COM */ 26*10639SDarren.Reed@Sun.COM 27*10639SDarren.Reed@Sun.COM #include <sys/types.h> 28*10639SDarren.Reed@Sun.COM #include <sys/param.h> 29*10639SDarren.Reed@Sun.COM #include <sys/systm.h> 30*10639SDarren.Reed@Sun.COM #include <sys/stropts.h> 31*10639SDarren.Reed@Sun.COM #include <sys/socket.h> 32*10639SDarren.Reed@Sun.COM #include <sys/socketvar.h> 33*10639SDarren.Reed@Sun.COM #include <sys/socket_proto.h> 34*10639SDarren.Reed@Sun.COM #include <sys/sockio.h> 35*10639SDarren.Reed@Sun.COM #include <sys/strsun.h> 36*10639SDarren.Reed@Sun.COM #include <sys/kstat.h> 37*10639SDarren.Reed@Sun.COM #include <sys/modctl.h> 38*10639SDarren.Reed@Sun.COM #include <sys/policy.h> 39*10639SDarren.Reed@Sun.COM #include <sys/priv_const.h> 40*10639SDarren.Reed@Sun.COM #include <sys/tihdr.h> 41*10639SDarren.Reed@Sun.COM #include <sys/zone.h> 42*10639SDarren.Reed@Sun.COM #include <sys/time.h> 43*10639SDarren.Reed@Sun.COM #include <fs/sockfs/sockcommon.h> 44*10639SDarren.Reed@Sun.COM #include <net/if.h> 45*10639SDarren.Reed@Sun.COM 46*10639SDarren.Reed@Sun.COM #include <sys/dls.h> 47*10639SDarren.Reed@Sun.COM #include <sys/mac.h> 48*10639SDarren.Reed@Sun.COM #include <sys/mac_client.h> 49*10639SDarren.Reed@Sun.COM #include <sys/mac_provider.h> 50*10639SDarren.Reed@Sun.COM #include <sys/mac_client_priv.h> 51*10639SDarren.Reed@Sun.COM 52*10639SDarren.Reed@Sun.COM #include <netpacket/packet.h> 53*10639SDarren.Reed@Sun.COM 54*10639SDarren.Reed@Sun.COM static void pfp_close(mac_handle_t, mac_client_handle_t); 55*10639SDarren.Reed@Sun.COM static int pfp_dl_to_arphrd(int); 56*10639SDarren.Reed@Sun.COM static int pfp_getpacket_sockopt(sock_lower_handle_t, int, void *, 57*10639SDarren.Reed@Sun.COM socklen_t *); 58*10639SDarren.Reed@Sun.COM static int pfp_ifreq_getlinkid(intptr_t, struct ifreq *, datalink_id_t *); 59*10639SDarren.Reed@Sun.COM static int pfp_lifreq_getlinkid(intptr_t, struct lifreq *, datalink_id_t *); 60*10639SDarren.Reed@Sun.COM static int pfp_open_index(int, mac_handle_t *, mac_client_handle_t *, 61*10639SDarren.Reed@Sun.COM cred_t *); 62*10639SDarren.Reed@Sun.COM static void pfp_packet(void *, mac_resource_handle_t, mblk_t *, boolean_t); 63*10639SDarren.Reed@Sun.COM static void pfp_release_bpf(struct pfpsock *); 64*10639SDarren.Reed@Sun.COM static int pfp_set_promisc(struct pfpsock *, mac_client_promisc_type_t); 65*10639SDarren.Reed@Sun.COM static int pfp_setsocket_sockopt(sock_lower_handle_t, int, const void *, 66*10639SDarren.Reed@Sun.COM socklen_t); 67*10639SDarren.Reed@Sun.COM static int pfp_setpacket_sockopt(sock_lower_handle_t, int, const void *, 68*10639SDarren.Reed@Sun.COM socklen_t); 69*10639SDarren.Reed@Sun.COM 70*10639SDarren.Reed@Sun.COM /* 71*10639SDarren.Reed@Sun.COM * PFP sockfs operations 72*10639SDarren.Reed@Sun.COM * Most are currently no-ops because they have no meaning for a connectionless 73*10639SDarren.Reed@Sun.COM * socket. 74*10639SDarren.Reed@Sun.COM */ 75*10639SDarren.Reed@Sun.COM static void sdpfp_activate(sock_lower_handle_t, sock_upper_handle_t, 76*10639SDarren.Reed@Sun.COM sock_upcalls_t *, int, struct cred *); 77*10639SDarren.Reed@Sun.COM static int sdpfp_bind(sock_lower_handle_t, struct sockaddr *, socklen_t, 78*10639SDarren.Reed@Sun.COM struct cred *); 79*10639SDarren.Reed@Sun.COM static int sdpfp_close(sock_lower_handle_t, int, struct cred *); 80*10639SDarren.Reed@Sun.COM static void sdpfp_clr_flowctrl(sock_lower_handle_t); 81*10639SDarren.Reed@Sun.COM static int sdpfp_getsockopt(sock_lower_handle_t, int, int, void *, 82*10639SDarren.Reed@Sun.COM socklen_t *, struct cred *); 83*10639SDarren.Reed@Sun.COM static int sdpfp_ioctl(sock_lower_handle_t, int, intptr_t, int, int32_t *, 84*10639SDarren.Reed@Sun.COM struct cred *); 85*10639SDarren.Reed@Sun.COM static int sdpfp_senduio(sock_lower_handle_t, struct uio *, struct nmsghdr *, 86*10639SDarren.Reed@Sun.COM struct cred *); 87*10639SDarren.Reed@Sun.COM static int sdpfp_setsockopt(sock_lower_handle_t, int, int, const void *, 88*10639SDarren.Reed@Sun.COM socklen_t, struct cred *); 89*10639SDarren.Reed@Sun.COM 90*10639SDarren.Reed@Sun.COM static sock_lower_handle_t sockpfp_create(int, int, int, sock_downcalls_t **, 91*10639SDarren.Reed@Sun.COM uint_t *, int *, int, cred_t *); 92*10639SDarren.Reed@Sun.COM 93*10639SDarren.Reed@Sun.COM static int sockpfp_init(void); 94*10639SDarren.Reed@Sun.COM static void sockpfp_fini(void); 95*10639SDarren.Reed@Sun.COM 96*10639SDarren.Reed@Sun.COM static kstat_t *pfp_ksp; 97*10639SDarren.Reed@Sun.COM static pfp_kstats_t ks_stats; 98*10639SDarren.Reed@Sun.COM static pfp_kstats_t pfp_kstats = { 99*10639SDarren.Reed@Sun.COM /* 100*10639SDarren.Reed@Sun.COM * Each one of these kstats is a different return path in handling 101*10639SDarren.Reed@Sun.COM * a packet received from the mac layer. 102*10639SDarren.Reed@Sun.COM */ 103*10639SDarren.Reed@Sun.COM { "recvMacHeaderFail", KSTAT_DATA_UINT64 }, 104*10639SDarren.Reed@Sun.COM { "recvBadProtocol", KSTAT_DATA_UINT64 }, 105*10639SDarren.Reed@Sun.COM { "recvAllocbFail", KSTAT_DATA_UINT64 }, 106*10639SDarren.Reed@Sun.COM { "recvOk", KSTAT_DATA_UINT64 }, 107*10639SDarren.Reed@Sun.COM { "recvFail", KSTAT_DATA_UINT64 }, 108*10639SDarren.Reed@Sun.COM { "recvFiltered", KSTAT_DATA_UINT64 }, 109*10639SDarren.Reed@Sun.COM { "recvFlowControl", KSTAT_DATA_UINT64 }, 110*10639SDarren.Reed@Sun.COM /* 111*10639SDarren.Reed@Sun.COM * A global set of counters is maintained to track the behaviour 112*10639SDarren.Reed@Sun.COM * of the system (kernel & applications) in sending packets. 113*10639SDarren.Reed@Sun.COM */ 114*10639SDarren.Reed@Sun.COM { "sendUnbound", KSTAT_DATA_UINT64 }, 115*10639SDarren.Reed@Sun.COM { "sendFailed", KSTAT_DATA_UINT64 }, 116*10639SDarren.Reed@Sun.COM { "sendTooBig", KSTAT_DATA_UINT64 }, 117*10639SDarren.Reed@Sun.COM { "sendAllocFail", KSTAT_DATA_UINT64 }, 118*10639SDarren.Reed@Sun.COM { "sendUiomoveFail", KSTAT_DATA_UINT64 }, 119*10639SDarren.Reed@Sun.COM { "sendNoMemory", KSTAT_DATA_UINT64 }, 120*10639SDarren.Reed@Sun.COM { "sendOpenFail", KSTAT_DATA_UINT64 }, 121*10639SDarren.Reed@Sun.COM { "sendWrongFamily", KSTAT_DATA_UINT64 }, 122*10639SDarren.Reed@Sun.COM { "sendShortMsg", KSTAT_DATA_UINT64 }, 123*10639SDarren.Reed@Sun.COM { "sendOk", KSTAT_DATA_UINT64 } 124*10639SDarren.Reed@Sun.COM }; 125*10639SDarren.Reed@Sun.COM 126*10639SDarren.Reed@Sun.COM sock_downcalls_t pfp_downcalls = { 127*10639SDarren.Reed@Sun.COM sdpfp_activate, 128*10639SDarren.Reed@Sun.COM sock_accept_notsupp, 129*10639SDarren.Reed@Sun.COM sdpfp_bind, 130*10639SDarren.Reed@Sun.COM sock_listen_notsupp, 131*10639SDarren.Reed@Sun.COM sock_connect_notsupp, 132*10639SDarren.Reed@Sun.COM sock_getpeername_notsupp, 133*10639SDarren.Reed@Sun.COM sock_getsockname_notsupp, 134*10639SDarren.Reed@Sun.COM sdpfp_getsockopt, 135*10639SDarren.Reed@Sun.COM sdpfp_setsockopt, 136*10639SDarren.Reed@Sun.COM sock_send_notsupp, 137*10639SDarren.Reed@Sun.COM sdpfp_senduio, 138*10639SDarren.Reed@Sun.COM NULL, 139*10639SDarren.Reed@Sun.COM sock_poll_notsupp, 140*10639SDarren.Reed@Sun.COM sock_shutdown_notsupp, 141*10639SDarren.Reed@Sun.COM sdpfp_clr_flowctrl, 142*10639SDarren.Reed@Sun.COM sdpfp_ioctl, 143*10639SDarren.Reed@Sun.COM sdpfp_close, 144*10639SDarren.Reed@Sun.COM }; 145*10639SDarren.Reed@Sun.COM 146*10639SDarren.Reed@Sun.COM static smod_reg_t sinfo = { 147*10639SDarren.Reed@Sun.COM SOCKMOD_VERSION, 148*10639SDarren.Reed@Sun.COM "sockpfp", 149*10639SDarren.Reed@Sun.COM SOCK_UC_VERSION, 150*10639SDarren.Reed@Sun.COM SOCK_DC_VERSION, 151*10639SDarren.Reed@Sun.COM sockpfp_create, 152*10639SDarren.Reed@Sun.COM NULL 153*10639SDarren.Reed@Sun.COM }; 154*10639SDarren.Reed@Sun.COM 155*10639SDarren.Reed@Sun.COM /* 156*10639SDarren.Reed@Sun.COM * Module linkage information for the kernel. 157*10639SDarren.Reed@Sun.COM */ 158*10639SDarren.Reed@Sun.COM static struct modlsockmod modlsockmod = { 159*10639SDarren.Reed@Sun.COM &mod_sockmodops, "PF Packet socket module", &sinfo 160*10639SDarren.Reed@Sun.COM }; 161*10639SDarren.Reed@Sun.COM 162*10639SDarren.Reed@Sun.COM static struct modlinkage modlinkage = { 163*10639SDarren.Reed@Sun.COM MODREV_1, 164*10639SDarren.Reed@Sun.COM &modlsockmod, 165*10639SDarren.Reed@Sun.COM NULL 166*10639SDarren.Reed@Sun.COM }; 167*10639SDarren.Reed@Sun.COM 168*10639SDarren.Reed@Sun.COM int 169*10639SDarren.Reed@Sun.COM _init(void) 170*10639SDarren.Reed@Sun.COM { 171*10639SDarren.Reed@Sun.COM int error; 172*10639SDarren.Reed@Sun.COM 173*10639SDarren.Reed@Sun.COM error = sockpfp_init(); 174*10639SDarren.Reed@Sun.COM if (error != 0) 175*10639SDarren.Reed@Sun.COM return (error); 176*10639SDarren.Reed@Sun.COM 177*10639SDarren.Reed@Sun.COM error = mod_install(&modlinkage); 178*10639SDarren.Reed@Sun.COM if (error != 0) 179*10639SDarren.Reed@Sun.COM sockpfp_fini(); 180*10639SDarren.Reed@Sun.COM 181*10639SDarren.Reed@Sun.COM return (error); 182*10639SDarren.Reed@Sun.COM } 183*10639SDarren.Reed@Sun.COM 184*10639SDarren.Reed@Sun.COM int 185*10639SDarren.Reed@Sun.COM _fini(void) 186*10639SDarren.Reed@Sun.COM { 187*10639SDarren.Reed@Sun.COM int error; 188*10639SDarren.Reed@Sun.COM 189*10639SDarren.Reed@Sun.COM error = mod_remove(&modlinkage); 190*10639SDarren.Reed@Sun.COM if (error == 0) 191*10639SDarren.Reed@Sun.COM sockpfp_fini(); 192*10639SDarren.Reed@Sun.COM 193*10639SDarren.Reed@Sun.COM return (error); 194*10639SDarren.Reed@Sun.COM } 195*10639SDarren.Reed@Sun.COM 196*10639SDarren.Reed@Sun.COM int 197*10639SDarren.Reed@Sun.COM _info(struct modinfo *modinfop) 198*10639SDarren.Reed@Sun.COM { 199*10639SDarren.Reed@Sun.COM return (mod_info(&modlinkage, modinfop)); 200*10639SDarren.Reed@Sun.COM } 201*10639SDarren.Reed@Sun.COM 202*10639SDarren.Reed@Sun.COM /* 203*10639SDarren.Reed@Sun.COM * sockpfp_init: called as part of the initialisation of the module when 204*10639SDarren.Reed@Sun.COM * loaded into the kernel. 205*10639SDarren.Reed@Sun.COM * 206*10639SDarren.Reed@Sun.COM * Being able to create and record the kstats data in the kernel is not 207*10639SDarren.Reed@Sun.COM * considered to be vital to the operation of this kernel module, thus 208*10639SDarren.Reed@Sun.COM * its failure is tolerated. 209*10639SDarren.Reed@Sun.COM */ 210*10639SDarren.Reed@Sun.COM static int 211*10639SDarren.Reed@Sun.COM sockpfp_init(void) 212*10639SDarren.Reed@Sun.COM { 213*10639SDarren.Reed@Sun.COM (void) memset(&ks_stats, 0, sizeof (ks_stats)); 214*10639SDarren.Reed@Sun.COM 215*10639SDarren.Reed@Sun.COM (void) memcpy(&ks_stats, &pfp_kstats, sizeof (pfp_kstats)); 216*10639SDarren.Reed@Sun.COM 217*10639SDarren.Reed@Sun.COM pfp_ksp = kstat_create("pfpacket", 0, "global", "misc", 218*10639SDarren.Reed@Sun.COM KSTAT_TYPE_NAMED, sizeof (pfp_kstats) / sizeof (kstat_named_t), 219*10639SDarren.Reed@Sun.COM KSTAT_FLAG_VIRTUAL); 220*10639SDarren.Reed@Sun.COM if (pfp_ksp != NULL) { 221*10639SDarren.Reed@Sun.COM pfp_ksp->ks_data = &ks_stats; 222*10639SDarren.Reed@Sun.COM kstat_install(pfp_ksp); 223*10639SDarren.Reed@Sun.COM } 224*10639SDarren.Reed@Sun.COM 225*10639SDarren.Reed@Sun.COM return (0); 226*10639SDarren.Reed@Sun.COM } 227*10639SDarren.Reed@Sun.COM 228*10639SDarren.Reed@Sun.COM /* 229*10639SDarren.Reed@Sun.COM * sockpfp_fini: called when the operating system wants to unload the 230*10639SDarren.Reed@Sun.COM * socket module from the kernel. 231*10639SDarren.Reed@Sun.COM */ 232*10639SDarren.Reed@Sun.COM static void 233*10639SDarren.Reed@Sun.COM sockpfp_fini(void) 234*10639SDarren.Reed@Sun.COM { 235*10639SDarren.Reed@Sun.COM if (pfp_ksp != NULL) 236*10639SDarren.Reed@Sun.COM kstat_delete(pfp_ksp); 237*10639SDarren.Reed@Sun.COM } 238*10639SDarren.Reed@Sun.COM 239*10639SDarren.Reed@Sun.COM /* 240*10639SDarren.Reed@Sun.COM * Due to sockets being created read-write by default, all PF_PACKET sockets 241*10639SDarren.Reed@Sun.COM * therefore require the NET_RAWACCESS priviliege, even if the socket is only 242*10639SDarren.Reed@Sun.COM * being used for reading packets from. 243*10639SDarren.Reed@Sun.COM * 244*10639SDarren.Reed@Sun.COM * This create function enforces this module only being used with PF_PACKET 245*10639SDarren.Reed@Sun.COM * sockets and the policy that we support via the sock2path.conf file: 246*10639SDarren.Reed@Sun.COM * PF_PACKET sockets must be either SOCK_DGRAM or SOCK_RAW. 247*10639SDarren.Reed@Sun.COM */ 248*10639SDarren.Reed@Sun.COM /* ARGSUSED */ 249*10639SDarren.Reed@Sun.COM static sock_lower_handle_t 250*10639SDarren.Reed@Sun.COM sockpfp_create(int family, int type, int proto, 251*10639SDarren.Reed@Sun.COM sock_downcalls_t **sock_downcalls, uint_t *smodep, int *errorp, 252*10639SDarren.Reed@Sun.COM int sflags, cred_t *cred) 253*10639SDarren.Reed@Sun.COM { 254*10639SDarren.Reed@Sun.COM struct pfpsock *ps; 255*10639SDarren.Reed@Sun.COM int kmflags; 256*10639SDarren.Reed@Sun.COM 257*10639SDarren.Reed@Sun.COM if (secpolicy_net_rawaccess(cred) != 0) { 258*10639SDarren.Reed@Sun.COM *errorp = EACCES; 259*10639SDarren.Reed@Sun.COM return (NULL); 260*10639SDarren.Reed@Sun.COM } 261*10639SDarren.Reed@Sun.COM 262*10639SDarren.Reed@Sun.COM if (family != AF_PACKET) { 263*10639SDarren.Reed@Sun.COM *errorp = EAFNOSUPPORT; 264*10639SDarren.Reed@Sun.COM return (NULL); 265*10639SDarren.Reed@Sun.COM } 266*10639SDarren.Reed@Sun.COM 267*10639SDarren.Reed@Sun.COM if ((type != SOCK_RAW) && (type != SOCK_DGRAM)) { 268*10639SDarren.Reed@Sun.COM *errorp = ESOCKTNOSUPPORT; 269*10639SDarren.Reed@Sun.COM return (NULL); 270*10639SDarren.Reed@Sun.COM } 271*10639SDarren.Reed@Sun.COM 272*10639SDarren.Reed@Sun.COM kmflags = (sflags & SOCKET_NOSLEEP) ? KM_NOSLEEP : KM_SLEEP; 273*10639SDarren.Reed@Sun.COM ps = kmem_zalloc(sizeof (*ps), kmflags); 274*10639SDarren.Reed@Sun.COM if (ps == NULL) { 275*10639SDarren.Reed@Sun.COM *errorp = ENOMEM; 276*10639SDarren.Reed@Sun.COM return (NULL); 277*10639SDarren.Reed@Sun.COM } 278*10639SDarren.Reed@Sun.COM 279*10639SDarren.Reed@Sun.COM ps->ps_type = type; 280*10639SDarren.Reed@Sun.COM ps->ps_proto = proto; 281*10639SDarren.Reed@Sun.COM rw_init(&ps->ps_bpflock, NULL, RW_DRIVER, NULL); 282*10639SDarren.Reed@Sun.COM mutex_init(&ps->ps_lock, NULL, MUTEX_DRIVER, NULL); 283*10639SDarren.Reed@Sun.COM 284*10639SDarren.Reed@Sun.COM *sock_downcalls = &pfp_downcalls; 285*10639SDarren.Reed@Sun.COM /* 286*10639SDarren.Reed@Sun.COM * Setting this causes bytes from a packet that do not fit into the 287*10639SDarren.Reed@Sun.COM * destination user buffer to be discarded. Thus the API is one 288*10639SDarren.Reed@Sun.COM * packet per receive and callers are required to use a buffer large 289*10639SDarren.Reed@Sun.COM * enough for the biggest packet that the interface can provide. 290*10639SDarren.Reed@Sun.COM */ 291*10639SDarren.Reed@Sun.COM *smodep = SM_ATOMIC; 292*10639SDarren.Reed@Sun.COM 293*10639SDarren.Reed@Sun.COM return ((sock_lower_handle_t)ps); 294*10639SDarren.Reed@Sun.COM } 295*10639SDarren.Reed@Sun.COM 296*10639SDarren.Reed@Sun.COM /* ************************************************************************* */ 297*10639SDarren.Reed@Sun.COM 298*10639SDarren.Reed@Sun.COM /* 299*10639SDarren.Reed@Sun.COM * pfp_packet is the callback function that is given to the mac layer for 300*10639SDarren.Reed@Sun.COM * PF_PACKET to receive packets with. One packet at a time is passed into 301*10639SDarren.Reed@Sun.COM * this function from the mac layer. Each packet is a private copy given 302*10639SDarren.Reed@Sun.COM * to PF_PACKET to modify or free as it wishes and does not harm the original 303*10639SDarren.Reed@Sun.COM * packet from which it was cloned. 304*10639SDarren.Reed@Sun.COM */ 305*10639SDarren.Reed@Sun.COM /* ARGSUSED */ 306*10639SDarren.Reed@Sun.COM static void 307*10639SDarren.Reed@Sun.COM pfp_packet(void *arg, mac_resource_handle_t mrh, mblk_t *mp, boolean_t flag) 308*10639SDarren.Reed@Sun.COM { 309*10639SDarren.Reed@Sun.COM struct T_unitdata_ind *tunit; 310*10639SDarren.Reed@Sun.COM struct sockaddr_ll *sll; 311*10639SDarren.Reed@Sun.COM struct sockaddr_ll *sol; 312*10639SDarren.Reed@Sun.COM mac_header_info_t hdr; 313*10639SDarren.Reed@Sun.COM struct pfpsock *ps; 314*10639SDarren.Reed@Sun.COM size_t tusz; 315*10639SDarren.Reed@Sun.COM mblk_t *mp0; 316*10639SDarren.Reed@Sun.COM int error; 317*10639SDarren.Reed@Sun.COM 318*10639SDarren.Reed@Sun.COM if (mp == NULL) 319*10639SDarren.Reed@Sun.COM return; 320*10639SDarren.Reed@Sun.COM 321*10639SDarren.Reed@Sun.COM ps = arg; 322*10639SDarren.Reed@Sun.COM if (ps->ps_flow_ctrld) { 323*10639SDarren.Reed@Sun.COM ps->ps_flow_ctrl_drops++; 324*10639SDarren.Reed@Sun.COM ps->ps_stats.tp_drops++; 325*10639SDarren.Reed@Sun.COM ks_stats.kp_recv_flow_cntrld.value.ui64++; 326*10639SDarren.Reed@Sun.COM freemsg(mp); 327*10639SDarren.Reed@Sun.COM return; 328*10639SDarren.Reed@Sun.COM } 329*10639SDarren.Reed@Sun.COM 330*10639SDarren.Reed@Sun.COM if (mac_header_info(ps->ps_mh, mp, &hdr) != 0) { 331*10639SDarren.Reed@Sun.COM /* 332*10639SDarren.Reed@Sun.COM * Can't decode the packet header information so drop it. 333*10639SDarren.Reed@Sun.COM */ 334*10639SDarren.Reed@Sun.COM ps->ps_stats.tp_drops++; 335*10639SDarren.Reed@Sun.COM ks_stats.kp_recv_mac_hdr_fail.value.ui64++; 336*10639SDarren.Reed@Sun.COM freemsg(mp); 337*10639SDarren.Reed@Sun.COM return; 338*10639SDarren.Reed@Sun.COM } 339*10639SDarren.Reed@Sun.COM 340*10639SDarren.Reed@Sun.COM if (mac_type(ps->ps_mh) == DL_ETHER && 341*10639SDarren.Reed@Sun.COM hdr.mhi_bindsap == ETHERTYPE_VLAN) { 342*10639SDarren.Reed@Sun.COM struct ether_vlan_header *evhp; 343*10639SDarren.Reed@Sun.COM struct ether_vlan_header evh; 344*10639SDarren.Reed@Sun.COM 345*10639SDarren.Reed@Sun.COM hdr.mhi_hdrsize = sizeof (struct ether_vlan_header); 346*10639SDarren.Reed@Sun.COM hdr.mhi_istagged = B_TRUE; 347*10639SDarren.Reed@Sun.COM 348*10639SDarren.Reed@Sun.COM if (MBLKL(mp) >= sizeof (*evhp)) { 349*10639SDarren.Reed@Sun.COM evhp = (struct ether_vlan_header *)mp->b_rptr; 350*10639SDarren.Reed@Sun.COM } else { 351*10639SDarren.Reed@Sun.COM int sz = sizeof (*evhp); 352*10639SDarren.Reed@Sun.COM char *s = (char *)&evh; 353*10639SDarren.Reed@Sun.COM mblk_t *tmp; 354*10639SDarren.Reed@Sun.COM int len; 355*10639SDarren.Reed@Sun.COM 356*10639SDarren.Reed@Sun.COM for (tmp = mp; sz > 0 && tmp != NULL; 357*10639SDarren.Reed@Sun.COM tmp = tmp->b_cont) { 358*10639SDarren.Reed@Sun.COM len = min(sz, MBLKL(tmp)); 359*10639SDarren.Reed@Sun.COM bcopy(tmp->b_rptr, s, len); 360*10639SDarren.Reed@Sun.COM sz -= len; 361*10639SDarren.Reed@Sun.COM } 362*10639SDarren.Reed@Sun.COM evhp = &evh; 363*10639SDarren.Reed@Sun.COM } 364*10639SDarren.Reed@Sun.COM hdr.mhi_tci = ntohs(evhp->ether_tci); 365*10639SDarren.Reed@Sun.COM hdr.mhi_bindsap = ntohs(evhp->ether_type); 366*10639SDarren.Reed@Sun.COM } 367*10639SDarren.Reed@Sun.COM 368*10639SDarren.Reed@Sun.COM if ((ps->ps_proto != 0) && (ps->ps_proto != hdr.mhi_bindsap)) { 369*10639SDarren.Reed@Sun.COM /* 370*10639SDarren.Reed@Sun.COM * The packet is not of interest to this socket so 371*10639SDarren.Reed@Sun.COM * drop it on the floor. Here the SAP is being used 372*10639SDarren.Reed@Sun.COM * as a very course filter. 373*10639SDarren.Reed@Sun.COM */ 374*10639SDarren.Reed@Sun.COM ps->ps_stats.tp_drops++; 375*10639SDarren.Reed@Sun.COM ks_stats.kp_recv_bad_proto.value.ui64++; 376*10639SDarren.Reed@Sun.COM freemsg(mp); 377*10639SDarren.Reed@Sun.COM return; 378*10639SDarren.Reed@Sun.COM } 379*10639SDarren.Reed@Sun.COM 380*10639SDarren.Reed@Sun.COM /* 381*10639SDarren.Reed@Sun.COM * This field is not often set, even for ethernet, 382*10639SDarren.Reed@Sun.COM * by mac_header_info, so compute it if it is 0. 383*10639SDarren.Reed@Sun.COM */ 384*10639SDarren.Reed@Sun.COM if (hdr.mhi_pktsize == 0) 385*10639SDarren.Reed@Sun.COM hdr.mhi_pktsize = msgdsize(mp); 386*10639SDarren.Reed@Sun.COM 387*10639SDarren.Reed@Sun.COM /* 388*10639SDarren.Reed@Sun.COM * If a BPF filter is present, pass the raw packet into that. 389*10639SDarren.Reed@Sun.COM * A failed match will result in zero being returned, indicating 390*10639SDarren.Reed@Sun.COM * that this socket is not interested in the packet. 391*10639SDarren.Reed@Sun.COM */ 392*10639SDarren.Reed@Sun.COM if (ps->ps_bpf.bf_len != 0) { 393*10639SDarren.Reed@Sun.COM uchar_t *buffer; 394*10639SDarren.Reed@Sun.COM int buflen; 395*10639SDarren.Reed@Sun.COM 396*10639SDarren.Reed@Sun.COM buflen = MBLKL(mp); 397*10639SDarren.Reed@Sun.COM if (hdr.mhi_pktsize == buflen) { 398*10639SDarren.Reed@Sun.COM buffer = mp->b_rptr; 399*10639SDarren.Reed@Sun.COM } else { 400*10639SDarren.Reed@Sun.COM buflen = 0; 401*10639SDarren.Reed@Sun.COM buffer = (uchar_t *)mp; 402*10639SDarren.Reed@Sun.COM } 403*10639SDarren.Reed@Sun.COM rw_enter(&ps->ps_bpflock, RW_READER); 404*10639SDarren.Reed@Sun.COM if (bpf_filter(ps->ps_bpf.bf_insns, buffer, 405*10639SDarren.Reed@Sun.COM hdr.mhi_pktsize, buflen) == 0) { 406*10639SDarren.Reed@Sun.COM rw_exit(&ps->ps_bpflock); 407*10639SDarren.Reed@Sun.COM ps->ps_stats.tp_drops++; 408*10639SDarren.Reed@Sun.COM ks_stats.kp_recv_filtered.value.ui64++; 409*10639SDarren.Reed@Sun.COM freemsg(mp); 410*10639SDarren.Reed@Sun.COM return; 411*10639SDarren.Reed@Sun.COM } 412*10639SDarren.Reed@Sun.COM rw_exit(&ps->ps_bpflock); 413*10639SDarren.Reed@Sun.COM } 414*10639SDarren.Reed@Sun.COM 415*10639SDarren.Reed@Sun.COM if (ps->ps_type == SOCK_DGRAM) { 416*10639SDarren.Reed@Sun.COM /* 417*10639SDarren.Reed@Sun.COM * SOCK_DGRAM socket expect a "layer 3" packet, so advance 418*10639SDarren.Reed@Sun.COM * past the link layer header. 419*10639SDarren.Reed@Sun.COM */ 420*10639SDarren.Reed@Sun.COM mp->b_rptr += hdr.mhi_hdrsize; 421*10639SDarren.Reed@Sun.COM hdr.mhi_pktsize -= hdr.mhi_hdrsize; 422*10639SDarren.Reed@Sun.COM } 423*10639SDarren.Reed@Sun.COM 424*10639SDarren.Reed@Sun.COM tusz = sizeof (struct T_unitdata_ind) + sizeof (struct sockaddr_ll); 425*10639SDarren.Reed@Sun.COM if (ps->ps_auxdata) { 426*10639SDarren.Reed@Sun.COM tusz += _TPI_ALIGN_TOPT(sizeof (struct tpacket_auxdata)); 427*10639SDarren.Reed@Sun.COM tusz += _TPI_ALIGN_TOPT(sizeof (struct T_opthdr)); 428*10639SDarren.Reed@Sun.COM } 429*10639SDarren.Reed@Sun.COM 430*10639SDarren.Reed@Sun.COM /* 431*10639SDarren.Reed@Sun.COM * It is tempting to think that this could be optimised by having 432*10639SDarren.Reed@Sun.COM * the base mblk_t allocated and hung off the pfpsock structure, 433*10639SDarren.Reed@Sun.COM * except that then another one would need to be allocated for the 434*10639SDarren.Reed@Sun.COM * sockaddr_ll that is included. Even creating a template to copy 435*10639SDarren.Reed@Sun.COM * from is of questionable value, as read-write from one structure 436*10639SDarren.Reed@Sun.COM * to the other is going to be slower than all of the initialisation. 437*10639SDarren.Reed@Sun.COM */ 438*10639SDarren.Reed@Sun.COM mp0 = allocb(tusz, BPRI_HI); 439*10639SDarren.Reed@Sun.COM if (mp0 == NULL) { 440*10639SDarren.Reed@Sun.COM ps->ps_stats.tp_drops++; 441*10639SDarren.Reed@Sun.COM ks_stats.kp_recv_alloc_fail.value.ui64++; 442*10639SDarren.Reed@Sun.COM freemsg(mp); 443*10639SDarren.Reed@Sun.COM return; 444*10639SDarren.Reed@Sun.COM } 445*10639SDarren.Reed@Sun.COM 446*10639SDarren.Reed@Sun.COM (void) memset(mp0->b_rptr, 0, tusz); 447*10639SDarren.Reed@Sun.COM 448*10639SDarren.Reed@Sun.COM mp0->b_datap->db_type = M_PROTO; 449*10639SDarren.Reed@Sun.COM mp0->b_wptr = mp0->b_rptr + tusz; 450*10639SDarren.Reed@Sun.COM 451*10639SDarren.Reed@Sun.COM tunit = (struct T_unitdata_ind *)mp0->b_rptr; 452*10639SDarren.Reed@Sun.COM tunit->PRIM_type = T_UNITDATA_IND; 453*10639SDarren.Reed@Sun.COM tunit->SRC_length = sizeof (struct sockaddr); 454*10639SDarren.Reed@Sun.COM tunit->SRC_offset = sizeof (*tunit); 455*10639SDarren.Reed@Sun.COM 456*10639SDarren.Reed@Sun.COM sol = (struct sockaddr_ll *)&ps->ps_sock; 457*10639SDarren.Reed@Sun.COM sll = (struct sockaddr_ll *)(mp0->b_rptr + sizeof (*tunit)); 458*10639SDarren.Reed@Sun.COM sll->sll_ifindex = sol->sll_ifindex; 459*10639SDarren.Reed@Sun.COM sll->sll_hatype = (uint16_t)hdr.mhi_origsap; 460*10639SDarren.Reed@Sun.COM sll->sll_halen = sol->sll_halen; 461*10639SDarren.Reed@Sun.COM if (hdr.mhi_saddr != NULL) 462*10639SDarren.Reed@Sun.COM (void) memcpy(sll->sll_addr, hdr.mhi_saddr, sll->sll_halen); 463*10639SDarren.Reed@Sun.COM 464*10639SDarren.Reed@Sun.COM switch (hdr.mhi_dsttype) { 465*10639SDarren.Reed@Sun.COM case MAC_ADDRTYPE_MULTICAST : 466*10639SDarren.Reed@Sun.COM sll->sll_pkttype = PACKET_MULTICAST; 467*10639SDarren.Reed@Sun.COM break; 468*10639SDarren.Reed@Sun.COM case MAC_ADDRTYPE_BROADCAST : 469*10639SDarren.Reed@Sun.COM sll->sll_pkttype = PACKET_BROADCAST; 470*10639SDarren.Reed@Sun.COM break; 471*10639SDarren.Reed@Sun.COM case MAC_ADDRTYPE_UNICAST : 472*10639SDarren.Reed@Sun.COM if (memcmp(sol->sll_addr, hdr.mhi_daddr, sol->sll_halen) == 0) 473*10639SDarren.Reed@Sun.COM sll->sll_pkttype = PACKET_HOST; 474*10639SDarren.Reed@Sun.COM else 475*10639SDarren.Reed@Sun.COM sll->sll_pkttype = PACKET_OTHERHOST; 476*10639SDarren.Reed@Sun.COM break; 477*10639SDarren.Reed@Sun.COM } 478*10639SDarren.Reed@Sun.COM 479*10639SDarren.Reed@Sun.COM if (ps->ps_auxdata) { 480*10639SDarren.Reed@Sun.COM struct tpacket_auxdata *aux; 481*10639SDarren.Reed@Sun.COM struct T_opthdr *topt; 482*10639SDarren.Reed@Sun.COM 483*10639SDarren.Reed@Sun.COM tunit->OPT_offset = _TPI_ALIGN_TOPT(tunit->SRC_offset + 484*10639SDarren.Reed@Sun.COM sizeof (struct sockaddr_ll)); 485*10639SDarren.Reed@Sun.COM tunit->OPT_length = _TPI_ALIGN_TOPT(sizeof (struct T_opthdr)) + 486*10639SDarren.Reed@Sun.COM _TPI_ALIGN_TOPT(sizeof (struct tpacket_auxdata)); 487*10639SDarren.Reed@Sun.COM 488*10639SDarren.Reed@Sun.COM topt = (struct T_opthdr *)(mp0->b_rptr + tunit->OPT_offset); 489*10639SDarren.Reed@Sun.COM aux = (struct tpacket_auxdata *) 490*10639SDarren.Reed@Sun.COM ((char *)topt + _TPI_ALIGN_TOPT(sizeof (*topt))); 491*10639SDarren.Reed@Sun.COM 492*10639SDarren.Reed@Sun.COM topt->len = tunit->OPT_length; 493*10639SDarren.Reed@Sun.COM topt->level = SOL_PACKET; 494*10639SDarren.Reed@Sun.COM topt->name = PACKET_AUXDATA; 495*10639SDarren.Reed@Sun.COM topt->status = 0; 496*10639SDarren.Reed@Sun.COM /* 497*10639SDarren.Reed@Sun.COM * libpcap doesn't seem to use any other field, 498*10639SDarren.Reed@Sun.COM * so it isn't clear how they should be filled in. 499*10639SDarren.Reed@Sun.COM */ 500*10639SDarren.Reed@Sun.COM aux->tp_vlan_vci = hdr.mhi_tci; 501*10639SDarren.Reed@Sun.COM } 502*10639SDarren.Reed@Sun.COM 503*10639SDarren.Reed@Sun.COM linkb(mp0, mp); 504*10639SDarren.Reed@Sun.COM 505*10639SDarren.Reed@Sun.COM ps->ps_upcalls->su_recv(ps->ps_upper, mp0, hdr.mhi_pktsize, 0, 506*10639SDarren.Reed@Sun.COM &error, NULL); 507*10639SDarren.Reed@Sun.COM 508*10639SDarren.Reed@Sun.COM if (error == 0) { 509*10639SDarren.Reed@Sun.COM ps->ps_stats.tp_packets++; 510*10639SDarren.Reed@Sun.COM ks_stats.kp_recv_ok.value.ui64++; 511*10639SDarren.Reed@Sun.COM } else { 512*10639SDarren.Reed@Sun.COM mutex_enter(&ps->ps_lock); 513*10639SDarren.Reed@Sun.COM if (error == ENOSPC) { 514*10639SDarren.Reed@Sun.COM ps->ps_upcalls->su_recv(ps->ps_upper, NULL, 0, 0, 515*10639SDarren.Reed@Sun.COM &error, NULL); 516*10639SDarren.Reed@Sun.COM if (error == ENOSPC) 517*10639SDarren.Reed@Sun.COM ps->ps_flow_ctrld = B_TRUE; 518*10639SDarren.Reed@Sun.COM } 519*10639SDarren.Reed@Sun.COM mutex_exit(&ps->ps_lock); 520*10639SDarren.Reed@Sun.COM ps->ps_stats.tp_drops++; 521*10639SDarren.Reed@Sun.COM ks_stats.kp_recv_fail.value.ui64++; 522*10639SDarren.Reed@Sun.COM } 523*10639SDarren.Reed@Sun.COM } 524*10639SDarren.Reed@Sun.COM 525*10639SDarren.Reed@Sun.COM /* 526*10639SDarren.Reed@Sun.COM * Bind a PF_PACKET socket to a network interface. 527*10639SDarren.Reed@Sun.COM * 528*10639SDarren.Reed@Sun.COM * The default operation of this bind() is to place the socket (and thus the 529*10639SDarren.Reed@Sun.COM * network interface) into promiscuous mode. It is then up to the application 530*10639SDarren.Reed@Sun.COM * to turn that down by issuing the relevant ioctls, if desired. 531*10639SDarren.Reed@Sun.COM */ 532*10639SDarren.Reed@Sun.COM /* ARGSUSED */ 533*10639SDarren.Reed@Sun.COM static int 534*10639SDarren.Reed@Sun.COM sdpfp_bind(sock_lower_handle_t handle, struct sockaddr *addr, 535*10639SDarren.Reed@Sun.COM socklen_t addrlen, struct cred *cred) 536*10639SDarren.Reed@Sun.COM { 537*10639SDarren.Reed@Sun.COM struct sockaddr_ll *addr_ll, *sol; 538*10639SDarren.Reed@Sun.COM mac_client_handle_t mch; 539*10639SDarren.Reed@Sun.COM struct pfpsock *ps; 540*10639SDarren.Reed@Sun.COM mac_handle_t mh; 541*10639SDarren.Reed@Sun.COM int error; 542*10639SDarren.Reed@Sun.COM 543*10639SDarren.Reed@Sun.COM ps = (struct pfpsock *)handle; 544*10639SDarren.Reed@Sun.COM if (ps->ps_bound) 545*10639SDarren.Reed@Sun.COM return (EINVAL); 546*10639SDarren.Reed@Sun.COM 547*10639SDarren.Reed@Sun.COM addr_ll = (struct sockaddr_ll *)addr; 548*10639SDarren.Reed@Sun.COM 549*10639SDarren.Reed@Sun.COM error = pfp_open_index(addr_ll->sll_ifindex, &mh, &mch, cred); 550*10639SDarren.Reed@Sun.COM if (error != 0) 551*10639SDarren.Reed@Sun.COM return (error); 552*10639SDarren.Reed@Sun.COM /* 553*10639SDarren.Reed@Sun.COM * Ensure that each socket is only bound once. 554*10639SDarren.Reed@Sun.COM */ 555*10639SDarren.Reed@Sun.COM mutex_enter(&ps->ps_lock); 556*10639SDarren.Reed@Sun.COM if (ps->ps_mh != 0) { 557*10639SDarren.Reed@Sun.COM mutex_exit(&ps->ps_lock); 558*10639SDarren.Reed@Sun.COM pfp_close(mh, mch); 559*10639SDarren.Reed@Sun.COM return (EADDRINUSE); 560*10639SDarren.Reed@Sun.COM } 561*10639SDarren.Reed@Sun.COM ps->ps_mh = mh; 562*10639SDarren.Reed@Sun.COM ps->ps_mch = mch; 563*10639SDarren.Reed@Sun.COM mutex_exit(&ps->ps_lock); 564*10639SDarren.Reed@Sun.COM 565*10639SDarren.Reed@Sun.COM /* 566*10639SDarren.Reed@Sun.COM * Cache all of the information from bind so that it's in an easy 567*10639SDarren.Reed@Sun.COM * place to get at when packets are received. 568*10639SDarren.Reed@Sun.COM */ 569*10639SDarren.Reed@Sun.COM sol = (struct sockaddr_ll *)&ps->ps_sock; 570*10639SDarren.Reed@Sun.COM sol->sll_family = AF_PACKET; 571*10639SDarren.Reed@Sun.COM sol->sll_ifindex = addr_ll->sll_ifindex; 572*10639SDarren.Reed@Sun.COM sol->sll_protocol = addr_ll->sll_protocol; 573*10639SDarren.Reed@Sun.COM sol->sll_halen = mac_addr_len(ps->ps_mh); 574*10639SDarren.Reed@Sun.COM mac_unicast_primary_get(ps->ps_mh, sol->sll_addr); 575*10639SDarren.Reed@Sun.COM mac_sdu_get(ps->ps_mh, NULL, &ps->ps_max_sdu); 576*10639SDarren.Reed@Sun.COM ps->ps_linkid = addr_ll->sll_ifindex; 577*10639SDarren.Reed@Sun.COM 578*10639SDarren.Reed@Sun.COM error = mac_promisc_add(ps->ps_mch, MAC_CLIENT_PROMISC_ALL, 579*10639SDarren.Reed@Sun.COM pfp_packet, ps, &ps->ps_phd, MAC_PROMISC_FLAGS_VLAN_TAG_STRIP); 580*10639SDarren.Reed@Sun.COM if (error == 0) { 581*10639SDarren.Reed@Sun.COM ps->ps_promisc = MAC_CLIENT_PROMISC_ALL; 582*10639SDarren.Reed@Sun.COM ps->ps_bound = B_TRUE; 583*10639SDarren.Reed@Sun.COM } 584*10639SDarren.Reed@Sun.COM 585*10639SDarren.Reed@Sun.COM return (error); 586*10639SDarren.Reed@Sun.COM } 587*10639SDarren.Reed@Sun.COM 588*10639SDarren.Reed@Sun.COM /* ARGSUSED */ 589*10639SDarren.Reed@Sun.COM static void 590*10639SDarren.Reed@Sun.COM sdpfp_activate(sock_lower_handle_t lower, sock_upper_handle_t upper, 591*10639SDarren.Reed@Sun.COM sock_upcalls_t *upcalls, int flags, cred_t *cred) 592*10639SDarren.Reed@Sun.COM { 593*10639SDarren.Reed@Sun.COM struct pfpsock *ps; 594*10639SDarren.Reed@Sun.COM 595*10639SDarren.Reed@Sun.COM ps = (struct pfpsock *)lower; 596*10639SDarren.Reed@Sun.COM ps->ps_upper = upper; 597*10639SDarren.Reed@Sun.COM ps->ps_upcalls = upcalls; 598*10639SDarren.Reed@Sun.COM } 599*10639SDarren.Reed@Sun.COM 600*10639SDarren.Reed@Sun.COM /* 601*10639SDarren.Reed@Sun.COM * This module only implements getting socket options for the new socket 602*10639SDarren.Reed@Sun.COM * option level (SOL_PACKET) that it introduces. All other requests are 603*10639SDarren.Reed@Sun.COM * passed back to the sockfs layer. 604*10639SDarren.Reed@Sun.COM */ 605*10639SDarren.Reed@Sun.COM /* ARGSUSED */ 606*10639SDarren.Reed@Sun.COM static int 607*10639SDarren.Reed@Sun.COM sdpfp_getsockopt(sock_lower_handle_t handle, int level, int option_name, 608*10639SDarren.Reed@Sun.COM void *optval, socklen_t *optlenp, struct cred *cred) 609*10639SDarren.Reed@Sun.COM { 610*10639SDarren.Reed@Sun.COM int error = 0; 611*10639SDarren.Reed@Sun.COM 612*10639SDarren.Reed@Sun.COM switch (level) { 613*10639SDarren.Reed@Sun.COM case SOL_PACKET : 614*10639SDarren.Reed@Sun.COM error = pfp_getpacket_sockopt(handle, option_name, optval, 615*10639SDarren.Reed@Sun.COM optlenp); 616*10639SDarren.Reed@Sun.COM break; 617*10639SDarren.Reed@Sun.COM default : 618*10639SDarren.Reed@Sun.COM /* 619*10639SDarren.Reed@Sun.COM * If sockfs code receives this error in return from the 620*10639SDarren.Reed@Sun.COM * getsockopt downcall it handles the option locally, if 621*10639SDarren.Reed@Sun.COM * it can. This implements SO_RCVBUF, etc. 622*10639SDarren.Reed@Sun.COM */ 623*10639SDarren.Reed@Sun.COM error = ENOPROTOOPT; 624*10639SDarren.Reed@Sun.COM break; 625*10639SDarren.Reed@Sun.COM } 626*10639SDarren.Reed@Sun.COM 627*10639SDarren.Reed@Sun.COM return (error); 628*10639SDarren.Reed@Sun.COM } 629*10639SDarren.Reed@Sun.COM 630*10639SDarren.Reed@Sun.COM /* 631*10639SDarren.Reed@Sun.COM * PF_PACKET supports setting socket options at only two levels: 632*10639SDarren.Reed@Sun.COM * SOL_SOCKET and SOL_PACKET. 633*10639SDarren.Reed@Sun.COM */ 634*10639SDarren.Reed@Sun.COM /* ARGSUSED */ 635*10639SDarren.Reed@Sun.COM static int 636*10639SDarren.Reed@Sun.COM sdpfp_setsockopt(sock_lower_handle_t handle, int level, int option_name, 637*10639SDarren.Reed@Sun.COM const void *optval, socklen_t optlen, struct cred *cred) 638*10639SDarren.Reed@Sun.COM { 639*10639SDarren.Reed@Sun.COM int error = 0; 640*10639SDarren.Reed@Sun.COM 641*10639SDarren.Reed@Sun.COM switch (level) { 642*10639SDarren.Reed@Sun.COM case SOL_SOCKET : 643*10639SDarren.Reed@Sun.COM error = pfp_setsocket_sockopt(handle, option_name, optval, 644*10639SDarren.Reed@Sun.COM optlen); 645*10639SDarren.Reed@Sun.COM break; 646*10639SDarren.Reed@Sun.COM case SOL_PACKET : 647*10639SDarren.Reed@Sun.COM error = pfp_setpacket_sockopt(handle, option_name, optval, 648*10639SDarren.Reed@Sun.COM optlen); 649*10639SDarren.Reed@Sun.COM break; 650*10639SDarren.Reed@Sun.COM default : 651*10639SDarren.Reed@Sun.COM error = EINVAL; 652*10639SDarren.Reed@Sun.COM break; 653*10639SDarren.Reed@Sun.COM } 654*10639SDarren.Reed@Sun.COM 655*10639SDarren.Reed@Sun.COM return (error); 656*10639SDarren.Reed@Sun.COM } 657*10639SDarren.Reed@Sun.COM 658*10639SDarren.Reed@Sun.COM /* 659*10639SDarren.Reed@Sun.COM * This function is incredibly inefficient for sending any packet that 660*10639SDarren.Reed@Sun.COM * comes with a msghdr asking to be sent to an interface to which the 661*10639SDarren.Reed@Sun.COM * socket has not been bound. Some possibilities here are keeping a 662*10639SDarren.Reed@Sun.COM * cache of all open mac's and mac_client's, for the purpose of sending, 663*10639SDarren.Reed@Sun.COM * and closing them after some amount of inactivity. Clearly, applications 664*10639SDarren.Reed@Sun.COM * should not be written to use one socket for multiple interfaces if 665*10639SDarren.Reed@Sun.COM * performance is desired with the code as is. 666*10639SDarren.Reed@Sun.COM */ 667*10639SDarren.Reed@Sun.COM /* ARGSUSED */ 668*10639SDarren.Reed@Sun.COM static int 669*10639SDarren.Reed@Sun.COM sdpfp_senduio(sock_lower_handle_t handle, struct uio *uiop, 670*10639SDarren.Reed@Sun.COM struct nmsghdr *msg, struct cred *cred) 671*10639SDarren.Reed@Sun.COM { 672*10639SDarren.Reed@Sun.COM struct sockaddr_ll *sol; 673*10639SDarren.Reed@Sun.COM mac_client_handle_t mch; 674*10639SDarren.Reed@Sun.COM struct pfpsock *ps; 675*10639SDarren.Reed@Sun.COM boolean_t new_open; 676*10639SDarren.Reed@Sun.COM mac_handle_t mh; 677*10639SDarren.Reed@Sun.COM size_t mpsize; 678*10639SDarren.Reed@Sun.COM uint_t maxsdu; 679*10639SDarren.Reed@Sun.COM mblk_t *mp0; 680*10639SDarren.Reed@Sun.COM mblk_t *mp; 681*10639SDarren.Reed@Sun.COM int error; 682*10639SDarren.Reed@Sun.COM 683*10639SDarren.Reed@Sun.COM mp = NULL; 684*10639SDarren.Reed@Sun.COM mp0 = NULL; 685*10639SDarren.Reed@Sun.COM new_open = B_FALSE; 686*10639SDarren.Reed@Sun.COM ps = (struct pfpsock *)handle; 687*10639SDarren.Reed@Sun.COM mh = ps->ps_mh; 688*10639SDarren.Reed@Sun.COM mch = ps->ps_mch; 689*10639SDarren.Reed@Sun.COM maxsdu = ps->ps_max_sdu; 690*10639SDarren.Reed@Sun.COM 691*10639SDarren.Reed@Sun.COM sol = (struct sockaddr_ll *)msg->msg_name; 692*10639SDarren.Reed@Sun.COM if (sol == NULL) { 693*10639SDarren.Reed@Sun.COM /* 694*10639SDarren.Reed@Sun.COM * If no sockaddr_ll has been provided with the send call, 695*10639SDarren.Reed@Sun.COM * use the one constructed when the socket was bound to an 696*10639SDarren.Reed@Sun.COM * interface and fail if it hasn't been bound. 697*10639SDarren.Reed@Sun.COM */ 698*10639SDarren.Reed@Sun.COM if (!ps->ps_bound) { 699*10639SDarren.Reed@Sun.COM ks_stats.kp_send_unbound.value.ui64++; 700*10639SDarren.Reed@Sun.COM return (EPROTO); 701*10639SDarren.Reed@Sun.COM } 702*10639SDarren.Reed@Sun.COM sol = (struct sockaddr_ll *)&ps->ps_sock; 703*10639SDarren.Reed@Sun.COM } else { 704*10639SDarren.Reed@Sun.COM /* 705*10639SDarren.Reed@Sun.COM * Verify the sockaddr_ll message passed down before using 706*10639SDarren.Reed@Sun.COM * it to send a packet out with. If it refers to an interface 707*10639SDarren.Reed@Sun.COM * that has not been bound, it is necessary to open it. 708*10639SDarren.Reed@Sun.COM */ 709*10639SDarren.Reed@Sun.COM struct sockaddr_ll *sll; 710*10639SDarren.Reed@Sun.COM 711*10639SDarren.Reed@Sun.COM if (msg->msg_namelen < sizeof (struct sockaddr_ll)) { 712*10639SDarren.Reed@Sun.COM ks_stats.kp_send_short_msg.value.ui64++; 713*10639SDarren.Reed@Sun.COM return (EINVAL); 714*10639SDarren.Reed@Sun.COM } 715*10639SDarren.Reed@Sun.COM 716*10639SDarren.Reed@Sun.COM if (sol->sll_family != AF_PACKET) { 717*10639SDarren.Reed@Sun.COM ks_stats.kp_send_wrong_family.value.ui64++; 718*10639SDarren.Reed@Sun.COM return (EAFNOSUPPORT); 719*10639SDarren.Reed@Sun.COM } 720*10639SDarren.Reed@Sun.COM 721*10639SDarren.Reed@Sun.COM sll = (struct sockaddr_ll *)&ps->ps_sock; 722*10639SDarren.Reed@Sun.COM if (sol->sll_ifindex != sll->sll_ifindex) { 723*10639SDarren.Reed@Sun.COM error = pfp_open_index(sol->sll_ifindex, &mh, &mch, 724*10639SDarren.Reed@Sun.COM cred); 725*10639SDarren.Reed@Sun.COM if (error != 0) { 726*10639SDarren.Reed@Sun.COM ks_stats.kp_send_open_fail.value.ui64++; 727*10639SDarren.Reed@Sun.COM return (error); 728*10639SDarren.Reed@Sun.COM } 729*10639SDarren.Reed@Sun.COM mac_sdu_get(mh, NULL, &maxsdu); 730*10639SDarren.Reed@Sun.COM new_open = B_TRUE; 731*10639SDarren.Reed@Sun.COM } 732*10639SDarren.Reed@Sun.COM } 733*10639SDarren.Reed@Sun.COM 734*10639SDarren.Reed@Sun.COM mpsize = uiop->uio_resid; 735*10639SDarren.Reed@Sun.COM if (mpsize > maxsdu) { 736*10639SDarren.Reed@Sun.COM ks_stats.kp_send_too_big.value.ui64++; 737*10639SDarren.Reed@Sun.COM error = EMSGSIZE; 738*10639SDarren.Reed@Sun.COM goto done; 739*10639SDarren.Reed@Sun.COM } 740*10639SDarren.Reed@Sun.COM 741*10639SDarren.Reed@Sun.COM if ((mp = allocb(mpsize, BPRI_HI)) == NULL) { 742*10639SDarren.Reed@Sun.COM ks_stats.kp_send_alloc_fail.value.ui64++; 743*10639SDarren.Reed@Sun.COM error = ENOBUFS; 744*10639SDarren.Reed@Sun.COM goto done; 745*10639SDarren.Reed@Sun.COM } 746*10639SDarren.Reed@Sun.COM 747*10639SDarren.Reed@Sun.COM mp->b_wptr = mp->b_rptr + mpsize; 748*10639SDarren.Reed@Sun.COM error = uiomove(mp->b_rptr, mpsize, UIO_WRITE, uiop); 749*10639SDarren.Reed@Sun.COM if (error != 0) { 750*10639SDarren.Reed@Sun.COM ks_stats.kp_send_uiomove_fail.value.ui64++; 751*10639SDarren.Reed@Sun.COM goto done; 752*10639SDarren.Reed@Sun.COM } 753*10639SDarren.Reed@Sun.COM 754*10639SDarren.Reed@Sun.COM if (ps->ps_type == SOCK_DGRAM) { 755*10639SDarren.Reed@Sun.COM mp0 = mac_header(mh, sol->sll_addr, sol->sll_protocol, mp, 0); 756*10639SDarren.Reed@Sun.COM if (mp0 == NULL) { 757*10639SDarren.Reed@Sun.COM ks_stats.kp_send_no_memory.value.ui64++; 758*10639SDarren.Reed@Sun.COM error = ENOBUFS; 759*10639SDarren.Reed@Sun.COM goto done; 760*10639SDarren.Reed@Sun.COM } 761*10639SDarren.Reed@Sun.COM linkb(mp0, mp); 762*10639SDarren.Reed@Sun.COM mp = mp0; 763*10639SDarren.Reed@Sun.COM } 764*10639SDarren.Reed@Sun.COM 765*10639SDarren.Reed@Sun.COM /* 766*10639SDarren.Reed@Sun.COM * As this is sending datagrams and no promise is made about 767*10639SDarren.Reed@Sun.COM * how or if a packet will be sent/delivered, no effort is to 768*10639SDarren.Reed@Sun.COM * be expended in recovering from a situation where the packet 769*10639SDarren.Reed@Sun.COM * cannot be sent - it is just dropped. 770*10639SDarren.Reed@Sun.COM */ 771*10639SDarren.Reed@Sun.COM error = mac_tx(mch, mp, 0, MAC_DROP_ON_NO_DESC, NULL); 772*10639SDarren.Reed@Sun.COM if (error == 0) { 773*10639SDarren.Reed@Sun.COM mp = NULL; 774*10639SDarren.Reed@Sun.COM ks_stats.kp_send_ok.value.ui64++; 775*10639SDarren.Reed@Sun.COM } else { 776*10639SDarren.Reed@Sun.COM ks_stats.kp_send_failed.value.ui64++; 777*10639SDarren.Reed@Sun.COM } 778*10639SDarren.Reed@Sun.COM 779*10639SDarren.Reed@Sun.COM done: 780*10639SDarren.Reed@Sun.COM 781*10639SDarren.Reed@Sun.COM if (new_open) { 782*10639SDarren.Reed@Sun.COM ASSERT(mch != ps->ps_mch); 783*10639SDarren.Reed@Sun.COM ASSERT(mh != ps->ps_mh); 784*10639SDarren.Reed@Sun.COM pfp_close(mh, mch); 785*10639SDarren.Reed@Sun.COM } 786*10639SDarren.Reed@Sun.COM if (mp != NULL) 787*10639SDarren.Reed@Sun.COM freemsg(mp); 788*10639SDarren.Reed@Sun.COM 789*10639SDarren.Reed@Sun.COM return (error); 790*10639SDarren.Reed@Sun.COM 791*10639SDarren.Reed@Sun.COM } 792*10639SDarren.Reed@Sun.COM 793*10639SDarren.Reed@Sun.COM /* 794*10639SDarren.Reed@Sun.COM * There's no use of a lock here, or at the bottom of pfp_packet() where 795*10639SDarren.Reed@Sun.COM * ps_flow_ctrld is set to true, because in a situation where these two 796*10639SDarren.Reed@Sun.COM * are racing to set the flag one way or the other, the end result is 797*10639SDarren.Reed@Sun.COM * going to be ultimately determined by the scheduler anyway - which of 798*10639SDarren.Reed@Sun.COM * the two threads gets the lock first? In such an operational environment, 799*10639SDarren.Reed@Sun.COM * we've got packets arriving too fast to be delt with so packets are going 800*10639SDarren.Reed@Sun.COM * to be dropped. Grabbing a lock just makes the drop more expensive. 801*10639SDarren.Reed@Sun.COM */ 802*10639SDarren.Reed@Sun.COM static void 803*10639SDarren.Reed@Sun.COM sdpfp_clr_flowctrl(sock_lower_handle_t handle) 804*10639SDarren.Reed@Sun.COM { 805*10639SDarren.Reed@Sun.COM struct pfpsock *ps; 806*10639SDarren.Reed@Sun.COM 807*10639SDarren.Reed@Sun.COM ps = (struct pfpsock *)handle; 808*10639SDarren.Reed@Sun.COM 809*10639SDarren.Reed@Sun.COM mutex_enter(&ps->ps_lock); 810*10639SDarren.Reed@Sun.COM ps->ps_flow_ctrld = B_FALSE; 811*10639SDarren.Reed@Sun.COM mutex_exit(&ps->ps_lock); 812*10639SDarren.Reed@Sun.COM } 813*10639SDarren.Reed@Sun.COM 814*10639SDarren.Reed@Sun.COM /* 815*10639SDarren.Reed@Sun.COM * The implementation of this ioctl() handler is intended to function 816*10639SDarren.Reed@Sun.COM * in the absence of a bind() being made before it is called. Thus the 817*10639SDarren.Reed@Sun.COM * function calls mac_open() itself to provide a handle 818*10639SDarren.Reed@Sun.COM * This function is structured like this: 819*10639SDarren.Reed@Sun.COM * - determine the linkid for the interface being targetted 820*10639SDarren.Reed@Sun.COM * - open the interface with said linkid 821*10639SDarren.Reed@Sun.COM * - perform ioctl 822*10639SDarren.Reed@Sun.COM * - copy results back to caller 823*10639SDarren.Reed@Sun.COM * 824*10639SDarren.Reed@Sun.COM * The ioctls that interact with interface flags have been implented below 825*10639SDarren.Reed@Sun.COM * to assume that the interface is always up and running (IFF_RUNNING) and 826*10639SDarren.Reed@Sun.COM * to use the state of this socket to determine whether or not the network 827*10639SDarren.Reed@Sun.COM * interface is in promiscuous mode. Thus an ioctl to get the interface flags 828*10639SDarren.Reed@Sun.COM * of an interface that has been put in promiscuous mode by another socket 829*10639SDarren.Reed@Sun.COM * (in the same program or different), will not report that status. 830*10639SDarren.Reed@Sun.COM */ 831*10639SDarren.Reed@Sun.COM /* ARGSUSED */ 832*10639SDarren.Reed@Sun.COM static int 833*10639SDarren.Reed@Sun.COM sdpfp_ioctl(sock_lower_handle_t handle, int cmd, intptr_t arg, int mod, 834*10639SDarren.Reed@Sun.COM int32_t *rval, struct cred *cr) 835*10639SDarren.Reed@Sun.COM { 836*10639SDarren.Reed@Sun.COM #if defined(_SYSCALL32) 837*10639SDarren.Reed@Sun.COM struct timeval32 tival; 838*10639SDarren.Reed@Sun.COM #else 839*10639SDarren.Reed@Sun.COM struct timeval tival; 840*10639SDarren.Reed@Sun.COM #endif 841*10639SDarren.Reed@Sun.COM mac_client_promisc_type_t mtype; 842*10639SDarren.Reed@Sun.COM datalink_id_t linkid; 843*10639SDarren.Reed@Sun.COM struct lifreq lifreq; 844*10639SDarren.Reed@Sun.COM struct ifreq ifreq; 845*10639SDarren.Reed@Sun.COM struct pfpsock *ps; 846*10639SDarren.Reed@Sun.COM mac_handle_t mh; 847*10639SDarren.Reed@Sun.COM timespec_t tv; 848*10639SDarren.Reed@Sun.COM int error; 849*10639SDarren.Reed@Sun.COM 850*10639SDarren.Reed@Sun.COM switch (cmd) { 851*10639SDarren.Reed@Sun.COM /* 852*10639SDarren.Reed@Sun.COM * ioctls that work on "struct lifreq" 853*10639SDarren.Reed@Sun.COM */ 854*10639SDarren.Reed@Sun.COM case SIOCSLIFFLAGS : 855*10639SDarren.Reed@Sun.COM case SIOCGLIFINDEX : 856*10639SDarren.Reed@Sun.COM case SIOCGLIFFLAGS : 857*10639SDarren.Reed@Sun.COM case SIOCGLIFMTU : 858*10639SDarren.Reed@Sun.COM error = pfp_lifreq_getlinkid(arg, &lifreq, &linkid); 859*10639SDarren.Reed@Sun.COM if (error != 0) 860*10639SDarren.Reed@Sun.COM return (error); 861*10639SDarren.Reed@Sun.COM break; 862*10639SDarren.Reed@Sun.COM 863*10639SDarren.Reed@Sun.COM /* 864*10639SDarren.Reed@Sun.COM * ioctls that work on "struct ifreq". 865*10639SDarren.Reed@Sun.COM * Not all of these have a "struct lifreq" partner, for example 866*10639SDarren.Reed@Sun.COM * SIOCGIFHWADDR, for the simple reason that the logical interface 867*10639SDarren.Reed@Sun.COM * does not have a hardware address. 868*10639SDarren.Reed@Sun.COM */ 869*10639SDarren.Reed@Sun.COM case SIOCSIFFLAGS : 870*10639SDarren.Reed@Sun.COM case SIOCGIFINDEX : 871*10639SDarren.Reed@Sun.COM case SIOCGIFFLAGS : 872*10639SDarren.Reed@Sun.COM case SIOCGIFMTU : 873*10639SDarren.Reed@Sun.COM case SIOCGIFHWADDR : 874*10639SDarren.Reed@Sun.COM error = pfp_ifreq_getlinkid(arg, &ifreq, &linkid); 875*10639SDarren.Reed@Sun.COM if (error != 0) 876*10639SDarren.Reed@Sun.COM return (error); 877*10639SDarren.Reed@Sun.COM break; 878*10639SDarren.Reed@Sun.COM } 879*10639SDarren.Reed@Sun.COM 880*10639SDarren.Reed@Sun.COM error = mac_open_by_linkid(linkid, &mh); 881*10639SDarren.Reed@Sun.COM if (error != 0) 882*10639SDarren.Reed@Sun.COM return (error); 883*10639SDarren.Reed@Sun.COM 884*10639SDarren.Reed@Sun.COM ps = (struct pfpsock *)handle; 885*10639SDarren.Reed@Sun.COM 886*10639SDarren.Reed@Sun.COM switch (cmd) { 887*10639SDarren.Reed@Sun.COM case SIOCGLIFINDEX : 888*10639SDarren.Reed@Sun.COM lifreq.lifr_index = linkid; 889*10639SDarren.Reed@Sun.COM break; 890*10639SDarren.Reed@Sun.COM 891*10639SDarren.Reed@Sun.COM case SIOCGIFINDEX : 892*10639SDarren.Reed@Sun.COM ifreq.ifr_index = linkid; 893*10639SDarren.Reed@Sun.COM break; 894*10639SDarren.Reed@Sun.COM 895*10639SDarren.Reed@Sun.COM case SIOCGIFFLAGS : 896*10639SDarren.Reed@Sun.COM ifreq.ifr_flags = IFF_RUNNING; 897*10639SDarren.Reed@Sun.COM if (ps->ps_promisc == MAC_CLIENT_PROMISC_ALL) 898*10639SDarren.Reed@Sun.COM ifreq.ifr_flags |= IFF_PROMISC; 899*10639SDarren.Reed@Sun.COM break; 900*10639SDarren.Reed@Sun.COM 901*10639SDarren.Reed@Sun.COM case SIOCGLIFFLAGS : 902*10639SDarren.Reed@Sun.COM lifreq.lifr_flags = IFF_RUNNING; 903*10639SDarren.Reed@Sun.COM if (ps->ps_promisc == MAC_CLIENT_PROMISC_ALL) 904*10639SDarren.Reed@Sun.COM lifreq.lifr_flags |= IFF_PROMISC; 905*10639SDarren.Reed@Sun.COM break; 906*10639SDarren.Reed@Sun.COM 907*10639SDarren.Reed@Sun.COM case SIOCSIFFLAGS : 908*10639SDarren.Reed@Sun.COM if (linkid != ps->ps_linkid) { 909*10639SDarren.Reed@Sun.COM error = EINVAL; 910*10639SDarren.Reed@Sun.COM } else { 911*10639SDarren.Reed@Sun.COM if ((ifreq.ifr_flags & IFF_PROMISC) != 0) 912*10639SDarren.Reed@Sun.COM mtype = MAC_CLIENT_PROMISC_ALL; 913*10639SDarren.Reed@Sun.COM else 914*10639SDarren.Reed@Sun.COM mtype = MAC_CLIENT_PROMISC_FILTERED; 915*10639SDarren.Reed@Sun.COM error = pfp_set_promisc(ps, mtype); 916*10639SDarren.Reed@Sun.COM } 917*10639SDarren.Reed@Sun.COM break; 918*10639SDarren.Reed@Sun.COM 919*10639SDarren.Reed@Sun.COM case SIOCSLIFFLAGS : 920*10639SDarren.Reed@Sun.COM if (linkid != ps->ps_linkid) { 921*10639SDarren.Reed@Sun.COM error = EINVAL; 922*10639SDarren.Reed@Sun.COM } else { 923*10639SDarren.Reed@Sun.COM if ((lifreq.lifr_flags & IFF_PROMISC) != 0) 924*10639SDarren.Reed@Sun.COM mtype = MAC_CLIENT_PROMISC_ALL; 925*10639SDarren.Reed@Sun.COM else 926*10639SDarren.Reed@Sun.COM mtype = MAC_CLIENT_PROMISC_FILTERED; 927*10639SDarren.Reed@Sun.COM error = pfp_set_promisc(ps, mtype); 928*10639SDarren.Reed@Sun.COM } 929*10639SDarren.Reed@Sun.COM break; 930*10639SDarren.Reed@Sun.COM 931*10639SDarren.Reed@Sun.COM case SIOCGIFMTU : 932*10639SDarren.Reed@Sun.COM mac_sdu_get(mh, NULL, &ifreq.ifr_mtu); 933*10639SDarren.Reed@Sun.COM break; 934*10639SDarren.Reed@Sun.COM 935*10639SDarren.Reed@Sun.COM case SIOCGLIFMTU : 936*10639SDarren.Reed@Sun.COM mac_sdu_get(mh, NULL, &lifreq.lifr_mtu); 937*10639SDarren.Reed@Sun.COM break; 938*10639SDarren.Reed@Sun.COM 939*10639SDarren.Reed@Sun.COM case SIOCGIFHWADDR : 940*10639SDarren.Reed@Sun.COM mac_unicast_primary_get(mh, (uint8_t *)ifreq.ifr_addr.sa_data); 941*10639SDarren.Reed@Sun.COM ifreq.ifr_addr.sa_family = pfp_dl_to_arphrd(mac_type(mh)); 942*10639SDarren.Reed@Sun.COM break; 943*10639SDarren.Reed@Sun.COM 944*10639SDarren.Reed@Sun.COM case SIOCGSTAMP : 945*10639SDarren.Reed@Sun.COM (void) gethrestime(&tv); 946*10639SDarren.Reed@Sun.COM tival.tv_sec = (time_t)tv.tv_sec; 947*10639SDarren.Reed@Sun.COM tival.tv_usec = tv.tv_nsec / 1000; 948*10639SDarren.Reed@Sun.COM error = ddi_copyout(&tival, (void *)arg, sizeof (tival), 0); 949*10639SDarren.Reed@Sun.COM break; 950*10639SDarren.Reed@Sun.COM 951*10639SDarren.Reed@Sun.COM default : 952*10639SDarren.Reed@Sun.COM break; 953*10639SDarren.Reed@Sun.COM } 954*10639SDarren.Reed@Sun.COM 955*10639SDarren.Reed@Sun.COM mac_close(mh); 956*10639SDarren.Reed@Sun.COM 957*10639SDarren.Reed@Sun.COM if (error == 0) { 958*10639SDarren.Reed@Sun.COM /* 959*10639SDarren.Reed@Sun.COM * Only the "GET" ioctls need to copy data back to userace. 960*10639SDarren.Reed@Sun.COM */ 961*10639SDarren.Reed@Sun.COM switch (cmd) { 962*10639SDarren.Reed@Sun.COM case SIOCGLIFINDEX : 963*10639SDarren.Reed@Sun.COM case SIOCGLIFFLAGS : 964*10639SDarren.Reed@Sun.COM case SIOCGLIFMTU : 965*10639SDarren.Reed@Sun.COM error = ddi_copyout(&lifreq, (void *)arg, 966*10639SDarren.Reed@Sun.COM sizeof (lifreq), 0); 967*10639SDarren.Reed@Sun.COM break; 968*10639SDarren.Reed@Sun.COM 969*10639SDarren.Reed@Sun.COM case SIOCGIFINDEX : 970*10639SDarren.Reed@Sun.COM case SIOCGIFFLAGS : 971*10639SDarren.Reed@Sun.COM case SIOCGIFMTU : 972*10639SDarren.Reed@Sun.COM case SIOCGIFHWADDR : 973*10639SDarren.Reed@Sun.COM error = ddi_copyout(&ifreq, (void *)arg, 974*10639SDarren.Reed@Sun.COM sizeof (ifreq), 0); 975*10639SDarren.Reed@Sun.COM break; 976*10639SDarren.Reed@Sun.COM default : 977*10639SDarren.Reed@Sun.COM break; 978*10639SDarren.Reed@Sun.COM } 979*10639SDarren.Reed@Sun.COM } 980*10639SDarren.Reed@Sun.COM 981*10639SDarren.Reed@Sun.COM return (error); 982*10639SDarren.Reed@Sun.COM } 983*10639SDarren.Reed@Sun.COM 984*10639SDarren.Reed@Sun.COM /* 985*10639SDarren.Reed@Sun.COM * Closing the socket requires that all open references to network 986*10639SDarren.Reed@Sun.COM * interfaces be closed. 987*10639SDarren.Reed@Sun.COM */ 988*10639SDarren.Reed@Sun.COM /* ARGSUSED */ 989*10639SDarren.Reed@Sun.COM static int 990*10639SDarren.Reed@Sun.COM sdpfp_close(sock_lower_handle_t handle, int flag, struct cred *cr) 991*10639SDarren.Reed@Sun.COM { 992*10639SDarren.Reed@Sun.COM struct pfpsock *ps = (struct pfpsock *)handle; 993*10639SDarren.Reed@Sun.COM 994*10639SDarren.Reed@Sun.COM if (ps->ps_phd != 0) { 995*10639SDarren.Reed@Sun.COM mac_promisc_remove(ps->ps_phd); 996*10639SDarren.Reed@Sun.COM ps->ps_phd = 0; 997*10639SDarren.Reed@Sun.COM } 998*10639SDarren.Reed@Sun.COM 999*10639SDarren.Reed@Sun.COM if (ps->ps_mch != 0) { 1000*10639SDarren.Reed@Sun.COM mac_client_close(ps->ps_mch, 0); 1001*10639SDarren.Reed@Sun.COM ps->ps_mch = 0; 1002*10639SDarren.Reed@Sun.COM } 1003*10639SDarren.Reed@Sun.COM 1004*10639SDarren.Reed@Sun.COM if (ps->ps_mh != 0) { 1005*10639SDarren.Reed@Sun.COM mac_close(ps->ps_mh); 1006*10639SDarren.Reed@Sun.COM ps->ps_mh = 0; 1007*10639SDarren.Reed@Sun.COM } 1008*10639SDarren.Reed@Sun.COM 1009*10639SDarren.Reed@Sun.COM kmem_free(ps, sizeof (*ps)); 1010*10639SDarren.Reed@Sun.COM 1011*10639SDarren.Reed@Sun.COM return (0); 1012*10639SDarren.Reed@Sun.COM } 1013*10639SDarren.Reed@Sun.COM 1014*10639SDarren.Reed@Sun.COM /* ************************************************************************* */ 1015*10639SDarren.Reed@Sun.COM 1016*10639SDarren.Reed@Sun.COM /* 1017*10639SDarren.Reed@Sun.COM * Given a pointer (arg) to a "struct ifreq" (potentially in user space), 1018*10639SDarren.Reed@Sun.COM * determine the linkid for the interface name stored in that structure. 1019*10639SDarren.Reed@Sun.COM * name is used as a buffer so that we can ensure a trailing \0 is appended 1020*10639SDarren.Reed@Sun.COM * to the name safely. 1021*10639SDarren.Reed@Sun.COM */ 1022*10639SDarren.Reed@Sun.COM static int 1023*10639SDarren.Reed@Sun.COM pfp_ifreq_getlinkid(intptr_t arg, struct ifreq *ifreqp, 1024*10639SDarren.Reed@Sun.COM datalink_id_t *linkidp) 1025*10639SDarren.Reed@Sun.COM { 1026*10639SDarren.Reed@Sun.COM char name[IFNAMSIZ + 1]; 1027*10639SDarren.Reed@Sun.COM int error; 1028*10639SDarren.Reed@Sun.COM 1029*10639SDarren.Reed@Sun.COM if (ddi_copyin((void *)arg, ifreqp, sizeof (*ifreqp), 0) != 0) 1030*10639SDarren.Reed@Sun.COM return (EFAULT); 1031*10639SDarren.Reed@Sun.COM 1032*10639SDarren.Reed@Sun.COM (void) strlcpy(name, ifreqp->ifr_name, sizeof (name)); 1033*10639SDarren.Reed@Sun.COM 1034*10639SDarren.Reed@Sun.COM error = dls_mgmt_get_linkid(name, linkidp); 1035*10639SDarren.Reed@Sun.COM if (error != 0) 1036*10639SDarren.Reed@Sun.COM error = dls_devnet_macname2linkid(name, linkidp); 1037*10639SDarren.Reed@Sun.COM 1038*10639SDarren.Reed@Sun.COM return (error); 1039*10639SDarren.Reed@Sun.COM } 1040*10639SDarren.Reed@Sun.COM 1041*10639SDarren.Reed@Sun.COM /* 1042*10639SDarren.Reed@Sun.COM * Given a pointer (arg) to a "struct lifreq" (potentially in user space), 1043*10639SDarren.Reed@Sun.COM * determine the linkid for the interface name stored in that structure. 1044*10639SDarren.Reed@Sun.COM * name is used as a buffer so that we can ensure a trailing \0 is appended 1045*10639SDarren.Reed@Sun.COM * to the name safely. 1046*10639SDarren.Reed@Sun.COM */ 1047*10639SDarren.Reed@Sun.COM static int 1048*10639SDarren.Reed@Sun.COM pfp_lifreq_getlinkid(intptr_t arg, struct lifreq *lifreqp, 1049*10639SDarren.Reed@Sun.COM datalink_id_t *linkidp) 1050*10639SDarren.Reed@Sun.COM { 1051*10639SDarren.Reed@Sun.COM char name[LIFNAMSIZ + 1]; 1052*10639SDarren.Reed@Sun.COM int error; 1053*10639SDarren.Reed@Sun.COM 1054*10639SDarren.Reed@Sun.COM if (ddi_copyin((void *)arg, lifreqp, sizeof (*lifreqp), 0) != 0) 1055*10639SDarren.Reed@Sun.COM return (EFAULT); 1056*10639SDarren.Reed@Sun.COM 1057*10639SDarren.Reed@Sun.COM (void) strlcpy(name, lifreqp->lifr_name, sizeof (name)); 1058*10639SDarren.Reed@Sun.COM 1059*10639SDarren.Reed@Sun.COM error = dls_mgmt_get_linkid(name, linkidp); 1060*10639SDarren.Reed@Sun.COM if (error != 0) 1061*10639SDarren.Reed@Sun.COM error = dls_devnet_macname2linkid(name, linkidp); 1062*10639SDarren.Reed@Sun.COM 1063*10639SDarren.Reed@Sun.COM return (error); 1064*10639SDarren.Reed@Sun.COM } 1065*10639SDarren.Reed@Sun.COM 1066*10639SDarren.Reed@Sun.COM /* 1067*10639SDarren.Reed@Sun.COM * Although there are several new SOL_PACKET options that can be set and 1068*10639SDarren.Reed@Sun.COM * are specific to this implementation of PF_PACKET, the current API does 1069*10639SDarren.Reed@Sun.COM * not support doing a get on them to retrieve accompanying status. Thus 1070*10639SDarren.Reed@Sun.COM * it is only currently possible to use SOL_PACKET with getsockopt to 1071*10639SDarren.Reed@Sun.COM * retrieve statistical information. This remains consistant with the 1072*10639SDarren.Reed@Sun.COM * Linux API at the time of writing. 1073*10639SDarren.Reed@Sun.COM */ 1074*10639SDarren.Reed@Sun.COM static int 1075*10639SDarren.Reed@Sun.COM pfp_getpacket_sockopt(sock_lower_handle_t handle, int option_name, 1076*10639SDarren.Reed@Sun.COM void *optval, socklen_t *optlenp) 1077*10639SDarren.Reed@Sun.COM { 1078*10639SDarren.Reed@Sun.COM struct pfpsock *ps; 1079*10639SDarren.Reed@Sun.COM int error = 0; 1080*10639SDarren.Reed@Sun.COM 1081*10639SDarren.Reed@Sun.COM ps = (struct pfpsock *)handle; 1082*10639SDarren.Reed@Sun.COM 1083*10639SDarren.Reed@Sun.COM switch (option_name) { 1084*10639SDarren.Reed@Sun.COM case PACKET_STATISTICS : 1085*10639SDarren.Reed@Sun.COM if (*optlenp < sizeof (ps->ps_stats)) { 1086*10639SDarren.Reed@Sun.COM error = EINVAL; 1087*10639SDarren.Reed@Sun.COM break; 1088*10639SDarren.Reed@Sun.COM } 1089*10639SDarren.Reed@Sun.COM *optlenp = sizeof (ps->ps_stats); 1090*10639SDarren.Reed@Sun.COM bcopy(&ps->ps_stats, optval, sizeof (ps->ps_stats)); 1091*10639SDarren.Reed@Sun.COM break; 1092*10639SDarren.Reed@Sun.COM default : 1093*10639SDarren.Reed@Sun.COM error = EINVAL; 1094*10639SDarren.Reed@Sun.COM break; 1095*10639SDarren.Reed@Sun.COM } 1096*10639SDarren.Reed@Sun.COM 1097*10639SDarren.Reed@Sun.COM return (error); 1098*10639SDarren.Reed@Sun.COM } 1099*10639SDarren.Reed@Sun.COM 1100*10639SDarren.Reed@Sun.COM /* 1101*10639SDarren.Reed@Sun.COM * The SOL_PACKET level for socket options supports three options, 1102*10639SDarren.Reed@Sun.COM * PACKET_ADD_MEMBERSHIP, PACKET_DROP_MEMBERSHIP and PACKET_AUXDATA. 1103*10639SDarren.Reed@Sun.COM * This function is responsible for mapping the two socket options 1104*10639SDarren.Reed@Sun.COM * that manage multicast membership into the appropriate internal 1105*10639SDarren.Reed@Sun.COM * function calls to bring the option into effect. Whilst direct 1106*10639SDarren.Reed@Sun.COM * changes to the multicast membership (ADD/DROP) groups is handled 1107*10639SDarren.Reed@Sun.COM * by calls directly into the mac module, changes to the promiscuos 1108*10639SDarren.Reed@Sun.COM * mode are vectored through pfp_set_promisc() so that the logic for 1109*10639SDarren.Reed@Sun.COM * managing the promiscuous mode is in one place. 1110*10639SDarren.Reed@Sun.COM */ 1111*10639SDarren.Reed@Sun.COM /* ARGSUSED */ 1112*10639SDarren.Reed@Sun.COM static int 1113*10639SDarren.Reed@Sun.COM pfp_setpacket_sockopt(sock_lower_handle_t handle, int option_name, 1114*10639SDarren.Reed@Sun.COM const void *optval, socklen_t optlen) 1115*10639SDarren.Reed@Sun.COM { 1116*10639SDarren.Reed@Sun.COM struct packet_mreq mreq; 1117*10639SDarren.Reed@Sun.COM struct pfpsock *ps; 1118*10639SDarren.Reed@Sun.COM int error = 0; 1119*10639SDarren.Reed@Sun.COM int opt; 1120*10639SDarren.Reed@Sun.COM 1121*10639SDarren.Reed@Sun.COM ps = (struct pfpsock *)handle; 1122*10639SDarren.Reed@Sun.COM if (!ps->ps_bound) 1123*10639SDarren.Reed@Sun.COM return (EPROTO); 1124*10639SDarren.Reed@Sun.COM 1125*10639SDarren.Reed@Sun.COM if ((option_name == PACKET_ADD_MEMBERSHIP) || 1126*10639SDarren.Reed@Sun.COM (option_name == PACKET_DROP_MEMBERSHIP)) { 1127*10639SDarren.Reed@Sun.COM if (!ps->ps_bound) 1128*10639SDarren.Reed@Sun.COM return (EPROTO); 1129*10639SDarren.Reed@Sun.COM bcopy(optval, &mreq, sizeof (mreq)); 1130*10639SDarren.Reed@Sun.COM if (ps->ps_linkid != mreq.mr_ifindex) 1131*10639SDarren.Reed@Sun.COM return (EINVAL); 1132*10639SDarren.Reed@Sun.COM 1133*10639SDarren.Reed@Sun.COM if (mreq.mr_alen != 1134*10639SDarren.Reed@Sun.COM ((struct sockaddr_ll *)&ps->ps_sock)->sll_halen) 1135*10639SDarren.Reed@Sun.COM return (EINVAL); 1136*10639SDarren.Reed@Sun.COM } 1137*10639SDarren.Reed@Sun.COM 1138*10639SDarren.Reed@Sun.COM switch (option_name) { 1139*10639SDarren.Reed@Sun.COM case PACKET_ADD_MEMBERSHIP : 1140*10639SDarren.Reed@Sun.COM switch (mreq.mr_type) { 1141*10639SDarren.Reed@Sun.COM case PACKET_MR_MULTICAST : 1142*10639SDarren.Reed@Sun.COM error = mac_multicast_add(ps->ps_mch, mreq.mr_address); 1143*10639SDarren.Reed@Sun.COM break; 1144*10639SDarren.Reed@Sun.COM 1145*10639SDarren.Reed@Sun.COM case PACKET_MR_PROMISC : 1146*10639SDarren.Reed@Sun.COM error = pfp_set_promisc(ps, MAC_CLIENT_PROMISC_ALL); 1147*10639SDarren.Reed@Sun.COM break; 1148*10639SDarren.Reed@Sun.COM 1149*10639SDarren.Reed@Sun.COM case PACKET_MR_ALLMULTI : 1150*10639SDarren.Reed@Sun.COM error = pfp_set_promisc(ps, MAC_CLIENT_PROMISC_MULTI); 1151*10639SDarren.Reed@Sun.COM break; 1152*10639SDarren.Reed@Sun.COM } 1153*10639SDarren.Reed@Sun.COM break; 1154*10639SDarren.Reed@Sun.COM 1155*10639SDarren.Reed@Sun.COM case PACKET_DROP_MEMBERSHIP : 1156*10639SDarren.Reed@Sun.COM switch (mreq.mr_type) { 1157*10639SDarren.Reed@Sun.COM case PACKET_MR_MULTICAST : 1158*10639SDarren.Reed@Sun.COM mac_multicast_remove(ps->ps_mch, mreq.mr_address); 1159*10639SDarren.Reed@Sun.COM break; 1160*10639SDarren.Reed@Sun.COM 1161*10639SDarren.Reed@Sun.COM case PACKET_MR_PROMISC : 1162*10639SDarren.Reed@Sun.COM if (ps->ps_promisc != MAC_CLIENT_PROMISC_ALL) 1163*10639SDarren.Reed@Sun.COM return (EINVAL); 1164*10639SDarren.Reed@Sun.COM error = pfp_set_promisc(ps, 1165*10639SDarren.Reed@Sun.COM MAC_CLIENT_PROMISC_FILTERED); 1166*10639SDarren.Reed@Sun.COM break; 1167*10639SDarren.Reed@Sun.COM 1168*10639SDarren.Reed@Sun.COM case PACKET_MR_ALLMULTI : 1169*10639SDarren.Reed@Sun.COM if (ps->ps_promisc != MAC_CLIENT_PROMISC_MULTI) 1170*10639SDarren.Reed@Sun.COM return (EINVAL); 1171*10639SDarren.Reed@Sun.COM error = pfp_set_promisc(ps, 1172*10639SDarren.Reed@Sun.COM MAC_CLIENT_PROMISC_FILTERED); 1173*10639SDarren.Reed@Sun.COM break; 1174*10639SDarren.Reed@Sun.COM } 1175*10639SDarren.Reed@Sun.COM break; 1176*10639SDarren.Reed@Sun.COM 1177*10639SDarren.Reed@Sun.COM case PACKET_AUXDATA : 1178*10639SDarren.Reed@Sun.COM if (optlen == sizeof (int)) { 1179*10639SDarren.Reed@Sun.COM opt = *(int *)optval; 1180*10639SDarren.Reed@Sun.COM ps->ps_auxdata = (opt != 0); 1181*10639SDarren.Reed@Sun.COM } else { 1182*10639SDarren.Reed@Sun.COM error = EINVAL; 1183*10639SDarren.Reed@Sun.COM } 1184*10639SDarren.Reed@Sun.COM break; 1185*10639SDarren.Reed@Sun.COM default : 1186*10639SDarren.Reed@Sun.COM error = EINVAL; 1187*10639SDarren.Reed@Sun.COM break; 1188*10639SDarren.Reed@Sun.COM } 1189*10639SDarren.Reed@Sun.COM 1190*10639SDarren.Reed@Sun.COM return (error); 1191*10639SDarren.Reed@Sun.COM } 1192*10639SDarren.Reed@Sun.COM 1193*10639SDarren.Reed@Sun.COM /* 1194*10639SDarren.Reed@Sun.COM * There are only two special setsockopt's for SOL_SOCKET with PF_PACKET: 1195*10639SDarren.Reed@Sun.COM * SO_ATTACH_FILTER and SO_DETACH_FILTER. All other setsockopt requests 1196*10639SDarren.Reed@Sun.COM * that are for SOL_SOCKET are passed back to the socket layer for its 1197*10639SDarren.Reed@Sun.COM * generic implementation. 1198*10639SDarren.Reed@Sun.COM * 1199*10639SDarren.Reed@Sun.COM * Both of these setsockopt values are candidates for being handled by the 1200*10639SDarren.Reed@Sun.COM * socket layer itself in future, however this requires understanding how 1201*10639SDarren.Reed@Sun.COM * they would interact with all other sockets. 1202*10639SDarren.Reed@Sun.COM */ 1203*10639SDarren.Reed@Sun.COM static int 1204*10639SDarren.Reed@Sun.COM pfp_setsocket_sockopt(sock_lower_handle_t handle, int option_name, 1205*10639SDarren.Reed@Sun.COM const void *optval, socklen_t optlen) 1206*10639SDarren.Reed@Sun.COM { 1207*10639SDarren.Reed@Sun.COM struct bpf_program prog; 1208*10639SDarren.Reed@Sun.COM struct bpf_insn *fcode; 1209*10639SDarren.Reed@Sun.COM struct pfpsock *ps; 1210*10639SDarren.Reed@Sun.COM int error = 0; 1211*10639SDarren.Reed@Sun.COM int size; 1212*10639SDarren.Reed@Sun.COM 1213*10639SDarren.Reed@Sun.COM ps = (struct pfpsock *)handle; 1214*10639SDarren.Reed@Sun.COM 1215*10639SDarren.Reed@Sun.COM switch (option_name) { 1216*10639SDarren.Reed@Sun.COM case SO_ATTACH_FILTER : 1217*10639SDarren.Reed@Sun.COM #ifdef _LP64 1218*10639SDarren.Reed@Sun.COM if (optlen == sizeof (struct bpf_program32)) { 1219*10639SDarren.Reed@Sun.COM struct bpf_program32 prog32; 1220*10639SDarren.Reed@Sun.COM 1221*10639SDarren.Reed@Sun.COM bcopy(optval, &prog32, sizeof (prog32)); 1222*10639SDarren.Reed@Sun.COM prog.bf_len = prog32.bf_len; 1223*10639SDarren.Reed@Sun.COM prog.bf_insns = (void *)(uint64_t)prog32.bf_insns; 1224*10639SDarren.Reed@Sun.COM } else 1225*10639SDarren.Reed@Sun.COM #endif 1226*10639SDarren.Reed@Sun.COM if (optlen == sizeof (struct bpf_program)) { 1227*10639SDarren.Reed@Sun.COM bcopy(optval, &prog, sizeof (prog)); 1228*10639SDarren.Reed@Sun.COM } else if (optlen != sizeof (struct bpf_program)) { 1229*10639SDarren.Reed@Sun.COM return (EINVAL); 1230*10639SDarren.Reed@Sun.COM } 1231*10639SDarren.Reed@Sun.COM 1232*10639SDarren.Reed@Sun.COM size = prog.bf_len * sizeof (*prog.bf_insns); 1233*10639SDarren.Reed@Sun.COM fcode = kmem_alloc(size, KM_SLEEP); 1234*10639SDarren.Reed@Sun.COM if (ddi_copyin(prog.bf_insns, fcode, size, 0) != 0) { 1235*10639SDarren.Reed@Sun.COM kmem_free(fcode, size); 1236*10639SDarren.Reed@Sun.COM return (EFAULT); 1237*10639SDarren.Reed@Sun.COM } 1238*10639SDarren.Reed@Sun.COM 1239*10639SDarren.Reed@Sun.COM if (bpf_validate(fcode, (int)prog.bf_len)) { 1240*10639SDarren.Reed@Sun.COM rw_enter(&ps->ps_bpflock, RW_WRITER); 1241*10639SDarren.Reed@Sun.COM pfp_release_bpf(ps); 1242*10639SDarren.Reed@Sun.COM ps->ps_bpf.bf_insns = fcode; 1243*10639SDarren.Reed@Sun.COM ps->ps_bpf.bf_len = size; 1244*10639SDarren.Reed@Sun.COM rw_exit(&ps->ps_bpflock); 1245*10639SDarren.Reed@Sun.COM 1246*10639SDarren.Reed@Sun.COM return (0); 1247*10639SDarren.Reed@Sun.COM } 1248*10639SDarren.Reed@Sun.COM kmem_free(fcode, size); 1249*10639SDarren.Reed@Sun.COM error = EINVAL; 1250*10639SDarren.Reed@Sun.COM break; 1251*10639SDarren.Reed@Sun.COM 1252*10639SDarren.Reed@Sun.COM case SO_DETACH_FILTER : 1253*10639SDarren.Reed@Sun.COM pfp_release_bpf(ps); 1254*10639SDarren.Reed@Sun.COM break; 1255*10639SDarren.Reed@Sun.COM default : 1256*10639SDarren.Reed@Sun.COM /* 1257*10639SDarren.Reed@Sun.COM * If sockfs code receives this error in return from the 1258*10639SDarren.Reed@Sun.COM * getsockopt downcall it handles the option locally, if 1259*10639SDarren.Reed@Sun.COM * it can. This implements SO_RCVBUF, etc. 1260*10639SDarren.Reed@Sun.COM */ 1261*10639SDarren.Reed@Sun.COM error = ENOPROTOOPT; 1262*10639SDarren.Reed@Sun.COM break; 1263*10639SDarren.Reed@Sun.COM } 1264*10639SDarren.Reed@Sun.COM 1265*10639SDarren.Reed@Sun.COM return (error); 1266*10639SDarren.Reed@Sun.COM } 1267*10639SDarren.Reed@Sun.COM 1268*10639SDarren.Reed@Sun.COM /* 1269*10639SDarren.Reed@Sun.COM * pfp_open_index is an internal function used to open a MAC device by 1270*10639SDarren.Reed@Sun.COM * its index. Both a mac_handle_t and mac_client_handle_t are acquired 1271*10639SDarren.Reed@Sun.COM * because some of the interfaces provided by the mac layer require either 1272*10639SDarren.Reed@Sun.COM * only the mac_handle_t or both it and mac_handle_t. 1273*10639SDarren.Reed@Sun.COM * 1274*10639SDarren.Reed@Sun.COM * Whilst inside the kernel we can access data structures supporting any 1275*10639SDarren.Reed@Sun.COM * zone, access to interfaces from non-global zones is restricted to those 1276*10639SDarren.Reed@Sun.COM * interfaces (if any) that are exclusively assigned to a zone. 1277*10639SDarren.Reed@Sun.COM */ 1278*10639SDarren.Reed@Sun.COM static int 1279*10639SDarren.Reed@Sun.COM pfp_open_index(int index, mac_handle_t *mhp, mac_client_handle_t *mcip, 1280*10639SDarren.Reed@Sun.COM cred_t *cred) 1281*10639SDarren.Reed@Sun.COM { 1282*10639SDarren.Reed@Sun.COM mac_client_handle_t mch; 1283*10639SDarren.Reed@Sun.COM zoneid_t ifzoneid; 1284*10639SDarren.Reed@Sun.COM mac_handle_t mh; 1285*10639SDarren.Reed@Sun.COM zoneid_t zoneid; 1286*10639SDarren.Reed@Sun.COM int error; 1287*10639SDarren.Reed@Sun.COM 1288*10639SDarren.Reed@Sun.COM mh = 0; 1289*10639SDarren.Reed@Sun.COM mch = 0; 1290*10639SDarren.Reed@Sun.COM error = mac_open_by_linkid(index, &mh); 1291*10639SDarren.Reed@Sun.COM if (error != 0) 1292*10639SDarren.Reed@Sun.COM goto bad_open; 1293*10639SDarren.Reed@Sun.COM 1294*10639SDarren.Reed@Sun.COM error = mac_client_open(mh, &mch, NULL, 1295*10639SDarren.Reed@Sun.COM MAC_OPEN_FLAGS_USE_DATALINK_NAME); 1296*10639SDarren.Reed@Sun.COM if (error != 0) 1297*10639SDarren.Reed@Sun.COM goto bad_open; 1298*10639SDarren.Reed@Sun.COM 1299*10639SDarren.Reed@Sun.COM zoneid = crgetzoneid(cred); 1300*10639SDarren.Reed@Sun.COM if (zoneid != GLOBAL_ZONEID) { 1301*10639SDarren.Reed@Sun.COM mac_perim_handle_t perim; 1302*10639SDarren.Reed@Sun.COM 1303*10639SDarren.Reed@Sun.COM mac_perim_enter_by_mh(mh, &perim); 1304*10639SDarren.Reed@Sun.COM error = dls_link_getzid(mac_client_name(mch), &ifzoneid); 1305*10639SDarren.Reed@Sun.COM mac_perim_exit(perim); 1306*10639SDarren.Reed@Sun.COM if (error != 0) 1307*10639SDarren.Reed@Sun.COM goto bad_open; 1308*10639SDarren.Reed@Sun.COM if (ifzoneid != zoneid) { 1309*10639SDarren.Reed@Sun.COM error = EACCES; 1310*10639SDarren.Reed@Sun.COM goto bad_open; 1311*10639SDarren.Reed@Sun.COM } 1312*10639SDarren.Reed@Sun.COM } 1313*10639SDarren.Reed@Sun.COM 1314*10639SDarren.Reed@Sun.COM *mcip = mch; 1315*10639SDarren.Reed@Sun.COM *mhp = mh; 1316*10639SDarren.Reed@Sun.COM 1317*10639SDarren.Reed@Sun.COM return (0); 1318*10639SDarren.Reed@Sun.COM bad_open: 1319*10639SDarren.Reed@Sun.COM if (mch != 0) 1320*10639SDarren.Reed@Sun.COM mac_client_close(mch, 0); 1321*10639SDarren.Reed@Sun.COM if (mh != 0) 1322*10639SDarren.Reed@Sun.COM mac_close(mh); 1323*10639SDarren.Reed@Sun.COM return (error); 1324*10639SDarren.Reed@Sun.COM } 1325*10639SDarren.Reed@Sun.COM 1326*10639SDarren.Reed@Sun.COM static void 1327*10639SDarren.Reed@Sun.COM pfp_close(mac_handle_t mh, mac_client_handle_t mch) 1328*10639SDarren.Reed@Sun.COM { 1329*10639SDarren.Reed@Sun.COM mac_client_close(mch, 0); 1330*10639SDarren.Reed@Sun.COM mac_close(mh); 1331*10639SDarren.Reed@Sun.COM } 1332*10639SDarren.Reed@Sun.COM 1333*10639SDarren.Reed@Sun.COM /* 1334*10639SDarren.Reed@Sun.COM * The purpose of this function is to provide a single place where we free 1335*10639SDarren.Reed@Sun.COM * the loaded BPF program and reset all pointers/counters associated with 1336*10639SDarren.Reed@Sun.COM * it. 1337*10639SDarren.Reed@Sun.COM */ 1338*10639SDarren.Reed@Sun.COM static void 1339*10639SDarren.Reed@Sun.COM pfp_release_bpf(struct pfpsock *ps) 1340*10639SDarren.Reed@Sun.COM { 1341*10639SDarren.Reed@Sun.COM if (ps->ps_bpf.bf_len != 0) { 1342*10639SDarren.Reed@Sun.COM kmem_free(ps->ps_bpf.bf_insns, ps->ps_bpf.bf_len); 1343*10639SDarren.Reed@Sun.COM ps->ps_bpf.bf_len = 0; 1344*10639SDarren.Reed@Sun.COM ps->ps_bpf.bf_insns = NULL; 1345*10639SDarren.Reed@Sun.COM } 1346*10639SDarren.Reed@Sun.COM } 1347*10639SDarren.Reed@Sun.COM 1348*10639SDarren.Reed@Sun.COM /* 1349*10639SDarren.Reed@Sun.COM * Set the promiscuous mode of a network interface. 1350*10639SDarren.Reed@Sun.COM * This function only calls the mac layer when there is a change to the 1351*10639SDarren.Reed@Sun.COM * status of a network interface's promiscous mode. Tracking of how many 1352*10639SDarren.Reed@Sun.COM * sockets have the network interface in promiscuous mode, and thus the 1353*10639SDarren.Reed@Sun.COM * control over the physical device's status, is left to the mac layer. 1354*10639SDarren.Reed@Sun.COM */ 1355*10639SDarren.Reed@Sun.COM static int 1356*10639SDarren.Reed@Sun.COM pfp_set_promisc(struct pfpsock *ps, mac_client_promisc_type_t turnon) 1357*10639SDarren.Reed@Sun.COM { 1358*10639SDarren.Reed@Sun.COM int error = 0; 1359*10639SDarren.Reed@Sun.COM int flags; 1360*10639SDarren.Reed@Sun.COM 1361*10639SDarren.Reed@Sun.COM /* 1362*10639SDarren.Reed@Sun.COM * There are 4 combinations of turnon/ps_promisc. 1363*10639SDarren.Reed@Sun.COM * This if handles 2 (both false, both true) and the if() below 1364*10639SDarren.Reed@Sun.COM * handles the remaining one - when change is required. 1365*10639SDarren.Reed@Sun.COM */ 1366*10639SDarren.Reed@Sun.COM if (turnon == ps->ps_promisc) 1367*10639SDarren.Reed@Sun.COM return (error); 1368*10639SDarren.Reed@Sun.COM 1369*10639SDarren.Reed@Sun.COM if (ps->ps_phd != 0) { 1370*10639SDarren.Reed@Sun.COM mac_promisc_remove(ps->ps_phd); 1371*10639SDarren.Reed@Sun.COM ps->ps_phd = 0; 1372*10639SDarren.Reed@Sun.COM 1373*10639SDarren.Reed@Sun.COM /* 1374*10639SDarren.Reed@Sun.COM * ps_promisc is set here in case the call to mac_promisc_add 1375*10639SDarren.Reed@Sun.COM * fails: leaving it to indicate that the interface is still 1376*10639SDarren.Reed@Sun.COM * in some sort of promiscuous mode is false. 1377*10639SDarren.Reed@Sun.COM */ 1378*10639SDarren.Reed@Sun.COM if (ps->ps_promisc != MAC_CLIENT_PROMISC_FILTERED) { 1379*10639SDarren.Reed@Sun.COM ps->ps_promisc = MAC_CLIENT_PROMISC_FILTERED; 1380*10639SDarren.Reed@Sun.COM flags = MAC_PROMISC_FLAGS_NO_PHYS; 1381*10639SDarren.Reed@Sun.COM } else { 1382*10639SDarren.Reed@Sun.COM flags = 0; 1383*10639SDarren.Reed@Sun.COM } 1384*10639SDarren.Reed@Sun.COM flags |= MAC_PROMISC_FLAGS_VLAN_TAG_STRIP; 1385*10639SDarren.Reed@Sun.COM } 1386*10639SDarren.Reed@Sun.COM 1387*10639SDarren.Reed@Sun.COM error = mac_promisc_add(ps->ps_mch, turnon, pfp_packet, ps, 1388*10639SDarren.Reed@Sun.COM &ps->ps_phd, flags); 1389*10639SDarren.Reed@Sun.COM if (error == 0) 1390*10639SDarren.Reed@Sun.COM ps->ps_promisc = turnon; 1391*10639SDarren.Reed@Sun.COM 1392*10639SDarren.Reed@Sun.COM return (error); 1393*10639SDarren.Reed@Sun.COM } 1394*10639SDarren.Reed@Sun.COM 1395*10639SDarren.Reed@Sun.COM /* 1396*10639SDarren.Reed@Sun.COM * This table maps the MAC types in Solaris to the ARPHRD_* values used 1397*10639SDarren.Reed@Sun.COM * on Linux. This is used with the SIOCGIFHWADDR ioctl. 1398*10639SDarren.Reed@Sun.COM */ 1399*10639SDarren.Reed@Sun.COM static uint_t arphrd_to_dl[][2] = { 1400*10639SDarren.Reed@Sun.COM { ARPHRD_ETHER, DL_ETHER }, 1401*10639SDarren.Reed@Sun.COM { ARPHRD_IEEE80211, DL_WIFI }, 1402*10639SDarren.Reed@Sun.COM { 0, 0 } 1403*10639SDarren.Reed@Sun.COM }; 1404*10639SDarren.Reed@Sun.COM 1405*10639SDarren.Reed@Sun.COM static int 1406*10639SDarren.Reed@Sun.COM pfp_dl_to_arphrd(int dltype) 1407*10639SDarren.Reed@Sun.COM { 1408*10639SDarren.Reed@Sun.COM int i; 1409*10639SDarren.Reed@Sun.COM 1410*10639SDarren.Reed@Sun.COM for (i = 0; arphrd_to_dl[i][0] != 0; i++) 1411*10639SDarren.Reed@Sun.COM if (arphrd_to_dl[i][1] == dltype) 1412*10639SDarren.Reed@Sun.COM return (arphrd_to_dl[i][0]); 1413*10639SDarren.Reed@Sun.COM return (0); 1414*10639SDarren.Reed@Sun.COM } 1415