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