]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/netinet6/ip6_fw.c
xnu-4570.31.3.tar.gz
[apple/xnu.git] / bsd / netinet6 / ip6_fw.c
index f1b9f0508362516276f73fd4662be15a20bae75a..99d3e8c0208965c7a3554291b055adbc25670495 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003-2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2003-2012 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
@@ -86,8 +86,6 @@
 #endif
 
 #include <string.h>
-#include <machine/spl.h>
-
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/malloc.h>
@@ -150,11 +148,11 @@ static int ip6fw_sysctl SYSCTL_HANDLER_ARGS;
 SYSCTL_DECL(_net_inet6_ip6);
 SYSCTL_NODE(_net_inet6_ip6, OID_AUTO, fw, CTLFLAG_RW|CTLFLAG_LOCKED, 0, "Firewall");
 SYSCTL_PROC(_net_inet6_ip6_fw, OID_AUTO, enable, 
-       CTLTYPE_INT | CTLFLAG_RW,
+       CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
        &ip6_fw_enable, 0, ip6fw_sysctl, "I", "Enable ip6fw");
-SYSCTL_INT(_net_inet6_ip6_fw, OID_AUTO, debug, CTLFLAG_RW, &fw6_debug, 0, "");
-SYSCTL_INT(_net_inet6_ip6_fw, OID_AUTO, verbose, CTLFLAG_RW, &fw6_verbose, 0, "");
-SYSCTL_INT(_net_inet6_ip6_fw, OID_AUTO, verbose_limit, CTLFLAG_RW, &fw6_verbose_limit, 0, "");
+SYSCTL_INT(_net_inet6_ip6_fw, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_LOCKED, &fw6_debug, 0, "");
+SYSCTL_INT(_net_inet6_ip6_fw, OID_AUTO, verbose, CTLFLAG_RW | CTLFLAG_LOCKED, &fw6_verbose, 0, "");
+SYSCTL_INT(_net_inet6_ip6_fw, OID_AUTO, verbose_limit, CTLFLAG_RW | CTLFLAG_LOCKED, &fw6_verbose_limit, 0, "");
 
 static int
 ip6fw_sysctl SYSCTL_HANDLER_ARGS
@@ -202,7 +200,6 @@ static void cp_to_user_32( struct ip6_fw_32 *userrule_32, struct ip6_fw *rule);
 static void cp_from_user_32( struct ip6_fw_32 *userrule_32, struct ip6_fw *rule);
 
 static char err_prefix[] = "ip6_fw_ctl:";
-extern lck_mtx_t *ip6_mutex;
 
 /*
  * Returns 1 if the port is matched by the vector, 0 otherwise
@@ -390,17 +387,21 @@ iface_match(struct ifnet *ifp, union ip6_fw_if *ifu, int byname)
                struct ifaddr *ia;
 
                ifnet_lock_shared(ifp);
-               for (ia = ifp->if_addrlist.tqh_first; ia; ia = ia->ifa_list.tqe_next)
+               for (ia = ifp->if_addrlist.tqh_first; ia;
+                   ia = ia->ifa_list.tqe_next)
                {
-
-                       if (ia->ifa_addr == NULL)
-                               continue;
-                       if (ia->ifa_addr->sa_family != AF_INET6)
+                       IFA_LOCK_SPIN(ia);
+                       if (ia->ifa_addr->sa_family != AF_INET6) {
+                               IFA_UNLOCK(ia);
                                continue;
+                       }
                        if (!IN6_ARE_ADDR_EQUAL(&ifu->fu_via_ip6,
                            &(((struct sockaddr_in6 *)
-                           (ia->ifa_addr))->sin6_addr))) 
+                           (ia->ifa_addr))->sin6_addr))) {
+                               IFA_UNLOCK(ia);
                                continue;
+                       }
+                       IFA_UNLOCK(ia);
                        ifnet_lock_done(ifp);
                        return(1);
                }
@@ -558,7 +559,7 @@ ip6_fw_chk(struct ip6_hdr **pip6,
        struct ip6_fw_chain *chain;
        struct ip6_fw *rule = NULL;
        struct ip6_hdr *ip6 = *pip6;
-       struct ifnet *const rif = ((*m)->m_flags & M_LOOP) ? ifunit("lo0") : (*m)->m_pkthdr.rcvif;
+       struct ifnet *const rif = ((*m)->m_flags & M_LOOP) ? lo_ifp : (*m)->m_pkthdr.rcvif;
        u_short offset = 0;
        int off = sizeof(struct ip6_hdr), nxt = ip6->ip6_nxt;
        u_short src_port, dst_port;
@@ -568,6 +569,7 @@ ip6_fw_chk(struct ip6_hdr **pip6,
        u_int16_t ignport = ntohs(*cookie);
 #endif
        struct timeval timenow;
+       struct tcp_respond_args tra;
 
        getmicrotime(&timenow);
 
@@ -869,19 +871,19 @@ got_match:
                                flags = TH_RST|TH_ACK;
                        }
                        bcopy(&ti, ip6, sizeof(ti));
+                       bzero(&tra, sizeof(tra));
+                       tra.ifscope = IFSCOPE_NONE;
+                       tra.awdl_unrestricted = 1;
                        tcp_respond(NULL, ip6, (struct tcphdr *)(ip6 + 1),
-                               *m, ack, seq, flags, IFSCOPE_NONE);
+                               *m, ack, seq, flags, &tra);
                        *m = NULL;
                        break;
                  }
                default:        /* Send an ICMP unreachable using code */
                        if (oif)
                                (*m)->m_pkthdr.rcvif = oif;
-                       lck_mtx_assert(ip6_mutex, LCK_MTX_ASSERT_OWNED);
-                       lck_mtx_unlock(ip6_mutex);
                        icmp6_error(*m, ICMP6_DST_UNREACH,
                            rule->fw_reject_code, 0);
-                       lck_mtx_lock(ip6_mutex);
                        *m = NULL;
                        break;
                }
@@ -904,7 +906,6 @@ add_entry6(struct ip6_fw_head *chainptr, struct ip6_fw *frwl)
        struct ip6_fw *ftmp = 0;
        struct ip6_fw_chain *fwc = 0, *fcp, *fcpl = 0;
        u_short nbr = 0;
-       int s;
 
        fwc = _MALLOC(sizeof *fwc, M_IP6FW, M_WAITOK);
        ftmp = _MALLOC(sizeof *ftmp, M_IP6FW, M_WAITOK);
@@ -921,16 +922,12 @@ add_entry6(struct ip6_fw_head *chainptr, struct ip6_fw *frwl)
        ftmp->fw_bcnt = 0L;
        fwc->rule = ftmp;
        
-       s = splnet();
-
        if (!chainptr->lh_first) {
                LIST_INSERT_HEAD(chainptr, fwc, chain);
-               splx(s);
                return(0);
         } else if (ftmp->fw_number == (u_short)-1) {
                if (fwc)  FREE(fwc, M_IP6FW);
                if (ftmp) FREE(ftmp, M_IP6FW);
-               splx(s);
                dprintf(("%s bad rule number\n", err_prefix));
                return (EINVAL);
         }
@@ -962,7 +959,7 @@ add_entry6(struct ip6_fw_head *chainptr, struct ip6_fw *frwl)
                }
        }
 
-       splx(s);
+       bcopy(ftmp, frwl, sizeof(struct ip6_fw));
        return (0);
 }
 
@@ -970,16 +967,12 @@ static int
 del_entry6(struct ip6_fw_head *chainptr, u_short number)
 {
        struct ip6_fw_chain *fcp;
-       int s;
-
-       s = splnet();
 
        fcp = chainptr->lh_first;
        if (number != (u_short)-1) {
                for (; fcp; fcp = fcp->chain.le_next) {
                        if (fcp->rule->fw_number == number) {
                                LIST_REMOVE(fcp, chain);
-                               splx(s);
                                FREE(fcp->rule, M_IP6FW);
                                FREE(fcp, M_IP6FW);
                                return 0;
@@ -987,7 +980,6 @@ del_entry6(struct ip6_fw_head *chainptr, u_short number)
                }
        }
 
-       splx(s);
        return (EINVAL);
 }
 
@@ -995,20 +987,17 @@ static int
 zero_entry6(struct ip6_fw *frwl)
 {
        struct ip6_fw_chain *fcp;
-       int s;
 
        /*
         *      It's possible to insert multiple chain entries with the
         *      same number, so we don't stop after finding the first
         *      match if zeroing a specific entry.
         */
-       s = splnet();
        for (fcp = ip6_fw_chain.lh_first; fcp; fcp = fcp->chain.le_next)
                if (!frwl || frwl->fw_number == 0 || frwl->fw_number == fcp->rule->fw_number) {
                        fcp->rule->fw_bcnt = fcp->rule->fw_pcnt = 0;
                        fcp->rule->timestamp = 0;
                }
-       splx(s);
 
        if (fw6_verbose) {
                if (frwl)
@@ -1277,7 +1266,6 @@ static int
 ip6_fw_ctl(struct sockopt *sopt)
 {
        int error = 0;
-       int spl;
        int valsize;
        struct ip6_fw rule;
        int is64user=0;
@@ -1331,8 +1319,6 @@ ip6_fw_ctl(struct sockopt *sopt)
                        size_t size = 0;
                        size_t rulesize = 0;
 
-                       spl = splnet();
-                       
                        if ( is64user )
                                rulesize = sizeof(struct ip6_fw_64 );
                        else
@@ -1364,7 +1350,6 @@ ip6_fw_ctl(struct sockopt *sopt)
                                }
                        }
 
-                       splx(spl);
                        if (buf)
                        {
                                sopt->sopt_valsize = valsize;
@@ -1376,7 +1361,6 @@ ip6_fw_ctl(struct sockopt *sopt)
                }
 
                case IPV6_FW_FLUSH:
-                       spl = splnet();
                        while (ip6_fw_chain.lh_first &&
                                ip6_fw_chain.lh_first->rule->fw_number != (u_short)-1)
                        {
@@ -1385,7 +1369,6 @@ ip6_fw_ctl(struct sockopt *sopt)
                                FREE(fcp->rule, M_IP6FW);
                                FREE(fcp, M_IP6FW);
                        }
-                       splx(spl);
                        ip6fw_kev_post_msg(KEV_IP6FW_FLUSH);
                        break;
 
@@ -1400,6 +1383,17 @@ ip6_fw_ctl(struct sockopt *sopt)
                                ip6fw_kev_post_msg(KEV_IP6FW_ADD);
                        } else
                                error = EINVAL;
+
+                       if (is64user){
+                               struct ip6_fw_64 userrule_64;
+                               cp_to_user_64( &userrule_64, &rule);
+                               error = sooptcopyout(sopt, &userrule_64, userrulesize);
+                       }
+                       else {
+                               struct ip6_fw_32 userrule_32;
+                               cp_to_user_32( &userrule_32, &rule);
+                               error = sooptcopyout(sopt, &userrule_32, userrulesize);
+                       }
                        break;
 
                case IPV6_FW_DEL: