#define SMK_RECEIVING  1
 #define SMK_SENDING    2
 
+#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER)
 LIST_HEAD(smk_ipv6_port_list);
+#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */
 static struct kmem_cache *smack_inode_cache;
+int smack_enabled;
 
 #ifdef CONFIG_SECURITY_SMACK_BRINGUP
 static void smk_bu_mode(int mode, char *s)
        return smack_netlabel(sk, sk_lbl);
 }
 
+#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER)
 /**
  * smk_ipv6_port_label - Smack port access table management
  * @sock: socket
        rc = smk_bu_note("IPv6 port check", skp, object, MAY_WRITE, rc);
        return rc;
 }
+#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */
 
 /**
  * smack_inode_setsecurity - set smack xattrs
        } else
                return -EOPNOTSUPP;
 
+#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER)
        if (sock->sk->sk_family == PF_INET6)
                smk_ipv6_port_label(sock, NULL);
+#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */
 
        return 0;
 }
        return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
 }
 
+#ifndef CONFIG_SECURITY_SMACK_NETFILTER
 /**
  * smack_socket_bind - record port binding information.
  * @sock: the socket
 static int smack_socket_bind(struct socket *sock, struct sockaddr *address,
                                int addrlen)
 {
+#if IS_ENABLED(CONFIG_IPV6)
        if (sock->sk != NULL && sock->sk->sk_family == PF_INET6)
                smk_ipv6_port_label(sock, address);
+#endif
 
        return 0;
 }
+#endif /* !CONFIG_SECURITY_SMACK_NETFILTER */
 
 /**
  * smack_socket_connect - connect access check
        case PF_INET6:
                if (addrlen < sizeof(struct sockaddr_in6))
                        return -EINVAL;
+#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER)
                rc = smk_ipv6_port_check(sock->sk, (struct sockaddr_in6 *)sap,
                                                SMK_CONNECTING);
+#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */
                break;
        }
        return rc;
                                int size)
 {
        struct sockaddr_in *sip = (struct sockaddr_in *) msg->msg_name;
+#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER)
        struct sockaddr_in6 *sap = (struct sockaddr_in6 *) msg->msg_name;
+#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */
        int rc = 0;
 
        /*
                rc = smack_netlabel_send(sock->sk, sip);
                break;
        case AF_INET6:
+#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER)
                rc = smk_ipv6_port_check(sock->sk, sap, SMK_SENDING);
+#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */
                break;
        }
        return rc;
        return smack_net_ambient;
 }
 
+#if IS_ENABLED(CONFIG_IPV6)
 static int smk_skb_to_addr_ipv6(struct sk_buff *skb, struct sockaddr_in6 *sip)
 {
        u8 nexthdr;
        }
        return proto;
 }
+#endif /* CONFIG_IPV6 */
 
 /**
  * smack_socket_sock_rcv_skb - Smack packet delivery access check
 {
        struct netlbl_lsm_secattr secattr;
        struct socket_smack *ssp = sk->sk_security;
-       struct smack_known *skp;
-       struct sockaddr_in6 sadd;
+       struct smack_known *skp = NULL;
        int rc = 0;
        struct smk_audit_info ad;
 #ifdef CONFIG_AUDIT
        struct lsm_network_audit net;
 #endif
+#if IS_ENABLED(CONFIG_IPV6)
+       struct sockaddr_in6 sadd;
+       int proto;
+#endif /* CONFIG_IPV6 */
+
        switch (sk->sk_family) {
        case PF_INET:
+#ifdef CONFIG_SECURITY_SMACK_NETFILTER
+               /*
+                * If there is a secmark use it rather than the CIPSO label.
+                * If there is no secmark fall back to CIPSO.
+                * The secmark is assumed to reflect policy better.
+                */
+               if (skb && skb->secmark != 0) {
+                       skp = smack_from_secid(skb->secmark);
+                       goto access_check;
+               }
+#endif /* CONFIG_SECURITY_SMACK_NETFILTER */
                /*
                 * Translate what netlabel gave us.
                 */
 
                netlbl_secattr_destroy(&secattr);
 
+#ifdef CONFIG_SECURITY_SMACK_NETFILTER
+access_check:
+#endif
 #ifdef CONFIG_AUDIT
                smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
                ad.a.u.net->family = sk->sk_family;
                if (rc != 0)
                        netlbl_skbuff_err(skb, rc, 0);
                break;
+#if IS_ENABLED(CONFIG_IPV6)
        case PF_INET6:
-               rc = smk_skb_to_addr_ipv6(skb, &sadd);
-               if (rc == IPPROTO_UDP || rc == IPPROTO_TCP)
-                       rc = smk_ipv6_port_check(sk, &sadd, SMK_RECEIVING);
+               proto = smk_skb_to_addr_ipv6(skb, &sadd);
+               if (proto != IPPROTO_UDP && proto != IPPROTO_TCP)
+                       break;
+#ifdef CONFIG_SECURITY_SMACK_NETFILTER
+               if (skb && skb->secmark != 0)
+                       skp = smack_from_secid(skb->secmark);
                else
-                       rc = 0;
+                       skp = smack_net_ambient;
+#ifdef CONFIG_AUDIT
+               smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
+               ad.a.u.net->family = sk->sk_family;
+               ad.a.u.net->netif = skb->skb_iif;
+               ipv6_skb_to_auditdata(skb, &ad.a, NULL);
+#endif /* CONFIG_AUDIT */
+               rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad);
+               rc = smk_bu_note("IPv6 delivery", skp, ssp->smk_in,
+                                       MAY_WRITE, rc);
+#else /* CONFIG_SECURITY_SMACK_NETFILTER */
+               rc = smk_ipv6_port_check(sk, &sadd, SMK_RECEIVING);
+#endif /* CONFIG_SECURITY_SMACK_NETFILTER */
                break;
+#endif /* CONFIG_IPV6 */
        }
+
        return rc;
 }
 
        if (skb != NULL) {
                if (skb->protocol == htons(ETH_P_IP))
                        family = PF_INET;
+#if IS_ENABLED(CONFIG_IPV6)
                else if (skb->protocol == htons(ETH_P_IPV6))
                        family = PF_INET6;
+#endif /* CONFIG_IPV6 */
        }
        if (family == PF_UNSPEC && sock != NULL)
                family = sock->sk->sk_family;
 
-       if (family == PF_UNIX) {
+       switch (family) {
+       case PF_UNIX:
                ssp = sock->sk->sk_security;
                s = ssp->smk_out->smk_secid;
-       } else if (family == PF_INET || family == PF_INET6) {
+               break;
+       case PF_INET:
+#ifdef CONFIG_SECURITY_SMACK_NETFILTER
+               s = skb->secmark;
+               if (s != 0)
+                       break;
+#endif
                /*
                 * Translate what netlabel gave us.
                 */
                        s = skp->smk_secid;
                }
                netlbl_secattr_destroy(&secattr);
+               break;
+#if IS_ENABLED(CONFIG_IPV6)
+       case PF_INET6:
+#ifdef CONFIG_SECURITY_SMACK_NETFILTER
+               s = skb->secmark;
+#endif /* CONFIG_SECURITY_SMACK_NETFILTER */
+               break;
+#endif /* CONFIG_IPV6 */
        }
        *secid = s;
        if (s == 0)
        struct lsm_network_audit net;
 #endif
 
+#if IS_ENABLED(CONFIG_IPV6)
        if (family == PF_INET6) {
                /*
                 * Handle mapped IPv4 packets arriving
                else
                        return 0;
        }
+#endif /* CONFIG_IPV6 */
 
        netlbl_secattr_init(&secattr);
        rc = netlbl_skbuff_getattr(skb, family, &secattr);
        .unix_may_send =                smack_unix_may_send,
 
        .socket_post_create =           smack_socket_post_create,
+#ifndef CONFIG_SECURITY_SMACK_NETFILTER
        .socket_bind =                  smack_socket_bind,
+#endif /* CONFIG_SECURITY_SMACK_NETFILTER */
        .socket_connect =               smack_socket_connect,
        .socket_sendmsg =               smack_socket_sendmsg,
        .socket_sock_rcv_skb =          smack_socket_sock_rcv_skb,
        if (!security_module_enable(&smack_ops))
                return 0;
 
+       smack_enabled = 1;
+
        smack_inode_cache = KMEM_CACHE(inode_smack, 0);
        if (!smack_inode_cache)
                return -ENOMEM;
 
--- /dev/null
+/*
+ *  Simplified MAC Kernel (smack) security module
+ *
+ *  This file contains the Smack netfilter implementation
+ *
+ *  Author:
+ *     Casey Schaufler <casey@schaufler-ca.com>
+ *
+ *  Copyright (C) 2014 Casey Schaufler <casey@schaufler-ca.com>
+ *  Copyright (C) 2014 Intel Corporation.
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License version 2,
+ *     as published by the Free Software Foundation.
+ */
+
+#include <linux/netfilter_ipv4.h>
+#include <linux/netfilter_ipv6.h>
+#include <linux/netdevice.h>
+#include "smack.h"
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+
+static unsigned int smack_ipv6_output(const struct nf_hook_ops *ops,
+                                       struct sk_buff *skb,
+                                       const struct net_device *in,
+                                       const struct net_device *out,
+                                       int (*okfn)(struct sk_buff *))
+{
+       struct socket_smack *ssp;
+       struct smack_known *skp;
+
+       if (skb && skb->sk && skb->sk->sk_security) {
+               ssp = skb->sk->sk_security;
+               skp = ssp->smk_out;
+               skb->secmark = skp->smk_secid;
+       }
+
+       return NF_ACCEPT;
+}
+#endif /* IPV6 */
+
+static unsigned int smack_ipv4_output(const struct nf_hook_ops *ops,
+                                       struct sk_buff *skb,
+                                       const struct net_device *in,
+                                       const struct net_device *out,
+                                       int (*okfn)(struct sk_buff *))
+{
+       struct socket_smack *ssp;
+       struct smack_known *skp;
+
+       if (skb && skb->sk && skb->sk->sk_security) {
+               ssp = skb->sk->sk_security;
+               skp = ssp->smk_out;
+               skb->secmark = skp->smk_secid;
+       }
+
+       return NF_ACCEPT;
+}
+
+static struct nf_hook_ops smack_nf_ops[] = {
+       {
+               .hook =         smack_ipv4_output,
+               .owner =        THIS_MODULE,
+               .pf =           NFPROTO_IPV4,
+               .hooknum =      NF_INET_LOCAL_OUT,
+               .priority =     NF_IP_PRI_SELINUX_FIRST,
+       },
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       {
+               .hook =         smack_ipv6_output,
+               .owner =        THIS_MODULE,
+               .pf =           NFPROTO_IPV6,
+               .hooknum =      NF_INET_LOCAL_OUT,
+               .priority =     NF_IP6_PRI_SELINUX_FIRST,
+       },
+#endif /* IPV6 */
+};
+
+static int __init smack_nf_ip_init(void)
+{
+       int err;
+
+       if (smack_enabled == 0)
+               return 0;
+
+       printk(KERN_DEBUG "Smack: Registering netfilter hooks\n");
+
+       err = nf_register_hooks(smack_nf_ops, ARRAY_SIZE(smack_nf_ops));
+       if (err)
+               pr_info("Smack: nf_register_hooks: error %d\n", err);
+
+       return 0;
+}
+
+__initcall(smack_nf_ip_init);