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