1/*
2 * Copyright (c) 2000-2011 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28/*
29 * Copyright (c) 1982, 1986, 1993
30 *	The Regents of the University of California.  All rights reserved.
31 *
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
34 * are met:
35 * 1. Redistributions of source code must retain the above copyright
36 *    notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 *    notice, this list of conditions and the following disclaimer in the
39 *    documentation and/or other materials provided with the distribution.
40 * 3. All advertising materials mentioning features or use of this software
41 *    must display the following acknowledgement:
42 *	This product includes software developed by the University of
43 *	California, Berkeley and its contributors.
44 * 4. Neither the name of the University nor the names of its contributors
45 *    may be used to endorse or promote products derived from this software
46 *    without specific prior written permission.
47 *
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
59 *
60 *	@(#)if_loop.c	8.1 (Berkeley) 6/10/93
61 * $FreeBSD: src/sys/net/if_loop.c,v 1.47.2.5 2001/07/03 11:01:41 ume Exp $
62 */
63/*
64 * NOTICE: This file was modified by SPARTA, Inc. in 2006 to introduce
65 * support for mandatory and extensible security protections.  This notice
66 * is included in support of clause 2.2 (b) of the Apple Public License,
67 * Version 2.0.
68 */
69
70/*
71 * Loopback interface driver for protocol testing and timing.
72 */
73#include "loop.h"
74#if NLOOP > 0
75
76#if NLOOP != 1
77#error "More than one loopback interface is not supported."
78#endif
79
80#include <sys/param.h>
81#include <sys/systm.h>
82#include <sys/kernel.h>
83#include <sys/mbuf.h>
84#include <sys/socket.h>
85#include <sys/sockio.h>
86#include <sys/mcache.h>
87#include <sys/sysctl.h>
88
89#include <net/if.h>
90#include <net/if_types.h>
91#include <net/route.h>
92#include <net/bpf.h>
93#include <sys/malloc.h>
94
95#if INET
96#include <netinet/in.h>
97#include <netinet/in_var.h>
98#endif
99
100#if INET6
101#if !INET
102#include <netinet/in.h>
103#endif
104#include <netinet6/in6_var.h>
105#include <netinet/ip6.h>
106#endif
107
108#include <net/dlil.h>
109#include <net/kpi_protocol.h>
110
111#if CONFIG_MACF_NET
112#include <security/mac_framework.h>
113#endif
114
115#include <pexpert/pexpert.h>
116
117#define	LOMTU		16384
118#define	LOSNDQ_MAXLEN	256
119
120#define	LO_BPF_TAP_OUT(_m) {						\
121	if (lo_statics[0].bpf_callback != NULL) {			\
122		bpf_tap_out(lo_ifp, DLT_NULL, _m,			\
123		    &((struct loopback_header *)_m->m_pkthdr.header)->protocol,\
124		    sizeof (u_int32_t));				\
125	}								\
126}
127
128#define	LO_BPF_TAP_OUT_MULTI(_m) {					\
129	if (lo_statics[0].bpf_callback != NULL) {			\
130		struct mbuf *_n;					\
131		for (_n = _m; _n != NULL; _n = _n->m_nextpkt)		\
132			LO_BPF_TAP_OUT(_n);				\
133	}								\
134}
135
136struct lo_statics_str {
137	int		bpf_mode;
138	bpf_packet_func	bpf_callback;
139};
140
141static struct lo_statics_str lo_statics[NLOOP];
142static int lo_txstart = 0;
143
144struct ifnet *lo_ifp = NULL;
145
146struct	loopback_header {
147	protocol_family_t	protocol;
148};
149
150/* Local forward declerations */
151void loopattach(void);
152static errno_t lo_demux(struct ifnet *, struct mbuf *, char *,
153    protocol_family_t *);
154#if !KPI_INTERFACE_EMBEDDED
155static errno_t lo_framer(struct ifnet *, struct mbuf **,
156    const struct sockaddr *,
157    const char *, const char *);
158#else
159static errno_t
160lo_framer(struct ifnet *, struct mbuf **, const struct sockaddr *,
161    const char *, const char *, u_int32_t *, u_int32_t *);
162#endif
163static errno_t lo_add_proto(struct ifnet *, protocol_family_t,
164    const struct ifnet_demux_desc *, u_int32_t);
165static errno_t lo_del_proto(struct ifnet *, protocol_family_t);
166static int lo_output(struct ifnet *, struct mbuf *);
167static errno_t lo_pre_enqueue(struct ifnet *, struct mbuf *);
168static void lo_start(struct ifnet *);
169static errno_t lo_pre_output(struct ifnet *, protocol_family_t, struct mbuf **,
170    const struct sockaddr *, void *, char *, char *);
171static errno_t lo_input(struct ifnet *, protocol_family_t, struct mbuf *);
172static void lo_rtrequest(int, struct rtentry *, struct sockaddr *);
173static errno_t lo_ioctl(struct ifnet *, u_long, void *);
174static errno_t lo_attach_proto(struct ifnet *, protocol_family_t);
175static void lo_reg_if_mods(void);
176static errno_t lo_set_bpf_tap(struct ifnet *, bpf_tap_mode, bpf_packet_func);
177static int sysctl_dequeue_max SYSCTL_HANDLER_ARGS;
178static int sysctl_sched_model SYSCTL_HANDLER_ARGS;
179static int sysctl_dequeue_scidx SYSCTL_HANDLER_ARGS;
180
181SYSCTL_DECL(_net_link);
182
183SYSCTL_NODE(_net_link, OID_AUTO, loopback, CTLFLAG_RW | CTLFLAG_LOCKED, 0,
184    "loopback interface");
185
186#define	LO_BW_SLEEP	10
187static u_int32_t lo_bw_sleep_usec = LO_BW_SLEEP;
188SYSCTL_UINT(_net_link_loopback, OID_AUTO, bw_sleep_usec,
189    CTLFLAG_RW | CTLFLAG_LOCKED, &lo_bw_sleep_usec, LO_BW_SLEEP, "");
190
191static u_int32_t lo_bw_measure = 0;
192SYSCTL_UINT(_net_link_loopback, OID_AUTO, bw_measure,
193    CTLFLAG_RW | CTLFLAG_LOCKED, &lo_bw_measure, 0, "");
194
195static u_int32_t lo_dequeue_max = LOSNDQ_MAXLEN;
196SYSCTL_PROC(_net_link_loopback, OID_AUTO, max_dequeue,
197    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED, &lo_dequeue_max, LOSNDQ_MAXLEN,
198    sysctl_dequeue_max, "I", "Maximum number of packets dequeued at a time");
199
200static u_int32_t lo_sched_model = IFNET_SCHED_MODEL_NORMAL;
201SYSCTL_PROC(_net_link_loopback, OID_AUTO, sched_model,
202    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED, &lo_sched_model,
203    IFNET_SCHED_MODEL_NORMAL, sysctl_sched_model, "I", "Scheduling model");
204
205static u_int32_t lo_dequeue_sc = MBUF_SC_BE;
206static int lo_dequeue_scidx = MBUF_SCIDX(MBUF_SC_BE);
207SYSCTL_PROC(_net_link_loopback, OID_AUTO, dequeue_sc,
208    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED, &lo_dequeue_scidx,
209    MBUF_SC_BE, sysctl_dequeue_scidx, "I", "Dequeue a specific SC index");
210
211static errno_t
212lo_demux(struct ifnet *ifp, struct mbuf *m, char *frame_header,
213    protocol_family_t *protocol_family)
214{
215#pragma unused(ifp, m)
216	struct loopback_header *header =
217	    (struct loopback_header *)(void *)frame_header;
218
219	*protocol_family = header->protocol;
220
221	return (0);
222}
223
224#if !KPI_INTERFACE_EMBEDDED
225static errno_t
226lo_framer(struct ifnet *ifp, struct mbuf **m, const struct sockaddr *dest,
227    const char *dest_linkaddr, const char *frame_type)
228#else
229static errno_t
230lo_framer(struct ifnet *ifp, struct mbuf **m, const struct sockaddr *dest,
231    const char *dest_linkaddr, const char *frame_type,
232    u_int32_t *prepend_len, u_int32_t *postpend_len)
233#endif
234{
235#pragma unused(ifp, dest, dest_linkaddr)
236	struct loopback_header  *header;
237
238	M_PREPEND(*m, sizeof (struct loopback_header), M_WAITOK);
239	if (*m == NULL) {
240		/* Tell caller not to try to free passed-in mbuf */
241		return (EJUSTRETURN);
242	}
243
244#if KPI_INTERFACE_EMBEDDED
245	*prepend_len = sizeof (struct loopback_header);
246	*postpend_len = 0;
247#endif /* KPI_INTERFACE_EMBEDDED */
248
249	header = mtod(*m, struct loopback_header *);
250	bcopy(frame_type, &header->protocol, sizeof (u_int32_t));
251	return (0);
252}
253
254static errno_t
255lo_add_proto(struct ifnet *interface, protocol_family_t protocol_family,
256    const struct ifnet_demux_desc *demux_array, u_int32_t demux_count)
257{
258#pragma unused(interface, protocol_family, demux_array, demux_count)
259	return (0);
260}
261
262static errno_t
263lo_del_proto(struct ifnet *ifp, protocol_family_t protocol)
264{
265#pragma unused(ifp, protocol)
266	return (0);
267}
268
269/*
270 * Output callback.
271 *
272 * This routine is called only when lo_txstart is disabled.
273 */
274static int
275lo_output(struct ifnet *ifp, struct mbuf *m_list)
276{
277	struct mbuf *m, *m_tail = NULL;
278	struct ifnet_stat_increment_param s;
279	u_int32_t cnt = 0, len = 0;
280
281	bzero(&s, sizeof(s));
282
283	for (m = m_list; m; m = m->m_nextpkt) {
284		if ((m->m_flags & M_PKTHDR) == 0)
285			panic("lo_output: no HDR");
286		cnt++;
287		len += m->m_pkthdr.len;
288
289		/*
290		 * Don't overwrite the rcvif field if it is in use.
291		 *  This is used to match multicast packets, sent looping
292		 *  back, with the appropriate group record on input.
293		 */
294		if (m->m_pkthdr.rcvif == NULL)
295			m->m_pkthdr.rcvif = ifp;
296
297		m->m_pkthdr.header = mtod(m, char *);
298		if (apple_hwcksum_tx != 0) {
299			/* loopback checksums are always OK */
300			m->m_pkthdr.csum_data = 0xffff;
301			m->m_pkthdr.csum_flags =
302			    CSUM_DATA_VALID | CSUM_PSEUDO_HDR |
303			    CSUM_IP_CHECKED | CSUM_IP_VALID;
304		}
305		m_adj(m, sizeof (struct loopback_header));
306
307		LO_BPF_TAP_OUT(m);
308		if (m->m_nextpkt == NULL) {
309			m_tail = m;
310		}
311	}
312
313	s.packets_in = cnt;
314	s.packets_out = cnt;
315	s.bytes_in = len;
316	s.bytes_out = len;
317
318	return (ifnet_input_extended(ifp, m_list, m_tail, &s));
319}
320
321/*
322 * Pre-enqueue callback.
323 *
324 * This routine is called only when lo_txstart is enabled.
325 */
326static errno_t
327lo_pre_enqueue(struct ifnet *ifp, struct mbuf *m0)
328{
329	struct mbuf *m = m0, *n;
330	int error = 0;
331
332	while (m != NULL) {
333		VERIFY((m->m_flags & M_PKTHDR));
334
335		n = m->m_nextpkt;
336		m->m_nextpkt = NULL;
337
338		/*
339		 * Don't overwrite the rcvif field if it is in use.
340		 *  This is used to match multicast packets, sent looping
341		 *  back, with the appropriate group record on input.
342		 */
343		if (m->m_pkthdr.rcvif == NULL)
344			m->m_pkthdr.rcvif = ifp;
345
346		m->m_pkthdr.header = mtod(m, char *);
347		if (apple_hwcksum_tx != 0) {
348			/* loopback checksums are always OK */
349			m->m_pkthdr.csum_data = 0xffff;
350			m->m_pkthdr.csum_flags =
351			    CSUM_DATA_VALID | CSUM_PSEUDO_HDR |
352			    CSUM_IP_CHECKED | CSUM_IP_VALID;
353		}
354		m_adj(m, sizeof (struct loopback_header));
355
356		/*
357		 * Let the callee free it in case of error,
358		 * and perform any necessary accounting.
359		 */
360		(void) ifnet_enqueue(ifp, m);
361
362		m = n;
363	}
364
365	return (error);
366}
367
368/*
369 * Start output callback.
370 *
371 * This routine is invoked by the start worker thread; because we never call
372 * it directly, there is no need do deploy any serialization mechanism other
373 * than what's already used by the worker thread, i.e. this is already single
374 * threaded.
375 *
376 * This routine is called only when lo_txstart is enabled.
377 */
378static void
379lo_start(struct ifnet *ifp)
380{
381	struct ifnet_stat_increment_param s;
382
383	bzero(&s, sizeof (s));
384
385	for (;;) {
386		struct mbuf *m = NULL, *m_tail = NULL;
387		u_int32_t cnt, len = 0;
388		int sleep_chan = 0;
389		struct timespec ts;
390
391		if (lo_sched_model == IFNET_SCHED_MODEL_NORMAL) {
392			if (ifnet_dequeue_multi(ifp, lo_dequeue_max, &m,
393			    &m_tail, &cnt, &len) != 0)
394				break;
395		} else {
396			if (ifnet_dequeue_service_class_multi(ifp,
397			    lo_dequeue_sc, lo_dequeue_max, &m,
398			    &m_tail, &cnt, &len) != 0)
399				break;
400		}
401
402		LO_BPF_TAP_OUT_MULTI(m);
403
404		if (lo_bw_measure) {
405			if (cnt >= if_bw_measure_size)
406				ifnet_transmit_burst_start(ifp, m);
407			if (lo_bw_sleep_usec > 0) {
408				bzero(&ts, sizeof(ts));
409				ts.tv_nsec = (lo_bw_sleep_usec << 10) * cnt;
410
411				/* Add msleep with timeout */
412				(void) msleep(&sleep_chan, NULL,
413				    PSOCK, "lo_start", &ts);
414			}
415			if (cnt >= if_bw_measure_size)
416				ifnet_transmit_burst_end(ifp, m_tail);
417		}
418
419		/* stats are required for extended variant */
420		s.packets_in = cnt;
421		s.packets_out = cnt;
422		s.bytes_in = len;
423		s.bytes_out = len;
424
425		(void) ifnet_input_extended(ifp, m, m_tail, &s);
426	}
427}
428
429/*
430 * This is a common pre-output route used by INET and INET6. This could
431 * (should?) be split into separate pre-output routines for each protocol.
432 */
433static errno_t
434lo_pre_output(struct ifnet *ifp, protocol_family_t protocol_family,
435    struct mbuf **m, const struct sockaddr *dst, void *route, char *frame_type,
436    char *dst_addr)
437{
438#pragma unused(ifp, dst, dst_addr)
439	struct rtentry *rt = route;
440
441	(*m)->m_flags |= M_LOOP;
442
443	if (((*m)->m_flags & M_PKTHDR) == 0)
444		panic("looutput no HDR");
445
446	if (rt != NULL) {
447		u_int32_t rt_flags = rt->rt_flags;
448		if (rt_flags & (RTF_REJECT | RTF_BLACKHOLE)) {
449			if (rt_flags & RTF_BLACKHOLE) {
450				m_freem(*m);
451				return (EJUSTRETURN);
452			} else {
453				return ((rt_flags & RTF_HOST) ?
454				    EHOSTUNREACH : ENETUNREACH);
455			}
456		}
457	}
458
459	bcopy(&protocol_family, frame_type, sizeof (protocol_family));
460
461	return (0);
462}
463
464/*
465 *  lo_input - This should work for all attached protocols that use the
466 *             ifq/schednetisr input mechanism.
467 */
468static errno_t
469lo_input(struct ifnet *ifp, protocol_family_t protocol_family, struct mbuf *m)
470{
471#pragma unused(ifp, protocol_family)
472	if (proto_input(protocol_family, m) != 0)
473		m_freem(m);
474	return (0);
475}
476
477/* ARGSUSED */
478static void
479lo_rtrequest(int cmd, struct rtentry *rt, struct sockaddr *sa)
480{
481#pragma unused(cmd, sa)
482	if (rt != NULL) {
483		RT_LOCK_ASSERT_HELD(rt);
484		rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu; /* for ISO */
485		/*
486		 * For optimal performance, the send and receive buffers
487		 * should be at least twice the MTU plus a little more for
488		 * overhead.
489		 */
490		rt->rt_rmx.rmx_recvpipe = rt->rt_rmx.rmx_sendpipe = 3 * LOMTU;
491	}
492}
493
494/*
495 * Process an ioctl request.
496 */
497static errno_t
498lo_ioctl(struct ifnet *ifp, u_long cmd, void *data)
499{
500	int error = 0;
501
502	switch (cmd) {
503
504	case SIOCSIFADDR: {		/* struct ifaddr pointer */
505		struct ifaddr *ifa = data;
506
507		ifnet_set_flags(ifp, IFF_UP|IFF_RUNNING, IFF_UP|IFF_RUNNING);
508		IFA_LOCK_SPIN(ifa);
509		ifa->ifa_rtrequest = lo_rtrequest;
510		IFA_UNLOCK(ifa);
511		/*
512		 * Everything else is done at a higher level.
513		 */
514		break;
515	}
516
517	case SIOCADDMULTI:		/* struct ifreq */
518	case SIOCDELMULTI: {		/* struct ifreq */
519		struct ifreq *ifr = data;
520
521		if (ifr == NULL) {
522			error = EAFNOSUPPORT;		/* XXX */
523			break;
524		}
525		switch (ifr->ifr_addr.sa_family) {
526
527#if INET
528		case AF_INET:
529			break;
530#endif
531#if INET6
532		case AF_INET6:
533			break;
534#endif
535
536		default:
537			error = EAFNOSUPPORT;
538			break;
539		}
540		break;
541	}
542
543	case SIOCSIFMTU: {		/* struct ifreq */
544		struct ifreq *ifr = data;
545
546		bcopy(&ifr->ifr_mtu, &ifp->if_mtu, sizeof (int));
547		break;
548	}
549
550	case SIOCSIFFLAGS:		/* struct ifreq */
551		break;
552
553	default:
554		error = EOPNOTSUPP;
555		break;
556	}
557	return (error);
558}
559#endif /* NLOOP > 0 */
560
561
562static errno_t
563lo_attach_proto(struct ifnet *ifp, protocol_family_t protocol_family)
564{
565	struct ifnet_attach_proto_param_v2	proto;
566	errno_t							result = 0;
567
568	bzero(&proto, sizeof (proto));
569	proto.input = lo_input;
570	proto.pre_output = lo_pre_output;
571
572	result = ifnet_attach_protocol_v2(ifp, protocol_family, &proto);
573
574	if (result && result != EEXIST) {
575		printf("lo_attach_proto: ifnet_attach_protocol for %u "
576		    "returned=%d\n", protocol_family, result);
577	}
578
579	return (result);
580}
581
582static void
583lo_reg_if_mods(void)
584{
585	int error;
586
587	/* Register protocol registration functions */
588	if ((error = proto_register_plumber(PF_INET,
589	    APPLE_IF_FAM_LOOPBACK, lo_attach_proto, NULL)) != 0)
590		printf("proto_register_plumber failed for AF_INET "
591		    "error=%d\n", error);
592
593	if ((error = proto_register_plumber(PF_INET6,
594	    APPLE_IF_FAM_LOOPBACK, lo_attach_proto, NULL)) != 0)
595		printf("proto_register_plumber failed for AF_INET6 "
596		    "error=%d\n", error);
597}
598
599static errno_t
600lo_set_bpf_tap(struct ifnet *ifp, bpf_tap_mode mode,
601    bpf_packet_func bpf_callback)
602{
603	VERIFY(ifp == lo_ifp);
604
605	lo_statics[0].bpf_mode = mode;
606
607	switch (mode) {
608		case BPF_TAP_DISABLE:
609		case BPF_TAP_INPUT:
610			lo_statics[0].bpf_callback = NULL;
611			break;
612
613		case BPF_TAP_OUTPUT:
614		case BPF_TAP_INPUT_OUTPUT:
615			lo_statics[0].bpf_callback = bpf_callback;
616			break;
617	}
618
619	return (0);
620}
621
622/* ARGSUSED */
623void
624loopattach(void)
625{
626	struct ifnet_init_eparams lo_init;
627	errno_t	result = 0;
628
629	PE_parse_boot_argn("lo_txstart", &lo_txstart, sizeof (lo_txstart));
630
631	lo_reg_if_mods();
632
633	lo_statics[0].bpf_callback = NULL;
634	lo_statics[0].bpf_mode = BPF_TAP_DISABLE;
635
636	bzero(&lo_init, sizeof (lo_init));
637	lo_init.ver			= IFNET_INIT_CURRENT_VERSION;
638	lo_init.len			= sizeof (lo_init);
639	lo_init.sndq_maxlen		= LOSNDQ_MAXLEN;
640	if (lo_txstart) {
641		lo_init.flags		= 0;
642		lo_init.pre_enqueue	= lo_pre_enqueue;
643		lo_init.start		= lo_start;
644		lo_init.output_sched_model = lo_sched_model;
645	} else {
646		lo_init.flags		= IFNET_INIT_LEGACY;
647		lo_init.output		= lo_output;
648	}
649	lo_init.name			= "lo";
650	lo_init.unit			= 0;
651	lo_init.family			= IFNET_FAMILY_LOOPBACK;
652	lo_init.type			= IFT_LOOP;
653	lo_init.demux			= lo_demux;
654	lo_init.add_proto		= lo_add_proto;
655	lo_init.del_proto		= lo_del_proto;
656	lo_init.framer			= lo_framer;
657	lo_init.softc			= &lo_statics[0];
658	lo_init.ioctl			= lo_ioctl;
659	lo_init.set_bpf_tap		= lo_set_bpf_tap;
660
661	result = ifnet_allocate_extended(&lo_init, &lo_ifp);
662	if (result != 0) {
663		panic("%s: couldn't allocate loopback ifnet (%d)\n",
664		    __func__, result);
665		/* NOTREACHED */
666	}
667
668	ifnet_set_mtu(lo_ifp, LOMTU);
669	ifnet_set_flags(lo_ifp, IFF_LOOPBACK | IFF_MULTICAST,
670	    IFF_LOOPBACK | IFF_MULTICAST);
671	ifnet_set_offload(lo_ifp,
672	    IFNET_CSUM_IP | IFNET_CSUM_TCP | IFNET_CSUM_UDP |
673	    IFNET_CSUM_TCPIPV6 | IFNET_CSUM_UDPIPV6 | IFNET_IPV6_FRAGMENT |
674	    IFNET_CSUM_FRAGMENT | IFNET_IP_FRAGMENT | IFNET_MULTIPAGES);
675	ifnet_set_hdrlen(lo_ifp, sizeof (struct loopback_header));
676	ifnet_set_eflags(lo_ifp, IFEF_SENDLIST, IFEF_SENDLIST);
677
678#if CONFIG_MACF_NET
679	mac_ifnet_label_init(ifp);
680#endif
681
682	result = ifnet_attach(lo_ifp, NULL);
683	if (result != 0) {
684		panic("%s: couldn't attach loopback ifnet (%d)\n",
685		    __func__, result);
686		/* NOTREACHED */
687	}
688	bpfattach(lo_ifp, DLT_NULL, sizeof (u_int32_t));
689}
690
691static int
692sysctl_dequeue_max SYSCTL_HANDLER_ARGS
693{
694#pragma unused(arg1, arg2)
695	u_int32_t i;
696	int err;
697
698	i = lo_dequeue_max;
699
700	err = sysctl_handle_int(oidp, &i, 0, req);
701	if (err != 0 || req->newptr == USER_ADDR_NULL)
702		return (err);
703
704	if (i < 1)
705		i = 1;
706	else if (i > LOSNDQ_MAXLEN)
707		i = LOSNDQ_MAXLEN;
708
709	lo_dequeue_max = i;
710
711	return (err);
712}
713
714static int
715sysctl_sched_model SYSCTL_HANDLER_ARGS
716{
717#pragma unused(arg1, arg2)
718	u_int32_t i;
719	int err;
720
721	i = lo_sched_model;
722
723	err = sysctl_handle_int(oidp, &i, 0, req);
724	if (err != 0 || req->newptr == USER_ADDR_NULL)
725		return (err);
726
727	switch (i) {
728	case IFNET_SCHED_MODEL_NORMAL:
729	case IFNET_SCHED_MODEL_DRIVER_MANAGED:
730		break;
731
732	default:
733		err = EINVAL;
734		break;
735	}
736
737	if (err == 0 && (err = ifnet_set_output_sched_model(lo_ifp, i)) == 0)
738		lo_sched_model = i;
739
740	return (err);
741}
742
743static int
744sysctl_dequeue_scidx SYSCTL_HANDLER_ARGS
745{
746#pragma unused(arg1, arg2)
747	u_int32_t i;
748	int err;
749
750	i = lo_dequeue_scidx;
751
752	err = sysctl_handle_int(oidp, &i, 0, req);
753	if (err != 0 || req->newptr == USER_ADDR_NULL)
754		return (err);
755
756	if (!MBUF_VALID_SCIDX(i))
757		return (EINVAL);
758
759	if (lo_sched_model != IFNET_SCHED_MODEL_DRIVER_MANAGED)
760		return (ENODEV);
761
762	lo_dequeue_sc = m_service_class_from_idx(i);
763	lo_dequeue_scidx = MBUF_SCIDX(lo_dequeue_sc);
764
765	return (err);
766}
767