1/* 2 * Copyright (c) 1998-2012 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/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ 29/* 30 * Copyright (c) 1982, 1986, 1993 31 * The Regents of the University of California. All rights reserved. 32 * 33 * Redistribution and use in source and binary forms, with or without 34 * modification, are permitted provided that the following conditions 35 * are met: 36 * 1. Redistributions of source code must retain the above copyright 37 * notice, this list of conditions and the following disclaimer. 38 * 2. Redistributions in binary form must reproduce the above copyright 39 * notice, this list of conditions and the following disclaimer in the 40 * documentation and/or other materials provided with the distribution. 41 * 3. All advertising materials mentioning features or use of this software 42 * must display the following acknowledgement: 43 * This product includes software developed by the University of 44 * California, Berkeley and its contributors. 45 * 4. Neither the name of the University nor the names of its contributors 46 * may be used to endorse or promote products derived from this software 47 * without specific prior written permission. 48 * 49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 52 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 59 * SUCH DAMAGE. 60 * 61 * @(#)uipc_domain.c 8.3 (Berkeley) 2/14/95 62 */ 63 64#include <sys/param.h> 65#include <sys/socket.h> 66#include <sys/protosw.h> 67#include <sys/domain.h> 68#include <sys/mcache.h> 69#include <sys/mbuf.h> 70#include <sys/time.h> 71#include <sys/kernel.h> 72#include <sys/systm.h> 73#include <sys/proc_internal.h> 74#include <sys/sysctl.h> 75#include <sys/syslog.h> 76#include <sys/queue.h> 77 78#include <net/dlil.h> 79 80#include <pexpert/pexpert.h> 81 82void init_domain(struct domain *dp) __attribute__((section("__TEXT, initcode"))); 83void prepend_domain(struct domain *dp) __attribute__((section("__TEXT, initcode"))); 84 85void pfslowtimo(void *); 86 87struct protosw *pffindprotonotype(int, int); 88struct protosw *pffindprotonotype_locked(int , int , int); 89struct domain *pffinddomain(int); 90static void net_update_uptime(void); 91 92/* 93 * Add/delete 'domain': Link structure into system list, 94 * invoke the domain init, and then the proto inits. 95 * To delete, just remove from the list (dom_refs must be zero) 96 */ 97 98lck_grp_t *domain_proto_mtx_grp; 99lck_attr_t *domain_proto_mtx_attr; 100static lck_grp_attr_t *domain_proto_mtx_grp_attr; 101decl_lck_mtx_data(static, domain_proto_mtx); 102extern int do_reclaim; 103 104extern sysctlfn net_sysctl; 105 106static u_int64_t _net_uptime; 107 108static void 109init_proto(struct protosw *pr) 110{ 111 TAILQ_INIT(&pr->pr_filter_head); 112 if (pr->pr_init) 113 (*pr->pr_init)(); 114 115 /* Make sure pr_init isn't called again!! */ 116 pr->pr_init = 0; 117} 118 119void 120init_domain(struct domain *dp) 121{ 122 struct protosw *pr; 123 124 if ((dp->dom_mtx = lck_mtx_alloc_init(domain_proto_mtx_grp, domain_proto_mtx_attr)) == NULL) { 125 printf("init_domain: can't init domain mtx for domain=%s\n", dp->dom_name); 126 return; /* we have a problem... */ 127 } 128 129 if (dp->dom_init) 130 (*dp->dom_init)(); 131 132 /* and then init the currently installed protos in this domain */ 133 134 for (pr = dp->dom_protosw; pr; pr = pr->pr_next) { 135 if (pr->pr_usrreqs == 0) 136 panic("domaininit: %ssw[%d] has no usrreqs!", 137 dp->dom_name, 138 (int)(pr - dp->dom_protosw)); 139 140#if __APPLE__ 141 /* 142 * Warn that pr_fasttimo (now pr_unused) is deprecated since rdar://7617868 143 */ 144 if (pr->pr_unused != NULL) { 145 printf("init_domain: warning %s, proto %d: pr_fasttimo is deprecated and won't be called\n", 146 dp->dom_name, pr->pr_protocol); 147 } 148#endif 149 150 init_proto(pr); 151 152 } 153 154 /* Recompute for new protocol */ 155 if (_max_linkhdr < 16) /* XXX - Sheesh; everything's ether? */ 156 _max_linkhdr = 16; 157 _max_linkhdr = max_linkhdr; /* round it up */ 158 159 if (dp->dom_protohdrlen > _max_protohdr) 160 _max_protohdr = dp->dom_protohdrlen; 161 _max_protohdr = max_protohdr; /* round it up */ 162 163 max_hdr = max_linkhdr + max_protohdr; 164 max_datalen = MHLEN - max_hdr; 165} 166 167void 168prepend_domain(struct domain *dp) 169{ 170 lck_mtx_assert(&domain_proto_mtx, LCK_MTX_ASSERT_OWNED); 171 dp->dom_next = domains; 172 domains = dp; 173} 174 175void 176net_add_domain(struct domain *dp) 177{ 178 int do_unlock; 179 180 kprintf("Adding domain %s (family %d)\n", dp->dom_name, 181 dp->dom_family); 182 /* First, link in the domain */ 183 184 do_unlock = domain_proto_mtx_lock(); 185 prepend_domain(dp); 186 187 init_domain(dp); 188 domain_proto_mtx_unlock(do_unlock); 189 190} 191 192int 193net_del_domain(struct domain *dp) 194{ register struct domain *dp1, *dp2; 195 register int retval = 0; 196 int do_unlock; 197 198 do_unlock = domain_proto_mtx_lock(); 199 200 if (dp->dom_refs) { 201 domain_proto_mtx_unlock(do_unlock); 202 return(EBUSY); 203 } 204 205 for (dp2 = NULL, dp1 = domains; dp1; dp2 = dp1, dp1 = dp1->dom_next) 206 { if (dp == dp1) 207 break; 208 } 209 if (dp1) 210 { if (dp2) 211 dp2->dom_next = dp1->dom_next; 212 else 213 domains = dp1->dom_next; 214 } else 215 retval = EPFNOSUPPORT; 216 domain_proto_mtx_unlock(do_unlock); 217 218 return(retval); 219} 220 221/* 222 * net_add_proto - link a protosw into a domain's protosw chain 223 * 224 * note: protocols must use their own domain lock before calling net_add_proto 225 */ 226int 227net_add_proto(struct protosw *pp, struct domain *dp) 228{ register struct protosw *pp1, *pp2; 229 230 for (pp2 = NULL, pp1 = dp->dom_protosw; pp1; pp1 = pp1->pr_next) 231 { if (pp1->pr_type == pp->pr_type && 232 pp1->pr_protocol == pp->pr_protocol) { 233 return(EEXIST); 234 } 235 pp2 = pp1; 236 } 237 if (pp2 == NULL) 238 dp->dom_protosw = pp; 239 else 240 pp2->pr_next = pp; 241 242 init_proto(pp); 243 244 return(0); 245} 246 247/* 248 * net_del_proto - remove a protosw from a domain's protosw chain. 249 * Search the protosw chain for the element with matching data. 250 * Then unlink and return. 251 * 252 * note: protocols must use their own domain lock before calling net_del_proto 253 */ 254int 255net_del_proto(int type, int protocol, struct domain *dp) 256{ 257 register struct protosw *pp1, *pp2; 258 259 for (pp2 = NULL, pp1 = dp->dom_protosw; pp1; pp1 = pp1->pr_next) 260 { if (pp1->pr_type == type && 261 pp1->pr_protocol == protocol) 262 break; 263 pp2 = pp1; 264 } 265 if (pp1 == NULL) { 266 return(ENXIO); 267 } 268 if (pp2) 269 pp2->pr_next = pp1->pr_next; 270 else 271 dp->dom_protosw = pp1->pr_next; 272 return(0); 273} 274 275 276#if NS 277extern struct domain nsdomain; 278#endif 279#if ISO 280extern struct domain isodomain; 281#endif 282#if CCITT 283extern struct domain ccittdomain; 284#endif 285 286#if NETAT 287extern struct domain atalkdomain; 288#endif 289#if INET6 290extern struct domain inet6domain; 291#endif 292#if IPSEC 293extern struct domain keydomain; 294#endif 295 296extern struct domain routedomain, ndrvdomain, inetdomain; 297extern struct domain systemdomain; 298 299void 300domaininit(void) 301{ 302 register struct domain *dp; 303 int do_unlock; 304 305 /* 306 * allocate lock group attribute and group for domain mutexes 307 */ 308 domain_proto_mtx_grp_attr = lck_grp_attr_alloc_init(); 309 310 domain_proto_mtx_grp = lck_grp_alloc_init("domain", domain_proto_mtx_grp_attr); 311 312 /* 313 * allocate the lock attribute for per domain mutexes 314 */ 315 domain_proto_mtx_attr = lck_attr_alloc_init(); 316 317 lck_mtx_init(&domain_proto_mtx, domain_proto_mtx_grp, 318 domain_proto_mtx_attr); 319 /* 320 * Add all the static domains to the domains list 321 */ 322 323 do_unlock = domain_proto_mtx_lock(); 324 325 prepend_domain(&localdomain); 326 prepend_domain(&inetdomain); 327#if NETAT 328 prepend_domain(&atalkdomain); 329#endif 330#if INET6 331 prepend_domain(&inet6domain); 332#endif 333 prepend_domain(&routedomain); 334 335#if IPSEC 336 prepend_domain(&keydomain); 337#endif 338 339#if NS 340 prepend_domain(&nsdomain); 341#endif 342#if ISO 343 prepend_domain(&isodomain); 344#endif 345#if CCITT 346 prepend_domain(&ccittdomain); 347#endif 348 prepend_domain(&ndrvdomain); 349 350 prepend_domain(&systemdomain); 351 352 /* 353 * Now ask them all to init (XXX including the routing domain, 354 * see above) 355 */ 356 for (dp = domains; dp; dp = dp->dom_next) 357 init_domain(dp); 358 359 domain_proto_mtx_unlock(do_unlock); 360 timeout(pfslowtimo, NULL, 1); 361} 362 363static __inline__ struct domain * 364pffinddomain_locked(int pf) 365{ 366 struct domain *dp; 367 368 dp = domains; 369 while (dp != NULL) 370 { if (dp->dom_family == pf) { 371 break; 372 } 373 dp = dp->dom_next; 374 } 375 return (dp); 376} 377 378struct protosw * 379pffindtype(int family, int type) 380{ 381 register struct domain *dp; 382 register struct protosw *pr; 383 int do_unlock; 384 385 do_unlock = domain_proto_mtx_lock(); 386 dp = pffinddomain_locked(family); 387 if (dp == NULL) { 388 domain_proto_mtx_unlock(do_unlock); 389 return (NULL); 390 } 391 for (pr = dp->dom_protosw; pr; pr = pr->pr_next) 392 if (pr->pr_type && pr->pr_type == type) { 393 domain_proto_mtx_unlock(do_unlock); 394 return (pr); 395 } 396 domain_proto_mtx_unlock(do_unlock); 397 return (0); 398} 399 400struct domain * 401pffinddomain(int pf) 402{ 403 struct domain *dp; 404 int do_unlock; 405 406 do_unlock = domain_proto_mtx_lock(); 407 dp = pffinddomain_locked(pf); 408 domain_proto_mtx_unlock(do_unlock); 409 return(dp); 410} 411 412struct protosw * 413pffindproto(int family, int protocol, int type) 414{ 415 register struct protosw *pr; 416 int do_unlock; 417 do_unlock = domain_proto_mtx_lock(); 418 pr = pffindproto_locked(family, protocol, type); 419 domain_proto_mtx_unlock(do_unlock); 420 return (pr); 421} 422 423struct protosw * 424pffindproto_locked(int family, int protocol, int type) 425{ 426 register struct domain *dp; 427 register struct protosw *pr; 428 struct protosw *maybe = 0; 429 430 if (family == 0) 431 return (0); 432 dp = pffinddomain_locked(family); 433 if (dp == NULL) { 434 return (NULL); 435 } 436 for (pr = dp->dom_protosw; pr; pr = pr->pr_next) { 437 if ((pr->pr_protocol == protocol) && (pr->pr_type == type)) 438 return (pr); 439 440 if (type == SOCK_RAW && pr->pr_type == SOCK_RAW && 441 pr->pr_protocol == 0 && maybe == (struct protosw *)0) 442 maybe = pr; 443 } 444 return (maybe); 445} 446 447struct protosw * 448pffindprotonotype_locked(int family, int protocol, __unused int type) 449{ 450 register struct domain *dp; 451 register struct protosw *pr; 452 453 if (family == 0) 454 return (0); 455 dp = pffinddomain_locked(family); 456 if (dp == NULL) { 457 return (NULL); 458 } 459 for (pr = dp->dom_protosw; pr; pr = pr->pr_next) { 460 if (pr->pr_protocol == protocol) { 461 return (pr); 462 } 463 } 464 return (NULL); 465} 466 467struct protosw * 468pffindprotonotype(int family, int protocol) 469{ 470 register struct protosw *pr; 471 int do_unlock; 472 if (protocol == 0) { 473 return (NULL); 474 } 475 do_unlock = domain_proto_mtx_lock(); 476 pr = pffindprotonotype_locked(family, protocol, 0); 477 domain_proto_mtx_unlock(do_unlock); 478 return (pr); 479} 480 481int 482net_sysctl(int *name, u_int namelen, user_addr_t oldp, size_t *oldlenp, 483 user_addr_t newp, size_t newlen, __unused struct proc *p) 484{ 485 register struct domain *dp; 486 register struct protosw *pr; 487 int family, protocol, error; 488 int do_unlock; 489 490 /* 491 * All sysctl names at this level are nonterminal; 492 * next two components are protocol family and protocol number, 493 * then at least one addition component. 494 */ 495 if (namelen < 3) 496 return (EISDIR); /* overloaded */ 497 family = name[0]; 498 protocol = name[1]; 499 500 if (family == 0) 501 return (0); 502 do_unlock = domain_proto_mtx_lock(); 503 for (dp = domains; dp; dp = dp->dom_next) 504 if (dp->dom_family == family) 505 goto found; 506 domain_proto_mtx_unlock(do_unlock); 507 return (ENOPROTOOPT); 508found: 509 for (pr = dp->dom_protosw; pr; pr = pr->pr_next) 510 if (pr->pr_protocol == protocol && pr->pr_sysctl) { 511 error = (*pr->pr_sysctl)(name + 2, namelen - 2, 512 (void *)(uintptr_t)oldp, oldlenp, (void *)(uintptr_t)newp, newlen); 513 domain_proto_mtx_unlock(do_unlock); 514 return (error); 515 } 516 domain_proto_mtx_unlock(do_unlock); 517 return (ENOPROTOOPT); 518} 519 520void 521pfctlinput(int cmd, struct sockaddr *sa) 522{ 523 pfctlinput2(cmd, sa, (void*)0); 524} 525 526void 527pfctlinput2(int cmd, struct sockaddr *sa, void *ctlparam) 528{ 529 struct domain *dp; 530 struct protosw *pr; 531 int do_unlock; 532 533 if (!sa) 534 return; 535 536 do_unlock = domain_proto_mtx_lock(); 537 for (dp = domains; dp; dp = dp->dom_next) 538 for (pr = dp->dom_protosw; pr; pr = pr->pr_next) 539 if (pr->pr_ctlinput) 540 (*pr->pr_ctlinput)(cmd, sa, ctlparam); 541 domain_proto_mtx_unlock(do_unlock); 542} 543 544void 545pfslowtimo(__unused void *arg) 546{ 547 register struct domain *dp; 548 register struct protosw *pr; 549 int do_unlock; 550 551 /* 552 * Update coarse-grained networking timestamp (in sec.); the idea 553 * is to piggy-back on the periodic slow timeout callout to update 554 * the counter returnable via net_uptime(). 555 */ 556 net_update_uptime(); 557 558 do_unlock = domain_proto_mtx_lock(); 559 for (dp = domains; dp; dp = dp->dom_next) 560 for (pr = dp->dom_protosw; pr; pr = pr->pr_next) { 561 if (pr->pr_slowtimo) 562 (*pr->pr_slowtimo)(); 563 if ((do_reclaim || (pr->pr_flags & PR_AGGDRAIN)) && 564 pr->pr_drain) 565 (*pr->pr_drain)(); 566 } 567 do_reclaim = 0; 568 domain_proto_mtx_unlock(do_unlock); 569 timeout(pfslowtimo, NULL, hz/PR_SLOWHZ); 570} 571 572static void 573net_update_uptime(void) 574{ 575 struct timeval tv; 576 577 microuptime(&tv); 578 _net_uptime = tv.tv_sec; 579} 580 581/* 582 * An alternative way to obtain the coarse-grained uptime (in seconds) 583 * for networking code which do not require high-precision timestamp, 584 * as this is significantly cheaper than microuptime(). 585 */ 586u_int64_t 587net_uptime(void) 588{ 589 /* If we get here before pfslowtimo() fires for the first time */ 590 if (_net_uptime == 0) 591 net_update_uptime(); 592 593 return (_net_uptime); 594} 595 596int 597domain_proto_mtx_lock(void) 598{ 599 int held = net_thread_check_lock(NET_THREAD_HELD_DOMAIN); 600 if (!held) { 601 lck_mtx_lock(&domain_proto_mtx); 602 net_thread_set_lock(NET_THREAD_HELD_DOMAIN); 603 } 604 lck_mtx_assert(&domain_proto_mtx, LCK_MTX_ASSERT_OWNED); 605 return !held; 606} 607 608void 609domain_proto_mtx_unlock(int do_unlock) 610{ 611 if (do_unlock) { 612 net_thread_unset_lock(NET_THREAD_HELD_DOMAIN); 613 lck_mtx_unlock(&domain_proto_mtx); 614 lck_mtx_assert(&domain_proto_mtx, LCK_MTX_ASSERT_NOTOWNED); 615 } 616} 617