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