]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/netinet/in_proto.c
xnu-4570.51.1.tar.gz
[apple/xnu.git] / bsd / netinet / in_proto.c
index 69ac504cc5eb7c5f2aea213cd7ed5b620f9f8e8d..4a9d198192cacb8b178dc064cf5fa766c2b5fd1a 100644 (file)
@@ -1,14 +1,19 @@
 /*
- * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2013 Apple Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ * 
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
  * 
  * The Original Code and all software distributed under the License are
  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
@@ -18,7 +23,7 @@
  * Please see the License for the specific language governing rights and
  * limitations under the License.
  * 
- * @APPLE_LICENSE_HEADER_END@
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
  */
 /*
  * Copyright (c) 1982, 1986, 1993
 #include <sys/sysctl.h>
 #include <sys/mbuf.h>
 
+#include <kern/debug.h>
+
 #include <net/if.h>
 #include <net/route.h>
+#include <net/kpi_protocol.h>
 
 #include <netinet/in.h>
+#include <netinet/in_var.h>
 #include <netinet/in_systm.h>
 #include <netinet/ip.h>
 #include <netinet/ip_var.h>
 #include <netinet6/ipcomp.h>
 #endif /* IPSEC */
 
-#if IPXIP
-#include <netipx/ipx_ip.h>
-#endif
+static void in_dinit(struct domain *);
+static void ip_proto_input(protocol_family_t, mbuf_t);
 
-extern struct domain inetdomain;
-static struct pr_usrreqs nousrreqs;
-extern struct   pr_usrreqs icmp_dgram_usrreqs;
+extern struct domain inetdomain_s;
+static struct pr_usrreqs nousrreqs;
+extern struct pr_usrreqs icmp_dgram_usrreqs;
 extern int icmp_dgram_ctloutput(struct socket *, struct sockopt *);
 
+struct domain *inetdomain = NULL;
 
-struct protosw inetsw[] = {
-{ 0,           &inetdomain,    0,              0,
-  0,           0,              0,              0,
-  0,
-  ip_init,     0,              ip_slowtimo,    ip_drain,
-  0,   
-  &nousrreqs,
-  0,           0,              0,      { 0, 0 },       0,      { 0 }
+/* Thanks to PPP, this still needs to be exported */
+lck_mtx_t      *inet_domain_mutex;
+
+static struct protosw inetsw[] = {
+{
+       .pr_type =              0,
+       .pr_protocol =          0,
+       .pr_init =              ip_init,
+       .pr_drain =             ip_drain,
+       .pr_usrreqs =           &nousrreqs,
 },
-{ SOCK_DGRAM,  &inetdomain,    IPPROTO_UDP,    PR_ATOMIC|PR_ADDR|PR_PROTOLOCK|PR_PCBLOCK,
-  udp_input,   0,              udp_ctlinput,   ip_ctloutput,
-  0,
-  udp_init,    0,              udp_slowtimo,           0,
-  0,
-  &udp_usrreqs,
-  udp_lock,    udp_unlock,     udp_getlock,    { 0, 0 },       0,      { 0 }
+{
+       .pr_type =              SOCK_DGRAM,
+       .pr_protocol =          IPPROTO_UDP,
+       .pr_flags =             PR_ATOMIC|PR_ADDR|PR_PROTOLOCK|PR_PCBLOCK|
+                               PR_EVCONNINFO|PR_PRECONN_WRITE,
+       .pr_input =             udp_input,
+       .pr_ctlinput =          udp_ctlinput,
+       .pr_ctloutput =         udp_ctloutput,
+       .pr_init =              udp_init,
+       .pr_usrreqs =           &udp_usrreqs,
+       .pr_lock =              udp_lock,
+       .pr_unlock =            udp_unlock,
+       .pr_getlock =           udp_getlock,
 },
-{ SOCK_STREAM, &inetdomain,    IPPROTO_TCP, 
-       PR_CONNREQUIRED|PR_IMPLOPCL|PR_WANTRCVD|PR_PCBLOCK|PR_PROTOLOCK|PR_DISPOSE,
-  tcp_input,   0,              tcp_ctlinput,   tcp_ctloutput,
-  0,
-  tcp_init,    tcp_fasttimo,   tcp_slowtimo,   tcp_drain,
-  0,
-  &tcp_usrreqs,
-  tcp_lock,    tcp_unlock,     tcp_getlock,    { 0, 0 },       0,      { 0 }
+{
+       .pr_type =              SOCK_STREAM,
+       .pr_protocol =          IPPROTO_TCP,
+       .pr_flags =             PR_CONNREQUIRED|PR_WANTRCVD|PR_PCBLOCK|
+                               PR_PROTOLOCK|PR_DISPOSE|PR_EVCONNINFO|
+                               PR_PRECONN_WRITE|PR_DATA_IDEMPOTENT,
+       .pr_input =             tcp_input,
+       .pr_ctlinput =          tcp_ctlinput,
+       .pr_ctloutput =         tcp_ctloutput,
+       .pr_init =              tcp_init,
+       .pr_drain =             tcp_drain,
+       .pr_usrreqs =           &tcp_usrreqs,
+       .pr_lock =              tcp_lock,
+       .pr_unlock =            tcp_unlock,
+       .pr_getlock =           tcp_getlock,
 },
-{ SOCK_RAW,    &inetdomain,    IPPROTO_RAW,    PR_ATOMIC|PR_ADDR,
-  rip_input,   0,              rip_ctlinput,   rip_ctloutput,
-  0,
-  0,           0,              0,              0,
-  0,
-  &rip_usrreqs,
-  0,           rip_unlock,             0,      { 0, 0 },       0,      { 0 }
+{
+       .pr_type =              SOCK_RAW,
+       .pr_protocol =          IPPROTO_RAW,
+       .pr_flags =             PR_ATOMIC|PR_ADDR,
+       .pr_input =             rip_input,
+       .pr_ctlinput =          rip_ctlinput,
+       .pr_ctloutput =         rip_ctloutput,
+       .pr_usrreqs =           &rip_usrreqs,
+       .pr_unlock =            rip_unlock,
 },
-{ SOCK_RAW,    &inetdomain,    IPPROTO_ICMP,   PR_ATOMIC|PR_ADDR|PR_LASTHDR,
-  icmp_input,  0,              0,              rip_ctloutput,
-  0,
-  0,           0,              0,              0,
-  0,
-  &rip_usrreqs,
-  0,           rip_unlock,     0,      { 0, 0 },       0,      { 0 }
+{
+       .pr_type =              SOCK_RAW,
+       .pr_protocol =          IPPROTO_ICMP,
+       .pr_flags =             PR_ATOMIC|PR_ADDR|PR_LASTHDR,
+       .pr_input =             icmp_input,
+       .pr_ctloutput =         rip_ctloutput,
+       .pr_usrreqs =           &rip_usrreqs,
+       .pr_unlock =            rip_unlock,
 },
-{ SOCK_DGRAM, &inetdomain,     IPPROTO_ICMP,   PR_ATOMIC|PR_ADDR|PR_LASTHDR,
-  icmp_input,  0,              0,              icmp_dgram_ctloutput,
-  0,
-  0,           0,              0,              0,
-  0,   
-  &icmp_dgram_usrreqs,
-  0,           rip_unlock,             0,      { 0, 0 },       0,      { 0 }
+{
+       .pr_type =              SOCK_DGRAM,
+       .pr_protocol =          IPPROTO_ICMP,
+       .pr_flags =             PR_ATOMIC|PR_ADDR|PR_LASTHDR,
+       .pr_input =             icmp_input,
+       .pr_ctloutput =         icmp_dgram_ctloutput,
+       .pr_usrreqs =           &icmp_dgram_usrreqs,
+       .pr_unlock =            rip_unlock,
 },
-{ SOCK_RAW,    &inetdomain,    IPPROTO_IGMP,   PR_ATOMIC|PR_ADDR|PR_LASTHDR,
-  igmp_input,  0,              0,              rip_ctloutput,
-  0,
-  igmp_init,   igmp_fasttimo,  igmp_slowtimo,  0,
-  0,
-  &rip_usrreqs,
-  0,           rip_unlock,     0,      { 0, 0 },       0,      { 0 }
+{
+       .pr_type =              SOCK_RAW,
+       .pr_protocol =          IPPROTO_IGMP,
+       .pr_flags =             PR_ATOMIC|PR_ADDR|PR_LASTHDR,
+       .pr_input =             igmp_input,
+       .pr_ctloutput =         rip_ctloutput,
+       .pr_init =              igmp_init,
+       .pr_usrreqs =           &rip_usrreqs,
+       .pr_unlock =            rip_unlock,
 },
-{ SOCK_RAW,    &inetdomain,    IPPROTO_RSVP,   PR_ATOMIC|PR_ADDR|PR_LASTHDR,
-  rsvp_input,  0,              0,              rip_ctloutput,
-  0,
-  0,           0,              0,              0,
-  0,
-  &rip_usrreqs,
-  0,           rip_unlock,             0,      { 0, 0 },       0,      { 0 }
+{
+       .pr_type =              SOCK_RAW,
+       .pr_protocol =          IPPROTO_GRE,
+       .pr_flags =             PR_ATOMIC|PR_ADDR,
+       .pr_input =             gre_input,
+       .pr_ctlinput =          rip_ctlinput,
+       .pr_ctloutput =         rip_ctloutput,
+       .pr_usrreqs =           &rip_usrreqs,
+       .pr_unlock =            rip_unlock,
 },
 #if IPSEC
-{ SOCK_RAW,    &inetdomain,    IPPROTO_AH,     PR_ATOMIC|PR_ADDR|PR_PROTOLOCK,
-  ah4_input,   0,              0,              0,
-  0,     
-  0,           0,              0,              0,
-  0,
-  &nousrreqs,
-  0,           0,              0,      { 0, 0 },       0,      { 0 }
+{
+       .pr_type =              SOCK_RAW,
+       .pr_protocol =          IPPROTO_AH,
+       .pr_flags =             PR_ATOMIC|PR_ADDR|PR_PROTOLOCK,
+       .pr_input =             ah4_input,
+       .pr_usrreqs =           &nousrreqs,
 },
 #if IPSEC_ESP
-{ SOCK_RAW,    &inetdomain,    IPPROTO_ESP,    PR_ATOMIC|PR_ADDR|PR_PROTOLOCK,
-  esp4_input,  0,              0,              0,
-  0,     
-  0,           0,              0,              0,
-  0,
-  &nousrreqs,
-  0,           0,              0,      { 0, 0 },       0,      { 0 }
+{
+       .pr_type =              SOCK_RAW,
+       .pr_protocol =          IPPROTO_ESP,
+       .pr_flags =             PR_ATOMIC|PR_ADDR|PR_PROTOLOCK,
+       .pr_input =             esp4_input,
+       .pr_usrreqs =           &nousrreqs,
 },
-#endif
-{ SOCK_RAW,    &inetdomain,    IPPROTO_IPCOMP, PR_ATOMIC|PR_ADDR|PR_PROTOLOCK,
-  ipcomp4_input, 0,            0,              0,
-  0,     
-  0,           0,              0,              0,
-  0,
-  &nousrreqs,
-  0,           0,              0,      { 0, 0 },       0,      { 0 }
+#endif /* IPSEC_ESP */
+{
+       .pr_type =              SOCK_RAW,
+       .pr_protocol =          IPPROTO_IPCOMP,
+       .pr_flags =             PR_ATOMIC|PR_ADDR|PR_PROTOLOCK,
+       .pr_input =             ipcomp4_input,
+       .pr_usrreqs =           &nousrreqs,
 },
 #endif /* IPSEC */
-{ SOCK_RAW,    &inetdomain,    IPPROTO_IPV4,   PR_ATOMIC|PR_ADDR|PR_LASTHDR,
-  encap4_input,        0,              0,              rip_ctloutput,
-  0,
-  encap_init,          0,              0,              0,
-  0,
-  &rip_usrreqs,
-  0,           0,              0,      { 0, 0 },       0,      { 0 }
+{
+       .pr_type =              SOCK_RAW,
+       .pr_protocol =          IPPROTO_IPV4,
+       .pr_flags =             PR_ATOMIC|PR_ADDR|PR_LASTHDR,
+       .pr_input =             encap4_input,
+       .pr_ctloutput =         rip_ctloutput,
+       .pr_init =              encap4_init,
+       .pr_usrreqs =           &rip_usrreqs,
+       .pr_unlock =            rip_unlock,
 },
-# if INET6
-{ SOCK_RAW,    &inetdomain,    IPPROTO_IPV6,   PR_ATOMIC|PR_ADDR|PR_LASTHDR,
-  encap4_input,        0,              0,              rip_ctloutput,
-  0,
-  encap_init,  0,              0,              0,
-  0,
-  &rip_usrreqs,
-  0,           0,              0,      { 0, 0 },       0,      { 0 }
+#if INET6
+{
+       .pr_type =              SOCK_RAW,
+       .pr_protocol =          IPPROTO_IPV6,
+       .pr_flags =             PR_ATOMIC|PR_ADDR|PR_LASTHDR,
+       .pr_input =             encap4_input,
+       .pr_ctloutput =         rip_ctloutput,
+       .pr_init =              encap4_init,
+       .pr_usrreqs =           &rip_usrreqs,
+       .pr_unlock =            rip_unlock,
 },
-#endif
+#endif /* INET6 */
 #if IPDIVERT
-{ SOCK_RAW,    &inetdomain,    IPPROTO_DIVERT, PR_ATOMIC|PR_ADDR|PR_PCBLOCK,
-  div_input,   0,              0,              ip_ctloutput,
-  0,
-  div_init,    0,              0,              0,
-  0,
-  &div_usrreqs,
-  div_lock,            div_unlock,             div_getlock,    { 0, 0 },       0,      { 0 }
+{
+       .pr_type =              SOCK_RAW,
+       .pr_protocol =          IPPROTO_DIVERT,
+       .pr_flags =             PR_ATOMIC|PR_ADDR|PR_PCBLOCK,
+       .pr_input =             div_input,
+       .pr_ctloutput =         ip_ctloutput,
+       .pr_init =              div_init,
+       .pr_usrreqs =           &div_usrreqs,
+       .pr_lock =              div_lock,
+       .pr_unlock =            div_unlock,
+       .pr_getlock =           div_getlock,
 },
-#endif
-#if IPXIP
-{ SOCK_RAW,    &inetdomain,    IPPROTO_IDP,    PR_ATOMIC|PR_ADDR|PR_LASTHDR,
-  ipxip_input, 0,              ipxip_ctlinput, 0,
-  0,
-  0,           0,              0,              0,
-  0,
-  &rip_usrreqs,
-  0,           0,              0,      { 0, 0 },       0,      { 0 }
-},
-#endif
-#if NSIP
-{ SOCK_RAW,    &inetdomain,    IPPROTO_IDP,    PR_ATOMIC|PR_ADDR|PR_LASTHDR,
-  idpip_input, 0,              nsip_ctlinput,  0,
-  0,
-  0,           0,              0,              0,
-  0,
-  &rip_usrreqs,
-  0,           0,              0,      { 0, 0 },       0,      { 0 }
-},
-#endif
-       /* raw wildcard */
-{ SOCK_RAW,    &inetdomain,    0,              PR_ATOMIC|PR_ADDR|PR_LASTHDR,
-  rip_input,   0,              0,              rip_ctloutput,
-  0,
-  rip_init,    0,              0,              0,
-  0,
-  &rip_usrreqs,
-  0,                   rip_unlock,             0,      { 0, 0 },       0,      { 0 }
+#endif /* IPDIVERT */
+/* raw wildcard */
+{
+       .pr_type =              SOCK_RAW,
+       .pr_flags =             PR_ATOMIC|PR_ADDR|PR_LASTHDR,
+       .pr_input =             rip_input,
+       .pr_ctloutput =         rip_ctloutput,
+       .pr_init =              rip_init,
+       .pr_usrreqs =           &rip_usrreqs,
+       .pr_unlock =            rip_unlock,
 },
 };
 
-extern int in_inithead(void **, int);
+static int in_proto_count = (sizeof (inetsw) / sizeof (struct protosw));
 
-int in_proto_count = (sizeof (inetsw) / sizeof (struct protosw));
+struct domain inetdomain_s = {
+       .dom_family =           PF_INET,
+       .dom_flags =            DOM_REENTRANT,
+       .dom_name =             "internet",
+       .dom_init =             in_dinit,
+       .dom_rtattach =         in_inithead,
+       .dom_rtoffset =         32,
+       .dom_maxrtkey =         sizeof (struct sockaddr_in),
+       .dom_protohdrlen =      sizeof (struct tcpiphdr),
+};
+
+/* Initialize the PF_INET domain, and add in the pre-defined protos */
+void
+in_dinit(struct domain *dp)
+{
+       struct protosw *pr;
+       int i;
+       domain_unguard_t unguard;
+
+       VERIFY(!(dp->dom_flags & DOM_INITIALIZED));
+       VERIFY(inetdomain == NULL);
+
+       inetdomain = dp;
+
+       /*
+        * Verify that the maximum possible tcp/ip header will still
+        * fit in a small mbuf because m_pullup only puls into 256
+        * byte mbuf
+        */
+       _CASSERT((sizeof(struct tcpiphdr) + TCP_MAXOLEN) <= _MHLEN);
 
-extern void in_dinit(void);
-/* A routing init function, and a header size */
-struct domain inetdomain =
-    { AF_INET, 
-      "internet", 
-      in_dinit, 
-      0, 
-      0, 
-      inetsw, 
-      0,
-      in_inithead, 
-      32, 
-      sizeof(struct sockaddr_in),
-      sizeof(struct tcpiphdr), 
-      0, 
-      0, 
-      0, 
-      { 0, 0}
-    };
+       /*
+        * Attach first, then initialize; ip_init() needs raw IP handler.
+        */
+       for (i = 0, pr = &inetsw[0]; i < in_proto_count; i++, pr++)
+               net_add_proto(pr, dp, 0);
+       for (i = 0, pr = &inetsw[0]; i < in_proto_count; i++, pr++)
+               net_init_proto(pr, dp);
 
-DOMAIN_SET(inet);
+       inet_domain_mutex = dp->dom_mtx;
 
-SYSCTL_NODE(_net,      PF_INET,                inet,   CTLFLAG_RW, 0,
-       "Internet Family");
+       unguard = domain_unguard_deploy();
+       i = proto_register_input(PF_INET, ip_proto_input, NULL, 1);
+       if (i != 0) {
+               panic("%s: failed to register PF_INET protocol: %d\n",
+                   __func__, i);
+               /* NOTREACHED */
+       }
+       domain_unguard_release(unguard);
+}
 
-SYSCTL_NODE(_net_inet, IPPROTO_IP,     ip,     CTLFLAG_RW, 0,  "IP");
-SYSCTL_NODE(_net_inet, IPPROTO_ICMP,   icmp,   CTLFLAG_RW, 0,  "ICMP");
-SYSCTL_NODE(_net_inet, IPPROTO_UDP,    udp,    CTLFLAG_RW, 0,  "UDP");
-SYSCTL_NODE(_net_inet, IPPROTO_TCP,    tcp,    CTLFLAG_RW, 0,  "TCP");
-SYSCTL_NODE(_net_inet, IPPROTO_IGMP,   igmp,   CTLFLAG_RW, 0,  "IGMP");
+static void
+ip_proto_input(protocol_family_t protocol, mbuf_t packet_list)
+{
+#pragma unused(protocol)
+
+       if (packet_list->m_nextpkt != NULL) {
+               ip_input_process_list(packet_list);
+       } else {
+               /*
+                * XXX remove this path if ip_input_process_list is proven
+                * to be stable and has minimum overhead on most platforms.
+                */
+               ip_input(packet_list);
+       }
+}
+
+SYSCTL_NODE(_net, PF_INET, inet,
+       CTLFLAG_RW|CTLFLAG_LOCKED, 0, "Internet Family");
+
+SYSCTL_NODE(_net_inet, IPPROTO_IP, ip,
+       CTLFLAG_RW|CTLFLAG_LOCKED, 0, "IP");
+SYSCTL_NODE(_net_inet, IPPROTO_ICMP, icmp,
+       CTLFLAG_RW|CTLFLAG_LOCKED, 0, "ICMP");
+SYSCTL_NODE(_net_inet, IPPROTO_UDP, udp,
+       CTLFLAG_RW|CTLFLAG_LOCKED, 0, "UDP");
+SYSCTL_NODE(_net_inet, IPPROTO_TCP, tcp,
+       CTLFLAG_RW|CTLFLAG_LOCKED, 0, "TCP");
+SYSCTL_NODE(_net_inet, IPPROTO_IGMP, igmp,
+       CTLFLAG_RW|CTLFLAG_LOCKED, 0, "IGMP");
 #if IPSEC
-SYSCTL_NODE(_net_inet, IPPROTO_AH,     ipsec,  CTLFLAG_RW, 0,  "IPSEC");
+SYSCTL_NODE(_net_inet, IPPROTO_AH, ipsec,
+       CTLFLAG_RW|CTLFLAG_LOCKED, 0, "IPSEC");
 #endif /* IPSEC */
-SYSCTL_NODE(_net_inet, IPPROTO_RAW,    raw,    CTLFLAG_RW, 0,  "RAW");
+SYSCTL_NODE(_net_inet, IPPROTO_RAW, raw,
+       CTLFLAG_RW|CTLFLAG_LOCKED, 0, "RAW");
 #if IPDIVERT
-SYSCTL_NODE(_net_inet, IPPROTO_DIVERT, div,    CTLFLAG_RW, 0,  "DIVERT");
-#endif
-
+SYSCTL_NODE(_net_inet, IPPROTO_DIVERT, div,
+       CTLFLAG_RW|CTLFLAG_LOCKED, 0, "DIVERT");
+#endif /* IPDIVERT */