]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/netinet6/ip6_fw.c
xnu-3789.70.16.tar.gz
[apple/xnu.git] / bsd / netinet6 / ip6_fw.c
index 63522da8d3c4c437f17fd372746a63495c1d7a52..dfa12ff11c336aa86d42d9b5b0f169a98d4aca15 100644 (file)
@@ -1,31 +1,29 @@
 /*
- * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
+ * Copyright (c) 2003-2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
- * @APPLE_LICENSE_OSREFERENCE_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. 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.
  * 
- * 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.  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 
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
- * Please see the License for the specific language governing rights and 
+ * 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
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
  * limitations under the License.
- *
- * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
+ * 
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
  */
 
 /*     $FreeBSD: src/sys/netinet6/ip6_fw.c,v 1.2.2.9 2002/04/28 05:40:27 suz Exp $     */
 #include <sys/syslog.h>
 #include <sys/lock.h>
 #include <sys/time.h>
+#include <sys/kern_event.h>
+
 #include <net/if.h>
 #include <net/route.h>
 #include <netinet/in_systm.h>
 
 MALLOC_DEFINE(M_IP6FW, "Ip6Fw/Ip6Acct", "Ip6Fw/Ip6Acct chain's");
 
-static int fw6_debug = 1;
+static int fw6_debug = 0;
 #ifdef IPV6FIREWALL_VERBOSE
 static int fw6_verbose = 1;
 #else
@@ -142,14 +142,35 @@ static int fw6_verbose_limit = 0;
 
 LIST_HEAD (ip6_fw_head, ip6_fw_chain) ip6_fw_chain;
 
+static void ip6fw_kev_post_msg(u_int32_t );
+
 #ifdef SYSCTL_NODE
+static int ip6fw_sysctl SYSCTL_HANDLER_ARGS;
+
 SYSCTL_DECL(_net_inet6_ip6);
-SYSCTL_NODE(_net_inet6_ip6, OID_AUTO, fw, CTLFLAG_RW, 0, "Firewall");
-SYSCTL_INT(_net_inet6_ip6_fw, OID_AUTO, enable, CTLFLAG_RW,
-       &ip6_fw_enable, 0, "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_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 | CTLFLAG_LOCKED,
+       &ip6_fw_enable, 0, ip6fw_sysctl, "I", "Enable ip6fw");
+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
+{
+#pragma unused(arg1, arg2)
+       int error;
+       
+       error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
+       if (error || !req->newptr)
+               return (error);
+       
+       ip6fw_kev_post_msg(KEV_IP6FW_ENABLE);
+       
+       return error;
+}
+
 #endif
 
 #define dprintf(a)     do {                                            \
@@ -175,9 +196,12 @@ static void        ip6fw_report __P((struct ip6_fw *f, struct ip6_hdr *ip6,
 static int     ip6_fw_chk __P((struct ip6_hdr **pip6,
                        struct ifnet *oif, u_int16_t *cookie, struct mbuf **m));
 static int     ip6_fw_ctl __P((struct sockopt *));
+static void cp_to_user_64( struct ip6_fw_64 *userrule_64, struct ip6_fw *rule);
+static void cp_from_user_64( struct ip6_fw_64 *userrule_64, struct ip6_fw *rule);
+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
@@ -365,17 +389,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);
                }
@@ -394,7 +422,7 @@ ip6fw_report(struct ip6_fw *f, struct ip6_hdr *ip6,
        struct udphdr *const udp = (struct udphdr *) ((caddr_t) ip6+ off);
        struct icmp6_hdr *const icmp6 = (struct icmp6_hdr *) ((caddr_t) ip6+ off);
        int count;
-       char *action;
+       const char *action;
        char action2[32], proto[102], name[18];
        int len;
 
@@ -533,7 +561,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_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;
@@ -543,6 +571,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);
 
@@ -844,19 +873,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);
+                               *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;
                }
@@ -937,6 +966,7 @@ add_entry6(struct ip6_fw_head *chainptr, struct ip6_fw *frwl)
                }
        }
 
+       bcopy(ftmp, frwl, sizeof(struct ip6_fw));
        splx(s);
        return (0);
 }
@@ -1116,123 +1146,137 @@ check_ip6fw_struct(struct ip6_fw *frwl)
        return frwl;
 }
 
-/*#####*/
-#if 0
-static int
-ip6_fw_ctl(int stage, struct mbuf **mm)
+static void
+ip6fw_kev_post_msg(u_int32_t event_code)
 {
-       int error;
-       struct mbuf *m;
-
-       if (stage == IPV6_FW_GET) {
-               struct ip6_fw_chain *fcp = ip6_fw_chain.lh_first;
-               *mm = m = m_get(M_WAIT, MT_DATA); /* XXX */
-               if (!m)
-                       return(ENOBUFS);
-               if (sizeof *(fcp->rule) > MLEN) {
-                       MCLGET(m, M_WAIT);
-                       if ((m->m_flags & M_EXT) == 0) {
-                               m_free(m);
-                               return(ENOBUFS);
-                       }
-               }
-               for (; fcp; fcp = fcp->chain.le_next) {
-                       bcopy(fcp->rule, m->m_data, sizeof *(fcp->rule));
-                       m->m_len = sizeof *(fcp->rule);
-                       m->m_next = m_get(M_WAIT, MT_DATA); /* XXX */
-                       if (!m->m_next) {
-                               m_freem(*mm);
-                               return(ENOBUFS);
-                       }
-                       m = m->m_next;
-                       if (sizeof *(fcp->rule) > MLEN) {
-                               MCLGET(m, M_WAIT);
-                               if ((m->m_flags & M_EXT) == 0) {
-                                       m_freem(*mm);
-                                       return(ENOBUFS);
-                               }
-                       }
-                       m->m_len = 0;
-               }
-               return (0);
-       }
-       m = *mm;
-       /* only allow get calls if secure mode > 2 */
-       if (securelevel > 2) {
-               if (m) {
-                       (void)m_freem(m);
-                       *mm = 0;
-               }
-               return(EPERM);
-       }
-       if (stage == IPV6_FW_FLUSH) {
-               while (ip6_fw_chain.lh_first != NULL &&
-                   ip6_fw_chain.lh_first->rule->fw_number != (u_short)-1) {
-                       struct ip6_fw_chain *fcp = ip6_fw_chain.lh_first;
-                       int s = splnet();
-                       LIST_REMOVE(ip6_fw_chain.lh_first, chain);
-                       splx(s);
-                       FREE(fcp->rule, M_IP6FW);
-                       FREE(fcp, M_IP6FW);
-               }
-               if (m) {
-                       (void)m_freem(m);
-                       *mm = 0;
-               }
-               return (0);
-       }
-       if (stage == IPV6_FW_ZERO) {
-               error = zero_entry6(m);
-               if (m) {
-                       (void)m_freem(m);
-                       *mm = 0;
-               }
-               return (error);
-       }
-       if (m == NULL) {
-               printf("%s NULL mbuf ptr\n", err_prefix);
-               return (EINVAL);
-       }
+       struct kev_msg          ev_msg;
 
-       if (stage == IPV6_FW_ADD) {
-               struct ip6_fw *frwl = check_ip6fw_mbuf(m);
+       bzero(&ev_msg, sizeof(struct kev_msg));
+       
+       ev_msg.vendor_code = KEV_VENDOR_APPLE;
+       ev_msg.kev_class = KEV_FIREWALL_CLASS;
+       ev_msg.kev_subclass = KEV_IP6FW_SUBCLASS;
+       ev_msg.event_code = event_code;
 
-               if (!frwl)
-                       error = EINVAL;
-               else
-                       error = add_entry6(&ip6_fw_chain, frwl);
-               if (m) {
-                       (void)m_freem(m);
-                       *mm = 0;
-               }
-               return error;
-       }
-       if (stage == IPV6_FW_DEL) {
-               if (m->m_len != sizeof(struct ip6_fw)) {
-                       dprintf(("%s len=%ld, want %lu\n", err_prefix, m->m_len,
-                           sizeof(struct ip6_fw)));
-                       error = EINVAL;
-               } else if (mtod(m, struct ip6_fw *)->fw_number == (u_short)-1) {
-                       dprintf(("%s can't delete rule 65535\n", err_prefix));
-                       error = EINVAL;
-               } else
-                       error = del_entry6(&ip6_fw_chain,
-                           mtod(m, struct ip6_fw *)->fw_number);
-               if (m) {
-                       (void)m_freem(m);
-                       *mm = 0;
-               }
-               return error;
-       }
+       kev_post_msg(&ev_msg);
 
-       dprintf(("%s unknown request %d\n", err_prefix, stage));
-       if (m) {
-               (void)m_freem(m);
-               *mm = 0;
-       }
-       return (EINVAL);
 }
-#endif
+
+
+static void
+cp_to_user_64( struct ip6_fw_64 *userrule_64, struct ip6_fw *rule)
+{
+       userrule_64->version = rule->version;
+       userrule_64->context = CAST_USER_ADDR_T(rule->context);
+       userrule_64->fw_pcnt = rule->fw_pcnt;
+       userrule_64->fw_bcnt = rule->fw_bcnt;
+       userrule_64->fw_src = rule->fw_src;
+       userrule_64->fw_dst = rule->fw_dst;
+       userrule_64->fw_smsk = rule->fw_smsk;
+       userrule_64->fw_dmsk = rule->fw_dmsk;
+       userrule_64->fw_number = rule->fw_number;
+       userrule_64->fw_flg = rule->fw_flg;
+       userrule_64->fw_ipflg = rule->fw_ipflg;
+       bcopy( rule->fw_pts, userrule_64->fw_pts, IPV6_FW_MAX_PORTS);
+       userrule_64->fw_ip6opt= rule->fw_ip6opt;
+       userrule_64->fw_ip6nopt = rule->fw_ip6nopt;
+       userrule_64->fw_tcpf = rule->fw_tcpf;
+       userrule_64->fw_tcpnf = rule->fw_tcpnf;
+       bcopy( rule->fw_icmp6types, userrule_64->fw_icmp6types, sizeof(userrule_64->fw_icmp6types));
+       userrule_64->fw_in_if = rule->fw_in_if;
+       userrule_64->fw_out_if = rule->fw_out_if;
+       userrule_64->timestamp = rule->timestamp;
+       userrule_64->fw_un.fu_divert_port = rule->fw_un.fu_divert_port;
+       userrule_64->fw_prot = rule->fw_prot;
+       userrule_64->fw_nports = rule->fw_nports;
+}
+
+
+static void
+cp_from_user_64( struct ip6_fw_64 *userrule_64, struct ip6_fw *rule)
+{
+       rule->version = userrule_64->version;
+       rule->context = CAST_DOWN(void *, userrule_64->context);
+       rule->fw_pcnt = userrule_64->fw_pcnt;
+       rule->fw_bcnt = userrule_64->fw_bcnt;
+       rule->fw_src = userrule_64->fw_src;
+       rule->fw_dst = userrule_64->fw_dst;
+       rule->fw_smsk = userrule_64->fw_smsk;
+       rule->fw_dmsk = userrule_64->fw_dmsk;
+       rule->fw_number = userrule_64->fw_number;
+       rule->fw_flg = userrule_64->fw_flg;
+       rule->fw_ipflg = userrule_64->fw_ipflg;
+       bcopy( userrule_64->fw_pts, rule->fw_pts, IPV6_FW_MAX_PORTS);
+       rule->fw_ip6opt  = userrule_64->fw_ip6opt;
+       rule->fw_ip6nopt = userrule_64->fw_ip6nopt;
+       rule->fw_tcpf = userrule_64->fw_tcpf;
+       rule->fw_tcpnf = userrule_64->fw_tcpnf;
+       bcopy( userrule_64->fw_icmp6types, rule->fw_icmp6types, sizeof(userrule_64->fw_icmp6types));
+       rule->fw_in_if = userrule_64->fw_in_if;
+       rule->fw_out_if = userrule_64->fw_out_if;
+       rule->timestamp = CAST_DOWN( long, userrule_64->timestamp);
+       rule->fw_un.fu_divert_port = userrule_64->fw_un.fu_divert_port;
+       rule->fw_prot = userrule_64->fw_prot;
+       rule->fw_nports = userrule_64->fw_nports;
+}
+
+
+static void
+cp_to_user_32( struct ip6_fw_32 *userrule_32, struct ip6_fw *rule)
+{
+       userrule_32->version = rule->version;
+       userrule_32->context = CAST_DOWN_EXPLICIT( user32_addr_t, rule->context);
+       userrule_32->fw_pcnt = rule->fw_pcnt;
+       userrule_32->fw_bcnt = rule->fw_bcnt;
+       userrule_32->fw_src = rule->fw_src;
+       userrule_32->fw_dst = rule->fw_dst;
+       userrule_32->fw_smsk = rule->fw_smsk;
+       userrule_32->fw_dmsk = rule->fw_dmsk;
+       userrule_32->fw_number = rule->fw_number;
+       userrule_32->fw_flg = rule->fw_flg;
+       userrule_32->fw_ipflg = rule->fw_ipflg;
+       bcopy( rule->fw_pts, userrule_32->fw_pts, IPV6_FW_MAX_PORTS);
+       userrule_32->fw_ip6opt = rule->fw_ip6opt ;
+       userrule_32->fw_ip6nopt = rule->fw_ip6nopt;
+       userrule_32->fw_tcpf = rule->fw_tcpf;
+       userrule_32->fw_tcpnf = rule->fw_tcpnf;
+       bcopy( rule->fw_icmp6types, userrule_32->fw_icmp6types, sizeof(rule->fw_icmp6types));
+       userrule_32->fw_in_if = rule->fw_in_if;
+       userrule_32->fw_out_if = rule->fw_out_if;
+       userrule_32->timestamp = rule->timestamp;
+       userrule_32->fw_un.fu_divert_port = rule->fw_un.fu_divert_port;
+       userrule_32->fw_prot = rule->fw_prot;
+       userrule_32->fw_nports = rule->fw_nports;
+}
+
+
+static void
+cp_from_user_32( struct ip6_fw_32 *userrule_32, struct ip6_fw *rule)
+{
+       rule->version = userrule_32->version;
+       rule->context = CAST_DOWN(void *, userrule_32->context);
+       rule->fw_pcnt = userrule_32->fw_pcnt;
+       rule->fw_bcnt = userrule_32->fw_bcnt;
+       rule->fw_src = userrule_32->fw_src;
+       rule->fw_dst = userrule_32->fw_dst;
+       rule->fw_smsk = userrule_32->fw_smsk;
+       rule->fw_dmsk = userrule_32->fw_dmsk;
+       rule->fw_number = userrule_32->fw_number;
+       rule->fw_flg = userrule_32->fw_flg;
+       rule->fw_ipflg = userrule_32->fw_ipflg;
+       bcopy( userrule_32->fw_pts, rule->fw_pts, IPV6_FW_MAX_PORTS);
+       rule->fw_ip6opt  = userrule_32->fw_ip6opt;
+       rule->fw_ip6nopt = userrule_32->fw_ip6nopt;
+       rule->fw_tcpf = userrule_32->fw_tcpf;
+       rule->fw_tcpnf = userrule_32->fw_tcpnf;
+       bcopy( userrule_32->fw_icmp6types, rule->fw_icmp6types, sizeof(userrule_32->fw_icmp6types));
+       rule->fw_in_if = userrule_32->fw_in_if;
+       rule->fw_out_if = userrule_32->fw_out_if;
+       rule->timestamp = CAST_DOWN(long, userrule_32->timestamp);
+       rule->fw_un.fu_divert_port = userrule_32->fw_un.fu_divert_port;
+       rule->fw_prot = userrule_32->fw_prot;
+       rule->fw_nports = userrule_32->fw_nports;
+}
 
 static int
 ip6_fw_ctl(struct sockopt *sopt)
@@ -1241,22 +1285,45 @@ ip6_fw_ctl(struct sockopt *sopt)
        int spl;
        int valsize;
        struct ip6_fw rule;
+       int is64user=0;
+       size_t  userrulesize;
 
        if (securelevel >= 3 &&
                (sopt->sopt_dir != SOPT_GET || sopt->sopt_name != IPV6_FW_GET))
                return (EPERM);
 
+       if ( proc_is64bit(sopt->sopt_p) ){
+               is64user = 1;
+               userrulesize = sizeof( struct ip6_fw_64 );
+       } else
+               userrulesize = sizeof( struct ip6_fw_32 );
+       
        /* We ALWAYS expect the client to pass in a rule structure so that we can
         * check the version of the API that they are using.  In the case of a
         * IPV6_FW_GET operation, the first rule of the output buffer passed to us
         * must have the version set. */
-       if (!sopt->sopt_val || sopt->sopt_valsize < sizeof rule) return EINVAL;
+       if (!sopt->sopt_val || sopt->sopt_valsize < userrulesize) return EINVAL;
 
        /* save sopt->sopt_valsize */
        valsize = sopt->sopt_valsize;
-       if (error = sooptcopyin(sopt, &rule, sizeof(rule), sizeof(rule)))
-               return error;
-
+       
+       if (is64user){
+               struct ip6_fw_64 userrule_64;
+               
+               if ((error = sooptcopyin(sopt, &userrule_64, userrulesize, userrulesize)))
+                       return error;
+               
+               cp_from_user_64( &userrule_64, &rule );
+       }
+       else {
+               struct ip6_fw_32 userrule_32;
+               
+               if ((error = sooptcopyin(sopt, &userrule_32, userrulesize, userrulesize)))
+                       return error;
+               
+               cp_from_user_32( &userrule_32, &rule );
+       }
+       
        if (rule.version != IPV6_FW_CURRENT_API_VERSION) return EINVAL;
        rule.version = 0xFFFFFFFF;      /* version is meaningless once rules "make it in the door". */
 
@@ -1267,21 +1334,38 @@ ip6_fw_ctl(struct sockopt *sopt)
                        struct ip6_fw_chain *fcp;
                        struct ip6_fw *buf;
                        size_t size = 0;
+                       size_t rulesize = 0;
 
                        spl = splnet();
+                       
+                       if ( is64user )
+                               rulesize = sizeof(struct ip6_fw_64 );
+                       else
+                               rulesize = sizeof(struct ip6_fw_32 );
+                       
                        LIST_FOREACH(fcp, &ip6_fw_chain, chain)
-                               size += sizeof *buf;
+                               size += rulesize;
 
                        buf = _MALLOC(size, M_TEMP, M_WAITOK);
                        if (!buf) error = ENOBUFS;
                        else
                        {
-                               struct ip6_fw *bp = buf;
+                               //struct ip6_fw *bp = buf;
+                               caddr_t bp = (caddr_t)buf;
+                               
                                LIST_FOREACH(fcp, &ip6_fw_chain, chain)
                                {
-                                       bcopy(fcp->rule, bp, sizeof *bp);
-                                       bp->version = IPV6_FW_CURRENT_API_VERSION;
-                                       bp++;
+                                       //bcopy(fcp->rule, bp, sizeof *bp);
+                                       if ( is64user ){
+                                               cp_to_user_64( (struct ip6_fw_64*)bp, fcp->rule);
+                                       }
+                                       else {
+                                               cp_to_user_32( (struct ip6_fw_32*)bp, fcp->rule);
+                                       }
+
+                                       ( (struct ip6_fw*)bp)->version = IPV6_FW_CURRENT_API_VERSION;
+                                       //bp++;
+                                       bp += rulesize;
                                }
                        }
 
@@ -1307,6 +1391,7 @@ ip6_fw_ctl(struct sockopt *sopt)
                                FREE(fcp, M_IP6FW);
                        }
                        splx(spl);
+                       ip6fw_kev_post_msg(KEV_IP6FW_FLUSH);
                        break;
 
                case IPV6_FW_ZERO:
@@ -1314,10 +1399,23 @@ ip6_fw_ctl(struct sockopt *sopt)
                        break;
 
                case IPV6_FW_ADD:
-                       if (check_ip6fw_struct(&rule))
+                       if (check_ip6fw_struct(&rule)) {
                                error = add_entry6(&ip6_fw_chain, &rule);
-                       else
+
+                               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:
@@ -1326,8 +1424,11 @@ ip6_fw_ctl(struct sockopt *sopt)
                                dprintf(("%s can't delete rule 65535\n", err_prefix));
                                error = EINVAL;
                        }
-                       else
+                       else {
                                error = del_entry6(&ip6_fw_chain, rule.fw_number);
+
+                               ip6fw_kev_post_msg(KEV_IP6FW_DEL);
+                       }
                        break;
 
                default:
@@ -1358,7 +1459,7 @@ ip6_fw_init(void)
        default_rule.fw_flg |= IPV6_FW_F_IN | IPV6_FW_F_OUT;
        if (check_ip6fw_struct(&default_rule) == NULL ||
                add_entry6(&ip6_fw_chain, &default_rule))
-               panic(__FUNCTION__);
+               panic("%s", __FUNCTION__);
 
        printf("IPv6 packet filtering initialized, ");
 #ifdef IPV6FIREWALL_DEFAULT_TO_ACCEPT