110639SDarren.Reed@Sun.COM /*
210639SDarren.Reed@Sun.COM * CDDL HEADER START
310639SDarren.Reed@Sun.COM *
410639SDarren.Reed@Sun.COM * The contents of this file are subject to the terms of the
510639SDarren.Reed@Sun.COM * Common Development and Distribution License (the "License").
610639SDarren.Reed@Sun.COM * You may not use this file except in compliance with the License.
710639SDarren.Reed@Sun.COM *
810639SDarren.Reed@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
910639SDarren.Reed@Sun.COM * or http://www.opensolaris.org/os/licensing.
1010639SDarren.Reed@Sun.COM * See the License for the specific language governing permissions
1110639SDarren.Reed@Sun.COM * and limitations under the License.
1210639SDarren.Reed@Sun.COM *
1310639SDarren.Reed@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
1410639SDarren.Reed@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1510639SDarren.Reed@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
1610639SDarren.Reed@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
1710639SDarren.Reed@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
1810639SDarren.Reed@Sun.COM *
1910639SDarren.Reed@Sun.COM * CDDL HEADER END
2010639SDarren.Reed@Sun.COM */
2110639SDarren.Reed@Sun.COM
2210639SDarren.Reed@Sun.COM /*
2313055SAnders.Persson@Sun.COM * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
2410639SDarren.Reed@Sun.COM */
2510639SDarren.Reed@Sun.COM
2610639SDarren.Reed@Sun.COM #include <sys/types.h>
2710639SDarren.Reed@Sun.COM #include <sys/param.h>
2810639SDarren.Reed@Sun.COM #include <sys/systm.h>
2910639SDarren.Reed@Sun.COM #include <sys/stropts.h>
3010639SDarren.Reed@Sun.COM #include <sys/socket.h>
3110639SDarren.Reed@Sun.COM #include <sys/socketvar.h>
3210639SDarren.Reed@Sun.COM #include <sys/socket_proto.h>
3310639SDarren.Reed@Sun.COM #include <sys/sockio.h>
3410639SDarren.Reed@Sun.COM #include <sys/strsun.h>
3510639SDarren.Reed@Sun.COM #include <sys/kstat.h>
3610639SDarren.Reed@Sun.COM #include <sys/modctl.h>
3710639SDarren.Reed@Sun.COM #include <sys/policy.h>
3810639SDarren.Reed@Sun.COM #include <sys/priv_const.h>
3910639SDarren.Reed@Sun.COM #include <sys/tihdr.h>
4010639SDarren.Reed@Sun.COM #include <sys/zone.h>
4110639SDarren.Reed@Sun.COM #include <sys/time.h>
42*13095SDarren.Reed@Oracle.COM #include <sys/ethernet.h>
43*13095SDarren.Reed@Oracle.COM #include <sys/llc1.h>
4410639SDarren.Reed@Sun.COM #include <fs/sockfs/sockcommon.h>
4510639SDarren.Reed@Sun.COM #include <net/if.h>
46*13095SDarren.Reed@Oracle.COM #include <inet/ip_arp.h>
4710639SDarren.Reed@Sun.COM
4810639SDarren.Reed@Sun.COM #include <sys/dls.h>
4910639SDarren.Reed@Sun.COM #include <sys/mac.h>
5010639SDarren.Reed@Sun.COM #include <sys/mac_client.h>
5110639SDarren.Reed@Sun.COM #include <sys/mac_provider.h>
5210639SDarren.Reed@Sun.COM #include <sys/mac_client_priv.h>
5310639SDarren.Reed@Sun.COM
5410639SDarren.Reed@Sun.COM #include <netpacket/packet.h>
5510639SDarren.Reed@Sun.COM
5610639SDarren.Reed@Sun.COM static void pfp_close(mac_handle_t, mac_client_handle_t);
5710639SDarren.Reed@Sun.COM static int pfp_dl_to_arphrd(int);
5810639SDarren.Reed@Sun.COM static int pfp_getpacket_sockopt(sock_lower_handle_t, int, void *,
5910639SDarren.Reed@Sun.COM socklen_t *);
6010639SDarren.Reed@Sun.COM static int pfp_ifreq_getlinkid(intptr_t, struct ifreq *, datalink_id_t *);
6110639SDarren.Reed@Sun.COM static int pfp_lifreq_getlinkid(intptr_t, struct lifreq *, datalink_id_t *);
6210639SDarren.Reed@Sun.COM static int pfp_open_index(int, mac_handle_t *, mac_client_handle_t *,
6310639SDarren.Reed@Sun.COM cred_t *);
6410639SDarren.Reed@Sun.COM static void pfp_packet(void *, mac_resource_handle_t, mblk_t *, boolean_t);
6510639SDarren.Reed@Sun.COM static void pfp_release_bpf(struct pfpsock *);
6610639SDarren.Reed@Sun.COM static int pfp_set_promisc(struct pfpsock *, mac_client_promisc_type_t);
6710639SDarren.Reed@Sun.COM static int pfp_setsocket_sockopt(sock_lower_handle_t, int, const void *,
6810639SDarren.Reed@Sun.COM socklen_t);
6910639SDarren.Reed@Sun.COM static int pfp_setpacket_sockopt(sock_lower_handle_t, int, const void *,
7010639SDarren.Reed@Sun.COM socklen_t);
7110639SDarren.Reed@Sun.COM
7210639SDarren.Reed@Sun.COM /*
7310639SDarren.Reed@Sun.COM * PFP sockfs operations
7410639SDarren.Reed@Sun.COM * Most are currently no-ops because they have no meaning for a connectionless
7510639SDarren.Reed@Sun.COM * socket.
7610639SDarren.Reed@Sun.COM */
7710639SDarren.Reed@Sun.COM static void sdpfp_activate(sock_lower_handle_t, sock_upper_handle_t,
7810639SDarren.Reed@Sun.COM sock_upcalls_t *, int, struct cred *);
7910639SDarren.Reed@Sun.COM static int sdpfp_bind(sock_lower_handle_t, struct sockaddr *, socklen_t,
8010639SDarren.Reed@Sun.COM struct cred *);
8110639SDarren.Reed@Sun.COM static int sdpfp_close(sock_lower_handle_t, int, struct cred *);
8210639SDarren.Reed@Sun.COM static void sdpfp_clr_flowctrl(sock_lower_handle_t);
8310639SDarren.Reed@Sun.COM static int sdpfp_getsockopt(sock_lower_handle_t, int, int, void *,
8410639SDarren.Reed@Sun.COM socklen_t *, struct cred *);
8510639SDarren.Reed@Sun.COM static int sdpfp_ioctl(sock_lower_handle_t, int, intptr_t, int, int32_t *,
8610639SDarren.Reed@Sun.COM struct cred *);
8710639SDarren.Reed@Sun.COM static int sdpfp_senduio(sock_lower_handle_t, struct uio *, struct nmsghdr *,
8810639SDarren.Reed@Sun.COM struct cred *);
8910639SDarren.Reed@Sun.COM static int sdpfp_setsockopt(sock_lower_handle_t, int, int, const void *,
9010639SDarren.Reed@Sun.COM socklen_t, struct cred *);
9110639SDarren.Reed@Sun.COM
9210639SDarren.Reed@Sun.COM static sock_lower_handle_t sockpfp_create(int, int, int, sock_downcalls_t **,
9310639SDarren.Reed@Sun.COM uint_t *, int *, int, cred_t *);
9410639SDarren.Reed@Sun.COM
9510639SDarren.Reed@Sun.COM static int sockpfp_init(void);
9610639SDarren.Reed@Sun.COM static void sockpfp_fini(void);
9710639SDarren.Reed@Sun.COM
9810639SDarren.Reed@Sun.COM static kstat_t *pfp_ksp;
9910639SDarren.Reed@Sun.COM static pfp_kstats_t ks_stats;
10010639SDarren.Reed@Sun.COM static pfp_kstats_t pfp_kstats = {
10110639SDarren.Reed@Sun.COM /*
10210639SDarren.Reed@Sun.COM * Each one of these kstats is a different return path in handling
10310639SDarren.Reed@Sun.COM * a packet received from the mac layer.
10410639SDarren.Reed@Sun.COM */
10510639SDarren.Reed@Sun.COM { "recvMacHeaderFail", KSTAT_DATA_UINT64 },
10610639SDarren.Reed@Sun.COM { "recvBadProtocol", KSTAT_DATA_UINT64 },
10710639SDarren.Reed@Sun.COM { "recvAllocbFail", KSTAT_DATA_UINT64 },
10810639SDarren.Reed@Sun.COM { "recvOk", KSTAT_DATA_UINT64 },
10910639SDarren.Reed@Sun.COM { "recvFail", KSTAT_DATA_UINT64 },
11010639SDarren.Reed@Sun.COM { "recvFiltered", KSTAT_DATA_UINT64 },
11110639SDarren.Reed@Sun.COM { "recvFlowControl", KSTAT_DATA_UINT64 },
11210639SDarren.Reed@Sun.COM /*
11310639SDarren.Reed@Sun.COM * A global set of counters is maintained to track the behaviour
11410639SDarren.Reed@Sun.COM * of the system (kernel & applications) in sending packets.
11510639SDarren.Reed@Sun.COM */
11610639SDarren.Reed@Sun.COM { "sendUnbound", KSTAT_DATA_UINT64 },
11710639SDarren.Reed@Sun.COM { "sendFailed", KSTAT_DATA_UINT64 },
11810639SDarren.Reed@Sun.COM { "sendTooBig", KSTAT_DATA_UINT64 },
11910639SDarren.Reed@Sun.COM { "sendAllocFail", KSTAT_DATA_UINT64 },
12010639SDarren.Reed@Sun.COM { "sendUiomoveFail", KSTAT_DATA_UINT64 },
12110639SDarren.Reed@Sun.COM { "sendNoMemory", KSTAT_DATA_UINT64 },
12210639SDarren.Reed@Sun.COM { "sendOpenFail", KSTAT_DATA_UINT64 },
12310639SDarren.Reed@Sun.COM { "sendWrongFamily", KSTAT_DATA_UINT64 },
12410639SDarren.Reed@Sun.COM { "sendShortMsg", KSTAT_DATA_UINT64 },
12510639SDarren.Reed@Sun.COM { "sendOk", KSTAT_DATA_UINT64 }
12610639SDarren.Reed@Sun.COM };
12710639SDarren.Reed@Sun.COM
12810639SDarren.Reed@Sun.COM sock_downcalls_t pfp_downcalls = {
12910639SDarren.Reed@Sun.COM sdpfp_activate,
13010639SDarren.Reed@Sun.COM sock_accept_notsupp,
13110639SDarren.Reed@Sun.COM sdpfp_bind,
13210639SDarren.Reed@Sun.COM sock_listen_notsupp,
13310639SDarren.Reed@Sun.COM sock_connect_notsupp,
13410639SDarren.Reed@Sun.COM sock_getpeername_notsupp,
13510639SDarren.Reed@Sun.COM sock_getsockname_notsupp,
13610639SDarren.Reed@Sun.COM sdpfp_getsockopt,
13710639SDarren.Reed@Sun.COM sdpfp_setsockopt,
13810639SDarren.Reed@Sun.COM sock_send_notsupp,
13910639SDarren.Reed@Sun.COM sdpfp_senduio,
14010639SDarren.Reed@Sun.COM NULL,
14110639SDarren.Reed@Sun.COM sock_poll_notsupp,
14210639SDarren.Reed@Sun.COM sock_shutdown_notsupp,
14310639SDarren.Reed@Sun.COM sdpfp_clr_flowctrl,
14410639SDarren.Reed@Sun.COM sdpfp_ioctl,
14510639SDarren.Reed@Sun.COM sdpfp_close,
14610639SDarren.Reed@Sun.COM };
14710639SDarren.Reed@Sun.COM
14810639SDarren.Reed@Sun.COM static smod_reg_t sinfo = {
14910639SDarren.Reed@Sun.COM SOCKMOD_VERSION,
15010639SDarren.Reed@Sun.COM "sockpfp",
15110639SDarren.Reed@Sun.COM SOCK_UC_VERSION,
15210639SDarren.Reed@Sun.COM SOCK_DC_VERSION,
15310639SDarren.Reed@Sun.COM sockpfp_create,
15410639SDarren.Reed@Sun.COM NULL
15510639SDarren.Reed@Sun.COM };
15610639SDarren.Reed@Sun.COM
157*13095SDarren.Reed@Oracle.COM static int accepted_protos[3][2] = {
158*13095SDarren.Reed@Oracle.COM { ETH_P_ALL, 0 },
159*13095SDarren.Reed@Oracle.COM { ETH_P_802_2, LLC_SNAP_SAP },
160*13095SDarren.Reed@Oracle.COM { ETH_P_803_3, 0 },
161*13095SDarren.Reed@Oracle.COM };
162*13095SDarren.Reed@Oracle.COM
16310639SDarren.Reed@Sun.COM /*
16410639SDarren.Reed@Sun.COM * Module linkage information for the kernel.
16510639SDarren.Reed@Sun.COM */
16610639SDarren.Reed@Sun.COM static struct modlsockmod modlsockmod = {
16710639SDarren.Reed@Sun.COM &mod_sockmodops, "PF Packet socket module", &sinfo
16810639SDarren.Reed@Sun.COM };
16910639SDarren.Reed@Sun.COM
17010639SDarren.Reed@Sun.COM static struct modlinkage modlinkage = {
17110639SDarren.Reed@Sun.COM MODREV_1,
17210639SDarren.Reed@Sun.COM &modlsockmod,
17310639SDarren.Reed@Sun.COM NULL
17410639SDarren.Reed@Sun.COM };
17510639SDarren.Reed@Sun.COM
17610639SDarren.Reed@Sun.COM int
_init(void)17710639SDarren.Reed@Sun.COM _init(void)
17810639SDarren.Reed@Sun.COM {
17910639SDarren.Reed@Sun.COM int error;
18010639SDarren.Reed@Sun.COM
18110639SDarren.Reed@Sun.COM error = sockpfp_init();
18210639SDarren.Reed@Sun.COM if (error != 0)
18310639SDarren.Reed@Sun.COM return (error);
18410639SDarren.Reed@Sun.COM
18510639SDarren.Reed@Sun.COM error = mod_install(&modlinkage);
18610639SDarren.Reed@Sun.COM if (error != 0)
18710639SDarren.Reed@Sun.COM sockpfp_fini();
18810639SDarren.Reed@Sun.COM
18910639SDarren.Reed@Sun.COM return (error);
19010639SDarren.Reed@Sun.COM }
19110639SDarren.Reed@Sun.COM
19210639SDarren.Reed@Sun.COM int
_fini(void)19310639SDarren.Reed@Sun.COM _fini(void)
19410639SDarren.Reed@Sun.COM {
19510639SDarren.Reed@Sun.COM int error;
19610639SDarren.Reed@Sun.COM
19710639SDarren.Reed@Sun.COM error = mod_remove(&modlinkage);
19810639SDarren.Reed@Sun.COM if (error == 0)
19910639SDarren.Reed@Sun.COM sockpfp_fini();
20010639SDarren.Reed@Sun.COM
20110639SDarren.Reed@Sun.COM return (error);
20210639SDarren.Reed@Sun.COM }
20310639SDarren.Reed@Sun.COM
20410639SDarren.Reed@Sun.COM int
_info(struct modinfo * modinfop)20510639SDarren.Reed@Sun.COM _info(struct modinfo *modinfop)
20610639SDarren.Reed@Sun.COM {
20710639SDarren.Reed@Sun.COM return (mod_info(&modlinkage, modinfop));
20810639SDarren.Reed@Sun.COM }
20910639SDarren.Reed@Sun.COM
21010639SDarren.Reed@Sun.COM /*
21110639SDarren.Reed@Sun.COM * sockpfp_init: called as part of the initialisation of the module when
21210639SDarren.Reed@Sun.COM * loaded into the kernel.
21310639SDarren.Reed@Sun.COM *
21410639SDarren.Reed@Sun.COM * Being able to create and record the kstats data in the kernel is not
21510639SDarren.Reed@Sun.COM * considered to be vital to the operation of this kernel module, thus
21610639SDarren.Reed@Sun.COM * its failure is tolerated.
21710639SDarren.Reed@Sun.COM */
21810639SDarren.Reed@Sun.COM static int
sockpfp_init(void)21910639SDarren.Reed@Sun.COM sockpfp_init(void)
22010639SDarren.Reed@Sun.COM {
22110639SDarren.Reed@Sun.COM (void) memset(&ks_stats, 0, sizeof (ks_stats));
22210639SDarren.Reed@Sun.COM
22310639SDarren.Reed@Sun.COM (void) memcpy(&ks_stats, &pfp_kstats, sizeof (pfp_kstats));
22410639SDarren.Reed@Sun.COM
22510639SDarren.Reed@Sun.COM pfp_ksp = kstat_create("pfpacket", 0, "global", "misc",
22610639SDarren.Reed@Sun.COM KSTAT_TYPE_NAMED, sizeof (pfp_kstats) / sizeof (kstat_named_t),
22710639SDarren.Reed@Sun.COM KSTAT_FLAG_VIRTUAL);
22810639SDarren.Reed@Sun.COM if (pfp_ksp != NULL) {
22910639SDarren.Reed@Sun.COM pfp_ksp->ks_data = &ks_stats;
23010639SDarren.Reed@Sun.COM kstat_install(pfp_ksp);
23110639SDarren.Reed@Sun.COM }
23210639SDarren.Reed@Sun.COM
23310639SDarren.Reed@Sun.COM return (0);
23410639SDarren.Reed@Sun.COM }
23510639SDarren.Reed@Sun.COM
23610639SDarren.Reed@Sun.COM /*
23710639SDarren.Reed@Sun.COM * sockpfp_fini: called when the operating system wants to unload the
23810639SDarren.Reed@Sun.COM * socket module from the kernel.
23910639SDarren.Reed@Sun.COM */
24010639SDarren.Reed@Sun.COM static void
sockpfp_fini(void)24110639SDarren.Reed@Sun.COM sockpfp_fini(void)
24210639SDarren.Reed@Sun.COM {
24310639SDarren.Reed@Sun.COM if (pfp_ksp != NULL)
24410639SDarren.Reed@Sun.COM kstat_delete(pfp_ksp);
24510639SDarren.Reed@Sun.COM }
24610639SDarren.Reed@Sun.COM
24710639SDarren.Reed@Sun.COM /*
24810639SDarren.Reed@Sun.COM * Due to sockets being created read-write by default, all PF_PACKET sockets
24910639SDarren.Reed@Sun.COM * therefore require the NET_RAWACCESS priviliege, even if the socket is only
25010639SDarren.Reed@Sun.COM * being used for reading packets from.
25110639SDarren.Reed@Sun.COM *
25210639SDarren.Reed@Sun.COM * This create function enforces this module only being used with PF_PACKET
25313055SAnders.Persson@Sun.COM * sockets and the policy that we support via the config file in sock2path.d:
25410639SDarren.Reed@Sun.COM * PF_PACKET sockets must be either SOCK_DGRAM or SOCK_RAW.
25510639SDarren.Reed@Sun.COM */
25610639SDarren.Reed@Sun.COM /* ARGSUSED */
25710639SDarren.Reed@Sun.COM static sock_lower_handle_t
sockpfp_create(int family,int type,int proto,sock_downcalls_t ** sock_downcalls,uint_t * smodep,int * errorp,int sflags,cred_t * cred)25810639SDarren.Reed@Sun.COM sockpfp_create(int family, int type, int proto,
25910639SDarren.Reed@Sun.COM sock_downcalls_t **sock_downcalls, uint_t *smodep, int *errorp,
26010639SDarren.Reed@Sun.COM int sflags, cred_t *cred)
26110639SDarren.Reed@Sun.COM {
26210639SDarren.Reed@Sun.COM struct pfpsock *ps;
26310639SDarren.Reed@Sun.COM int kmflags;
264*13095SDarren.Reed@Oracle.COM int newproto;
265*13095SDarren.Reed@Oracle.COM int i;
26610639SDarren.Reed@Sun.COM
26710639SDarren.Reed@Sun.COM if (secpolicy_net_rawaccess(cred) != 0) {
26810639SDarren.Reed@Sun.COM *errorp = EACCES;
26910639SDarren.Reed@Sun.COM return (NULL);
27010639SDarren.Reed@Sun.COM }
27110639SDarren.Reed@Sun.COM
27210639SDarren.Reed@Sun.COM if (family != AF_PACKET) {
27310639SDarren.Reed@Sun.COM *errorp = EAFNOSUPPORT;
27410639SDarren.Reed@Sun.COM return (NULL);
27510639SDarren.Reed@Sun.COM }
27610639SDarren.Reed@Sun.COM
27710639SDarren.Reed@Sun.COM if ((type != SOCK_RAW) && (type != SOCK_DGRAM)) {
27810639SDarren.Reed@Sun.COM *errorp = ESOCKTNOSUPPORT;
27910639SDarren.Reed@Sun.COM return (NULL);
28010639SDarren.Reed@Sun.COM }
28110639SDarren.Reed@Sun.COM
282*13095SDarren.Reed@Oracle.COM /*
283*13095SDarren.Reed@Oracle.COM * First check to see if the protocol number passed in via the socket
284*13095SDarren.Reed@Oracle.COM * creation should be mapped to a different number for internal use.
285*13095SDarren.Reed@Oracle.COM */
286*13095SDarren.Reed@Oracle.COM for (i = 0, newproto = -1;
287*13095SDarren.Reed@Oracle.COM i < sizeof (accepted_protos)/ sizeof (accepted_protos[0]); i++) {
288*13095SDarren.Reed@Oracle.COM if (accepted_protos[i][0] == proto) {
289*13095SDarren.Reed@Oracle.COM newproto = accepted_protos[i][1];
290*13095SDarren.Reed@Oracle.COM break;
291*13095SDarren.Reed@Oracle.COM }
292*13095SDarren.Reed@Oracle.COM }
293*13095SDarren.Reed@Oracle.COM
294*13095SDarren.Reed@Oracle.COM /*
295*13095SDarren.Reed@Oracle.COM * If the mapping of the protocol that was under 0x800 failed to find
296*13095SDarren.Reed@Oracle.COM * a local equivalent then fail the socket creation. If the protocol
297*13095SDarren.Reed@Oracle.COM * for the socket is over 0x800 and it was not found in the mapping
298*13095SDarren.Reed@Oracle.COM * table above, then use the value as is.
299*13095SDarren.Reed@Oracle.COM */
300*13095SDarren.Reed@Oracle.COM if (newproto == -1) {
301*13095SDarren.Reed@Oracle.COM if (proto < 0x800) {
302*13095SDarren.Reed@Oracle.COM *errorp = ENOPROTOOPT;
303*13095SDarren.Reed@Oracle.COM return (NULL);
304*13095SDarren.Reed@Oracle.COM }
305*13095SDarren.Reed@Oracle.COM newproto = proto;
306*13095SDarren.Reed@Oracle.COM }
307*13095SDarren.Reed@Oracle.COM proto = newproto;
308*13095SDarren.Reed@Oracle.COM
30910639SDarren.Reed@Sun.COM kmflags = (sflags & SOCKET_NOSLEEP) ? KM_NOSLEEP : KM_SLEEP;
31010639SDarren.Reed@Sun.COM ps = kmem_zalloc(sizeof (*ps), kmflags);
31110639SDarren.Reed@Sun.COM if (ps == NULL) {
31210639SDarren.Reed@Sun.COM *errorp = ENOMEM;
31310639SDarren.Reed@Sun.COM return (NULL);
31410639SDarren.Reed@Sun.COM }
31510639SDarren.Reed@Sun.COM
31610639SDarren.Reed@Sun.COM ps->ps_type = type;
31710639SDarren.Reed@Sun.COM ps->ps_proto = proto;
31810639SDarren.Reed@Sun.COM rw_init(&ps->ps_bpflock, NULL, RW_DRIVER, NULL);
31910639SDarren.Reed@Sun.COM mutex_init(&ps->ps_lock, NULL, MUTEX_DRIVER, NULL);
32010639SDarren.Reed@Sun.COM
32110639SDarren.Reed@Sun.COM *sock_downcalls = &pfp_downcalls;
32210639SDarren.Reed@Sun.COM /*
32310639SDarren.Reed@Sun.COM * Setting this causes bytes from a packet that do not fit into the
32410639SDarren.Reed@Sun.COM * destination user buffer to be discarded. Thus the API is one
32510639SDarren.Reed@Sun.COM * packet per receive and callers are required to use a buffer large
32610639SDarren.Reed@Sun.COM * enough for the biggest packet that the interface can provide.
32710639SDarren.Reed@Sun.COM */
32810639SDarren.Reed@Sun.COM *smodep = SM_ATOMIC;
32910639SDarren.Reed@Sun.COM
33010639SDarren.Reed@Sun.COM return ((sock_lower_handle_t)ps);
33110639SDarren.Reed@Sun.COM }
33210639SDarren.Reed@Sun.COM
33310639SDarren.Reed@Sun.COM /* ************************************************************************* */
33410639SDarren.Reed@Sun.COM
33510639SDarren.Reed@Sun.COM /*
33610639SDarren.Reed@Sun.COM * pfp_packet is the callback function that is given to the mac layer for
33710639SDarren.Reed@Sun.COM * PF_PACKET to receive packets with. One packet at a time is passed into
33810639SDarren.Reed@Sun.COM * this function from the mac layer. Each packet is a private copy given
33910639SDarren.Reed@Sun.COM * to PF_PACKET to modify or free as it wishes and does not harm the original
34010639SDarren.Reed@Sun.COM * packet from which it was cloned.
34110639SDarren.Reed@Sun.COM */
34210639SDarren.Reed@Sun.COM /* ARGSUSED */
34310639SDarren.Reed@Sun.COM static void
pfp_packet(void * arg,mac_resource_handle_t mrh,mblk_t * mp,boolean_t flag)34410639SDarren.Reed@Sun.COM pfp_packet(void *arg, mac_resource_handle_t mrh, mblk_t *mp, boolean_t flag)
34510639SDarren.Reed@Sun.COM {
34610639SDarren.Reed@Sun.COM struct T_unitdata_ind *tunit;
34710639SDarren.Reed@Sun.COM struct sockaddr_ll *sll;
34810639SDarren.Reed@Sun.COM struct sockaddr_ll *sol;
34910639SDarren.Reed@Sun.COM mac_header_info_t hdr;
35010639SDarren.Reed@Sun.COM struct pfpsock *ps;
35110639SDarren.Reed@Sun.COM size_t tusz;
35210639SDarren.Reed@Sun.COM mblk_t *mp0;
35310639SDarren.Reed@Sun.COM int error;
35410639SDarren.Reed@Sun.COM
35510639SDarren.Reed@Sun.COM if (mp == NULL)
35610639SDarren.Reed@Sun.COM return;
35710639SDarren.Reed@Sun.COM
35810639SDarren.Reed@Sun.COM ps = arg;
35910639SDarren.Reed@Sun.COM if (ps->ps_flow_ctrld) {
36010639SDarren.Reed@Sun.COM ps->ps_flow_ctrl_drops++;
36110639SDarren.Reed@Sun.COM ps->ps_stats.tp_drops++;
36210639SDarren.Reed@Sun.COM ks_stats.kp_recv_flow_cntrld.value.ui64++;
36310639SDarren.Reed@Sun.COM freemsg(mp);
36410639SDarren.Reed@Sun.COM return;
36510639SDarren.Reed@Sun.COM }
36610639SDarren.Reed@Sun.COM
36710639SDarren.Reed@Sun.COM if (mac_header_info(ps->ps_mh, mp, &hdr) != 0) {
36810639SDarren.Reed@Sun.COM /*
36910639SDarren.Reed@Sun.COM * Can't decode the packet header information so drop it.
37010639SDarren.Reed@Sun.COM */
37110639SDarren.Reed@Sun.COM ps->ps_stats.tp_drops++;
37210639SDarren.Reed@Sun.COM ks_stats.kp_recv_mac_hdr_fail.value.ui64++;
37310639SDarren.Reed@Sun.COM freemsg(mp);
37410639SDarren.Reed@Sun.COM return;
37510639SDarren.Reed@Sun.COM }
37610639SDarren.Reed@Sun.COM
37710639SDarren.Reed@Sun.COM if (mac_type(ps->ps_mh) == DL_ETHER &&
37810639SDarren.Reed@Sun.COM hdr.mhi_bindsap == ETHERTYPE_VLAN) {
37910639SDarren.Reed@Sun.COM struct ether_vlan_header *evhp;
38010639SDarren.Reed@Sun.COM struct ether_vlan_header evh;
38110639SDarren.Reed@Sun.COM
38210639SDarren.Reed@Sun.COM hdr.mhi_hdrsize = sizeof (struct ether_vlan_header);
38310639SDarren.Reed@Sun.COM hdr.mhi_istagged = B_TRUE;
38410639SDarren.Reed@Sun.COM
38510639SDarren.Reed@Sun.COM if (MBLKL(mp) >= sizeof (*evhp)) {
38610639SDarren.Reed@Sun.COM evhp = (struct ether_vlan_header *)mp->b_rptr;
38710639SDarren.Reed@Sun.COM } else {
38810639SDarren.Reed@Sun.COM int sz = sizeof (*evhp);
38910639SDarren.Reed@Sun.COM char *s = (char *)&evh;
39010639SDarren.Reed@Sun.COM mblk_t *tmp;
39110639SDarren.Reed@Sun.COM int len;
39210639SDarren.Reed@Sun.COM
39310639SDarren.Reed@Sun.COM for (tmp = mp; sz > 0 && tmp != NULL;
39410639SDarren.Reed@Sun.COM tmp = tmp->b_cont) {
39510639SDarren.Reed@Sun.COM len = min(sz, MBLKL(tmp));
39610639SDarren.Reed@Sun.COM bcopy(tmp->b_rptr, s, len);
39710639SDarren.Reed@Sun.COM sz -= len;
39810639SDarren.Reed@Sun.COM }
39910639SDarren.Reed@Sun.COM evhp = &evh;
40010639SDarren.Reed@Sun.COM }
40110639SDarren.Reed@Sun.COM hdr.mhi_tci = ntohs(evhp->ether_tci);
40210639SDarren.Reed@Sun.COM hdr.mhi_bindsap = ntohs(evhp->ether_type);
40310639SDarren.Reed@Sun.COM }
40410639SDarren.Reed@Sun.COM
40510639SDarren.Reed@Sun.COM if ((ps->ps_proto != 0) && (ps->ps_proto != hdr.mhi_bindsap)) {
40610639SDarren.Reed@Sun.COM /*
40710639SDarren.Reed@Sun.COM * The packet is not of interest to this socket so
40810639SDarren.Reed@Sun.COM * drop it on the floor. Here the SAP is being used
40910639SDarren.Reed@Sun.COM * as a very course filter.
41010639SDarren.Reed@Sun.COM */
41110639SDarren.Reed@Sun.COM ps->ps_stats.tp_drops++;
41210639SDarren.Reed@Sun.COM ks_stats.kp_recv_bad_proto.value.ui64++;
41310639SDarren.Reed@Sun.COM freemsg(mp);
41410639SDarren.Reed@Sun.COM return;
41510639SDarren.Reed@Sun.COM }
41610639SDarren.Reed@Sun.COM
41710639SDarren.Reed@Sun.COM /*
41810639SDarren.Reed@Sun.COM * This field is not often set, even for ethernet,
41910639SDarren.Reed@Sun.COM * by mac_header_info, so compute it if it is 0.
42010639SDarren.Reed@Sun.COM */
42110639SDarren.Reed@Sun.COM if (hdr.mhi_pktsize == 0)
42210639SDarren.Reed@Sun.COM hdr.mhi_pktsize = msgdsize(mp);
42310639SDarren.Reed@Sun.COM
42410639SDarren.Reed@Sun.COM /*
42510639SDarren.Reed@Sun.COM * If a BPF filter is present, pass the raw packet into that.
42610639SDarren.Reed@Sun.COM * A failed match will result in zero being returned, indicating
42710639SDarren.Reed@Sun.COM * that this socket is not interested in the packet.
42810639SDarren.Reed@Sun.COM */
42910639SDarren.Reed@Sun.COM if (ps->ps_bpf.bf_len != 0) {
43010639SDarren.Reed@Sun.COM uchar_t *buffer;
43110639SDarren.Reed@Sun.COM int buflen;
43210639SDarren.Reed@Sun.COM
43310639SDarren.Reed@Sun.COM buflen = MBLKL(mp);
43410639SDarren.Reed@Sun.COM if (hdr.mhi_pktsize == buflen) {
43510639SDarren.Reed@Sun.COM buffer = mp->b_rptr;
43610639SDarren.Reed@Sun.COM } else {
43710639SDarren.Reed@Sun.COM buflen = 0;
43810639SDarren.Reed@Sun.COM buffer = (uchar_t *)mp;
43910639SDarren.Reed@Sun.COM }
44010639SDarren.Reed@Sun.COM rw_enter(&ps->ps_bpflock, RW_READER);
44110639SDarren.Reed@Sun.COM if (bpf_filter(ps->ps_bpf.bf_insns, buffer,
44210639SDarren.Reed@Sun.COM hdr.mhi_pktsize, buflen) == 0) {
44310639SDarren.Reed@Sun.COM rw_exit(&ps->ps_bpflock);
44410639SDarren.Reed@Sun.COM ps->ps_stats.tp_drops++;
44510639SDarren.Reed@Sun.COM ks_stats.kp_recv_filtered.value.ui64++;
44610639SDarren.Reed@Sun.COM freemsg(mp);
44710639SDarren.Reed@Sun.COM return;
44810639SDarren.Reed@Sun.COM }
44910639SDarren.Reed@Sun.COM rw_exit(&ps->ps_bpflock);
45010639SDarren.Reed@Sun.COM }
45110639SDarren.Reed@Sun.COM
45210639SDarren.Reed@Sun.COM if (ps->ps_type == SOCK_DGRAM) {
45310639SDarren.Reed@Sun.COM /*
45410639SDarren.Reed@Sun.COM * SOCK_DGRAM socket expect a "layer 3" packet, so advance
45510639SDarren.Reed@Sun.COM * past the link layer header.
45610639SDarren.Reed@Sun.COM */
45710639SDarren.Reed@Sun.COM mp->b_rptr += hdr.mhi_hdrsize;
45810639SDarren.Reed@Sun.COM hdr.mhi_pktsize -= hdr.mhi_hdrsize;
45910639SDarren.Reed@Sun.COM }
46010639SDarren.Reed@Sun.COM
46110639SDarren.Reed@Sun.COM tusz = sizeof (struct T_unitdata_ind) + sizeof (struct sockaddr_ll);
46210639SDarren.Reed@Sun.COM if (ps->ps_auxdata) {
46310639SDarren.Reed@Sun.COM tusz += _TPI_ALIGN_TOPT(sizeof (struct tpacket_auxdata));
46410639SDarren.Reed@Sun.COM tusz += _TPI_ALIGN_TOPT(sizeof (struct T_opthdr));
46510639SDarren.Reed@Sun.COM }
46610639SDarren.Reed@Sun.COM
46710639SDarren.Reed@Sun.COM /*
46810639SDarren.Reed@Sun.COM * It is tempting to think that this could be optimised by having
46910639SDarren.Reed@Sun.COM * the base mblk_t allocated and hung off the pfpsock structure,
47010639SDarren.Reed@Sun.COM * except that then another one would need to be allocated for the
47110639SDarren.Reed@Sun.COM * sockaddr_ll that is included. Even creating a template to copy
47210639SDarren.Reed@Sun.COM * from is of questionable value, as read-write from one structure
47310639SDarren.Reed@Sun.COM * to the other is going to be slower than all of the initialisation.
47410639SDarren.Reed@Sun.COM */
47510639SDarren.Reed@Sun.COM mp0 = allocb(tusz, BPRI_HI);
47610639SDarren.Reed@Sun.COM if (mp0 == NULL) {
47710639SDarren.Reed@Sun.COM ps->ps_stats.tp_drops++;
47810639SDarren.Reed@Sun.COM ks_stats.kp_recv_alloc_fail.value.ui64++;
47910639SDarren.Reed@Sun.COM freemsg(mp);
48010639SDarren.Reed@Sun.COM return;
48110639SDarren.Reed@Sun.COM }
48210639SDarren.Reed@Sun.COM
48310639SDarren.Reed@Sun.COM (void) memset(mp0->b_rptr, 0, tusz);
48410639SDarren.Reed@Sun.COM
48510639SDarren.Reed@Sun.COM mp0->b_datap->db_type = M_PROTO;
48610639SDarren.Reed@Sun.COM mp0->b_wptr = mp0->b_rptr + tusz;
48710639SDarren.Reed@Sun.COM
48810639SDarren.Reed@Sun.COM tunit = (struct T_unitdata_ind *)mp0->b_rptr;
48910639SDarren.Reed@Sun.COM tunit->PRIM_type = T_UNITDATA_IND;
49010639SDarren.Reed@Sun.COM tunit->SRC_length = sizeof (struct sockaddr);
49110639SDarren.Reed@Sun.COM tunit->SRC_offset = sizeof (*tunit);
49210639SDarren.Reed@Sun.COM
49310639SDarren.Reed@Sun.COM sol = (struct sockaddr_ll *)&ps->ps_sock;
49410639SDarren.Reed@Sun.COM sll = (struct sockaddr_ll *)(mp0->b_rptr + sizeof (*tunit));
49510639SDarren.Reed@Sun.COM sll->sll_ifindex = sol->sll_ifindex;
49610639SDarren.Reed@Sun.COM sll->sll_hatype = (uint16_t)hdr.mhi_origsap;
49710639SDarren.Reed@Sun.COM sll->sll_halen = sol->sll_halen;
49810639SDarren.Reed@Sun.COM if (hdr.mhi_saddr != NULL)
49910639SDarren.Reed@Sun.COM (void) memcpy(sll->sll_addr, hdr.mhi_saddr, sll->sll_halen);
50010639SDarren.Reed@Sun.COM
50110639SDarren.Reed@Sun.COM switch (hdr.mhi_dsttype) {
50210639SDarren.Reed@Sun.COM case MAC_ADDRTYPE_MULTICAST :
50310639SDarren.Reed@Sun.COM sll->sll_pkttype = PACKET_MULTICAST;
50410639SDarren.Reed@Sun.COM break;
50510639SDarren.Reed@Sun.COM case MAC_ADDRTYPE_BROADCAST :
50610639SDarren.Reed@Sun.COM sll->sll_pkttype = PACKET_BROADCAST;
50710639SDarren.Reed@Sun.COM break;
50810639SDarren.Reed@Sun.COM case MAC_ADDRTYPE_UNICAST :
50910639SDarren.Reed@Sun.COM if (memcmp(sol->sll_addr, hdr.mhi_daddr, sol->sll_halen) == 0)
51010639SDarren.Reed@Sun.COM sll->sll_pkttype = PACKET_HOST;
51110639SDarren.Reed@Sun.COM else
51210639SDarren.Reed@Sun.COM sll->sll_pkttype = PACKET_OTHERHOST;
51310639SDarren.Reed@Sun.COM break;
51410639SDarren.Reed@Sun.COM }
51510639SDarren.Reed@Sun.COM
51610639SDarren.Reed@Sun.COM if (ps->ps_auxdata) {
51710639SDarren.Reed@Sun.COM struct tpacket_auxdata *aux;
51810639SDarren.Reed@Sun.COM struct T_opthdr *topt;
51910639SDarren.Reed@Sun.COM
52010639SDarren.Reed@Sun.COM tunit->OPT_offset = _TPI_ALIGN_TOPT(tunit->SRC_offset +
52110639SDarren.Reed@Sun.COM sizeof (struct sockaddr_ll));
52210639SDarren.Reed@Sun.COM tunit->OPT_length = _TPI_ALIGN_TOPT(sizeof (struct T_opthdr)) +
52310639SDarren.Reed@Sun.COM _TPI_ALIGN_TOPT(sizeof (struct tpacket_auxdata));
52410639SDarren.Reed@Sun.COM
52510639SDarren.Reed@Sun.COM topt = (struct T_opthdr *)(mp0->b_rptr + tunit->OPT_offset);
52610639SDarren.Reed@Sun.COM aux = (struct tpacket_auxdata *)
52710639SDarren.Reed@Sun.COM ((char *)topt + _TPI_ALIGN_TOPT(sizeof (*topt)));
52810639SDarren.Reed@Sun.COM
52910639SDarren.Reed@Sun.COM topt->len = tunit->OPT_length;
53010639SDarren.Reed@Sun.COM topt->level = SOL_PACKET;
53110639SDarren.Reed@Sun.COM topt->name = PACKET_AUXDATA;
53210639SDarren.Reed@Sun.COM topt->status = 0;
53310639SDarren.Reed@Sun.COM /*
53410639SDarren.Reed@Sun.COM * libpcap doesn't seem to use any other field,
53510639SDarren.Reed@Sun.COM * so it isn't clear how they should be filled in.
53610639SDarren.Reed@Sun.COM */
53710639SDarren.Reed@Sun.COM aux->tp_vlan_vci = hdr.mhi_tci;
53810639SDarren.Reed@Sun.COM }
53910639SDarren.Reed@Sun.COM
54010639SDarren.Reed@Sun.COM linkb(mp0, mp);
54110639SDarren.Reed@Sun.COM
54210639SDarren.Reed@Sun.COM ps->ps_upcalls->su_recv(ps->ps_upper, mp0, hdr.mhi_pktsize, 0,
54310639SDarren.Reed@Sun.COM &error, NULL);
54410639SDarren.Reed@Sun.COM
54510639SDarren.Reed@Sun.COM if (error == 0) {
54610639SDarren.Reed@Sun.COM ps->ps_stats.tp_packets++;
54710639SDarren.Reed@Sun.COM ks_stats.kp_recv_ok.value.ui64++;
54810639SDarren.Reed@Sun.COM } else {
54910639SDarren.Reed@Sun.COM mutex_enter(&ps->ps_lock);
55010639SDarren.Reed@Sun.COM if (error == ENOSPC) {
55110639SDarren.Reed@Sun.COM ps->ps_upcalls->su_recv(ps->ps_upper, NULL, 0, 0,
55210639SDarren.Reed@Sun.COM &error, NULL);
55310639SDarren.Reed@Sun.COM if (error == ENOSPC)
55410639SDarren.Reed@Sun.COM ps->ps_flow_ctrld = B_TRUE;
55510639SDarren.Reed@Sun.COM }
55610639SDarren.Reed@Sun.COM mutex_exit(&ps->ps_lock);
55710639SDarren.Reed@Sun.COM ps->ps_stats.tp_drops++;
55810639SDarren.Reed@Sun.COM ks_stats.kp_recv_fail.value.ui64++;
55910639SDarren.Reed@Sun.COM }
56010639SDarren.Reed@Sun.COM }
56110639SDarren.Reed@Sun.COM
56210639SDarren.Reed@Sun.COM /*
56310639SDarren.Reed@Sun.COM * Bind a PF_PACKET socket to a network interface.
56410639SDarren.Reed@Sun.COM *
56510639SDarren.Reed@Sun.COM * The default operation of this bind() is to place the socket (and thus the
56610639SDarren.Reed@Sun.COM * network interface) into promiscuous mode. It is then up to the application
56710639SDarren.Reed@Sun.COM * to turn that down by issuing the relevant ioctls, if desired.
56810639SDarren.Reed@Sun.COM */
56910639SDarren.Reed@Sun.COM /* ARGSUSED */
57010639SDarren.Reed@Sun.COM static int
sdpfp_bind(sock_lower_handle_t handle,struct sockaddr * addr,socklen_t addrlen,struct cred * cred)57110639SDarren.Reed@Sun.COM sdpfp_bind(sock_lower_handle_t handle, struct sockaddr *addr,
57210639SDarren.Reed@Sun.COM socklen_t addrlen, struct cred *cred)
57310639SDarren.Reed@Sun.COM {
57410639SDarren.Reed@Sun.COM struct sockaddr_ll *addr_ll, *sol;
57510639SDarren.Reed@Sun.COM mac_client_handle_t mch;
57610639SDarren.Reed@Sun.COM struct pfpsock *ps;
57710639SDarren.Reed@Sun.COM mac_handle_t mh;
57810639SDarren.Reed@Sun.COM int error;
57910639SDarren.Reed@Sun.COM
58010639SDarren.Reed@Sun.COM ps = (struct pfpsock *)handle;
58110639SDarren.Reed@Sun.COM if (ps->ps_bound)
58210639SDarren.Reed@Sun.COM return (EINVAL);
58310639SDarren.Reed@Sun.COM
58410639SDarren.Reed@Sun.COM addr_ll = (struct sockaddr_ll *)addr;
58510639SDarren.Reed@Sun.COM
58610639SDarren.Reed@Sun.COM error = pfp_open_index(addr_ll->sll_ifindex, &mh, &mch, cred);
58710639SDarren.Reed@Sun.COM if (error != 0)
58810639SDarren.Reed@Sun.COM return (error);
58910639SDarren.Reed@Sun.COM /*
59010639SDarren.Reed@Sun.COM * Ensure that each socket is only bound once.
59110639SDarren.Reed@Sun.COM */
59210639SDarren.Reed@Sun.COM mutex_enter(&ps->ps_lock);
59310639SDarren.Reed@Sun.COM if (ps->ps_mh != 0) {
59410639SDarren.Reed@Sun.COM mutex_exit(&ps->ps_lock);
59510639SDarren.Reed@Sun.COM pfp_close(mh, mch);
59610639SDarren.Reed@Sun.COM return (EADDRINUSE);
59710639SDarren.Reed@Sun.COM }
59810639SDarren.Reed@Sun.COM ps->ps_mh = mh;
59910639SDarren.Reed@Sun.COM ps->ps_mch = mch;
60010639SDarren.Reed@Sun.COM mutex_exit(&ps->ps_lock);
60110639SDarren.Reed@Sun.COM
60210639SDarren.Reed@Sun.COM /*
60310639SDarren.Reed@Sun.COM * Cache all of the information from bind so that it's in an easy
60410639SDarren.Reed@Sun.COM * place to get at when packets are received.
60510639SDarren.Reed@Sun.COM */
60610639SDarren.Reed@Sun.COM sol = (struct sockaddr_ll *)&ps->ps_sock;
60710639SDarren.Reed@Sun.COM sol->sll_family = AF_PACKET;
60810639SDarren.Reed@Sun.COM sol->sll_ifindex = addr_ll->sll_ifindex;
60910639SDarren.Reed@Sun.COM sol->sll_protocol = addr_ll->sll_protocol;
61010639SDarren.Reed@Sun.COM sol->sll_halen = mac_addr_len(ps->ps_mh);
61110639SDarren.Reed@Sun.COM mac_unicast_primary_get(ps->ps_mh, sol->sll_addr);
61210639SDarren.Reed@Sun.COM mac_sdu_get(ps->ps_mh, NULL, &ps->ps_max_sdu);
61310639SDarren.Reed@Sun.COM ps->ps_linkid = addr_ll->sll_ifindex;
61410639SDarren.Reed@Sun.COM
61510639SDarren.Reed@Sun.COM error = mac_promisc_add(ps->ps_mch, MAC_CLIENT_PROMISC_ALL,
61610639SDarren.Reed@Sun.COM pfp_packet, ps, &ps->ps_phd, MAC_PROMISC_FLAGS_VLAN_TAG_STRIP);
61710639SDarren.Reed@Sun.COM if (error == 0) {
61810639SDarren.Reed@Sun.COM ps->ps_promisc = MAC_CLIENT_PROMISC_ALL;
61910639SDarren.Reed@Sun.COM ps->ps_bound = B_TRUE;
62010639SDarren.Reed@Sun.COM }
62110639SDarren.Reed@Sun.COM
62210639SDarren.Reed@Sun.COM return (error);
62310639SDarren.Reed@Sun.COM }
62410639SDarren.Reed@Sun.COM
62510639SDarren.Reed@Sun.COM /* ARGSUSED */
62610639SDarren.Reed@Sun.COM static void
sdpfp_activate(sock_lower_handle_t lower,sock_upper_handle_t upper,sock_upcalls_t * upcalls,int flags,cred_t * cred)62710639SDarren.Reed@Sun.COM sdpfp_activate(sock_lower_handle_t lower, sock_upper_handle_t upper,
62810639SDarren.Reed@Sun.COM sock_upcalls_t *upcalls, int flags, cred_t *cred)
62910639SDarren.Reed@Sun.COM {
63010639SDarren.Reed@Sun.COM struct pfpsock *ps;
63110639SDarren.Reed@Sun.COM
63210639SDarren.Reed@Sun.COM ps = (struct pfpsock *)lower;
63310639SDarren.Reed@Sun.COM ps->ps_upper = upper;
63410639SDarren.Reed@Sun.COM ps->ps_upcalls = upcalls;
63510639SDarren.Reed@Sun.COM }
63610639SDarren.Reed@Sun.COM
63710639SDarren.Reed@Sun.COM /*
63810639SDarren.Reed@Sun.COM * This module only implements getting socket options for the new socket
63910639SDarren.Reed@Sun.COM * option level (SOL_PACKET) that it introduces. All other requests are
64010639SDarren.Reed@Sun.COM * passed back to the sockfs layer.
64110639SDarren.Reed@Sun.COM */
64210639SDarren.Reed@Sun.COM /* ARGSUSED */
64310639SDarren.Reed@Sun.COM static int
sdpfp_getsockopt(sock_lower_handle_t handle,int level,int option_name,void * optval,socklen_t * optlenp,struct cred * cred)64410639SDarren.Reed@Sun.COM sdpfp_getsockopt(sock_lower_handle_t handle, int level, int option_name,
64510639SDarren.Reed@Sun.COM void *optval, socklen_t *optlenp, struct cred *cred)
64610639SDarren.Reed@Sun.COM {
64710639SDarren.Reed@Sun.COM int error = 0;
64810639SDarren.Reed@Sun.COM
64910639SDarren.Reed@Sun.COM switch (level) {
65010639SDarren.Reed@Sun.COM case SOL_PACKET :
65110639SDarren.Reed@Sun.COM error = pfp_getpacket_sockopt(handle, option_name, optval,
65210639SDarren.Reed@Sun.COM optlenp);
65310639SDarren.Reed@Sun.COM break;
65410639SDarren.Reed@Sun.COM default :
65510639SDarren.Reed@Sun.COM /*
65610639SDarren.Reed@Sun.COM * If sockfs code receives this error in return from the
65710639SDarren.Reed@Sun.COM * getsockopt downcall it handles the option locally, if
65810639SDarren.Reed@Sun.COM * it can. This implements SO_RCVBUF, etc.
65910639SDarren.Reed@Sun.COM */
66010639SDarren.Reed@Sun.COM error = ENOPROTOOPT;
66110639SDarren.Reed@Sun.COM break;
66210639SDarren.Reed@Sun.COM }
66310639SDarren.Reed@Sun.COM
66410639SDarren.Reed@Sun.COM return (error);
66510639SDarren.Reed@Sun.COM }
66610639SDarren.Reed@Sun.COM
66710639SDarren.Reed@Sun.COM /*
66810639SDarren.Reed@Sun.COM * PF_PACKET supports setting socket options at only two levels:
66910639SDarren.Reed@Sun.COM * SOL_SOCKET and SOL_PACKET.
67010639SDarren.Reed@Sun.COM */
67110639SDarren.Reed@Sun.COM /* ARGSUSED */
67210639SDarren.Reed@Sun.COM static int
sdpfp_setsockopt(sock_lower_handle_t handle,int level,int option_name,const void * optval,socklen_t optlen,struct cred * cred)67310639SDarren.Reed@Sun.COM sdpfp_setsockopt(sock_lower_handle_t handle, int level, int option_name,
67410639SDarren.Reed@Sun.COM const void *optval, socklen_t optlen, struct cred *cred)
67510639SDarren.Reed@Sun.COM {
67610639SDarren.Reed@Sun.COM int error = 0;
67710639SDarren.Reed@Sun.COM
67810639SDarren.Reed@Sun.COM switch (level) {
67910639SDarren.Reed@Sun.COM case SOL_SOCKET :
68010639SDarren.Reed@Sun.COM error = pfp_setsocket_sockopt(handle, option_name, optval,
68110639SDarren.Reed@Sun.COM optlen);
68210639SDarren.Reed@Sun.COM break;
68310639SDarren.Reed@Sun.COM case SOL_PACKET :
68410639SDarren.Reed@Sun.COM error = pfp_setpacket_sockopt(handle, option_name, optval,
68510639SDarren.Reed@Sun.COM optlen);
68610639SDarren.Reed@Sun.COM break;
68710639SDarren.Reed@Sun.COM default :
68810639SDarren.Reed@Sun.COM error = EINVAL;
68910639SDarren.Reed@Sun.COM break;
69010639SDarren.Reed@Sun.COM }
69110639SDarren.Reed@Sun.COM
69210639SDarren.Reed@Sun.COM return (error);
69310639SDarren.Reed@Sun.COM }
69410639SDarren.Reed@Sun.COM
69510639SDarren.Reed@Sun.COM /*
69610639SDarren.Reed@Sun.COM * This function is incredibly inefficient for sending any packet that
69710639SDarren.Reed@Sun.COM * comes with a msghdr asking to be sent to an interface to which the
69810639SDarren.Reed@Sun.COM * socket has not been bound. Some possibilities here are keeping a
69910639SDarren.Reed@Sun.COM * cache of all open mac's and mac_client's, for the purpose of sending,
70010639SDarren.Reed@Sun.COM * and closing them after some amount of inactivity. Clearly, applications
70110639SDarren.Reed@Sun.COM * should not be written to use one socket for multiple interfaces if
70210639SDarren.Reed@Sun.COM * performance is desired with the code as is.
70310639SDarren.Reed@Sun.COM */
70410639SDarren.Reed@Sun.COM /* ARGSUSED */
70510639SDarren.Reed@Sun.COM static int
sdpfp_senduio(sock_lower_handle_t handle,struct uio * uiop,struct nmsghdr * msg,struct cred * cred)70610639SDarren.Reed@Sun.COM sdpfp_senduio(sock_lower_handle_t handle, struct uio *uiop,
70710639SDarren.Reed@Sun.COM struct nmsghdr *msg, struct cred *cred)
70810639SDarren.Reed@Sun.COM {
70910639SDarren.Reed@Sun.COM struct sockaddr_ll *sol;
71010639SDarren.Reed@Sun.COM mac_client_handle_t mch;
71110639SDarren.Reed@Sun.COM struct pfpsock *ps;
71210639SDarren.Reed@Sun.COM boolean_t new_open;
71310639SDarren.Reed@Sun.COM mac_handle_t mh;
71410639SDarren.Reed@Sun.COM size_t mpsize;
71510639SDarren.Reed@Sun.COM uint_t maxsdu;
71610639SDarren.Reed@Sun.COM mblk_t *mp0;
71710639SDarren.Reed@Sun.COM mblk_t *mp;
71810639SDarren.Reed@Sun.COM int error;
71910639SDarren.Reed@Sun.COM
72010639SDarren.Reed@Sun.COM mp = NULL;
72110639SDarren.Reed@Sun.COM mp0 = NULL;
72210639SDarren.Reed@Sun.COM new_open = B_FALSE;
72310639SDarren.Reed@Sun.COM ps = (struct pfpsock *)handle;
72410639SDarren.Reed@Sun.COM mh = ps->ps_mh;
72510639SDarren.Reed@Sun.COM mch = ps->ps_mch;
72610639SDarren.Reed@Sun.COM maxsdu = ps->ps_max_sdu;
72710639SDarren.Reed@Sun.COM
72810639SDarren.Reed@Sun.COM sol = (struct sockaddr_ll *)msg->msg_name;
72910639SDarren.Reed@Sun.COM if (sol == NULL) {
73010639SDarren.Reed@Sun.COM /*
73110639SDarren.Reed@Sun.COM * If no sockaddr_ll has been provided with the send call,
73210639SDarren.Reed@Sun.COM * use the one constructed when the socket was bound to an
73310639SDarren.Reed@Sun.COM * interface and fail if it hasn't been bound.
73410639SDarren.Reed@Sun.COM */
73510639SDarren.Reed@Sun.COM if (!ps->ps_bound) {
73610639SDarren.Reed@Sun.COM ks_stats.kp_send_unbound.value.ui64++;
73710639SDarren.Reed@Sun.COM return (EPROTO);
73810639SDarren.Reed@Sun.COM }
73910639SDarren.Reed@Sun.COM sol = (struct sockaddr_ll *)&ps->ps_sock;
74010639SDarren.Reed@Sun.COM } else {
74110639SDarren.Reed@Sun.COM /*
74210639SDarren.Reed@Sun.COM * Verify the sockaddr_ll message passed down before using
74310639SDarren.Reed@Sun.COM * it to send a packet out with. If it refers to an interface
74410639SDarren.Reed@Sun.COM * that has not been bound, it is necessary to open it.
74510639SDarren.Reed@Sun.COM */
74610639SDarren.Reed@Sun.COM struct sockaddr_ll *sll;
74710639SDarren.Reed@Sun.COM
74810639SDarren.Reed@Sun.COM if (msg->msg_namelen < sizeof (struct sockaddr_ll)) {
74910639SDarren.Reed@Sun.COM ks_stats.kp_send_short_msg.value.ui64++;
75010639SDarren.Reed@Sun.COM return (EINVAL);
75110639SDarren.Reed@Sun.COM }
75210639SDarren.Reed@Sun.COM
75310639SDarren.Reed@Sun.COM if (sol->sll_family != AF_PACKET) {
75410639SDarren.Reed@Sun.COM ks_stats.kp_send_wrong_family.value.ui64++;
75510639SDarren.Reed@Sun.COM return (EAFNOSUPPORT);
75610639SDarren.Reed@Sun.COM }
75710639SDarren.Reed@Sun.COM
75810639SDarren.Reed@Sun.COM sll = (struct sockaddr_ll *)&ps->ps_sock;
75910639SDarren.Reed@Sun.COM if (sol->sll_ifindex != sll->sll_ifindex) {
76010639SDarren.Reed@Sun.COM error = pfp_open_index(sol->sll_ifindex, &mh, &mch,
76110639SDarren.Reed@Sun.COM cred);
76210639SDarren.Reed@Sun.COM if (error != 0) {
76310639SDarren.Reed@Sun.COM ks_stats.kp_send_open_fail.value.ui64++;
76410639SDarren.Reed@Sun.COM return (error);
76510639SDarren.Reed@Sun.COM }
76610639SDarren.Reed@Sun.COM mac_sdu_get(mh, NULL, &maxsdu);
76710639SDarren.Reed@Sun.COM new_open = B_TRUE;
76810639SDarren.Reed@Sun.COM }
76910639SDarren.Reed@Sun.COM }
77010639SDarren.Reed@Sun.COM
77110639SDarren.Reed@Sun.COM mpsize = uiop->uio_resid;
77210639SDarren.Reed@Sun.COM if (mpsize > maxsdu) {
77310639SDarren.Reed@Sun.COM ks_stats.kp_send_too_big.value.ui64++;
77410639SDarren.Reed@Sun.COM error = EMSGSIZE;
77510639SDarren.Reed@Sun.COM goto done;
77610639SDarren.Reed@Sun.COM }
77710639SDarren.Reed@Sun.COM
77810639SDarren.Reed@Sun.COM if ((mp = allocb(mpsize, BPRI_HI)) == NULL) {
77910639SDarren.Reed@Sun.COM ks_stats.kp_send_alloc_fail.value.ui64++;
78010639SDarren.Reed@Sun.COM error = ENOBUFS;
78110639SDarren.Reed@Sun.COM goto done;
78210639SDarren.Reed@Sun.COM }
78310639SDarren.Reed@Sun.COM
78410639SDarren.Reed@Sun.COM mp->b_wptr = mp->b_rptr + mpsize;
78510639SDarren.Reed@Sun.COM error = uiomove(mp->b_rptr, mpsize, UIO_WRITE, uiop);
78610639SDarren.Reed@Sun.COM if (error != 0) {
78710639SDarren.Reed@Sun.COM ks_stats.kp_send_uiomove_fail.value.ui64++;
78810639SDarren.Reed@Sun.COM goto done;
78910639SDarren.Reed@Sun.COM }
79010639SDarren.Reed@Sun.COM
79110639SDarren.Reed@Sun.COM if (ps->ps_type == SOCK_DGRAM) {
79210639SDarren.Reed@Sun.COM mp0 = mac_header(mh, sol->sll_addr, sol->sll_protocol, mp, 0);
79310639SDarren.Reed@Sun.COM if (mp0 == NULL) {
79410639SDarren.Reed@Sun.COM ks_stats.kp_send_no_memory.value.ui64++;
79510639SDarren.Reed@Sun.COM error = ENOBUFS;
79610639SDarren.Reed@Sun.COM goto done;
79710639SDarren.Reed@Sun.COM }
79810639SDarren.Reed@Sun.COM linkb(mp0, mp);
79910639SDarren.Reed@Sun.COM mp = mp0;
80010639SDarren.Reed@Sun.COM }
80110639SDarren.Reed@Sun.COM
80210639SDarren.Reed@Sun.COM /*
80310639SDarren.Reed@Sun.COM * As this is sending datagrams and no promise is made about
80410639SDarren.Reed@Sun.COM * how or if a packet will be sent/delivered, no effort is to
80510639SDarren.Reed@Sun.COM * be expended in recovering from a situation where the packet
80610639SDarren.Reed@Sun.COM * cannot be sent - it is just dropped.
80710639SDarren.Reed@Sun.COM */
80810639SDarren.Reed@Sun.COM error = mac_tx(mch, mp, 0, MAC_DROP_ON_NO_DESC, NULL);
80910639SDarren.Reed@Sun.COM if (error == 0) {
81010639SDarren.Reed@Sun.COM mp = NULL;
81110639SDarren.Reed@Sun.COM ks_stats.kp_send_ok.value.ui64++;
81210639SDarren.Reed@Sun.COM } else {
81310639SDarren.Reed@Sun.COM ks_stats.kp_send_failed.value.ui64++;
81410639SDarren.Reed@Sun.COM }
81510639SDarren.Reed@Sun.COM
81610639SDarren.Reed@Sun.COM done:
81710639SDarren.Reed@Sun.COM
81810639SDarren.Reed@Sun.COM if (new_open) {
81910639SDarren.Reed@Sun.COM ASSERT(mch != ps->ps_mch);
82010639SDarren.Reed@Sun.COM ASSERT(mh != ps->ps_mh);
82110639SDarren.Reed@Sun.COM pfp_close(mh, mch);
82210639SDarren.Reed@Sun.COM }
82310639SDarren.Reed@Sun.COM if (mp != NULL)
82410639SDarren.Reed@Sun.COM freemsg(mp);
82510639SDarren.Reed@Sun.COM
82610639SDarren.Reed@Sun.COM return (error);
82710639SDarren.Reed@Sun.COM
82810639SDarren.Reed@Sun.COM }
82910639SDarren.Reed@Sun.COM
83010639SDarren.Reed@Sun.COM /*
83110639SDarren.Reed@Sun.COM * There's no use of a lock here, or at the bottom of pfp_packet() where
83210639SDarren.Reed@Sun.COM * ps_flow_ctrld is set to true, because in a situation where these two
83310639SDarren.Reed@Sun.COM * are racing to set the flag one way or the other, the end result is
83410639SDarren.Reed@Sun.COM * going to be ultimately determined by the scheduler anyway - which of
83510639SDarren.Reed@Sun.COM * the two threads gets the lock first? In such an operational environment,
83610639SDarren.Reed@Sun.COM * we've got packets arriving too fast to be delt with so packets are going
83710639SDarren.Reed@Sun.COM * to be dropped. Grabbing a lock just makes the drop more expensive.
83810639SDarren.Reed@Sun.COM */
83910639SDarren.Reed@Sun.COM static void
sdpfp_clr_flowctrl(sock_lower_handle_t handle)84010639SDarren.Reed@Sun.COM sdpfp_clr_flowctrl(sock_lower_handle_t handle)
84110639SDarren.Reed@Sun.COM {
84210639SDarren.Reed@Sun.COM struct pfpsock *ps;
84310639SDarren.Reed@Sun.COM
84410639SDarren.Reed@Sun.COM ps = (struct pfpsock *)handle;
84510639SDarren.Reed@Sun.COM
84610639SDarren.Reed@Sun.COM mutex_enter(&ps->ps_lock);
84710639SDarren.Reed@Sun.COM ps->ps_flow_ctrld = B_FALSE;
84810639SDarren.Reed@Sun.COM mutex_exit(&ps->ps_lock);
84910639SDarren.Reed@Sun.COM }
85010639SDarren.Reed@Sun.COM
85110639SDarren.Reed@Sun.COM /*
85210639SDarren.Reed@Sun.COM * The implementation of this ioctl() handler is intended to function
85310639SDarren.Reed@Sun.COM * in the absence of a bind() being made before it is called. Thus the
85410639SDarren.Reed@Sun.COM * function calls mac_open() itself to provide a handle
85510639SDarren.Reed@Sun.COM * This function is structured like this:
85610639SDarren.Reed@Sun.COM * - determine the linkid for the interface being targetted
85710639SDarren.Reed@Sun.COM * - open the interface with said linkid
85810639SDarren.Reed@Sun.COM * - perform ioctl
85910639SDarren.Reed@Sun.COM * - copy results back to caller
86010639SDarren.Reed@Sun.COM *
86110639SDarren.Reed@Sun.COM * The ioctls that interact with interface flags have been implented below
86210639SDarren.Reed@Sun.COM * to assume that the interface is always up and running (IFF_RUNNING) and
86310639SDarren.Reed@Sun.COM * to use the state of this socket to determine whether or not the network
86410639SDarren.Reed@Sun.COM * interface is in promiscuous mode. Thus an ioctl to get the interface flags
86510639SDarren.Reed@Sun.COM * of an interface that has been put in promiscuous mode by another socket
86610639SDarren.Reed@Sun.COM * (in the same program or different), will not report that status.
86710639SDarren.Reed@Sun.COM */
86810639SDarren.Reed@Sun.COM /* ARGSUSED */
86910639SDarren.Reed@Sun.COM static int
sdpfp_ioctl(sock_lower_handle_t handle,int cmd,intptr_t arg,int mod,int32_t * rval,struct cred * cr)87010639SDarren.Reed@Sun.COM sdpfp_ioctl(sock_lower_handle_t handle, int cmd, intptr_t arg, int mod,
87110639SDarren.Reed@Sun.COM int32_t *rval, struct cred *cr)
87210639SDarren.Reed@Sun.COM {
87310639SDarren.Reed@Sun.COM #if defined(_SYSCALL32)
87410639SDarren.Reed@Sun.COM struct timeval32 tival;
87510639SDarren.Reed@Sun.COM #else
87610639SDarren.Reed@Sun.COM struct timeval tival;
87710639SDarren.Reed@Sun.COM #endif
87810639SDarren.Reed@Sun.COM mac_client_promisc_type_t mtype;
879*13095SDarren.Reed@Oracle.COM struct sockaddr_dl *sock;
88010639SDarren.Reed@Sun.COM datalink_id_t linkid;
88110639SDarren.Reed@Sun.COM struct lifreq lifreq;
88210639SDarren.Reed@Sun.COM struct ifreq ifreq;
88310639SDarren.Reed@Sun.COM struct pfpsock *ps;
88410639SDarren.Reed@Sun.COM mac_handle_t mh;
88510639SDarren.Reed@Sun.COM timespec_t tv;
88610639SDarren.Reed@Sun.COM int error;
88710639SDarren.Reed@Sun.COM
88810639SDarren.Reed@Sun.COM switch (cmd) {
88910639SDarren.Reed@Sun.COM /*
89010639SDarren.Reed@Sun.COM * ioctls that work on "struct lifreq"
89110639SDarren.Reed@Sun.COM */
89210639SDarren.Reed@Sun.COM case SIOCSLIFFLAGS :
89310639SDarren.Reed@Sun.COM case SIOCGLIFINDEX :
89410639SDarren.Reed@Sun.COM case SIOCGLIFFLAGS :
89510639SDarren.Reed@Sun.COM case SIOCGLIFMTU :
896*13095SDarren.Reed@Oracle.COM case SIOCGLIFHWADDR :
89710639SDarren.Reed@Sun.COM error = pfp_lifreq_getlinkid(arg, &lifreq, &linkid);
89810639SDarren.Reed@Sun.COM if (error != 0)
89910639SDarren.Reed@Sun.COM return (error);
90010639SDarren.Reed@Sun.COM break;
90110639SDarren.Reed@Sun.COM
90210639SDarren.Reed@Sun.COM /*
90310639SDarren.Reed@Sun.COM * ioctls that work on "struct ifreq".
90410639SDarren.Reed@Sun.COM * Not all of these have a "struct lifreq" partner, for example
90510639SDarren.Reed@Sun.COM * SIOCGIFHWADDR, for the simple reason that the logical interface
90610639SDarren.Reed@Sun.COM * does not have a hardware address.
90710639SDarren.Reed@Sun.COM */
90810639SDarren.Reed@Sun.COM case SIOCSIFFLAGS :
90910639SDarren.Reed@Sun.COM case SIOCGIFINDEX :
91010639SDarren.Reed@Sun.COM case SIOCGIFFLAGS :
91110639SDarren.Reed@Sun.COM case SIOCGIFMTU :
91210639SDarren.Reed@Sun.COM case SIOCGIFHWADDR :
91310639SDarren.Reed@Sun.COM error = pfp_ifreq_getlinkid(arg, &ifreq, &linkid);
91410639SDarren.Reed@Sun.COM if (error != 0)
91510639SDarren.Reed@Sun.COM return (error);
91610639SDarren.Reed@Sun.COM break;
91710639SDarren.Reed@Sun.COM }
91810639SDarren.Reed@Sun.COM
91910639SDarren.Reed@Sun.COM error = mac_open_by_linkid(linkid, &mh);
92010639SDarren.Reed@Sun.COM if (error != 0)
92110639SDarren.Reed@Sun.COM return (error);
92210639SDarren.Reed@Sun.COM
92310639SDarren.Reed@Sun.COM ps = (struct pfpsock *)handle;
92410639SDarren.Reed@Sun.COM
92510639SDarren.Reed@Sun.COM switch (cmd) {
92610639SDarren.Reed@Sun.COM case SIOCGLIFINDEX :
92710639SDarren.Reed@Sun.COM lifreq.lifr_index = linkid;
92810639SDarren.Reed@Sun.COM break;
92910639SDarren.Reed@Sun.COM
93010639SDarren.Reed@Sun.COM case SIOCGIFINDEX :
93110639SDarren.Reed@Sun.COM ifreq.ifr_index = linkid;
93210639SDarren.Reed@Sun.COM break;
93310639SDarren.Reed@Sun.COM
93410639SDarren.Reed@Sun.COM case SIOCGIFFLAGS :
93510639SDarren.Reed@Sun.COM ifreq.ifr_flags = IFF_RUNNING;
93610639SDarren.Reed@Sun.COM if (ps->ps_promisc == MAC_CLIENT_PROMISC_ALL)
93710639SDarren.Reed@Sun.COM ifreq.ifr_flags |= IFF_PROMISC;
93810639SDarren.Reed@Sun.COM break;
93910639SDarren.Reed@Sun.COM
94010639SDarren.Reed@Sun.COM case SIOCGLIFFLAGS :
94110639SDarren.Reed@Sun.COM lifreq.lifr_flags = IFF_RUNNING;
94210639SDarren.Reed@Sun.COM if (ps->ps_promisc == MAC_CLIENT_PROMISC_ALL)
94310639SDarren.Reed@Sun.COM lifreq.lifr_flags |= IFF_PROMISC;
94410639SDarren.Reed@Sun.COM break;
94510639SDarren.Reed@Sun.COM
94610639SDarren.Reed@Sun.COM case SIOCSIFFLAGS :
94710639SDarren.Reed@Sun.COM if (linkid != ps->ps_linkid) {
94810639SDarren.Reed@Sun.COM error = EINVAL;
94910639SDarren.Reed@Sun.COM } else {
95010639SDarren.Reed@Sun.COM if ((ifreq.ifr_flags & IFF_PROMISC) != 0)
95110639SDarren.Reed@Sun.COM mtype = MAC_CLIENT_PROMISC_ALL;
95210639SDarren.Reed@Sun.COM else
95310639SDarren.Reed@Sun.COM mtype = MAC_CLIENT_PROMISC_FILTERED;
95410639SDarren.Reed@Sun.COM error = pfp_set_promisc(ps, mtype);
95510639SDarren.Reed@Sun.COM }
95610639SDarren.Reed@Sun.COM break;
95710639SDarren.Reed@Sun.COM
95810639SDarren.Reed@Sun.COM case SIOCSLIFFLAGS :
95910639SDarren.Reed@Sun.COM if (linkid != ps->ps_linkid) {
96010639SDarren.Reed@Sun.COM error = EINVAL;
96110639SDarren.Reed@Sun.COM } else {
96210639SDarren.Reed@Sun.COM if ((lifreq.lifr_flags & IFF_PROMISC) != 0)
96310639SDarren.Reed@Sun.COM mtype = MAC_CLIENT_PROMISC_ALL;
96410639SDarren.Reed@Sun.COM else
96510639SDarren.Reed@Sun.COM mtype = MAC_CLIENT_PROMISC_FILTERED;
96610639SDarren.Reed@Sun.COM error = pfp_set_promisc(ps, mtype);
96710639SDarren.Reed@Sun.COM }
96810639SDarren.Reed@Sun.COM break;
96910639SDarren.Reed@Sun.COM
97010639SDarren.Reed@Sun.COM case SIOCGIFMTU :
97110639SDarren.Reed@Sun.COM mac_sdu_get(mh, NULL, &ifreq.ifr_mtu);
97210639SDarren.Reed@Sun.COM break;
97310639SDarren.Reed@Sun.COM
97410639SDarren.Reed@Sun.COM case SIOCGLIFMTU :
97510639SDarren.Reed@Sun.COM mac_sdu_get(mh, NULL, &lifreq.lifr_mtu);
97610639SDarren.Reed@Sun.COM break;
97710639SDarren.Reed@Sun.COM
97810639SDarren.Reed@Sun.COM case SIOCGIFHWADDR :
979*13095SDarren.Reed@Oracle.COM if (mac_addr_len(mh) > sizeof (ifreq.ifr_addr.sa_data)) {
980*13095SDarren.Reed@Oracle.COM error = EPFNOSUPPORT;
981*13095SDarren.Reed@Oracle.COM break;
982*13095SDarren.Reed@Oracle.COM }
983*13095SDarren.Reed@Oracle.COM
984*13095SDarren.Reed@Oracle.COM if (mac_addr_len(mh) == 0) {
985*13095SDarren.Reed@Oracle.COM (void) memset(ifreq.ifr_addr.sa_data, 0,
986*13095SDarren.Reed@Oracle.COM sizeof (ifreq.ifr_addr.sa_data));
987*13095SDarren.Reed@Oracle.COM } else {
988*13095SDarren.Reed@Oracle.COM mac_unicast_primary_get(mh,
989*13095SDarren.Reed@Oracle.COM (uint8_t *)ifreq.ifr_addr.sa_data);
990*13095SDarren.Reed@Oracle.COM }
991*13095SDarren.Reed@Oracle.COM
992*13095SDarren.Reed@Oracle.COM /*
993*13095SDarren.Reed@Oracle.COM * The behaviour here in setting sa_family is consistent
994*13095SDarren.Reed@Oracle.COM * with what applications such as tcpdump would expect
995*13095SDarren.Reed@Oracle.COM * for a Linux PF_PACKET socket.
996*13095SDarren.Reed@Oracle.COM */
99710639SDarren.Reed@Sun.COM ifreq.ifr_addr.sa_family = pfp_dl_to_arphrd(mac_type(mh));
99810639SDarren.Reed@Sun.COM break;
99910639SDarren.Reed@Sun.COM
1000*13095SDarren.Reed@Oracle.COM case SIOCGLIFHWADDR :
1001*13095SDarren.Reed@Oracle.COM lifreq.lifr_type = 0;
1002*13095SDarren.Reed@Oracle.COM sock = (struct sockaddr_dl *)&lifreq.lifr_addr;
1003*13095SDarren.Reed@Oracle.COM
1004*13095SDarren.Reed@Oracle.COM if (mac_addr_len(mh) > sizeof (sock->sdl_data)) {
1005*13095SDarren.Reed@Oracle.COM error = EPFNOSUPPORT;
1006*13095SDarren.Reed@Oracle.COM break;
1007*13095SDarren.Reed@Oracle.COM }
1008*13095SDarren.Reed@Oracle.COM
1009*13095SDarren.Reed@Oracle.COM /*
1010*13095SDarren.Reed@Oracle.COM * Fill in the sockaddr_dl with link layer details. Of note,
1011*13095SDarren.Reed@Oracle.COM * the index is returned as 0 for a couple of reasons:
1012*13095SDarren.Reed@Oracle.COM * (1) there is no public API that uses or requires it
1013*13095SDarren.Reed@Oracle.COM * (2) the MAC index is currently 32bits and sdl_index is 16.
1014*13095SDarren.Reed@Oracle.COM */
1015*13095SDarren.Reed@Oracle.COM sock->sdl_family = AF_LINK;
1016*13095SDarren.Reed@Oracle.COM sock->sdl_index = 0;
1017*13095SDarren.Reed@Oracle.COM sock->sdl_type = mac_type(mh);
1018*13095SDarren.Reed@Oracle.COM sock->sdl_nlen = 0;
1019*13095SDarren.Reed@Oracle.COM sock->sdl_alen = mac_addr_len(mh);
1020*13095SDarren.Reed@Oracle.COM sock->sdl_slen = 0;
1021*13095SDarren.Reed@Oracle.COM if (mac_addr_len(mh) == 0) {
1022*13095SDarren.Reed@Oracle.COM (void) memset(sock->sdl_data, 0,
1023*13095SDarren.Reed@Oracle.COM sizeof (sock->sdl_data));
1024*13095SDarren.Reed@Oracle.COM } else {
1025*13095SDarren.Reed@Oracle.COM mac_unicast_primary_get(mh, (uint8_t *)sock->sdl_data);
1026*13095SDarren.Reed@Oracle.COM }
1027*13095SDarren.Reed@Oracle.COM break;
1028*13095SDarren.Reed@Oracle.COM
102910639SDarren.Reed@Sun.COM case SIOCGSTAMP :
103010639SDarren.Reed@Sun.COM (void) gethrestime(&tv);
103110639SDarren.Reed@Sun.COM tival.tv_sec = (time_t)tv.tv_sec;
103210639SDarren.Reed@Sun.COM tival.tv_usec = tv.tv_nsec / 1000;
103310639SDarren.Reed@Sun.COM error = ddi_copyout(&tival, (void *)arg, sizeof (tival), 0);
103410639SDarren.Reed@Sun.COM break;
103510639SDarren.Reed@Sun.COM
103610639SDarren.Reed@Sun.COM default :
103710639SDarren.Reed@Sun.COM break;
103810639SDarren.Reed@Sun.COM }
103910639SDarren.Reed@Sun.COM
104010639SDarren.Reed@Sun.COM mac_close(mh);
104110639SDarren.Reed@Sun.COM
104210639SDarren.Reed@Sun.COM if (error == 0) {
104310639SDarren.Reed@Sun.COM /*
104410639SDarren.Reed@Sun.COM * Only the "GET" ioctls need to copy data back to userace.
104510639SDarren.Reed@Sun.COM */
104610639SDarren.Reed@Sun.COM switch (cmd) {
104710639SDarren.Reed@Sun.COM case SIOCGLIFINDEX :
104810639SDarren.Reed@Sun.COM case SIOCGLIFFLAGS :
104910639SDarren.Reed@Sun.COM case SIOCGLIFMTU :
1050*13095SDarren.Reed@Oracle.COM case SIOCGLIFHWADDR :
105110639SDarren.Reed@Sun.COM error = ddi_copyout(&lifreq, (void *)arg,
105210639SDarren.Reed@Sun.COM sizeof (lifreq), 0);
105310639SDarren.Reed@Sun.COM break;
105410639SDarren.Reed@Sun.COM
105510639SDarren.Reed@Sun.COM case SIOCGIFINDEX :
105610639SDarren.Reed@Sun.COM case SIOCGIFFLAGS :
105710639SDarren.Reed@Sun.COM case SIOCGIFMTU :
105810639SDarren.Reed@Sun.COM case SIOCGIFHWADDR :
105910639SDarren.Reed@Sun.COM error = ddi_copyout(&ifreq, (void *)arg,
106010639SDarren.Reed@Sun.COM sizeof (ifreq), 0);
106110639SDarren.Reed@Sun.COM break;
106210639SDarren.Reed@Sun.COM default :
106310639SDarren.Reed@Sun.COM break;
106410639SDarren.Reed@Sun.COM }
106510639SDarren.Reed@Sun.COM }
106610639SDarren.Reed@Sun.COM
106710639SDarren.Reed@Sun.COM return (error);
106810639SDarren.Reed@Sun.COM }
106910639SDarren.Reed@Sun.COM
107010639SDarren.Reed@Sun.COM /*
107110639SDarren.Reed@Sun.COM * Closing the socket requires that all open references to network
107210639SDarren.Reed@Sun.COM * interfaces be closed.
107310639SDarren.Reed@Sun.COM */
107410639SDarren.Reed@Sun.COM /* ARGSUSED */
107510639SDarren.Reed@Sun.COM static int
sdpfp_close(sock_lower_handle_t handle,int flag,struct cred * cr)107610639SDarren.Reed@Sun.COM sdpfp_close(sock_lower_handle_t handle, int flag, struct cred *cr)
107710639SDarren.Reed@Sun.COM {
107810639SDarren.Reed@Sun.COM struct pfpsock *ps = (struct pfpsock *)handle;
107910639SDarren.Reed@Sun.COM
108010639SDarren.Reed@Sun.COM if (ps->ps_phd != 0) {
108110639SDarren.Reed@Sun.COM mac_promisc_remove(ps->ps_phd);
108210639SDarren.Reed@Sun.COM ps->ps_phd = 0;
108310639SDarren.Reed@Sun.COM }
108410639SDarren.Reed@Sun.COM
108510639SDarren.Reed@Sun.COM if (ps->ps_mch != 0) {
108610639SDarren.Reed@Sun.COM mac_client_close(ps->ps_mch, 0);
108710639SDarren.Reed@Sun.COM ps->ps_mch = 0;
108810639SDarren.Reed@Sun.COM }
108910639SDarren.Reed@Sun.COM
109010639SDarren.Reed@Sun.COM if (ps->ps_mh != 0) {
109110639SDarren.Reed@Sun.COM mac_close(ps->ps_mh);
109210639SDarren.Reed@Sun.COM ps->ps_mh = 0;
109310639SDarren.Reed@Sun.COM }
109410639SDarren.Reed@Sun.COM
109510639SDarren.Reed@Sun.COM kmem_free(ps, sizeof (*ps));
109610639SDarren.Reed@Sun.COM
109710639SDarren.Reed@Sun.COM return (0);
109810639SDarren.Reed@Sun.COM }
109910639SDarren.Reed@Sun.COM
110010639SDarren.Reed@Sun.COM /* ************************************************************************* */
110110639SDarren.Reed@Sun.COM
110210639SDarren.Reed@Sun.COM /*
110310639SDarren.Reed@Sun.COM * Given a pointer (arg) to a "struct ifreq" (potentially in user space),
110410639SDarren.Reed@Sun.COM * determine the linkid for the interface name stored in that structure.
110510639SDarren.Reed@Sun.COM * name is used as a buffer so that we can ensure a trailing \0 is appended
110610639SDarren.Reed@Sun.COM * to the name safely.
110710639SDarren.Reed@Sun.COM */
110810639SDarren.Reed@Sun.COM static int
pfp_ifreq_getlinkid(intptr_t arg,struct ifreq * ifreqp,datalink_id_t * linkidp)110910639SDarren.Reed@Sun.COM pfp_ifreq_getlinkid(intptr_t arg, struct ifreq *ifreqp,
111010639SDarren.Reed@Sun.COM datalink_id_t *linkidp)
111110639SDarren.Reed@Sun.COM {
111210639SDarren.Reed@Sun.COM char name[IFNAMSIZ + 1];
111310639SDarren.Reed@Sun.COM int error;
111410639SDarren.Reed@Sun.COM
111510639SDarren.Reed@Sun.COM if (ddi_copyin((void *)arg, ifreqp, sizeof (*ifreqp), 0) != 0)
111610639SDarren.Reed@Sun.COM return (EFAULT);
111710639SDarren.Reed@Sun.COM
111810639SDarren.Reed@Sun.COM (void) strlcpy(name, ifreqp->ifr_name, sizeof (name));
111910639SDarren.Reed@Sun.COM
112010639SDarren.Reed@Sun.COM error = dls_mgmt_get_linkid(name, linkidp);
112110639SDarren.Reed@Sun.COM if (error != 0)
112210639SDarren.Reed@Sun.COM error = dls_devnet_macname2linkid(name, linkidp);
112310639SDarren.Reed@Sun.COM
112410639SDarren.Reed@Sun.COM return (error);
112510639SDarren.Reed@Sun.COM }
112610639SDarren.Reed@Sun.COM
112710639SDarren.Reed@Sun.COM /*
112810639SDarren.Reed@Sun.COM * Given a pointer (arg) to a "struct lifreq" (potentially in user space),
112910639SDarren.Reed@Sun.COM * determine the linkid for the interface name stored in that structure.
113010639SDarren.Reed@Sun.COM * name is used as a buffer so that we can ensure a trailing \0 is appended
113110639SDarren.Reed@Sun.COM * to the name safely.
113210639SDarren.Reed@Sun.COM */
113310639SDarren.Reed@Sun.COM static int
pfp_lifreq_getlinkid(intptr_t arg,struct lifreq * lifreqp,datalink_id_t * linkidp)113410639SDarren.Reed@Sun.COM pfp_lifreq_getlinkid(intptr_t arg, struct lifreq *lifreqp,
113510639SDarren.Reed@Sun.COM datalink_id_t *linkidp)
113610639SDarren.Reed@Sun.COM {
113710639SDarren.Reed@Sun.COM char name[LIFNAMSIZ + 1];
113810639SDarren.Reed@Sun.COM int error;
113910639SDarren.Reed@Sun.COM
114010639SDarren.Reed@Sun.COM if (ddi_copyin((void *)arg, lifreqp, sizeof (*lifreqp), 0) != 0)
114110639SDarren.Reed@Sun.COM return (EFAULT);
114210639SDarren.Reed@Sun.COM
114310639SDarren.Reed@Sun.COM (void) strlcpy(name, lifreqp->lifr_name, sizeof (name));
114410639SDarren.Reed@Sun.COM
114510639SDarren.Reed@Sun.COM error = dls_mgmt_get_linkid(name, linkidp);
114610639SDarren.Reed@Sun.COM if (error != 0)
114710639SDarren.Reed@Sun.COM error = dls_devnet_macname2linkid(name, linkidp);
114810639SDarren.Reed@Sun.COM
114910639SDarren.Reed@Sun.COM return (error);
115010639SDarren.Reed@Sun.COM }
115110639SDarren.Reed@Sun.COM
115210639SDarren.Reed@Sun.COM /*
115310639SDarren.Reed@Sun.COM * Although there are several new SOL_PACKET options that can be set and
115410639SDarren.Reed@Sun.COM * are specific to this implementation of PF_PACKET, the current API does
115510639SDarren.Reed@Sun.COM * not support doing a get on them to retrieve accompanying status. Thus
115610639SDarren.Reed@Sun.COM * it is only currently possible to use SOL_PACKET with getsockopt to
115710639SDarren.Reed@Sun.COM * retrieve statistical information. This remains consistant with the
115810639SDarren.Reed@Sun.COM * Linux API at the time of writing.
115910639SDarren.Reed@Sun.COM */
116010639SDarren.Reed@Sun.COM static int
pfp_getpacket_sockopt(sock_lower_handle_t handle,int option_name,void * optval,socklen_t * optlenp)116110639SDarren.Reed@Sun.COM pfp_getpacket_sockopt(sock_lower_handle_t handle, int option_name,
116210639SDarren.Reed@Sun.COM void *optval, socklen_t *optlenp)
116310639SDarren.Reed@Sun.COM {
116410639SDarren.Reed@Sun.COM struct pfpsock *ps;
116510639SDarren.Reed@Sun.COM int error = 0;
116610639SDarren.Reed@Sun.COM
116710639SDarren.Reed@Sun.COM ps = (struct pfpsock *)handle;
116810639SDarren.Reed@Sun.COM
116910639SDarren.Reed@Sun.COM switch (option_name) {
117010639SDarren.Reed@Sun.COM case PACKET_STATISTICS :
117110639SDarren.Reed@Sun.COM if (*optlenp < sizeof (ps->ps_stats)) {
117210639SDarren.Reed@Sun.COM error = EINVAL;
117310639SDarren.Reed@Sun.COM break;
117410639SDarren.Reed@Sun.COM }
117510639SDarren.Reed@Sun.COM *optlenp = sizeof (ps->ps_stats);
117610639SDarren.Reed@Sun.COM bcopy(&ps->ps_stats, optval, sizeof (ps->ps_stats));
117710639SDarren.Reed@Sun.COM break;
117810639SDarren.Reed@Sun.COM default :
117910639SDarren.Reed@Sun.COM error = EINVAL;
118010639SDarren.Reed@Sun.COM break;
118110639SDarren.Reed@Sun.COM }
118210639SDarren.Reed@Sun.COM
118310639SDarren.Reed@Sun.COM return (error);
118410639SDarren.Reed@Sun.COM }
118510639SDarren.Reed@Sun.COM
118610639SDarren.Reed@Sun.COM /*
118710639SDarren.Reed@Sun.COM * The SOL_PACKET level for socket options supports three options,
118810639SDarren.Reed@Sun.COM * PACKET_ADD_MEMBERSHIP, PACKET_DROP_MEMBERSHIP and PACKET_AUXDATA.
118910639SDarren.Reed@Sun.COM * This function is responsible for mapping the two socket options
119010639SDarren.Reed@Sun.COM * that manage multicast membership into the appropriate internal
119110639SDarren.Reed@Sun.COM * function calls to bring the option into effect. Whilst direct
119210639SDarren.Reed@Sun.COM * changes to the multicast membership (ADD/DROP) groups is handled
119310639SDarren.Reed@Sun.COM * by calls directly into the mac module, changes to the promiscuos
119410639SDarren.Reed@Sun.COM * mode are vectored through pfp_set_promisc() so that the logic for
119510639SDarren.Reed@Sun.COM * managing the promiscuous mode is in one place.
119610639SDarren.Reed@Sun.COM */
119710639SDarren.Reed@Sun.COM /* ARGSUSED */
119810639SDarren.Reed@Sun.COM static int
pfp_setpacket_sockopt(sock_lower_handle_t handle,int option_name,const void * optval,socklen_t optlen)119910639SDarren.Reed@Sun.COM pfp_setpacket_sockopt(sock_lower_handle_t handle, int option_name,
120010639SDarren.Reed@Sun.COM const void *optval, socklen_t optlen)
120110639SDarren.Reed@Sun.COM {
120210639SDarren.Reed@Sun.COM struct packet_mreq mreq;
120310639SDarren.Reed@Sun.COM struct pfpsock *ps;
120410639SDarren.Reed@Sun.COM int error = 0;
120510639SDarren.Reed@Sun.COM int opt;
120610639SDarren.Reed@Sun.COM
120710639SDarren.Reed@Sun.COM ps = (struct pfpsock *)handle;
120810639SDarren.Reed@Sun.COM if (!ps->ps_bound)
120910639SDarren.Reed@Sun.COM return (EPROTO);
121010639SDarren.Reed@Sun.COM
121110639SDarren.Reed@Sun.COM if ((option_name == PACKET_ADD_MEMBERSHIP) ||
121210639SDarren.Reed@Sun.COM (option_name == PACKET_DROP_MEMBERSHIP)) {
121310639SDarren.Reed@Sun.COM if (!ps->ps_bound)
121410639SDarren.Reed@Sun.COM return (EPROTO);
121510639SDarren.Reed@Sun.COM bcopy(optval, &mreq, sizeof (mreq));
121610639SDarren.Reed@Sun.COM if (ps->ps_linkid != mreq.mr_ifindex)
121710639SDarren.Reed@Sun.COM return (EINVAL);
121810639SDarren.Reed@Sun.COM }
121910639SDarren.Reed@Sun.COM
122010639SDarren.Reed@Sun.COM switch (option_name) {
122110639SDarren.Reed@Sun.COM case PACKET_ADD_MEMBERSHIP :
122210639SDarren.Reed@Sun.COM switch (mreq.mr_type) {
122310639SDarren.Reed@Sun.COM case PACKET_MR_MULTICAST :
1224*13095SDarren.Reed@Oracle.COM if (mreq.mr_alen !=
1225*13095SDarren.Reed@Oracle.COM ((struct sockaddr_ll *)&ps->ps_sock)->sll_halen)
1226*13095SDarren.Reed@Oracle.COM return (EINVAL);
1227*13095SDarren.Reed@Oracle.COM
122810639SDarren.Reed@Sun.COM error = mac_multicast_add(ps->ps_mch, mreq.mr_address);
122910639SDarren.Reed@Sun.COM break;
123010639SDarren.Reed@Sun.COM
123110639SDarren.Reed@Sun.COM case PACKET_MR_PROMISC :
123210639SDarren.Reed@Sun.COM error = pfp_set_promisc(ps, MAC_CLIENT_PROMISC_ALL);
123310639SDarren.Reed@Sun.COM break;
123410639SDarren.Reed@Sun.COM
123510639SDarren.Reed@Sun.COM case PACKET_MR_ALLMULTI :
123610639SDarren.Reed@Sun.COM error = pfp_set_promisc(ps, MAC_CLIENT_PROMISC_MULTI);
123710639SDarren.Reed@Sun.COM break;
123810639SDarren.Reed@Sun.COM }
123910639SDarren.Reed@Sun.COM break;
124010639SDarren.Reed@Sun.COM
124110639SDarren.Reed@Sun.COM case PACKET_DROP_MEMBERSHIP :
124210639SDarren.Reed@Sun.COM switch (mreq.mr_type) {
124310639SDarren.Reed@Sun.COM case PACKET_MR_MULTICAST :
1244*13095SDarren.Reed@Oracle.COM if (mreq.mr_alen !=
1245*13095SDarren.Reed@Oracle.COM ((struct sockaddr_ll *)&ps->ps_sock)->sll_halen)
1246*13095SDarren.Reed@Oracle.COM return (EINVAL);
1247*13095SDarren.Reed@Oracle.COM
124810639SDarren.Reed@Sun.COM mac_multicast_remove(ps->ps_mch, mreq.mr_address);
124910639SDarren.Reed@Sun.COM break;
125010639SDarren.Reed@Sun.COM
125110639SDarren.Reed@Sun.COM case PACKET_MR_PROMISC :
125210639SDarren.Reed@Sun.COM if (ps->ps_promisc != MAC_CLIENT_PROMISC_ALL)
125310639SDarren.Reed@Sun.COM return (EINVAL);
125410639SDarren.Reed@Sun.COM error = pfp_set_promisc(ps,
125510639SDarren.Reed@Sun.COM MAC_CLIENT_PROMISC_FILTERED);
125610639SDarren.Reed@Sun.COM break;
125710639SDarren.Reed@Sun.COM
125810639SDarren.Reed@Sun.COM case PACKET_MR_ALLMULTI :
125910639SDarren.Reed@Sun.COM if (ps->ps_promisc != MAC_CLIENT_PROMISC_MULTI)
126010639SDarren.Reed@Sun.COM return (EINVAL);
126110639SDarren.Reed@Sun.COM error = pfp_set_promisc(ps,
126210639SDarren.Reed@Sun.COM MAC_CLIENT_PROMISC_FILTERED);
126310639SDarren.Reed@Sun.COM break;
126410639SDarren.Reed@Sun.COM }
126510639SDarren.Reed@Sun.COM break;
126610639SDarren.Reed@Sun.COM
126710639SDarren.Reed@Sun.COM case PACKET_AUXDATA :
126810639SDarren.Reed@Sun.COM if (optlen == sizeof (int)) {
126910639SDarren.Reed@Sun.COM opt = *(int *)optval;
127010639SDarren.Reed@Sun.COM ps->ps_auxdata = (opt != 0);
127110639SDarren.Reed@Sun.COM } else {
127210639SDarren.Reed@Sun.COM error = EINVAL;
127310639SDarren.Reed@Sun.COM }
127410639SDarren.Reed@Sun.COM break;
127510639SDarren.Reed@Sun.COM default :
127610639SDarren.Reed@Sun.COM error = EINVAL;
127710639SDarren.Reed@Sun.COM break;
127810639SDarren.Reed@Sun.COM }
127910639SDarren.Reed@Sun.COM
128010639SDarren.Reed@Sun.COM return (error);
128110639SDarren.Reed@Sun.COM }
128210639SDarren.Reed@Sun.COM
128310639SDarren.Reed@Sun.COM /*
128410639SDarren.Reed@Sun.COM * There are only two special setsockopt's for SOL_SOCKET with PF_PACKET:
128510639SDarren.Reed@Sun.COM * SO_ATTACH_FILTER and SO_DETACH_FILTER. All other setsockopt requests
128610639SDarren.Reed@Sun.COM * that are for SOL_SOCKET are passed back to the socket layer for its
128710639SDarren.Reed@Sun.COM * generic implementation.
128810639SDarren.Reed@Sun.COM *
128910639SDarren.Reed@Sun.COM * Both of these setsockopt values are candidates for being handled by the
129010639SDarren.Reed@Sun.COM * socket layer itself in future, however this requires understanding how
129110639SDarren.Reed@Sun.COM * they would interact with all other sockets.
129210639SDarren.Reed@Sun.COM */
129310639SDarren.Reed@Sun.COM static int
pfp_setsocket_sockopt(sock_lower_handle_t handle,int option_name,const void * optval,socklen_t optlen)129410639SDarren.Reed@Sun.COM pfp_setsocket_sockopt(sock_lower_handle_t handle, int option_name,
129510639SDarren.Reed@Sun.COM const void *optval, socklen_t optlen)
129610639SDarren.Reed@Sun.COM {
129710639SDarren.Reed@Sun.COM struct bpf_program prog;
129810639SDarren.Reed@Sun.COM struct bpf_insn *fcode;
129910639SDarren.Reed@Sun.COM struct pfpsock *ps;
130010639SDarren.Reed@Sun.COM int error = 0;
130110639SDarren.Reed@Sun.COM int size;
130210639SDarren.Reed@Sun.COM
130310639SDarren.Reed@Sun.COM ps = (struct pfpsock *)handle;
130410639SDarren.Reed@Sun.COM
130510639SDarren.Reed@Sun.COM switch (option_name) {
130610639SDarren.Reed@Sun.COM case SO_ATTACH_FILTER :
130710639SDarren.Reed@Sun.COM #ifdef _LP64
130810639SDarren.Reed@Sun.COM if (optlen == sizeof (struct bpf_program32)) {
130910639SDarren.Reed@Sun.COM struct bpf_program32 prog32;
131010639SDarren.Reed@Sun.COM
131110639SDarren.Reed@Sun.COM bcopy(optval, &prog32, sizeof (prog32));
131210639SDarren.Reed@Sun.COM prog.bf_len = prog32.bf_len;
131310639SDarren.Reed@Sun.COM prog.bf_insns = (void *)(uint64_t)prog32.bf_insns;
131410639SDarren.Reed@Sun.COM } else
131510639SDarren.Reed@Sun.COM #endif
131610639SDarren.Reed@Sun.COM if (optlen == sizeof (struct bpf_program)) {
131710639SDarren.Reed@Sun.COM bcopy(optval, &prog, sizeof (prog));
131810639SDarren.Reed@Sun.COM } else if (optlen != sizeof (struct bpf_program)) {
131910639SDarren.Reed@Sun.COM return (EINVAL);
132010639SDarren.Reed@Sun.COM }
132110639SDarren.Reed@Sun.COM
132210639SDarren.Reed@Sun.COM size = prog.bf_len * sizeof (*prog.bf_insns);
132310639SDarren.Reed@Sun.COM fcode = kmem_alloc(size, KM_SLEEP);
132410639SDarren.Reed@Sun.COM if (ddi_copyin(prog.bf_insns, fcode, size, 0) != 0) {
132510639SDarren.Reed@Sun.COM kmem_free(fcode, size);
132610639SDarren.Reed@Sun.COM return (EFAULT);
132710639SDarren.Reed@Sun.COM }
132810639SDarren.Reed@Sun.COM
132910639SDarren.Reed@Sun.COM if (bpf_validate(fcode, (int)prog.bf_len)) {
133010639SDarren.Reed@Sun.COM rw_enter(&ps->ps_bpflock, RW_WRITER);
133110639SDarren.Reed@Sun.COM pfp_release_bpf(ps);
133210639SDarren.Reed@Sun.COM ps->ps_bpf.bf_insns = fcode;
133310639SDarren.Reed@Sun.COM ps->ps_bpf.bf_len = size;
133410639SDarren.Reed@Sun.COM rw_exit(&ps->ps_bpflock);
133510639SDarren.Reed@Sun.COM
133610639SDarren.Reed@Sun.COM return (0);
133710639SDarren.Reed@Sun.COM }
133810639SDarren.Reed@Sun.COM kmem_free(fcode, size);
133910639SDarren.Reed@Sun.COM error = EINVAL;
134010639SDarren.Reed@Sun.COM break;
134110639SDarren.Reed@Sun.COM
134210639SDarren.Reed@Sun.COM case SO_DETACH_FILTER :
134310639SDarren.Reed@Sun.COM pfp_release_bpf(ps);
134410639SDarren.Reed@Sun.COM break;
134510639SDarren.Reed@Sun.COM default :
134610639SDarren.Reed@Sun.COM /*
134710639SDarren.Reed@Sun.COM * If sockfs code receives this error in return from the
134810639SDarren.Reed@Sun.COM * getsockopt downcall it handles the option locally, if
134910639SDarren.Reed@Sun.COM * it can. This implements SO_RCVBUF, etc.
135010639SDarren.Reed@Sun.COM */
135110639SDarren.Reed@Sun.COM error = ENOPROTOOPT;
135210639SDarren.Reed@Sun.COM break;
135310639SDarren.Reed@Sun.COM }
135410639SDarren.Reed@Sun.COM
135510639SDarren.Reed@Sun.COM return (error);
135610639SDarren.Reed@Sun.COM }
135710639SDarren.Reed@Sun.COM
135810639SDarren.Reed@Sun.COM /*
135910639SDarren.Reed@Sun.COM * pfp_open_index is an internal function used to open a MAC device by
136010639SDarren.Reed@Sun.COM * its index. Both a mac_handle_t and mac_client_handle_t are acquired
136110639SDarren.Reed@Sun.COM * because some of the interfaces provided by the mac layer require either
136210639SDarren.Reed@Sun.COM * only the mac_handle_t or both it and mac_handle_t.
136310639SDarren.Reed@Sun.COM *
136410639SDarren.Reed@Sun.COM * Whilst inside the kernel we can access data structures supporting any
136510639SDarren.Reed@Sun.COM * zone, access to interfaces from non-global zones is restricted to those
136610639SDarren.Reed@Sun.COM * interfaces (if any) that are exclusively assigned to a zone.
136710639SDarren.Reed@Sun.COM */
136810639SDarren.Reed@Sun.COM static int
pfp_open_index(int index,mac_handle_t * mhp,mac_client_handle_t * mcip,cred_t * cred)136910639SDarren.Reed@Sun.COM pfp_open_index(int index, mac_handle_t *mhp, mac_client_handle_t *mcip,
137010639SDarren.Reed@Sun.COM cred_t *cred)
137110639SDarren.Reed@Sun.COM {
137210639SDarren.Reed@Sun.COM mac_client_handle_t mch;
137310639SDarren.Reed@Sun.COM zoneid_t ifzoneid;
137410639SDarren.Reed@Sun.COM mac_handle_t mh;
137510639SDarren.Reed@Sun.COM zoneid_t zoneid;
137610639SDarren.Reed@Sun.COM int error;
137710639SDarren.Reed@Sun.COM
137810639SDarren.Reed@Sun.COM mh = 0;
137910639SDarren.Reed@Sun.COM mch = 0;
138010639SDarren.Reed@Sun.COM error = mac_open_by_linkid(index, &mh);
138110639SDarren.Reed@Sun.COM if (error != 0)
138210639SDarren.Reed@Sun.COM goto bad_open;
138310639SDarren.Reed@Sun.COM
138410639SDarren.Reed@Sun.COM error = mac_client_open(mh, &mch, NULL,
138510639SDarren.Reed@Sun.COM MAC_OPEN_FLAGS_USE_DATALINK_NAME);
138610639SDarren.Reed@Sun.COM if (error != 0)
138710639SDarren.Reed@Sun.COM goto bad_open;
138810639SDarren.Reed@Sun.COM
138910639SDarren.Reed@Sun.COM zoneid = crgetzoneid(cred);
139010639SDarren.Reed@Sun.COM if (zoneid != GLOBAL_ZONEID) {
139110639SDarren.Reed@Sun.COM mac_perim_handle_t perim;
139210639SDarren.Reed@Sun.COM
139310639SDarren.Reed@Sun.COM mac_perim_enter_by_mh(mh, &perim);
139410639SDarren.Reed@Sun.COM error = dls_link_getzid(mac_client_name(mch), &ifzoneid);
139510639SDarren.Reed@Sun.COM mac_perim_exit(perim);
139610639SDarren.Reed@Sun.COM if (error != 0)
139710639SDarren.Reed@Sun.COM goto bad_open;
139810639SDarren.Reed@Sun.COM if (ifzoneid != zoneid) {
139910639SDarren.Reed@Sun.COM error = EACCES;
140010639SDarren.Reed@Sun.COM goto bad_open;
140110639SDarren.Reed@Sun.COM }
140210639SDarren.Reed@Sun.COM }
140310639SDarren.Reed@Sun.COM
140410639SDarren.Reed@Sun.COM *mcip = mch;
140510639SDarren.Reed@Sun.COM *mhp = mh;
140610639SDarren.Reed@Sun.COM
140710639SDarren.Reed@Sun.COM return (0);
140810639SDarren.Reed@Sun.COM bad_open:
140910639SDarren.Reed@Sun.COM if (mch != 0)
141010639SDarren.Reed@Sun.COM mac_client_close(mch, 0);
141110639SDarren.Reed@Sun.COM if (mh != 0)
141210639SDarren.Reed@Sun.COM mac_close(mh);
141310639SDarren.Reed@Sun.COM return (error);
141410639SDarren.Reed@Sun.COM }
141510639SDarren.Reed@Sun.COM
141610639SDarren.Reed@Sun.COM static void
pfp_close(mac_handle_t mh,mac_client_handle_t mch)141710639SDarren.Reed@Sun.COM pfp_close(mac_handle_t mh, mac_client_handle_t mch)
141810639SDarren.Reed@Sun.COM {
141910639SDarren.Reed@Sun.COM mac_client_close(mch, 0);
142010639SDarren.Reed@Sun.COM mac_close(mh);
142110639SDarren.Reed@Sun.COM }
142210639SDarren.Reed@Sun.COM
142310639SDarren.Reed@Sun.COM /*
142410639SDarren.Reed@Sun.COM * The purpose of this function is to provide a single place where we free
142510639SDarren.Reed@Sun.COM * the loaded BPF program and reset all pointers/counters associated with
142610639SDarren.Reed@Sun.COM * it.
142710639SDarren.Reed@Sun.COM */
142810639SDarren.Reed@Sun.COM static void
pfp_release_bpf(struct pfpsock * ps)142910639SDarren.Reed@Sun.COM pfp_release_bpf(struct pfpsock *ps)
143010639SDarren.Reed@Sun.COM {
143110639SDarren.Reed@Sun.COM if (ps->ps_bpf.bf_len != 0) {
143210639SDarren.Reed@Sun.COM kmem_free(ps->ps_bpf.bf_insns, ps->ps_bpf.bf_len);
143310639SDarren.Reed@Sun.COM ps->ps_bpf.bf_len = 0;
143410639SDarren.Reed@Sun.COM ps->ps_bpf.bf_insns = NULL;
143510639SDarren.Reed@Sun.COM }
143610639SDarren.Reed@Sun.COM }
143710639SDarren.Reed@Sun.COM
143810639SDarren.Reed@Sun.COM /*
143910639SDarren.Reed@Sun.COM * Set the promiscuous mode of a network interface.
144010639SDarren.Reed@Sun.COM * This function only calls the mac layer when there is a change to the
144110639SDarren.Reed@Sun.COM * status of a network interface's promiscous mode. Tracking of how many
144210639SDarren.Reed@Sun.COM * sockets have the network interface in promiscuous mode, and thus the
144310639SDarren.Reed@Sun.COM * control over the physical device's status, is left to the mac layer.
144410639SDarren.Reed@Sun.COM */
144510639SDarren.Reed@Sun.COM static int
pfp_set_promisc(struct pfpsock * ps,mac_client_promisc_type_t turnon)144610639SDarren.Reed@Sun.COM pfp_set_promisc(struct pfpsock *ps, mac_client_promisc_type_t turnon)
144710639SDarren.Reed@Sun.COM {
144810639SDarren.Reed@Sun.COM int error = 0;
144910639SDarren.Reed@Sun.COM int flags;
145010639SDarren.Reed@Sun.COM
145110639SDarren.Reed@Sun.COM /*
145210639SDarren.Reed@Sun.COM * There are 4 combinations of turnon/ps_promisc.
145310639SDarren.Reed@Sun.COM * This if handles 2 (both false, both true) and the if() below
145410639SDarren.Reed@Sun.COM * handles the remaining one - when change is required.
145510639SDarren.Reed@Sun.COM */
145610639SDarren.Reed@Sun.COM if (turnon == ps->ps_promisc)
145710639SDarren.Reed@Sun.COM return (error);
145810639SDarren.Reed@Sun.COM
145910639SDarren.Reed@Sun.COM if (ps->ps_phd != 0) {
146010639SDarren.Reed@Sun.COM mac_promisc_remove(ps->ps_phd);
146110639SDarren.Reed@Sun.COM ps->ps_phd = 0;
146210639SDarren.Reed@Sun.COM
146310639SDarren.Reed@Sun.COM /*
146410639SDarren.Reed@Sun.COM * ps_promisc is set here in case the call to mac_promisc_add
146510639SDarren.Reed@Sun.COM * fails: leaving it to indicate that the interface is still
146610639SDarren.Reed@Sun.COM * in some sort of promiscuous mode is false.
146710639SDarren.Reed@Sun.COM */
146810639SDarren.Reed@Sun.COM if (ps->ps_promisc != MAC_CLIENT_PROMISC_FILTERED) {
146910639SDarren.Reed@Sun.COM ps->ps_promisc = MAC_CLIENT_PROMISC_FILTERED;
147010639SDarren.Reed@Sun.COM flags = MAC_PROMISC_FLAGS_NO_PHYS;
147110639SDarren.Reed@Sun.COM } else {
147210639SDarren.Reed@Sun.COM flags = 0;
147310639SDarren.Reed@Sun.COM }
147410639SDarren.Reed@Sun.COM flags |= MAC_PROMISC_FLAGS_VLAN_TAG_STRIP;
147510639SDarren.Reed@Sun.COM }
147610639SDarren.Reed@Sun.COM
147710639SDarren.Reed@Sun.COM error = mac_promisc_add(ps->ps_mch, turnon, pfp_packet, ps,
147810639SDarren.Reed@Sun.COM &ps->ps_phd, flags);
147910639SDarren.Reed@Sun.COM if (error == 0)
148010639SDarren.Reed@Sun.COM ps->ps_promisc = turnon;
148110639SDarren.Reed@Sun.COM
148210639SDarren.Reed@Sun.COM return (error);
148310639SDarren.Reed@Sun.COM }
148410639SDarren.Reed@Sun.COM
148510639SDarren.Reed@Sun.COM /*
148610639SDarren.Reed@Sun.COM * This table maps the MAC types in Solaris to the ARPHRD_* values used
1487*13095SDarren.Reed@Oracle.COM * on Linux. This is used with the SIOCGIFHWADDR/SIOCGLIFHWADDR ioctl.
1488*13095SDarren.Reed@Oracle.COM *
1489*13095SDarren.Reed@Oracle.COM * The symbols in this table are *not* pulled in from <net/if_arp.h>,
1490*13095SDarren.Reed@Oracle.COM * they are pulled from <netpacket/packet.h>, thus it acts as a source
1491*13095SDarren.Reed@Oracle.COM * of supplementary information to the ARP table.
149210639SDarren.Reed@Sun.COM */
149310639SDarren.Reed@Sun.COM static uint_t arphrd_to_dl[][2] = {
149410639SDarren.Reed@Sun.COM { ARPHRD_IEEE80211, DL_WIFI },
1495*13095SDarren.Reed@Oracle.COM { ARPHRD_TUNNEL, DL_IPV4 },
1496*13095SDarren.Reed@Oracle.COM { ARPHRD_TUNNEL, DL_IPV6 },
1497*13095SDarren.Reed@Oracle.COM { ARPHRD_TUNNEL, DL_6TO4 },
1498*13095SDarren.Reed@Oracle.COM { ARPHRD_AX25, DL_X25 },
1499*13095SDarren.Reed@Oracle.COM { ARPHRD_ATM, DL_ATM },
150010639SDarren.Reed@Sun.COM { 0, 0 }
150110639SDarren.Reed@Sun.COM };
150210639SDarren.Reed@Sun.COM
150310639SDarren.Reed@Sun.COM static int
pfp_dl_to_arphrd(int dltype)150410639SDarren.Reed@Sun.COM pfp_dl_to_arphrd(int dltype)
150510639SDarren.Reed@Sun.COM {
150610639SDarren.Reed@Sun.COM int i;
150710639SDarren.Reed@Sun.COM
150810639SDarren.Reed@Sun.COM for (i = 0; arphrd_to_dl[i][0] != 0; i++)
150910639SDarren.Reed@Sun.COM if (arphrd_to_dl[i][1] == dltype)
151010639SDarren.Reed@Sun.COM return (arphrd_to_dl[i][0]);
1511*13095SDarren.Reed@Oracle.COM return (arp_hw_type(dltype));
151210639SDarren.Reed@Sun.COM }
1513