10a0e9771SDarren Reed /* 20a0e9771SDarren Reed * CDDL HEADER START 30a0e9771SDarren Reed * 40a0e9771SDarren Reed * The contents of this file are subject to the terms of the 50a0e9771SDarren Reed * Common Development and Distribution License (the "License"). 60a0e9771SDarren Reed * You may not use this file except in compliance with the License. 70a0e9771SDarren Reed * 80a0e9771SDarren Reed * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90a0e9771SDarren Reed * or http://www.opensolaris.org/os/licensing. 100a0e9771SDarren Reed * See the License for the specific language governing permissions 110a0e9771SDarren Reed * and limitations under the License. 120a0e9771SDarren Reed * 130a0e9771SDarren Reed * When distributing Covered Code, include this CDDL HEADER in each 140a0e9771SDarren Reed * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150a0e9771SDarren Reed * If applicable, add the following below this CDDL HEADER, with the 160a0e9771SDarren Reed * fields enclosed by brackets "[]" replaced with your own identifying 170a0e9771SDarren Reed * information: Portions Copyright [yyyy] [name of copyright owner] 180a0e9771SDarren Reed * 190a0e9771SDarren Reed * CDDL HEADER END 200a0e9771SDarren Reed */ 210a0e9771SDarren Reed 220a0e9771SDarren Reed /* 23d2b5b2d3SAnders Persson * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 24336069c2SPatrick Mooney * Copyright 2015 Joyent, Inc. All rights reserved. 250a0e9771SDarren Reed */ 260a0e9771SDarren Reed 270a0e9771SDarren Reed #include <sys/types.h> 280a0e9771SDarren Reed #include <sys/param.h> 290a0e9771SDarren Reed #include <sys/systm.h> 300a0e9771SDarren Reed #include <sys/stropts.h> 310a0e9771SDarren Reed #include <sys/socket.h> 320a0e9771SDarren Reed #include <sys/socketvar.h> 330a0e9771SDarren Reed #include <sys/socket_proto.h> 340a0e9771SDarren Reed #include <sys/sockio.h> 350a0e9771SDarren Reed #include <sys/strsun.h> 360a0e9771SDarren Reed #include <sys/kstat.h> 370a0e9771SDarren Reed #include <sys/modctl.h> 380a0e9771SDarren Reed #include <sys/policy.h> 390a0e9771SDarren Reed #include <sys/priv_const.h> 400a0e9771SDarren Reed #include <sys/tihdr.h> 410a0e9771SDarren Reed #include <sys/zone.h> 420a0e9771SDarren Reed #include <sys/time.h> 43a6911619SDarren Reed #include <sys/ethernet.h> 44a6911619SDarren Reed #include <sys/llc1.h> 450a0e9771SDarren Reed #include <fs/sockfs/sockcommon.h> 460a0e9771SDarren Reed #include <net/if.h> 47a6911619SDarren Reed #include <inet/ip_arp.h> 480a0e9771SDarren Reed 490a0e9771SDarren Reed #include <sys/dls.h> 500a0e9771SDarren Reed #include <sys/mac.h> 510a0e9771SDarren Reed #include <sys/mac_client.h> 520a0e9771SDarren Reed #include <sys/mac_provider.h> 530a0e9771SDarren Reed #include <sys/mac_client_priv.h> 540a0e9771SDarren Reed 550a0e9771SDarren Reed #include <netpacket/packet.h> 560a0e9771SDarren Reed 570a0e9771SDarren Reed static void pfp_close(mac_handle_t, mac_client_handle_t); 580a0e9771SDarren Reed static int pfp_dl_to_arphrd(int); 590a0e9771SDarren Reed static int pfp_getpacket_sockopt(sock_lower_handle_t, int, void *, 600a0e9771SDarren Reed socklen_t *); 61336069c2SPatrick Mooney static int pfp_ifreq_getlinkid(intptr_t, struct ifreq *, datalink_id_t *, int); 62336069c2SPatrick Mooney static int pfp_lifreq_getlinkid(intptr_t, struct lifreq *, datalink_id_t *, 63336069c2SPatrick Mooney int); 640a0e9771SDarren Reed static int pfp_open_index(int, mac_handle_t *, mac_client_handle_t *, 650a0e9771SDarren Reed cred_t *); 660a0e9771SDarren Reed static void pfp_packet(void *, mac_resource_handle_t, mblk_t *, boolean_t); 670a0e9771SDarren Reed static void pfp_release_bpf(struct pfpsock *); 680a0e9771SDarren Reed static int pfp_set_promisc(struct pfpsock *, mac_client_promisc_type_t); 690a0e9771SDarren Reed static int pfp_setsocket_sockopt(sock_lower_handle_t, int, const void *, 700a0e9771SDarren Reed socklen_t); 710a0e9771SDarren Reed static int pfp_setpacket_sockopt(sock_lower_handle_t, int, const void *, 720a0e9771SDarren Reed socklen_t); 730a0e9771SDarren Reed 740a0e9771SDarren Reed /* 750a0e9771SDarren Reed * PFP sockfs operations 760a0e9771SDarren Reed * Most are currently no-ops because they have no meaning for a connectionless 770a0e9771SDarren Reed * socket. 780a0e9771SDarren Reed */ 790a0e9771SDarren Reed static void sdpfp_activate(sock_lower_handle_t, sock_upper_handle_t, 800a0e9771SDarren Reed sock_upcalls_t *, int, struct cred *); 810a0e9771SDarren Reed static int sdpfp_bind(sock_lower_handle_t, struct sockaddr *, socklen_t, 820a0e9771SDarren Reed struct cred *); 830a0e9771SDarren Reed static int sdpfp_close(sock_lower_handle_t, int, struct cred *); 840a0e9771SDarren Reed static void sdpfp_clr_flowctrl(sock_lower_handle_t); 850a0e9771SDarren Reed static int sdpfp_getsockopt(sock_lower_handle_t, int, int, void *, 860a0e9771SDarren Reed socklen_t *, struct cred *); 870a0e9771SDarren Reed static int sdpfp_ioctl(sock_lower_handle_t, int, intptr_t, int, int32_t *, 880a0e9771SDarren Reed struct cred *); 890a0e9771SDarren Reed static int sdpfp_senduio(sock_lower_handle_t, struct uio *, struct nmsghdr *, 900a0e9771SDarren Reed struct cred *); 910a0e9771SDarren Reed static int sdpfp_setsockopt(sock_lower_handle_t, int, int, const void *, 920a0e9771SDarren Reed socklen_t, struct cred *); 930a0e9771SDarren Reed 940a0e9771SDarren Reed static sock_lower_handle_t sockpfp_create(int, int, int, sock_downcalls_t **, 950a0e9771SDarren Reed uint_t *, int *, int, cred_t *); 960a0e9771SDarren Reed 970a0e9771SDarren Reed static int sockpfp_init(void); 980a0e9771SDarren Reed static void sockpfp_fini(void); 990a0e9771SDarren Reed 1000a0e9771SDarren Reed static kstat_t *pfp_ksp; 1010a0e9771SDarren Reed static pfp_kstats_t ks_stats; 1020a0e9771SDarren Reed static pfp_kstats_t pfp_kstats = { 1030a0e9771SDarren Reed /* 1040a0e9771SDarren Reed * Each one of these kstats is a different return path in handling 1050a0e9771SDarren Reed * a packet received from the mac layer. 1060a0e9771SDarren Reed */ 1070a0e9771SDarren Reed { "recvMacHeaderFail", KSTAT_DATA_UINT64 }, 1080a0e9771SDarren Reed { "recvBadProtocol", KSTAT_DATA_UINT64 }, 1090a0e9771SDarren Reed { "recvAllocbFail", KSTAT_DATA_UINT64 }, 1100a0e9771SDarren Reed { "recvOk", KSTAT_DATA_UINT64 }, 1110a0e9771SDarren Reed { "recvFail", KSTAT_DATA_UINT64 }, 1120a0e9771SDarren Reed { "recvFiltered", KSTAT_DATA_UINT64 }, 1130a0e9771SDarren Reed { "recvFlowControl", KSTAT_DATA_UINT64 }, 1140a0e9771SDarren Reed /* 1150a0e9771SDarren Reed * A global set of counters is maintained to track the behaviour 1160a0e9771SDarren Reed * of the system (kernel & applications) in sending packets. 1170a0e9771SDarren Reed */ 1180a0e9771SDarren Reed { "sendUnbound", KSTAT_DATA_UINT64 }, 1190a0e9771SDarren Reed { "sendFailed", KSTAT_DATA_UINT64 }, 1200a0e9771SDarren Reed { "sendTooBig", KSTAT_DATA_UINT64 }, 1210a0e9771SDarren Reed { "sendAllocFail", KSTAT_DATA_UINT64 }, 1220a0e9771SDarren Reed { "sendUiomoveFail", KSTAT_DATA_UINT64 }, 1230a0e9771SDarren Reed { "sendNoMemory", KSTAT_DATA_UINT64 }, 1240a0e9771SDarren Reed { "sendOpenFail", KSTAT_DATA_UINT64 }, 1250a0e9771SDarren Reed { "sendWrongFamily", KSTAT_DATA_UINT64 }, 1260a0e9771SDarren Reed { "sendShortMsg", KSTAT_DATA_UINT64 }, 1270a0e9771SDarren Reed { "sendOk", KSTAT_DATA_UINT64 } 1280a0e9771SDarren Reed }; 1290a0e9771SDarren Reed 1300a0e9771SDarren Reed sock_downcalls_t pfp_downcalls = { 1310a0e9771SDarren Reed sdpfp_activate, 1320a0e9771SDarren Reed sock_accept_notsupp, 1330a0e9771SDarren Reed sdpfp_bind, 1340a0e9771SDarren Reed sock_listen_notsupp, 1350a0e9771SDarren Reed sock_connect_notsupp, 1360a0e9771SDarren Reed sock_getpeername_notsupp, 1370a0e9771SDarren Reed sock_getsockname_notsupp, 1380a0e9771SDarren Reed sdpfp_getsockopt, 1390a0e9771SDarren Reed sdpfp_setsockopt, 1400a0e9771SDarren Reed sock_send_notsupp, 1410a0e9771SDarren Reed sdpfp_senduio, 1420a0e9771SDarren Reed NULL, 1430a0e9771SDarren Reed sock_poll_notsupp, 1440a0e9771SDarren Reed sock_shutdown_notsupp, 1450a0e9771SDarren Reed sdpfp_clr_flowctrl, 1460a0e9771SDarren Reed sdpfp_ioctl, 1470a0e9771SDarren Reed sdpfp_close, 1480a0e9771SDarren Reed }; 1490a0e9771SDarren Reed 1500a0e9771SDarren Reed static smod_reg_t sinfo = { 1510a0e9771SDarren Reed SOCKMOD_VERSION, 1520a0e9771SDarren Reed "sockpfp", 1530a0e9771SDarren Reed SOCK_UC_VERSION, 1540a0e9771SDarren Reed SOCK_DC_VERSION, 1550a0e9771SDarren Reed sockpfp_create, 1560a0e9771SDarren Reed NULL 1570a0e9771SDarren Reed }; 1580a0e9771SDarren Reed 159a6911619SDarren Reed static int accepted_protos[3][2] = { 160a6911619SDarren Reed { ETH_P_ALL, 0 }, 161a6911619SDarren Reed { ETH_P_802_2, LLC_SNAP_SAP }, 162a6911619SDarren Reed { ETH_P_803_3, 0 }, 163a6911619SDarren Reed }; 164a6911619SDarren Reed 1650a0e9771SDarren Reed /* 166336069c2SPatrick Mooney * This sets an upper bound on the size of the receive buffer for a PF_PACKET 167336069c2SPatrick Mooney * socket. More properly, this should be controlled through ipadm, ala TCP, UDP, 168336069c2SPatrick Mooney * SCTP, etc. Until that's done, this provides a hard cap of 4 MB and allows an 169336069c2SPatrick Mooney * opportunity for it to be changed, should it be needed. 170336069c2SPatrick Mooney */ 171336069c2SPatrick Mooney int sockmod_pfp_rcvbuf_max = 1024 * 1024 * 4; 172336069c2SPatrick Mooney 173336069c2SPatrick Mooney /* 1740a0e9771SDarren Reed * Module linkage information for the kernel. 1750a0e9771SDarren Reed */ 1760a0e9771SDarren Reed static struct modlsockmod modlsockmod = { 1770a0e9771SDarren Reed &mod_sockmodops, "PF Packet socket module", &sinfo 1780a0e9771SDarren Reed }; 1790a0e9771SDarren Reed 1800a0e9771SDarren Reed static struct modlinkage modlinkage = { 1810a0e9771SDarren Reed MODREV_1, 1820a0e9771SDarren Reed &modlsockmod, 1830a0e9771SDarren Reed NULL 1840a0e9771SDarren Reed }; 1850a0e9771SDarren Reed 1860a0e9771SDarren Reed int 1870a0e9771SDarren Reed _init(void) 1880a0e9771SDarren Reed { 1890a0e9771SDarren Reed int error; 1900a0e9771SDarren Reed 1910a0e9771SDarren Reed error = sockpfp_init(); 1920a0e9771SDarren Reed if (error != 0) 1930a0e9771SDarren Reed return (error); 1940a0e9771SDarren Reed 1950a0e9771SDarren Reed error = mod_install(&modlinkage); 1960a0e9771SDarren Reed if (error != 0) 1970a0e9771SDarren Reed sockpfp_fini(); 1980a0e9771SDarren Reed 1990a0e9771SDarren Reed return (error); 2000a0e9771SDarren Reed } 2010a0e9771SDarren Reed 2020a0e9771SDarren Reed int 2030a0e9771SDarren Reed _fini(void) 2040a0e9771SDarren Reed { 2050a0e9771SDarren Reed int error; 2060a0e9771SDarren Reed 2070a0e9771SDarren Reed error = mod_remove(&modlinkage); 2080a0e9771SDarren Reed if (error == 0) 2090a0e9771SDarren Reed sockpfp_fini(); 2100a0e9771SDarren Reed 2110a0e9771SDarren Reed return (error); 2120a0e9771SDarren Reed } 2130a0e9771SDarren Reed 2140a0e9771SDarren Reed int 2150a0e9771SDarren Reed _info(struct modinfo *modinfop) 2160a0e9771SDarren Reed { 2170a0e9771SDarren Reed return (mod_info(&modlinkage, modinfop)); 2180a0e9771SDarren Reed } 2190a0e9771SDarren Reed 2200a0e9771SDarren Reed /* 2210a0e9771SDarren Reed * sockpfp_init: called as part of the initialisation of the module when 2220a0e9771SDarren Reed * loaded into the kernel. 2230a0e9771SDarren Reed * 2240a0e9771SDarren Reed * Being able to create and record the kstats data in the kernel is not 2250a0e9771SDarren Reed * considered to be vital to the operation of this kernel module, thus 2260a0e9771SDarren Reed * its failure is tolerated. 2270a0e9771SDarren Reed */ 2280a0e9771SDarren Reed static int 2290a0e9771SDarren Reed sockpfp_init(void) 2300a0e9771SDarren Reed { 2310a0e9771SDarren Reed (void) memset(&ks_stats, 0, sizeof (ks_stats)); 2320a0e9771SDarren Reed 2330a0e9771SDarren Reed (void) memcpy(&ks_stats, &pfp_kstats, sizeof (pfp_kstats)); 2340a0e9771SDarren Reed 2350a0e9771SDarren Reed pfp_ksp = kstat_create("pfpacket", 0, "global", "misc", 2360a0e9771SDarren Reed KSTAT_TYPE_NAMED, sizeof (pfp_kstats) / sizeof (kstat_named_t), 2370a0e9771SDarren Reed KSTAT_FLAG_VIRTUAL); 2380a0e9771SDarren Reed if (pfp_ksp != NULL) { 2390a0e9771SDarren Reed pfp_ksp->ks_data = &ks_stats; 2400a0e9771SDarren Reed kstat_install(pfp_ksp); 2410a0e9771SDarren Reed } 2420a0e9771SDarren Reed 2430a0e9771SDarren Reed return (0); 2440a0e9771SDarren Reed } 2450a0e9771SDarren Reed 2460a0e9771SDarren Reed /* 2470a0e9771SDarren Reed * sockpfp_fini: called when the operating system wants to unload the 2480a0e9771SDarren Reed * socket module from the kernel. 2490a0e9771SDarren Reed */ 2500a0e9771SDarren Reed static void 2510a0e9771SDarren Reed sockpfp_fini(void) 2520a0e9771SDarren Reed { 2530a0e9771SDarren Reed if (pfp_ksp != NULL) 2540a0e9771SDarren Reed kstat_delete(pfp_ksp); 2550a0e9771SDarren Reed } 2560a0e9771SDarren Reed 2570a0e9771SDarren Reed /* 2580a0e9771SDarren Reed * Due to sockets being created read-write by default, all PF_PACKET sockets 2590a0e9771SDarren Reed * therefore require the NET_RAWACCESS priviliege, even if the socket is only 2600a0e9771SDarren Reed * being used for reading packets from. 2610a0e9771SDarren Reed * 2620a0e9771SDarren Reed * This create function enforces this module only being used with PF_PACKET 263d2b5b2d3SAnders Persson * sockets and the policy that we support via the config file in sock2path.d: 2640a0e9771SDarren Reed * PF_PACKET sockets must be either SOCK_DGRAM or SOCK_RAW. 2650a0e9771SDarren Reed */ 2660a0e9771SDarren Reed /* ARGSUSED */ 2670a0e9771SDarren Reed static sock_lower_handle_t 2680a0e9771SDarren Reed sockpfp_create(int family, int type, int proto, 2690a0e9771SDarren Reed sock_downcalls_t **sock_downcalls, uint_t *smodep, int *errorp, 2700a0e9771SDarren Reed int sflags, cred_t *cred) 2710a0e9771SDarren Reed { 2720a0e9771SDarren Reed struct pfpsock *ps; 2730a0e9771SDarren Reed int kmflags; 274a6911619SDarren Reed int newproto; 275a6911619SDarren Reed int i; 2760a0e9771SDarren Reed 2770a0e9771SDarren Reed if (secpolicy_net_rawaccess(cred) != 0) { 2780a0e9771SDarren Reed *errorp = EACCES; 2790a0e9771SDarren Reed return (NULL); 2800a0e9771SDarren Reed } 2810a0e9771SDarren Reed 2820a0e9771SDarren Reed if (family != AF_PACKET) { 2830a0e9771SDarren Reed *errorp = EAFNOSUPPORT; 2840a0e9771SDarren Reed return (NULL); 2850a0e9771SDarren Reed } 2860a0e9771SDarren Reed 2870a0e9771SDarren Reed if ((type != SOCK_RAW) && (type != SOCK_DGRAM)) { 2880a0e9771SDarren Reed *errorp = ESOCKTNOSUPPORT; 2890a0e9771SDarren Reed return (NULL); 2900a0e9771SDarren Reed } 2910a0e9771SDarren Reed 292a6911619SDarren Reed /* 293a6911619SDarren Reed * First check to see if the protocol number passed in via the socket 294a6911619SDarren Reed * creation should be mapped to a different number for internal use. 295a6911619SDarren Reed */ 296a6911619SDarren Reed for (i = 0, newproto = -1; 297a6911619SDarren Reed i < sizeof (accepted_protos)/ sizeof (accepted_protos[0]); i++) { 298a6911619SDarren Reed if (accepted_protos[i][0] == proto) { 299a6911619SDarren Reed newproto = accepted_protos[i][1]; 300a6911619SDarren Reed break; 301a6911619SDarren Reed } 302a6911619SDarren Reed } 303a6911619SDarren Reed 304a6911619SDarren Reed /* 305a6911619SDarren Reed * If the mapping of the protocol that was under 0x800 failed to find 306a6911619SDarren Reed * a local equivalent then fail the socket creation. If the protocol 307a6911619SDarren Reed * for the socket is over 0x800 and it was not found in the mapping 308a6911619SDarren Reed * table above, then use the value as is. 309a6911619SDarren Reed */ 310a6911619SDarren Reed if (newproto == -1) { 311a6911619SDarren Reed if (proto < 0x800) { 312a6911619SDarren Reed *errorp = ENOPROTOOPT; 313a6911619SDarren Reed return (NULL); 314a6911619SDarren Reed } 315a6911619SDarren Reed newproto = proto; 316a6911619SDarren Reed } 317a6911619SDarren Reed proto = newproto; 318a6911619SDarren Reed 3190a0e9771SDarren Reed kmflags = (sflags & SOCKET_NOSLEEP) ? KM_NOSLEEP : KM_SLEEP; 3200a0e9771SDarren Reed ps = kmem_zalloc(sizeof (*ps), kmflags); 3210a0e9771SDarren Reed if (ps == NULL) { 3220a0e9771SDarren Reed *errorp = ENOMEM; 3230a0e9771SDarren Reed return (NULL); 3240a0e9771SDarren Reed } 3250a0e9771SDarren Reed 3260a0e9771SDarren Reed ps->ps_type = type; 3270a0e9771SDarren Reed ps->ps_proto = proto; 3280a0e9771SDarren Reed rw_init(&ps->ps_bpflock, NULL, RW_DRIVER, NULL); 3290a0e9771SDarren Reed mutex_init(&ps->ps_lock, NULL, MUTEX_DRIVER, NULL); 3300a0e9771SDarren Reed 3310a0e9771SDarren Reed *sock_downcalls = &pfp_downcalls; 3320a0e9771SDarren Reed /* 3330a0e9771SDarren Reed * Setting this causes bytes from a packet that do not fit into the 3340a0e9771SDarren Reed * destination user buffer to be discarded. Thus the API is one 3350a0e9771SDarren Reed * packet per receive and callers are required to use a buffer large 3360a0e9771SDarren Reed * enough for the biggest packet that the interface can provide. 3370a0e9771SDarren Reed */ 3380a0e9771SDarren Reed *smodep = SM_ATOMIC; 3390a0e9771SDarren Reed 3400a0e9771SDarren Reed return ((sock_lower_handle_t)ps); 3410a0e9771SDarren Reed } 3420a0e9771SDarren Reed 3430a0e9771SDarren Reed /* ************************************************************************* */ 3440a0e9771SDarren Reed 3450a0e9771SDarren Reed /* 3460a0e9771SDarren Reed * pfp_packet is the callback function that is given to the mac layer for 3470a0e9771SDarren Reed * PF_PACKET to receive packets with. One packet at a time is passed into 3480a0e9771SDarren Reed * this function from the mac layer. Each packet is a private copy given 3490a0e9771SDarren Reed * to PF_PACKET to modify or free as it wishes and does not harm the original 3500a0e9771SDarren Reed * packet from which it was cloned. 3510a0e9771SDarren Reed */ 3520a0e9771SDarren Reed /* ARGSUSED */ 3530a0e9771SDarren Reed static void 3540a0e9771SDarren Reed pfp_packet(void *arg, mac_resource_handle_t mrh, mblk_t *mp, boolean_t flag) 3550a0e9771SDarren Reed { 3560a0e9771SDarren Reed struct T_unitdata_ind *tunit; 3570a0e9771SDarren Reed struct sockaddr_ll *sll; 3580a0e9771SDarren Reed struct sockaddr_ll *sol; 3590a0e9771SDarren Reed mac_header_info_t hdr; 3600a0e9771SDarren Reed struct pfpsock *ps; 3610a0e9771SDarren Reed size_t tusz; 3620a0e9771SDarren Reed mblk_t *mp0; 3630a0e9771SDarren Reed int error; 3640a0e9771SDarren Reed 3650a0e9771SDarren Reed if (mp == NULL) 3660a0e9771SDarren Reed return; 3670a0e9771SDarren Reed 3680a0e9771SDarren Reed ps = arg; 3690a0e9771SDarren Reed if (ps->ps_flow_ctrld) { 3700a0e9771SDarren Reed ps->ps_flow_ctrl_drops++; 3710a0e9771SDarren Reed ps->ps_stats.tp_drops++; 3720a0e9771SDarren Reed ks_stats.kp_recv_flow_cntrld.value.ui64++; 3730a0e9771SDarren Reed freemsg(mp); 3740a0e9771SDarren Reed return; 3750a0e9771SDarren Reed } 3760a0e9771SDarren Reed 3770a0e9771SDarren Reed if (mac_header_info(ps->ps_mh, mp, &hdr) != 0) { 3780a0e9771SDarren Reed /* 3790a0e9771SDarren Reed * Can't decode the packet header information so drop it. 3800a0e9771SDarren Reed */ 3810a0e9771SDarren Reed ps->ps_stats.tp_drops++; 3820a0e9771SDarren Reed ks_stats.kp_recv_mac_hdr_fail.value.ui64++; 3830a0e9771SDarren Reed freemsg(mp); 3840a0e9771SDarren Reed return; 3850a0e9771SDarren Reed } 3860a0e9771SDarren Reed 3870a0e9771SDarren Reed if (mac_type(ps->ps_mh) == DL_ETHER && 3880a0e9771SDarren Reed hdr.mhi_bindsap == ETHERTYPE_VLAN) { 3890a0e9771SDarren Reed struct ether_vlan_header *evhp; 3900a0e9771SDarren Reed struct ether_vlan_header evh; 3910a0e9771SDarren Reed 3920a0e9771SDarren Reed hdr.mhi_hdrsize = sizeof (struct ether_vlan_header); 3930a0e9771SDarren Reed hdr.mhi_istagged = B_TRUE; 3940a0e9771SDarren Reed 3950a0e9771SDarren Reed if (MBLKL(mp) >= sizeof (*evhp)) { 3960a0e9771SDarren Reed evhp = (struct ether_vlan_header *)mp->b_rptr; 3970a0e9771SDarren Reed } else { 3980a0e9771SDarren Reed int sz = sizeof (*evhp); 3990a0e9771SDarren Reed char *s = (char *)&evh; 4000a0e9771SDarren Reed mblk_t *tmp; 4010a0e9771SDarren Reed int len; 4020a0e9771SDarren Reed 4030a0e9771SDarren Reed for (tmp = mp; sz > 0 && tmp != NULL; 4040a0e9771SDarren Reed tmp = tmp->b_cont) { 4050a0e9771SDarren Reed len = min(sz, MBLKL(tmp)); 4060a0e9771SDarren Reed bcopy(tmp->b_rptr, s, len); 4070a0e9771SDarren Reed sz -= len; 4080a0e9771SDarren Reed } 4090a0e9771SDarren Reed evhp = &evh; 4100a0e9771SDarren Reed } 4110a0e9771SDarren Reed hdr.mhi_tci = ntohs(evhp->ether_tci); 4120a0e9771SDarren Reed hdr.mhi_bindsap = ntohs(evhp->ether_type); 4130a0e9771SDarren Reed } 4140a0e9771SDarren Reed 4150a0e9771SDarren Reed if ((ps->ps_proto != 0) && (ps->ps_proto != hdr.mhi_bindsap)) { 4160a0e9771SDarren Reed /* 4170a0e9771SDarren Reed * The packet is not of interest to this socket so 4180a0e9771SDarren Reed * drop it on the floor. Here the SAP is being used 4190a0e9771SDarren Reed * as a very course filter. 4200a0e9771SDarren Reed */ 4210a0e9771SDarren Reed ps->ps_stats.tp_drops++; 4220a0e9771SDarren Reed ks_stats.kp_recv_bad_proto.value.ui64++; 4230a0e9771SDarren Reed freemsg(mp); 4240a0e9771SDarren Reed return; 4250a0e9771SDarren Reed } 4260a0e9771SDarren Reed 4270a0e9771SDarren Reed /* 4280a0e9771SDarren Reed * This field is not often set, even for ethernet, 4290a0e9771SDarren Reed * by mac_header_info, so compute it if it is 0. 4300a0e9771SDarren Reed */ 4310a0e9771SDarren Reed if (hdr.mhi_pktsize == 0) 4320a0e9771SDarren Reed hdr.mhi_pktsize = msgdsize(mp); 4330a0e9771SDarren Reed 4340a0e9771SDarren Reed /* 4350a0e9771SDarren Reed * If a BPF filter is present, pass the raw packet into that. 4360a0e9771SDarren Reed * A failed match will result in zero being returned, indicating 4370a0e9771SDarren Reed * that this socket is not interested in the packet. 4380a0e9771SDarren Reed */ 4390a0e9771SDarren Reed if (ps->ps_bpf.bf_len != 0) { 4400a0e9771SDarren Reed uchar_t *buffer; 4410a0e9771SDarren Reed int buflen; 4420a0e9771SDarren Reed 4430a0e9771SDarren Reed buflen = MBLKL(mp); 4440a0e9771SDarren Reed if (hdr.mhi_pktsize == buflen) { 4450a0e9771SDarren Reed buffer = mp->b_rptr; 4460a0e9771SDarren Reed } else { 4470a0e9771SDarren Reed buflen = 0; 4480a0e9771SDarren Reed buffer = (uchar_t *)mp; 4490a0e9771SDarren Reed } 4500a0e9771SDarren Reed rw_enter(&ps->ps_bpflock, RW_READER); 4510a0e9771SDarren Reed if (bpf_filter(ps->ps_bpf.bf_insns, buffer, 4520a0e9771SDarren Reed hdr.mhi_pktsize, buflen) == 0) { 4530a0e9771SDarren Reed rw_exit(&ps->ps_bpflock); 4540a0e9771SDarren Reed ps->ps_stats.tp_drops++; 4550a0e9771SDarren Reed ks_stats.kp_recv_filtered.value.ui64++; 4560a0e9771SDarren Reed freemsg(mp); 4570a0e9771SDarren Reed return; 4580a0e9771SDarren Reed } 4590a0e9771SDarren Reed rw_exit(&ps->ps_bpflock); 4600a0e9771SDarren Reed } 4610a0e9771SDarren Reed 4620a0e9771SDarren Reed if (ps->ps_type == SOCK_DGRAM) { 4630a0e9771SDarren Reed /* 4640a0e9771SDarren Reed * SOCK_DGRAM socket expect a "layer 3" packet, so advance 4650a0e9771SDarren Reed * past the link layer header. 4660a0e9771SDarren Reed */ 4670a0e9771SDarren Reed mp->b_rptr += hdr.mhi_hdrsize; 4680a0e9771SDarren Reed hdr.mhi_pktsize -= hdr.mhi_hdrsize; 4690a0e9771SDarren Reed } 4700a0e9771SDarren Reed 4710a0e9771SDarren Reed tusz = sizeof (struct T_unitdata_ind) + sizeof (struct sockaddr_ll); 4720a0e9771SDarren Reed if (ps->ps_auxdata) { 4730a0e9771SDarren Reed tusz += _TPI_ALIGN_TOPT(sizeof (struct tpacket_auxdata)); 4740a0e9771SDarren Reed tusz += _TPI_ALIGN_TOPT(sizeof (struct T_opthdr)); 4750a0e9771SDarren Reed } 4760a0e9771SDarren Reed 4770a0e9771SDarren Reed /* 4780a0e9771SDarren Reed * It is tempting to think that this could be optimised by having 4790a0e9771SDarren Reed * the base mblk_t allocated and hung off the pfpsock structure, 4800a0e9771SDarren Reed * except that then another one would need to be allocated for the 4810a0e9771SDarren Reed * sockaddr_ll that is included. Even creating a template to copy 4820a0e9771SDarren Reed * from is of questionable value, as read-write from one structure 4830a0e9771SDarren Reed * to the other is going to be slower than all of the initialisation. 4840a0e9771SDarren Reed */ 4850a0e9771SDarren Reed mp0 = allocb(tusz, BPRI_HI); 4860a0e9771SDarren Reed if (mp0 == NULL) { 4870a0e9771SDarren Reed ps->ps_stats.tp_drops++; 4880a0e9771SDarren Reed ks_stats.kp_recv_alloc_fail.value.ui64++; 4890a0e9771SDarren Reed freemsg(mp); 4900a0e9771SDarren Reed return; 4910a0e9771SDarren Reed } 4920a0e9771SDarren Reed 4930a0e9771SDarren Reed (void) memset(mp0->b_rptr, 0, tusz); 4940a0e9771SDarren Reed 4950a0e9771SDarren Reed mp0->b_datap->db_type = M_PROTO; 4960a0e9771SDarren Reed mp0->b_wptr = mp0->b_rptr + tusz; 4970a0e9771SDarren Reed 4980a0e9771SDarren Reed tunit = (struct T_unitdata_ind *)mp0->b_rptr; 4990a0e9771SDarren Reed tunit->PRIM_type = T_UNITDATA_IND; 5000a0e9771SDarren Reed tunit->SRC_length = sizeof (struct sockaddr); 5010a0e9771SDarren Reed tunit->SRC_offset = sizeof (*tunit); 5020a0e9771SDarren Reed 503*3b4315d3SPatrick Mooney sol = &ps->ps_sock; 5040a0e9771SDarren Reed sll = (struct sockaddr_ll *)(mp0->b_rptr + sizeof (*tunit)); 5050a0e9771SDarren Reed sll->sll_ifindex = sol->sll_ifindex; 5060a0e9771SDarren Reed sll->sll_hatype = (uint16_t)hdr.mhi_origsap; 5070a0e9771SDarren Reed sll->sll_halen = sol->sll_halen; 5080a0e9771SDarren Reed if (hdr.mhi_saddr != NULL) 5090a0e9771SDarren Reed (void) memcpy(sll->sll_addr, hdr.mhi_saddr, sll->sll_halen); 5100a0e9771SDarren Reed 5110a0e9771SDarren Reed switch (hdr.mhi_dsttype) { 5120a0e9771SDarren Reed case MAC_ADDRTYPE_MULTICAST : 5130a0e9771SDarren Reed sll->sll_pkttype = PACKET_MULTICAST; 5140a0e9771SDarren Reed break; 5150a0e9771SDarren Reed case MAC_ADDRTYPE_BROADCAST : 5160a0e9771SDarren Reed sll->sll_pkttype = PACKET_BROADCAST; 5170a0e9771SDarren Reed break; 5180a0e9771SDarren Reed case MAC_ADDRTYPE_UNICAST : 5190a0e9771SDarren Reed if (memcmp(sol->sll_addr, hdr.mhi_daddr, sol->sll_halen) == 0) 5200a0e9771SDarren Reed sll->sll_pkttype = PACKET_HOST; 5210a0e9771SDarren Reed else 5220a0e9771SDarren Reed sll->sll_pkttype = PACKET_OTHERHOST; 5230a0e9771SDarren Reed break; 5240a0e9771SDarren Reed } 5250a0e9771SDarren Reed 5260a0e9771SDarren Reed if (ps->ps_auxdata) { 5270a0e9771SDarren Reed struct tpacket_auxdata *aux; 5280a0e9771SDarren Reed struct T_opthdr *topt; 5290a0e9771SDarren Reed 5300a0e9771SDarren Reed tunit->OPT_offset = _TPI_ALIGN_TOPT(tunit->SRC_offset + 5310a0e9771SDarren Reed sizeof (struct sockaddr_ll)); 5320a0e9771SDarren Reed tunit->OPT_length = _TPI_ALIGN_TOPT(sizeof (struct T_opthdr)) + 5330a0e9771SDarren Reed _TPI_ALIGN_TOPT(sizeof (struct tpacket_auxdata)); 5340a0e9771SDarren Reed 5350a0e9771SDarren Reed topt = (struct T_opthdr *)(mp0->b_rptr + tunit->OPT_offset); 5360a0e9771SDarren Reed aux = (struct tpacket_auxdata *) 5370a0e9771SDarren Reed ((char *)topt + _TPI_ALIGN_TOPT(sizeof (*topt))); 5380a0e9771SDarren Reed 5390a0e9771SDarren Reed topt->len = tunit->OPT_length; 5400a0e9771SDarren Reed topt->level = SOL_PACKET; 5410a0e9771SDarren Reed topt->name = PACKET_AUXDATA; 5420a0e9771SDarren Reed topt->status = 0; 5430a0e9771SDarren Reed /* 5440a0e9771SDarren Reed * libpcap doesn't seem to use any other field, 5450a0e9771SDarren Reed * so it isn't clear how they should be filled in. 5460a0e9771SDarren Reed */ 5470a0e9771SDarren Reed aux->tp_vlan_vci = hdr.mhi_tci; 5480a0e9771SDarren Reed } 5490a0e9771SDarren Reed 5500a0e9771SDarren Reed linkb(mp0, mp); 5510a0e9771SDarren Reed 552336069c2SPatrick Mooney (void) gethrestime(&ps->ps_timestamp); 553336069c2SPatrick Mooney 5540a0e9771SDarren Reed ps->ps_upcalls->su_recv(ps->ps_upper, mp0, hdr.mhi_pktsize, 0, 5550a0e9771SDarren Reed &error, NULL); 5560a0e9771SDarren Reed 5570a0e9771SDarren Reed if (error == 0) { 5580a0e9771SDarren Reed ps->ps_stats.tp_packets++; 5590a0e9771SDarren Reed ks_stats.kp_recv_ok.value.ui64++; 5600a0e9771SDarren Reed } else { 5610a0e9771SDarren Reed mutex_enter(&ps->ps_lock); 5620a0e9771SDarren Reed if (error == ENOSPC) { 5630a0e9771SDarren Reed ps->ps_upcalls->su_recv(ps->ps_upper, NULL, 0, 0, 5640a0e9771SDarren Reed &error, NULL); 5650a0e9771SDarren Reed if (error == ENOSPC) 5660a0e9771SDarren Reed ps->ps_flow_ctrld = B_TRUE; 5670a0e9771SDarren Reed } 5680a0e9771SDarren Reed mutex_exit(&ps->ps_lock); 5690a0e9771SDarren Reed ps->ps_stats.tp_drops++; 5700a0e9771SDarren Reed ks_stats.kp_recv_fail.value.ui64++; 5710a0e9771SDarren Reed } 5720a0e9771SDarren Reed } 5730a0e9771SDarren Reed 5740a0e9771SDarren Reed /* 5750a0e9771SDarren Reed * Bind a PF_PACKET socket to a network interface. 5760a0e9771SDarren Reed * 5770a0e9771SDarren Reed * The default operation of this bind() is to place the socket (and thus the 5780a0e9771SDarren Reed * network interface) into promiscuous mode. It is then up to the application 5790a0e9771SDarren Reed * to turn that down by issuing the relevant ioctls, if desired. 5800a0e9771SDarren Reed */ 5810a0e9771SDarren Reed static int 5820a0e9771SDarren Reed sdpfp_bind(sock_lower_handle_t handle, struct sockaddr *addr, 5830a0e9771SDarren Reed socklen_t addrlen, struct cred *cred) 5840a0e9771SDarren Reed { 5850a0e9771SDarren Reed struct sockaddr_ll *addr_ll, *sol; 5860a0e9771SDarren Reed mac_client_handle_t mch; 5870a0e9771SDarren Reed struct pfpsock *ps; 5880a0e9771SDarren Reed mac_handle_t mh; 5890a0e9771SDarren Reed int error; 5900a0e9771SDarren Reed 5910a0e9771SDarren Reed ps = (struct pfpsock *)handle; 5920a0e9771SDarren Reed if (ps->ps_bound) 5930a0e9771SDarren Reed return (EINVAL); 5940a0e9771SDarren Reed 595*3b4315d3SPatrick Mooney if (addrlen < sizeof (struct sockaddr_ll) || addr == NULL) 596*3b4315d3SPatrick Mooney return (EINVAL); 597*3b4315d3SPatrick Mooney 5980a0e9771SDarren Reed addr_ll = (struct sockaddr_ll *)addr; 5990a0e9771SDarren Reed 6000a0e9771SDarren Reed error = pfp_open_index(addr_ll->sll_ifindex, &mh, &mch, cred); 6010a0e9771SDarren Reed if (error != 0) 6020a0e9771SDarren Reed return (error); 6030a0e9771SDarren Reed /* 6040a0e9771SDarren Reed * Ensure that each socket is only bound once. 6050a0e9771SDarren Reed */ 6060a0e9771SDarren Reed mutex_enter(&ps->ps_lock); 6070a0e9771SDarren Reed if (ps->ps_mh != 0) { 6080a0e9771SDarren Reed mutex_exit(&ps->ps_lock); 6090a0e9771SDarren Reed pfp_close(mh, mch); 6100a0e9771SDarren Reed return (EADDRINUSE); 6110a0e9771SDarren Reed } 6120a0e9771SDarren Reed ps->ps_mh = mh; 6130a0e9771SDarren Reed ps->ps_mch = mch; 6140a0e9771SDarren Reed mutex_exit(&ps->ps_lock); 6150a0e9771SDarren Reed 6160a0e9771SDarren Reed /* 6170a0e9771SDarren Reed * Cache all of the information from bind so that it's in an easy 6180a0e9771SDarren Reed * place to get at when packets are received. 6190a0e9771SDarren Reed */ 620*3b4315d3SPatrick Mooney sol = &ps->ps_sock; 6210a0e9771SDarren Reed sol->sll_family = AF_PACKET; 6220a0e9771SDarren Reed sol->sll_ifindex = addr_ll->sll_ifindex; 6230a0e9771SDarren Reed sol->sll_protocol = addr_ll->sll_protocol; 6240a0e9771SDarren Reed sol->sll_halen = mac_addr_len(ps->ps_mh); 6250a0e9771SDarren Reed mac_unicast_primary_get(ps->ps_mh, sol->sll_addr); 6260a0e9771SDarren Reed mac_sdu_get(ps->ps_mh, NULL, &ps->ps_max_sdu); 6270a0e9771SDarren Reed ps->ps_linkid = addr_ll->sll_ifindex; 6280a0e9771SDarren Reed 6290a0e9771SDarren Reed error = mac_promisc_add(ps->ps_mch, MAC_CLIENT_PROMISC_ALL, 6300a0e9771SDarren Reed pfp_packet, ps, &ps->ps_phd, MAC_PROMISC_FLAGS_VLAN_TAG_STRIP); 6310a0e9771SDarren Reed if (error == 0) { 6320a0e9771SDarren Reed ps->ps_promisc = MAC_CLIENT_PROMISC_ALL; 6330a0e9771SDarren Reed ps->ps_bound = B_TRUE; 6340a0e9771SDarren Reed } 6350a0e9771SDarren Reed 6360a0e9771SDarren Reed return (error); 6370a0e9771SDarren Reed } 6380a0e9771SDarren Reed 6390a0e9771SDarren Reed /* ARGSUSED */ 6400a0e9771SDarren Reed static void 6410a0e9771SDarren Reed sdpfp_activate(sock_lower_handle_t lower, sock_upper_handle_t upper, 6420a0e9771SDarren Reed sock_upcalls_t *upcalls, int flags, cred_t *cred) 6430a0e9771SDarren Reed { 6440a0e9771SDarren Reed struct pfpsock *ps; 6450a0e9771SDarren Reed 6460a0e9771SDarren Reed ps = (struct pfpsock *)lower; 6470a0e9771SDarren Reed ps->ps_upper = upper; 6480a0e9771SDarren Reed ps->ps_upcalls = upcalls; 6490a0e9771SDarren Reed } 6500a0e9771SDarren Reed 6510a0e9771SDarren Reed /* 6520a0e9771SDarren Reed * This module only implements getting socket options for the new socket 6530a0e9771SDarren Reed * option level (SOL_PACKET) that it introduces. All other requests are 6540a0e9771SDarren Reed * passed back to the sockfs layer. 6550a0e9771SDarren Reed */ 6560a0e9771SDarren Reed /* ARGSUSED */ 6570a0e9771SDarren Reed static int 6580a0e9771SDarren Reed sdpfp_getsockopt(sock_lower_handle_t handle, int level, int option_name, 6590a0e9771SDarren Reed void *optval, socklen_t *optlenp, struct cred *cred) 6600a0e9771SDarren Reed { 661336069c2SPatrick Mooney struct pfpsock *ps; 6620a0e9771SDarren Reed int error = 0; 6630a0e9771SDarren Reed 664336069c2SPatrick Mooney ps = (struct pfpsock *)handle; 665336069c2SPatrick Mooney 6660a0e9771SDarren Reed switch (level) { 6670a0e9771SDarren Reed case SOL_PACKET : 6680a0e9771SDarren Reed error = pfp_getpacket_sockopt(handle, option_name, optval, 6690a0e9771SDarren Reed optlenp); 6700a0e9771SDarren Reed break; 671336069c2SPatrick Mooney 672336069c2SPatrick Mooney case SOL_SOCKET : 673336069c2SPatrick Mooney if (option_name == SO_RCVBUF) { 674336069c2SPatrick Mooney if (*optlenp < sizeof (int32_t)) 675336069c2SPatrick Mooney return (EINVAL); 676336069c2SPatrick Mooney *((int32_t *)optval) = ps->ps_rcvbuf; 677336069c2SPatrick Mooney *optlenp = sizeof (int32_t); 678336069c2SPatrick Mooney } else { 679336069c2SPatrick Mooney error = ENOPROTOOPT; 680336069c2SPatrick Mooney } 681336069c2SPatrick Mooney break; 682336069c2SPatrick Mooney 6830a0e9771SDarren Reed default : 6840a0e9771SDarren Reed /* 6850a0e9771SDarren Reed * If sockfs code receives this error in return from the 6860a0e9771SDarren Reed * getsockopt downcall it handles the option locally, if 687336069c2SPatrick Mooney * it can. 6880a0e9771SDarren Reed */ 6890a0e9771SDarren Reed error = ENOPROTOOPT; 6900a0e9771SDarren Reed break; 6910a0e9771SDarren Reed } 6920a0e9771SDarren Reed 6930a0e9771SDarren Reed return (error); 6940a0e9771SDarren Reed } 6950a0e9771SDarren Reed 6960a0e9771SDarren Reed /* 6970a0e9771SDarren Reed * PF_PACKET supports setting socket options at only two levels: 6980a0e9771SDarren Reed * SOL_SOCKET and SOL_PACKET. 6990a0e9771SDarren Reed */ 7000a0e9771SDarren Reed /* ARGSUSED */ 7010a0e9771SDarren Reed static int 7020a0e9771SDarren Reed sdpfp_setsockopt(sock_lower_handle_t handle, int level, int option_name, 7030a0e9771SDarren Reed const void *optval, socklen_t optlen, struct cred *cred) 7040a0e9771SDarren Reed { 7050a0e9771SDarren Reed int error = 0; 7060a0e9771SDarren Reed 7070a0e9771SDarren Reed switch (level) { 7080a0e9771SDarren Reed case SOL_SOCKET : 7090a0e9771SDarren Reed error = pfp_setsocket_sockopt(handle, option_name, optval, 7100a0e9771SDarren Reed optlen); 7110a0e9771SDarren Reed break; 7120a0e9771SDarren Reed case SOL_PACKET : 7130a0e9771SDarren Reed error = pfp_setpacket_sockopt(handle, option_name, optval, 7140a0e9771SDarren Reed optlen); 7150a0e9771SDarren Reed break; 7160a0e9771SDarren Reed default : 7170a0e9771SDarren Reed error = EINVAL; 7180a0e9771SDarren Reed break; 7190a0e9771SDarren Reed } 7200a0e9771SDarren Reed 7210a0e9771SDarren Reed return (error); 7220a0e9771SDarren Reed } 7230a0e9771SDarren Reed 7240a0e9771SDarren Reed /* 7250a0e9771SDarren Reed * This function is incredibly inefficient for sending any packet that 7260a0e9771SDarren Reed * comes with a msghdr asking to be sent to an interface to which the 7270a0e9771SDarren Reed * socket has not been bound. Some possibilities here are keeping a 7280a0e9771SDarren Reed * cache of all open mac's and mac_client's, for the purpose of sending, 7290a0e9771SDarren Reed * and closing them after some amount of inactivity. Clearly, applications 7300a0e9771SDarren Reed * should not be written to use one socket for multiple interfaces if 7310a0e9771SDarren Reed * performance is desired with the code as is. 7320a0e9771SDarren Reed */ 7330a0e9771SDarren Reed /* ARGSUSED */ 7340a0e9771SDarren Reed static int 7350a0e9771SDarren Reed sdpfp_senduio(sock_lower_handle_t handle, struct uio *uiop, 7360a0e9771SDarren Reed struct nmsghdr *msg, struct cred *cred) 7370a0e9771SDarren Reed { 7380a0e9771SDarren Reed struct sockaddr_ll *sol; 7390a0e9771SDarren Reed mac_client_handle_t mch; 7400a0e9771SDarren Reed struct pfpsock *ps; 7410a0e9771SDarren Reed boolean_t new_open; 7420a0e9771SDarren Reed mac_handle_t mh; 7430a0e9771SDarren Reed size_t mpsize; 7440a0e9771SDarren Reed uint_t maxsdu; 7450a0e9771SDarren Reed mblk_t *mp0; 7460a0e9771SDarren Reed mblk_t *mp; 7470a0e9771SDarren Reed int error; 7480a0e9771SDarren Reed 7490a0e9771SDarren Reed mp = NULL; 7500a0e9771SDarren Reed mp0 = NULL; 7510a0e9771SDarren Reed new_open = B_FALSE; 7520a0e9771SDarren Reed ps = (struct pfpsock *)handle; 7530a0e9771SDarren Reed mh = ps->ps_mh; 7540a0e9771SDarren Reed mch = ps->ps_mch; 7550a0e9771SDarren Reed maxsdu = ps->ps_max_sdu; 7560a0e9771SDarren Reed 7570a0e9771SDarren Reed sol = (struct sockaddr_ll *)msg->msg_name; 7580a0e9771SDarren Reed if (sol == NULL) { 7590a0e9771SDarren Reed /* 7600a0e9771SDarren Reed * If no sockaddr_ll has been provided with the send call, 7610a0e9771SDarren Reed * use the one constructed when the socket was bound to an 7620a0e9771SDarren Reed * interface and fail if it hasn't been bound. 7630a0e9771SDarren Reed */ 7640a0e9771SDarren Reed if (!ps->ps_bound) { 7650a0e9771SDarren Reed ks_stats.kp_send_unbound.value.ui64++; 7660a0e9771SDarren Reed return (EPROTO); 7670a0e9771SDarren Reed } 768*3b4315d3SPatrick Mooney sol = &ps->ps_sock; 7690a0e9771SDarren Reed } else { 7700a0e9771SDarren Reed /* 7710a0e9771SDarren Reed * Verify the sockaddr_ll message passed down before using 7720a0e9771SDarren Reed * it to send a packet out with. If it refers to an interface 7730a0e9771SDarren Reed * that has not been bound, it is necessary to open it. 7740a0e9771SDarren Reed */ 7750a0e9771SDarren Reed struct sockaddr_ll *sll; 7760a0e9771SDarren Reed 7770a0e9771SDarren Reed if (msg->msg_namelen < sizeof (struct sockaddr_ll)) { 7780a0e9771SDarren Reed ks_stats.kp_send_short_msg.value.ui64++; 7790a0e9771SDarren Reed return (EINVAL); 7800a0e9771SDarren Reed } 7810a0e9771SDarren Reed 7820a0e9771SDarren Reed if (sol->sll_family != AF_PACKET) { 7830a0e9771SDarren Reed ks_stats.kp_send_wrong_family.value.ui64++; 7840a0e9771SDarren Reed return (EAFNOSUPPORT); 7850a0e9771SDarren Reed } 7860a0e9771SDarren Reed 787*3b4315d3SPatrick Mooney sll = &ps->ps_sock; 7880a0e9771SDarren Reed if (sol->sll_ifindex != sll->sll_ifindex) { 7890a0e9771SDarren Reed error = pfp_open_index(sol->sll_ifindex, &mh, &mch, 7900a0e9771SDarren Reed cred); 7910a0e9771SDarren Reed if (error != 0) { 7920a0e9771SDarren Reed ks_stats.kp_send_open_fail.value.ui64++; 7930a0e9771SDarren Reed return (error); 7940a0e9771SDarren Reed } 7950a0e9771SDarren Reed mac_sdu_get(mh, NULL, &maxsdu); 7960a0e9771SDarren Reed new_open = B_TRUE; 7970a0e9771SDarren Reed } 7980a0e9771SDarren Reed } 7990a0e9771SDarren Reed 8000a0e9771SDarren Reed mpsize = uiop->uio_resid; 8010a0e9771SDarren Reed if (mpsize > maxsdu) { 8020a0e9771SDarren Reed ks_stats.kp_send_too_big.value.ui64++; 8030a0e9771SDarren Reed error = EMSGSIZE; 8040a0e9771SDarren Reed goto done; 8050a0e9771SDarren Reed } 8060a0e9771SDarren Reed 8070a0e9771SDarren Reed if ((mp = allocb(mpsize, BPRI_HI)) == NULL) { 8080a0e9771SDarren Reed ks_stats.kp_send_alloc_fail.value.ui64++; 8090a0e9771SDarren Reed error = ENOBUFS; 8100a0e9771SDarren Reed goto done; 8110a0e9771SDarren Reed } 8120a0e9771SDarren Reed 8130a0e9771SDarren Reed mp->b_wptr = mp->b_rptr + mpsize; 8140a0e9771SDarren Reed error = uiomove(mp->b_rptr, mpsize, UIO_WRITE, uiop); 8150a0e9771SDarren Reed if (error != 0) { 8160a0e9771SDarren Reed ks_stats.kp_send_uiomove_fail.value.ui64++; 8170a0e9771SDarren Reed goto done; 8180a0e9771SDarren Reed } 8190a0e9771SDarren Reed 8200a0e9771SDarren Reed if (ps->ps_type == SOCK_DGRAM) { 8210a0e9771SDarren Reed mp0 = mac_header(mh, sol->sll_addr, sol->sll_protocol, mp, 0); 8220a0e9771SDarren Reed if (mp0 == NULL) { 8230a0e9771SDarren Reed ks_stats.kp_send_no_memory.value.ui64++; 8240a0e9771SDarren Reed error = ENOBUFS; 8250a0e9771SDarren Reed goto done; 8260a0e9771SDarren Reed } 8270a0e9771SDarren Reed linkb(mp0, mp); 8280a0e9771SDarren Reed mp = mp0; 8290a0e9771SDarren Reed } 8300a0e9771SDarren Reed 8310a0e9771SDarren Reed /* 8320a0e9771SDarren Reed * As this is sending datagrams and no promise is made about 8330a0e9771SDarren Reed * how or if a packet will be sent/delivered, no effort is to 8340a0e9771SDarren Reed * be expended in recovering from a situation where the packet 8350a0e9771SDarren Reed * cannot be sent - it is just dropped. 8360a0e9771SDarren Reed */ 8370a0e9771SDarren Reed error = mac_tx(mch, mp, 0, MAC_DROP_ON_NO_DESC, NULL); 8380a0e9771SDarren Reed if (error == 0) { 8390a0e9771SDarren Reed mp = NULL; 8400a0e9771SDarren Reed ks_stats.kp_send_ok.value.ui64++; 8410a0e9771SDarren Reed } else { 8420a0e9771SDarren Reed ks_stats.kp_send_failed.value.ui64++; 8430a0e9771SDarren Reed } 8440a0e9771SDarren Reed 8450a0e9771SDarren Reed done: 8460a0e9771SDarren Reed 8470a0e9771SDarren Reed if (new_open) { 8480a0e9771SDarren Reed ASSERT(mch != ps->ps_mch); 8490a0e9771SDarren Reed ASSERT(mh != ps->ps_mh); 8500a0e9771SDarren Reed pfp_close(mh, mch); 8510a0e9771SDarren Reed } 8520a0e9771SDarren Reed if (mp != NULL) 8530a0e9771SDarren Reed freemsg(mp); 8540a0e9771SDarren Reed 8550a0e9771SDarren Reed return (error); 8560a0e9771SDarren Reed 8570a0e9771SDarren Reed } 8580a0e9771SDarren Reed 8590a0e9771SDarren Reed /* 8600a0e9771SDarren Reed * There's no use of a lock here, or at the bottom of pfp_packet() where 8610a0e9771SDarren Reed * ps_flow_ctrld is set to true, because in a situation where these two 8620a0e9771SDarren Reed * are racing to set the flag one way or the other, the end result is 8630a0e9771SDarren Reed * going to be ultimately determined by the scheduler anyway - which of 8640a0e9771SDarren Reed * the two threads gets the lock first? In such an operational environment, 8650a0e9771SDarren Reed * we've got packets arriving too fast to be delt with so packets are going 8660a0e9771SDarren Reed * to be dropped. Grabbing a lock just makes the drop more expensive. 8670a0e9771SDarren Reed */ 8680a0e9771SDarren Reed static void 8690a0e9771SDarren Reed sdpfp_clr_flowctrl(sock_lower_handle_t handle) 8700a0e9771SDarren Reed { 8710a0e9771SDarren Reed struct pfpsock *ps; 8720a0e9771SDarren Reed 8730a0e9771SDarren Reed ps = (struct pfpsock *)handle; 8740a0e9771SDarren Reed 8750a0e9771SDarren Reed mutex_enter(&ps->ps_lock); 8760a0e9771SDarren Reed ps->ps_flow_ctrld = B_FALSE; 8770a0e9771SDarren Reed mutex_exit(&ps->ps_lock); 8780a0e9771SDarren Reed } 8790a0e9771SDarren Reed 8800a0e9771SDarren Reed /* 8810a0e9771SDarren Reed * The implementation of this ioctl() handler is intended to function 8820a0e9771SDarren Reed * in the absence of a bind() being made before it is called. Thus the 8830a0e9771SDarren Reed * function calls mac_open() itself to provide a handle 8840a0e9771SDarren Reed * This function is structured like this: 8850a0e9771SDarren Reed * - determine the linkid for the interface being targetted 8860a0e9771SDarren Reed * - open the interface with said linkid 8870a0e9771SDarren Reed * - perform ioctl 8880a0e9771SDarren Reed * - copy results back to caller 8890a0e9771SDarren Reed * 8900a0e9771SDarren Reed * The ioctls that interact with interface flags have been implented below 8910a0e9771SDarren Reed * to assume that the interface is always up and running (IFF_RUNNING) and 8920a0e9771SDarren Reed * to use the state of this socket to determine whether or not the network 8930a0e9771SDarren Reed * interface is in promiscuous mode. Thus an ioctl to get the interface flags 8940a0e9771SDarren Reed * of an interface that has been put in promiscuous mode by another socket 8950a0e9771SDarren Reed * (in the same program or different), will not report that status. 8960a0e9771SDarren Reed */ 8970a0e9771SDarren Reed /* ARGSUSED */ 8980a0e9771SDarren Reed static int 8990a0e9771SDarren Reed sdpfp_ioctl(sock_lower_handle_t handle, int cmd, intptr_t arg, int mod, 9000a0e9771SDarren Reed int32_t *rval, struct cred *cr) 9010a0e9771SDarren Reed { 9020a0e9771SDarren Reed struct timeval tival; 9030a0e9771SDarren Reed mac_client_promisc_type_t mtype; 904a6911619SDarren Reed struct sockaddr_dl *sock; 9050a0e9771SDarren Reed datalink_id_t linkid; 9060a0e9771SDarren Reed struct lifreq lifreq; 9070a0e9771SDarren Reed struct ifreq ifreq; 9080a0e9771SDarren Reed struct pfpsock *ps; 9090a0e9771SDarren Reed mac_handle_t mh; 9100a0e9771SDarren Reed int error; 9110a0e9771SDarren Reed 912336069c2SPatrick Mooney ps = (struct pfpsock *)handle; 913336069c2SPatrick Mooney 9140a0e9771SDarren Reed switch (cmd) { 9150a0e9771SDarren Reed /* 9160a0e9771SDarren Reed * ioctls that work on "struct lifreq" 9170a0e9771SDarren Reed */ 9180a0e9771SDarren Reed case SIOCSLIFFLAGS : 9190a0e9771SDarren Reed case SIOCGLIFINDEX : 9200a0e9771SDarren Reed case SIOCGLIFFLAGS : 9210a0e9771SDarren Reed case SIOCGLIFMTU : 922a6911619SDarren Reed case SIOCGLIFHWADDR : 923336069c2SPatrick Mooney error = pfp_lifreq_getlinkid(arg, &lifreq, &linkid, mod); 9240a0e9771SDarren Reed if (error != 0) 9250a0e9771SDarren Reed return (error); 9260a0e9771SDarren Reed break; 9270a0e9771SDarren Reed 9280a0e9771SDarren Reed /* 9290a0e9771SDarren Reed * ioctls that work on "struct ifreq". 9300a0e9771SDarren Reed * Not all of these have a "struct lifreq" partner, for example 9310a0e9771SDarren Reed * SIOCGIFHWADDR, for the simple reason that the logical interface 9320a0e9771SDarren Reed * does not have a hardware address. 9330a0e9771SDarren Reed */ 9340a0e9771SDarren Reed case SIOCSIFFLAGS : 9350a0e9771SDarren Reed case SIOCGIFINDEX : 9360a0e9771SDarren Reed case SIOCGIFFLAGS : 9370a0e9771SDarren Reed case SIOCGIFMTU : 9380a0e9771SDarren Reed case SIOCGIFHWADDR : 939336069c2SPatrick Mooney error = pfp_ifreq_getlinkid(arg, &ifreq, &linkid, mod); 9400a0e9771SDarren Reed if (error != 0) 9410a0e9771SDarren Reed return (error); 9420a0e9771SDarren Reed break; 943336069c2SPatrick Mooney 944336069c2SPatrick Mooney case SIOCGSTAMP : 945336069c2SPatrick Mooney tival.tv_sec = (time_t)ps->ps_timestamp.tv_sec; 946336069c2SPatrick Mooney tival.tv_usec = ps->ps_timestamp.tv_nsec / 1000; 947336069c2SPatrick Mooney if (get_udatamodel() == DATAMODEL_NATIVE) { 948336069c2SPatrick Mooney error = ddi_copyout(&tival, (void *)arg, 949336069c2SPatrick Mooney sizeof (tival), mod); 950336069c2SPatrick Mooney } 951336069c2SPatrick Mooney #ifdef _SYSCALL32_IMPL 952336069c2SPatrick Mooney else { 953336069c2SPatrick Mooney struct timeval32 tv32; 954336069c2SPatrick Mooney TIMEVAL_TO_TIMEVAL32(&tv32, &tival); 955336069c2SPatrick Mooney error = ddi_copyout(&tv32, (void *)arg, 956336069c2SPatrick Mooney sizeof (tv32), mod); 957336069c2SPatrick Mooney } 958336069c2SPatrick Mooney #endif 959336069c2SPatrick Mooney return (error); 9600a0e9771SDarren Reed } 9610a0e9771SDarren Reed 9620a0e9771SDarren Reed error = mac_open_by_linkid(linkid, &mh); 9630a0e9771SDarren Reed if (error != 0) 9640a0e9771SDarren Reed return (error); 9650a0e9771SDarren Reed 9660a0e9771SDarren Reed switch (cmd) { 9670a0e9771SDarren Reed case SIOCGLIFINDEX : 9680a0e9771SDarren Reed lifreq.lifr_index = linkid; 9690a0e9771SDarren Reed break; 9700a0e9771SDarren Reed 9710a0e9771SDarren Reed case SIOCGIFINDEX : 9720a0e9771SDarren Reed ifreq.ifr_index = linkid; 9730a0e9771SDarren Reed break; 9740a0e9771SDarren Reed 9750a0e9771SDarren Reed case SIOCGIFFLAGS : 9760a0e9771SDarren Reed ifreq.ifr_flags = IFF_RUNNING; 9770a0e9771SDarren Reed if (ps->ps_promisc == MAC_CLIENT_PROMISC_ALL) 9780a0e9771SDarren Reed ifreq.ifr_flags |= IFF_PROMISC; 9790a0e9771SDarren Reed break; 9800a0e9771SDarren Reed 9810a0e9771SDarren Reed case SIOCGLIFFLAGS : 9820a0e9771SDarren Reed lifreq.lifr_flags = IFF_RUNNING; 9830a0e9771SDarren Reed if (ps->ps_promisc == MAC_CLIENT_PROMISC_ALL) 9840a0e9771SDarren Reed lifreq.lifr_flags |= IFF_PROMISC; 9850a0e9771SDarren Reed break; 9860a0e9771SDarren Reed 9870a0e9771SDarren Reed case SIOCSIFFLAGS : 9880a0e9771SDarren Reed if (linkid != ps->ps_linkid) { 9890a0e9771SDarren Reed error = EINVAL; 9900a0e9771SDarren Reed } else { 9910a0e9771SDarren Reed if ((ifreq.ifr_flags & IFF_PROMISC) != 0) 9920a0e9771SDarren Reed mtype = MAC_CLIENT_PROMISC_ALL; 9930a0e9771SDarren Reed else 9940a0e9771SDarren Reed mtype = MAC_CLIENT_PROMISC_FILTERED; 9950a0e9771SDarren Reed error = pfp_set_promisc(ps, mtype); 9960a0e9771SDarren Reed } 9970a0e9771SDarren Reed break; 9980a0e9771SDarren Reed 9990a0e9771SDarren Reed case SIOCSLIFFLAGS : 10000a0e9771SDarren Reed if (linkid != ps->ps_linkid) { 10010a0e9771SDarren Reed error = EINVAL; 10020a0e9771SDarren Reed } else { 10030a0e9771SDarren Reed if ((lifreq.lifr_flags & IFF_PROMISC) != 0) 10040a0e9771SDarren Reed mtype = MAC_CLIENT_PROMISC_ALL; 10050a0e9771SDarren Reed else 10060a0e9771SDarren Reed mtype = MAC_CLIENT_PROMISC_FILTERED; 10070a0e9771SDarren Reed error = pfp_set_promisc(ps, mtype); 10080a0e9771SDarren Reed } 10090a0e9771SDarren Reed break; 10100a0e9771SDarren Reed 10110a0e9771SDarren Reed case SIOCGIFMTU : 10120a0e9771SDarren Reed mac_sdu_get(mh, NULL, &ifreq.ifr_mtu); 10130a0e9771SDarren Reed break; 10140a0e9771SDarren Reed 10150a0e9771SDarren Reed case SIOCGLIFMTU : 10160a0e9771SDarren Reed mac_sdu_get(mh, NULL, &lifreq.lifr_mtu); 10170a0e9771SDarren Reed break; 10180a0e9771SDarren Reed 10190a0e9771SDarren Reed case SIOCGIFHWADDR : 1020a6911619SDarren Reed if (mac_addr_len(mh) > sizeof (ifreq.ifr_addr.sa_data)) { 1021a6911619SDarren Reed error = EPFNOSUPPORT; 1022a6911619SDarren Reed break; 1023a6911619SDarren Reed } 1024a6911619SDarren Reed 1025a6911619SDarren Reed if (mac_addr_len(mh) == 0) { 1026a6911619SDarren Reed (void) memset(ifreq.ifr_addr.sa_data, 0, 1027a6911619SDarren Reed sizeof (ifreq.ifr_addr.sa_data)); 1028a6911619SDarren Reed } else { 1029a6911619SDarren Reed mac_unicast_primary_get(mh, 1030a6911619SDarren Reed (uint8_t *)ifreq.ifr_addr.sa_data); 1031a6911619SDarren Reed } 1032a6911619SDarren Reed 1033a6911619SDarren Reed /* 1034a6911619SDarren Reed * The behaviour here in setting sa_family is consistent 1035a6911619SDarren Reed * with what applications such as tcpdump would expect 1036a6911619SDarren Reed * for a Linux PF_PACKET socket. 1037a6911619SDarren Reed */ 10380a0e9771SDarren Reed ifreq.ifr_addr.sa_family = pfp_dl_to_arphrd(mac_type(mh)); 10390a0e9771SDarren Reed break; 10400a0e9771SDarren Reed 1041a6911619SDarren Reed case SIOCGLIFHWADDR : 1042a6911619SDarren Reed lifreq.lifr_type = 0; 1043a6911619SDarren Reed sock = (struct sockaddr_dl *)&lifreq.lifr_addr; 1044a6911619SDarren Reed 1045a6911619SDarren Reed if (mac_addr_len(mh) > sizeof (sock->sdl_data)) { 1046a6911619SDarren Reed error = EPFNOSUPPORT; 1047a6911619SDarren Reed break; 1048a6911619SDarren Reed } 1049a6911619SDarren Reed 1050a6911619SDarren Reed /* 1051a6911619SDarren Reed * Fill in the sockaddr_dl with link layer details. Of note, 1052a6911619SDarren Reed * the index is returned as 0 for a couple of reasons: 1053a6911619SDarren Reed * (1) there is no public API that uses or requires it 1054a6911619SDarren Reed * (2) the MAC index is currently 32bits and sdl_index is 16. 1055a6911619SDarren Reed */ 1056a6911619SDarren Reed sock->sdl_family = AF_LINK; 1057a6911619SDarren Reed sock->sdl_index = 0; 1058a6911619SDarren Reed sock->sdl_type = mac_type(mh); 1059a6911619SDarren Reed sock->sdl_nlen = 0; 1060a6911619SDarren Reed sock->sdl_alen = mac_addr_len(mh); 1061a6911619SDarren Reed sock->sdl_slen = 0; 1062a6911619SDarren Reed if (mac_addr_len(mh) == 0) { 1063a6911619SDarren Reed (void) memset(sock->sdl_data, 0, 1064a6911619SDarren Reed sizeof (sock->sdl_data)); 1065a6911619SDarren Reed } else { 1066a6911619SDarren Reed mac_unicast_primary_get(mh, (uint8_t *)sock->sdl_data); 1067a6911619SDarren Reed } 1068a6911619SDarren Reed break; 1069a6911619SDarren Reed 10700a0e9771SDarren Reed default : 10710a0e9771SDarren Reed break; 10720a0e9771SDarren Reed } 10730a0e9771SDarren Reed 10740a0e9771SDarren Reed mac_close(mh); 10750a0e9771SDarren Reed 10760a0e9771SDarren Reed if (error == 0) { 10770a0e9771SDarren Reed /* 10780a0e9771SDarren Reed * Only the "GET" ioctls need to copy data back to userace. 10790a0e9771SDarren Reed */ 10800a0e9771SDarren Reed switch (cmd) { 10810a0e9771SDarren Reed case SIOCGLIFINDEX : 10820a0e9771SDarren Reed case SIOCGLIFFLAGS : 10830a0e9771SDarren Reed case SIOCGLIFMTU : 1084a6911619SDarren Reed case SIOCGLIFHWADDR : 10850a0e9771SDarren Reed error = ddi_copyout(&lifreq, (void *)arg, 1086336069c2SPatrick Mooney sizeof (lifreq), mod); 10870a0e9771SDarren Reed break; 10880a0e9771SDarren Reed 10890a0e9771SDarren Reed case SIOCGIFINDEX : 10900a0e9771SDarren Reed case SIOCGIFFLAGS : 10910a0e9771SDarren Reed case SIOCGIFMTU : 10920a0e9771SDarren Reed case SIOCGIFHWADDR : 10930a0e9771SDarren Reed error = ddi_copyout(&ifreq, (void *)arg, 1094336069c2SPatrick Mooney sizeof (ifreq), mod); 10950a0e9771SDarren Reed break; 10960a0e9771SDarren Reed default : 10970a0e9771SDarren Reed break; 10980a0e9771SDarren Reed } 10990a0e9771SDarren Reed } 11000a0e9771SDarren Reed 11010a0e9771SDarren Reed return (error); 11020a0e9771SDarren Reed } 11030a0e9771SDarren Reed 11040a0e9771SDarren Reed /* 11050a0e9771SDarren Reed * Closing the socket requires that all open references to network 11060a0e9771SDarren Reed * interfaces be closed. 11070a0e9771SDarren Reed */ 11080a0e9771SDarren Reed /* ARGSUSED */ 11090a0e9771SDarren Reed static int 11100a0e9771SDarren Reed sdpfp_close(sock_lower_handle_t handle, int flag, struct cred *cr) 11110a0e9771SDarren Reed { 11120a0e9771SDarren Reed struct pfpsock *ps = (struct pfpsock *)handle; 11130a0e9771SDarren Reed 11140a0e9771SDarren Reed if (ps->ps_phd != 0) { 11150a0e9771SDarren Reed mac_promisc_remove(ps->ps_phd); 11160a0e9771SDarren Reed ps->ps_phd = 0; 11170a0e9771SDarren Reed } 11180a0e9771SDarren Reed 11190a0e9771SDarren Reed if (ps->ps_mch != 0) { 11200a0e9771SDarren Reed mac_client_close(ps->ps_mch, 0); 11210a0e9771SDarren Reed ps->ps_mch = 0; 11220a0e9771SDarren Reed } 11230a0e9771SDarren Reed 11240a0e9771SDarren Reed if (ps->ps_mh != 0) { 11250a0e9771SDarren Reed mac_close(ps->ps_mh); 11260a0e9771SDarren Reed ps->ps_mh = 0; 11270a0e9771SDarren Reed } 11280a0e9771SDarren Reed 11290a0e9771SDarren Reed kmem_free(ps, sizeof (*ps)); 11300a0e9771SDarren Reed 11310a0e9771SDarren Reed return (0); 11320a0e9771SDarren Reed } 11330a0e9771SDarren Reed 11340a0e9771SDarren Reed /* ************************************************************************* */ 11350a0e9771SDarren Reed 11360a0e9771SDarren Reed /* 11370a0e9771SDarren Reed * Given a pointer (arg) to a "struct ifreq" (potentially in user space), 11380a0e9771SDarren Reed * determine the linkid for the interface name stored in that structure. 11390a0e9771SDarren Reed * name is used as a buffer so that we can ensure a trailing \0 is appended 11400a0e9771SDarren Reed * to the name safely. 11410a0e9771SDarren Reed */ 11420a0e9771SDarren Reed static int 11430a0e9771SDarren Reed pfp_ifreq_getlinkid(intptr_t arg, struct ifreq *ifreqp, 1144336069c2SPatrick Mooney datalink_id_t *linkidp, int mode) 11450a0e9771SDarren Reed { 11460a0e9771SDarren Reed char name[IFNAMSIZ + 1]; 11470a0e9771SDarren Reed int error; 11480a0e9771SDarren Reed 1149336069c2SPatrick Mooney if (ddi_copyin((void *)arg, ifreqp, sizeof (*ifreqp), mode) != 0) 11500a0e9771SDarren Reed return (EFAULT); 11510a0e9771SDarren Reed 11520a0e9771SDarren Reed (void) strlcpy(name, ifreqp->ifr_name, sizeof (name)); 11530a0e9771SDarren Reed 11540a0e9771SDarren Reed error = dls_mgmt_get_linkid(name, linkidp); 11550a0e9771SDarren Reed if (error != 0) 11560a0e9771SDarren Reed error = dls_devnet_macname2linkid(name, linkidp); 11570a0e9771SDarren Reed 11580a0e9771SDarren Reed return (error); 11590a0e9771SDarren Reed } 11600a0e9771SDarren Reed 11610a0e9771SDarren Reed /* 11620a0e9771SDarren Reed * Given a pointer (arg) to a "struct lifreq" (potentially in user space), 11630a0e9771SDarren Reed * determine the linkid for the interface name stored in that structure. 11640a0e9771SDarren Reed * name is used as a buffer so that we can ensure a trailing \0 is appended 11650a0e9771SDarren Reed * to the name safely. 11660a0e9771SDarren Reed */ 11670a0e9771SDarren Reed static int 11680a0e9771SDarren Reed pfp_lifreq_getlinkid(intptr_t arg, struct lifreq *lifreqp, 1169336069c2SPatrick Mooney datalink_id_t *linkidp, int mode) 11700a0e9771SDarren Reed { 11710a0e9771SDarren Reed char name[LIFNAMSIZ + 1]; 11720a0e9771SDarren Reed int error; 11730a0e9771SDarren Reed 1174336069c2SPatrick Mooney if (ddi_copyin((void *)arg, lifreqp, sizeof (*lifreqp), mode) != 0) 11750a0e9771SDarren Reed return (EFAULT); 11760a0e9771SDarren Reed 11770a0e9771SDarren Reed (void) strlcpy(name, lifreqp->lifr_name, sizeof (name)); 11780a0e9771SDarren Reed 11790a0e9771SDarren Reed error = dls_mgmt_get_linkid(name, linkidp); 11800a0e9771SDarren Reed if (error != 0) 11810a0e9771SDarren Reed error = dls_devnet_macname2linkid(name, linkidp); 11820a0e9771SDarren Reed 11830a0e9771SDarren Reed return (error); 11840a0e9771SDarren Reed } 11850a0e9771SDarren Reed 11860a0e9771SDarren Reed /* 11870a0e9771SDarren Reed * Although there are several new SOL_PACKET options that can be set and 11880a0e9771SDarren Reed * are specific to this implementation of PF_PACKET, the current API does 11890a0e9771SDarren Reed * not support doing a get on them to retrieve accompanying status. Thus 11900a0e9771SDarren Reed * it is only currently possible to use SOL_PACKET with getsockopt to 11910a0e9771SDarren Reed * retrieve statistical information. This remains consistant with the 11920a0e9771SDarren Reed * Linux API at the time of writing. 11930a0e9771SDarren Reed */ 11940a0e9771SDarren Reed static int 11950a0e9771SDarren Reed pfp_getpacket_sockopt(sock_lower_handle_t handle, int option_name, 11960a0e9771SDarren Reed void *optval, socklen_t *optlenp) 11970a0e9771SDarren Reed { 11980a0e9771SDarren Reed struct pfpsock *ps; 1199336069c2SPatrick Mooney struct tpacket_stats_short tpss; 12000a0e9771SDarren Reed int error = 0; 12010a0e9771SDarren Reed 12020a0e9771SDarren Reed ps = (struct pfpsock *)handle; 12030a0e9771SDarren Reed 12040a0e9771SDarren Reed switch (option_name) { 12050a0e9771SDarren Reed case PACKET_STATISTICS : 12060a0e9771SDarren Reed if (*optlenp < sizeof (ps->ps_stats)) { 12070a0e9771SDarren Reed error = EINVAL; 12080a0e9771SDarren Reed break; 12090a0e9771SDarren Reed } 12100a0e9771SDarren Reed *optlenp = sizeof (ps->ps_stats); 12110a0e9771SDarren Reed bcopy(&ps->ps_stats, optval, sizeof (ps->ps_stats)); 12120a0e9771SDarren Reed break; 1213336069c2SPatrick Mooney case PACKET_STATISTICS_SHORT : 1214336069c2SPatrick Mooney if (*optlenp < sizeof (tpss)) { 1215336069c2SPatrick Mooney error = EINVAL; 1216336069c2SPatrick Mooney break; 1217336069c2SPatrick Mooney } 1218336069c2SPatrick Mooney *optlenp = sizeof (tpss); 1219336069c2SPatrick Mooney tpss.tp_packets = ps->ps_stats.tp_packets; 1220336069c2SPatrick Mooney tpss.tp_drops = ps->ps_stats.tp_drops; 1221336069c2SPatrick Mooney bcopy(&tpss, optval, sizeof (tpss)); 1222336069c2SPatrick Mooney break; 12230a0e9771SDarren Reed default : 12240a0e9771SDarren Reed error = EINVAL; 12250a0e9771SDarren Reed break; 12260a0e9771SDarren Reed } 12270a0e9771SDarren Reed 12280a0e9771SDarren Reed return (error); 12290a0e9771SDarren Reed } 12300a0e9771SDarren Reed 12310a0e9771SDarren Reed /* 12320a0e9771SDarren Reed * The SOL_PACKET level for socket options supports three options, 12330a0e9771SDarren Reed * PACKET_ADD_MEMBERSHIP, PACKET_DROP_MEMBERSHIP and PACKET_AUXDATA. 12340a0e9771SDarren Reed * This function is responsible for mapping the two socket options 12350a0e9771SDarren Reed * that manage multicast membership into the appropriate internal 12360a0e9771SDarren Reed * function calls to bring the option into effect. Whilst direct 12370a0e9771SDarren Reed * changes to the multicast membership (ADD/DROP) groups is handled 12380a0e9771SDarren Reed * by calls directly into the mac module, changes to the promiscuos 12390a0e9771SDarren Reed * mode are vectored through pfp_set_promisc() so that the logic for 12400a0e9771SDarren Reed * managing the promiscuous mode is in one place. 12410a0e9771SDarren Reed */ 12420a0e9771SDarren Reed /* ARGSUSED */ 12430a0e9771SDarren Reed static int 12440a0e9771SDarren Reed pfp_setpacket_sockopt(sock_lower_handle_t handle, int option_name, 12450a0e9771SDarren Reed const void *optval, socklen_t optlen) 12460a0e9771SDarren Reed { 12470a0e9771SDarren Reed struct packet_mreq mreq; 12480a0e9771SDarren Reed struct pfpsock *ps; 12490a0e9771SDarren Reed int error = 0; 12500a0e9771SDarren Reed int opt; 12510a0e9771SDarren Reed 12520a0e9771SDarren Reed ps = (struct pfpsock *)handle; 12530a0e9771SDarren Reed if (!ps->ps_bound) 12540a0e9771SDarren Reed return (EPROTO); 12550a0e9771SDarren Reed 12560a0e9771SDarren Reed if ((option_name == PACKET_ADD_MEMBERSHIP) || 12570a0e9771SDarren Reed (option_name == PACKET_DROP_MEMBERSHIP)) { 12580a0e9771SDarren Reed if (!ps->ps_bound) 12590a0e9771SDarren Reed return (EPROTO); 12600a0e9771SDarren Reed bcopy(optval, &mreq, sizeof (mreq)); 12610a0e9771SDarren Reed if (ps->ps_linkid != mreq.mr_ifindex) 12620a0e9771SDarren Reed return (EINVAL); 12630a0e9771SDarren Reed } 12640a0e9771SDarren Reed 12650a0e9771SDarren Reed switch (option_name) { 12660a0e9771SDarren Reed case PACKET_ADD_MEMBERSHIP : 12670a0e9771SDarren Reed switch (mreq.mr_type) { 12680a0e9771SDarren Reed case PACKET_MR_MULTICAST : 1269*3b4315d3SPatrick Mooney if (mreq.mr_alen != ps->ps_sock.sll_halen) 1270a6911619SDarren Reed return (EINVAL); 1271a6911619SDarren Reed 12720a0e9771SDarren Reed error = mac_multicast_add(ps->ps_mch, mreq.mr_address); 12730a0e9771SDarren Reed break; 12740a0e9771SDarren Reed 12750a0e9771SDarren Reed case PACKET_MR_PROMISC : 12760a0e9771SDarren Reed error = pfp_set_promisc(ps, MAC_CLIENT_PROMISC_ALL); 12770a0e9771SDarren Reed break; 12780a0e9771SDarren Reed 12790a0e9771SDarren Reed case PACKET_MR_ALLMULTI : 12800a0e9771SDarren Reed error = pfp_set_promisc(ps, MAC_CLIENT_PROMISC_MULTI); 12810a0e9771SDarren Reed break; 12820a0e9771SDarren Reed } 12830a0e9771SDarren Reed break; 12840a0e9771SDarren Reed 12850a0e9771SDarren Reed case PACKET_DROP_MEMBERSHIP : 12860a0e9771SDarren Reed switch (mreq.mr_type) { 12870a0e9771SDarren Reed case PACKET_MR_MULTICAST : 1288*3b4315d3SPatrick Mooney if (mreq.mr_alen != ps->ps_sock.sll_halen) 1289a6911619SDarren Reed return (EINVAL); 1290a6911619SDarren Reed 12910a0e9771SDarren Reed mac_multicast_remove(ps->ps_mch, mreq.mr_address); 12920a0e9771SDarren Reed break; 12930a0e9771SDarren Reed 12940a0e9771SDarren Reed case PACKET_MR_PROMISC : 12950a0e9771SDarren Reed if (ps->ps_promisc != MAC_CLIENT_PROMISC_ALL) 12960a0e9771SDarren Reed return (EINVAL); 12970a0e9771SDarren Reed error = pfp_set_promisc(ps, 12980a0e9771SDarren Reed MAC_CLIENT_PROMISC_FILTERED); 12990a0e9771SDarren Reed break; 13000a0e9771SDarren Reed 13010a0e9771SDarren Reed case PACKET_MR_ALLMULTI : 13020a0e9771SDarren Reed if (ps->ps_promisc != MAC_CLIENT_PROMISC_MULTI) 13030a0e9771SDarren Reed return (EINVAL); 13040a0e9771SDarren Reed error = pfp_set_promisc(ps, 13050a0e9771SDarren Reed MAC_CLIENT_PROMISC_FILTERED); 13060a0e9771SDarren Reed break; 13070a0e9771SDarren Reed } 13080a0e9771SDarren Reed break; 13090a0e9771SDarren Reed 13100a0e9771SDarren Reed case PACKET_AUXDATA : 13110a0e9771SDarren Reed if (optlen == sizeof (int)) { 13120a0e9771SDarren Reed opt = *(int *)optval; 13130a0e9771SDarren Reed ps->ps_auxdata = (opt != 0); 13140a0e9771SDarren Reed } else { 13150a0e9771SDarren Reed error = EINVAL; 13160a0e9771SDarren Reed } 13170a0e9771SDarren Reed break; 13180a0e9771SDarren Reed default : 13190a0e9771SDarren Reed error = EINVAL; 13200a0e9771SDarren Reed break; 13210a0e9771SDarren Reed } 13220a0e9771SDarren Reed 13230a0e9771SDarren Reed return (error); 13240a0e9771SDarren Reed } 13250a0e9771SDarren Reed 13260a0e9771SDarren Reed /* 13270a0e9771SDarren Reed * There are only two special setsockopt's for SOL_SOCKET with PF_PACKET: 1328336069c2SPatrick Mooney * SO_ATTACH_FILTER and SO_DETACH_FILTER. 13290a0e9771SDarren Reed * 13300a0e9771SDarren Reed * Both of these setsockopt values are candidates for being handled by the 13310a0e9771SDarren Reed * socket layer itself in future, however this requires understanding how 13320a0e9771SDarren Reed * they would interact with all other sockets. 13330a0e9771SDarren Reed */ 13340a0e9771SDarren Reed static int 13350a0e9771SDarren Reed pfp_setsocket_sockopt(sock_lower_handle_t handle, int option_name, 13360a0e9771SDarren Reed const void *optval, socklen_t optlen) 13370a0e9771SDarren Reed { 13380a0e9771SDarren Reed struct bpf_program prog; 13390a0e9771SDarren Reed struct bpf_insn *fcode; 13400a0e9771SDarren Reed struct pfpsock *ps; 1341336069c2SPatrick Mooney struct sock_proto_props sopp; 13420a0e9771SDarren Reed int error = 0; 13430a0e9771SDarren Reed int size; 13440a0e9771SDarren Reed 13450a0e9771SDarren Reed ps = (struct pfpsock *)handle; 13460a0e9771SDarren Reed 13470a0e9771SDarren Reed switch (option_name) { 13480a0e9771SDarren Reed case SO_ATTACH_FILTER : 13490a0e9771SDarren Reed #ifdef _LP64 13500a0e9771SDarren Reed if (optlen == sizeof (struct bpf_program32)) { 13510a0e9771SDarren Reed struct bpf_program32 prog32; 13520a0e9771SDarren Reed 13530a0e9771SDarren Reed bcopy(optval, &prog32, sizeof (prog32)); 13540a0e9771SDarren Reed prog.bf_len = prog32.bf_len; 13550a0e9771SDarren Reed prog.bf_insns = (void *)(uint64_t)prog32.bf_insns; 13560a0e9771SDarren Reed } else 13570a0e9771SDarren Reed #endif 13580a0e9771SDarren Reed if (optlen == sizeof (struct bpf_program)) { 13590a0e9771SDarren Reed bcopy(optval, &prog, sizeof (prog)); 13600a0e9771SDarren Reed } else if (optlen != sizeof (struct bpf_program)) { 13610a0e9771SDarren Reed return (EINVAL); 13620a0e9771SDarren Reed } 1363336069c2SPatrick Mooney if (prog.bf_len > BPF_MAXINSNS) 1364336069c2SPatrick Mooney return (EINVAL); 13650a0e9771SDarren Reed 13660a0e9771SDarren Reed size = prog.bf_len * sizeof (*prog.bf_insns); 13670a0e9771SDarren Reed fcode = kmem_alloc(size, KM_SLEEP); 13680a0e9771SDarren Reed if (ddi_copyin(prog.bf_insns, fcode, size, 0) != 0) { 13690a0e9771SDarren Reed kmem_free(fcode, size); 13700a0e9771SDarren Reed return (EFAULT); 13710a0e9771SDarren Reed } 13720a0e9771SDarren Reed 13730a0e9771SDarren Reed if (bpf_validate(fcode, (int)prog.bf_len)) { 13740a0e9771SDarren Reed rw_enter(&ps->ps_bpflock, RW_WRITER); 13750a0e9771SDarren Reed pfp_release_bpf(ps); 13760a0e9771SDarren Reed ps->ps_bpf.bf_insns = fcode; 13770a0e9771SDarren Reed ps->ps_bpf.bf_len = size; 13780a0e9771SDarren Reed rw_exit(&ps->ps_bpflock); 13790a0e9771SDarren Reed 13800a0e9771SDarren Reed return (0); 13810a0e9771SDarren Reed } 13820a0e9771SDarren Reed kmem_free(fcode, size); 13830a0e9771SDarren Reed error = EINVAL; 13840a0e9771SDarren Reed break; 13850a0e9771SDarren Reed 13860a0e9771SDarren Reed case SO_DETACH_FILTER : 13870a0e9771SDarren Reed pfp_release_bpf(ps); 13880a0e9771SDarren Reed break; 1389336069c2SPatrick Mooney 1390336069c2SPatrick Mooney case SO_RCVBUF : 1391336069c2SPatrick Mooney size = *(int32_t *)optval; 1392336069c2SPatrick Mooney if (size > sockmod_pfp_rcvbuf_max || size < 0) 1393336069c2SPatrick Mooney return (ENOBUFS); 1394336069c2SPatrick Mooney sopp.sopp_flags = SOCKOPT_RCVHIWAT; 1395336069c2SPatrick Mooney sopp.sopp_rxhiwat = size; 1396336069c2SPatrick Mooney ps->ps_upcalls->su_set_proto_props(ps->ps_upper, &sopp); 1397336069c2SPatrick Mooney ps->ps_rcvbuf = size; 1398336069c2SPatrick Mooney break; 1399336069c2SPatrick Mooney 14000a0e9771SDarren Reed default : 14010a0e9771SDarren Reed error = ENOPROTOOPT; 14020a0e9771SDarren Reed break; 14030a0e9771SDarren Reed } 14040a0e9771SDarren Reed 14050a0e9771SDarren Reed return (error); 14060a0e9771SDarren Reed } 14070a0e9771SDarren Reed 14080a0e9771SDarren Reed /* 14090a0e9771SDarren Reed * pfp_open_index is an internal function used to open a MAC device by 14100a0e9771SDarren Reed * its index. Both a mac_handle_t and mac_client_handle_t are acquired 14110a0e9771SDarren Reed * because some of the interfaces provided by the mac layer require either 14120a0e9771SDarren Reed * only the mac_handle_t or both it and mac_handle_t. 14130a0e9771SDarren Reed * 14140a0e9771SDarren Reed * Whilst inside the kernel we can access data structures supporting any 14150a0e9771SDarren Reed * zone, access to interfaces from non-global zones is restricted to those 14160a0e9771SDarren Reed * interfaces (if any) that are exclusively assigned to a zone. 14170a0e9771SDarren Reed */ 14180a0e9771SDarren Reed static int 14190a0e9771SDarren Reed pfp_open_index(int index, mac_handle_t *mhp, mac_client_handle_t *mcip, 14200a0e9771SDarren Reed cred_t *cred) 14210a0e9771SDarren Reed { 14220a0e9771SDarren Reed mac_client_handle_t mch; 14230a0e9771SDarren Reed zoneid_t ifzoneid; 14240a0e9771SDarren Reed mac_handle_t mh; 14250a0e9771SDarren Reed zoneid_t zoneid; 14260a0e9771SDarren Reed int error; 14270a0e9771SDarren Reed 14280a0e9771SDarren Reed mh = 0; 14290a0e9771SDarren Reed mch = 0; 14300a0e9771SDarren Reed error = mac_open_by_linkid(index, &mh); 14310a0e9771SDarren Reed if (error != 0) 14320a0e9771SDarren Reed goto bad_open; 14330a0e9771SDarren Reed 14340a0e9771SDarren Reed error = mac_client_open(mh, &mch, NULL, 14350a0e9771SDarren Reed MAC_OPEN_FLAGS_USE_DATALINK_NAME); 14360a0e9771SDarren Reed if (error != 0) 14370a0e9771SDarren Reed goto bad_open; 14380a0e9771SDarren Reed 14390a0e9771SDarren Reed zoneid = crgetzoneid(cred); 14400a0e9771SDarren Reed if (zoneid != GLOBAL_ZONEID) { 14410a0e9771SDarren Reed mac_perim_handle_t perim; 14420a0e9771SDarren Reed 14430a0e9771SDarren Reed mac_perim_enter_by_mh(mh, &perim); 1444336069c2SPatrick Mooney error = dls_link_getzid(mac_name(mh), &ifzoneid); 14450a0e9771SDarren Reed mac_perim_exit(perim); 14460a0e9771SDarren Reed if (error != 0) 14470a0e9771SDarren Reed goto bad_open; 14480a0e9771SDarren Reed if (ifzoneid != zoneid) { 14490a0e9771SDarren Reed error = EACCES; 14500a0e9771SDarren Reed goto bad_open; 14510a0e9771SDarren Reed } 14520a0e9771SDarren Reed } 14530a0e9771SDarren Reed 14540a0e9771SDarren Reed *mcip = mch; 14550a0e9771SDarren Reed *mhp = mh; 14560a0e9771SDarren Reed 14570a0e9771SDarren Reed return (0); 14580a0e9771SDarren Reed bad_open: 14590a0e9771SDarren Reed if (mch != 0) 14600a0e9771SDarren Reed mac_client_close(mch, 0); 14610a0e9771SDarren Reed if (mh != 0) 14620a0e9771SDarren Reed mac_close(mh); 14630a0e9771SDarren Reed return (error); 14640a0e9771SDarren Reed } 14650a0e9771SDarren Reed 14660a0e9771SDarren Reed static void 14670a0e9771SDarren Reed pfp_close(mac_handle_t mh, mac_client_handle_t mch) 14680a0e9771SDarren Reed { 14690a0e9771SDarren Reed mac_client_close(mch, 0); 14700a0e9771SDarren Reed mac_close(mh); 14710a0e9771SDarren Reed } 14720a0e9771SDarren Reed 14730a0e9771SDarren Reed /* 14740a0e9771SDarren Reed * The purpose of this function is to provide a single place where we free 14750a0e9771SDarren Reed * the loaded BPF program and reset all pointers/counters associated with 14760a0e9771SDarren Reed * it. 14770a0e9771SDarren Reed */ 14780a0e9771SDarren Reed static void 14790a0e9771SDarren Reed pfp_release_bpf(struct pfpsock *ps) 14800a0e9771SDarren Reed { 14810a0e9771SDarren Reed if (ps->ps_bpf.bf_len != 0) { 14820a0e9771SDarren Reed kmem_free(ps->ps_bpf.bf_insns, ps->ps_bpf.bf_len); 14830a0e9771SDarren Reed ps->ps_bpf.bf_len = 0; 14840a0e9771SDarren Reed ps->ps_bpf.bf_insns = NULL; 14850a0e9771SDarren Reed } 14860a0e9771SDarren Reed } 14870a0e9771SDarren Reed 14880a0e9771SDarren Reed /* 14890a0e9771SDarren Reed * Set the promiscuous mode of a network interface. 14900a0e9771SDarren Reed * This function only calls the mac layer when there is a change to the 14910a0e9771SDarren Reed * status of a network interface's promiscous mode. Tracking of how many 14920a0e9771SDarren Reed * sockets have the network interface in promiscuous mode, and thus the 14930a0e9771SDarren Reed * control over the physical device's status, is left to the mac layer. 14940a0e9771SDarren Reed */ 14950a0e9771SDarren Reed static int 14960a0e9771SDarren Reed pfp_set_promisc(struct pfpsock *ps, mac_client_promisc_type_t turnon) 14970a0e9771SDarren Reed { 14980a0e9771SDarren Reed int error = 0; 14990a0e9771SDarren Reed int flags; 15000a0e9771SDarren Reed 15010a0e9771SDarren Reed /* 15020a0e9771SDarren Reed * There are 4 combinations of turnon/ps_promisc. 15030a0e9771SDarren Reed * This if handles 2 (both false, both true) and the if() below 15040a0e9771SDarren Reed * handles the remaining one - when change is required. 15050a0e9771SDarren Reed */ 15060a0e9771SDarren Reed if (turnon == ps->ps_promisc) 15070a0e9771SDarren Reed return (error); 15080a0e9771SDarren Reed 15090a0e9771SDarren Reed if (ps->ps_phd != 0) { 15100a0e9771SDarren Reed mac_promisc_remove(ps->ps_phd); 15110a0e9771SDarren Reed ps->ps_phd = 0; 15120a0e9771SDarren Reed 15130a0e9771SDarren Reed /* 15140a0e9771SDarren Reed * ps_promisc is set here in case the call to mac_promisc_add 15150a0e9771SDarren Reed * fails: leaving it to indicate that the interface is still 15160a0e9771SDarren Reed * in some sort of promiscuous mode is false. 15170a0e9771SDarren Reed */ 15180a0e9771SDarren Reed if (ps->ps_promisc != MAC_CLIENT_PROMISC_FILTERED) { 15190a0e9771SDarren Reed ps->ps_promisc = MAC_CLIENT_PROMISC_FILTERED; 15200a0e9771SDarren Reed flags = MAC_PROMISC_FLAGS_NO_PHYS; 15210a0e9771SDarren Reed } else { 15220a0e9771SDarren Reed flags = 0; 15230a0e9771SDarren Reed } 15240a0e9771SDarren Reed flags |= MAC_PROMISC_FLAGS_VLAN_TAG_STRIP; 15250a0e9771SDarren Reed } 15260a0e9771SDarren Reed 15270a0e9771SDarren Reed error = mac_promisc_add(ps->ps_mch, turnon, pfp_packet, ps, 15280a0e9771SDarren Reed &ps->ps_phd, flags); 15290a0e9771SDarren Reed if (error == 0) 15300a0e9771SDarren Reed ps->ps_promisc = turnon; 15310a0e9771SDarren Reed 15320a0e9771SDarren Reed return (error); 15330a0e9771SDarren Reed } 15340a0e9771SDarren Reed 15350a0e9771SDarren Reed /* 15360a0e9771SDarren Reed * This table maps the MAC types in Solaris to the ARPHRD_* values used 1537a6911619SDarren Reed * on Linux. This is used with the SIOCGIFHWADDR/SIOCGLIFHWADDR ioctl. 1538a6911619SDarren Reed * 1539a6911619SDarren Reed * The symbols in this table are *not* pulled in from <net/if_arp.h>, 1540a6911619SDarren Reed * they are pulled from <netpacket/packet.h>, thus it acts as a source 1541a6911619SDarren Reed * of supplementary information to the ARP table. 15420a0e9771SDarren Reed */ 15430a0e9771SDarren Reed static uint_t arphrd_to_dl[][2] = { 15440a0e9771SDarren Reed { ARPHRD_IEEE80211, DL_WIFI }, 1545a6911619SDarren Reed { ARPHRD_TUNNEL, DL_IPV4 }, 1546a6911619SDarren Reed { ARPHRD_TUNNEL, DL_IPV6 }, 1547a6911619SDarren Reed { ARPHRD_TUNNEL, DL_6TO4 }, 1548a6911619SDarren Reed { ARPHRD_AX25, DL_X25 }, 1549a6911619SDarren Reed { ARPHRD_ATM, DL_ATM }, 15500a0e9771SDarren Reed { 0, 0 } 15510a0e9771SDarren Reed }; 15520a0e9771SDarren Reed 15530a0e9771SDarren Reed static int 15540a0e9771SDarren Reed pfp_dl_to_arphrd(int dltype) 15550a0e9771SDarren Reed { 15560a0e9771SDarren Reed int i; 15570a0e9771SDarren Reed 15580a0e9771SDarren Reed for (i = 0; arphrd_to_dl[i][0] != 0; i++) 15590a0e9771SDarren Reed if (arphrd_to_dl[i][1] == dltype) 15600a0e9771SDarren Reed return (arphrd_to_dl[i][0]); 1561a6911619SDarren Reed return (arp_hw_type(dltype)); 15620a0e9771SDarren Reed } 1563