]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/net/packet_mangler.c
xnu-7195.50.7.100.1.tar.gz
[apple/xnu.git] / bsd / net / packet_mangler.c
index b2666ee19156de2039297f32d4ce9662d1b5a303..d55219469e2fc4a983cd8d202003badd9e220f0b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 Apple Inc. All rights reserved.
+ * Copyright (c) 2015-2020 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
 #include <netinet/tcp.h>
 #include <netinet/tcp_var.h>
 #include <netinet/ip.h>
+#include <netinet/ip6.h>
 #include <netinet/kpi_ipfilter.h>
 #include <string.h>
 #include <libkern/libkern.h>
 
-#define        MAX_PACKET_MANGLER                      1
+#define MAX_PACKET_MANGLER                      1
 
-#define        PKT_MNGLR_FLG_IPFILTER_ATTACHED         0x00000001
+#define PKT_MNGLR_FLG_IPFILTER_ATTACHED         0x00000001
 
-SYSCTL_NODE(_net, OID_AUTO, pktmnglr, CTLFLAG_RW|CTLFLAG_LOCKED, 0, "pktmnglr");
-SYSCTL_INT(_net_pktmnglr, OID_AUTO, log, CTLFLAG_RW|CTLFLAG_LOCKED,
-               &pkt_mnglr_log_level, 0, "");
+SYSCTL_NODE(_net, OID_AUTO, pktmnglr, CTLFLAG_RW | CTLFLAG_LOCKED, 0, "pktmnglr");
+SYSCTL_INT(_net_pktmnglr, OID_AUTO, log, CTLFLAG_RW | CTLFLAG_LOCKED,
+    &pkt_mnglr_log_level, 0, "");
 /*
  * The structure packet_mangler represents a user space packet filter
  * It's created and associated with a kernel control socket instance
  */
 struct packet_mangler {
-       kern_ctl_ref                    pkt_mnglr_kcref;
-       uint32_t                        pkt_mnglr_kcunit;
-       uint32_t                        pkt_mnglr_flags;
+       kern_ctl_ref                    pkt_mnglr_kcref;
+       uint32_t                        pkt_mnglr_kcunit;
+       uint32_t                        pkt_mnglr_flags;
        /* IP filter related params */
-       ipfilter_t                      pkt_mnglr_ipfref;
-       ipfilter_t                      pkt_mnglr_ipfrefv6;
-       struct ipf_filter               pkt_mnglr_ipfilter;
+       ipfilter_t                      pkt_mnglr_ipfref;
+       ipfilter_t                      pkt_mnglr_ipfrefv6;
+       struct ipf_filter               pkt_mnglr_ipfilter;
 
        /* Options */
-       uint8_t                         activate;
-       Pkt_Mnglr_Flow                  dir;
-       struct sockaddr_storage         lsaddr;
-       struct sockaddr_storage         rsaddr;
-       struct sockaddr_storage         swap_lsaddr;
-       struct sockaddr_storage         swap_rsaddr;
-       uint32_t                        ip_action_mask;
-       uint16_t                        lport;
-       uint16_t                        rport;
-       uint32_t                        proto;
-       uint32_t                        proto_action_mask;
+       uint8_t                         activate;
+       Pkt_Mnglr_Flow                  dir;
+       struct sockaddr_storage         lsaddr;
+       struct sockaddr_storage         rsaddr;
+       struct sockaddr_storage         swap_lsaddr;
+       struct sockaddr_storage         swap_rsaddr;
+       uint32_t                        ip_action_mask;
+       uint16_t                        lport;
+       uint16_t                        rport;
+       uint32_t                        proto;
+       uint32_t                        proto_action_mask;
 };
 
 /* Array of all the packet mangler instancesi */
 struct packet_mangler **packet_manglers = NULL;
 
-uint32_t pkt_mnglr_active_count = 0;   /* Number of active packet filters */
+uint32_t pkt_mnglr_active_count = 0;    /* Number of active packet filters */
 uint32_t pkt_mnglr_close_wait_timeout = 1000; /* in milliseconds */
 
 static kern_ctl_ref pkt_mnglr_kctlref = NULL;
@@ -103,7 +104,7 @@ static lck_grp_t *pkt_mnglr_lck_grp = NULL;
 /* The lock below protects packet_manglers DS, packet_mangler DS */
 decl_lck_rw_data(static, pkt_mnglr_lck_rw);
 
-#define        PKT_MNGLR_RW_LCK_MAX    8
+#define PKT_MNGLR_RW_LCK_MAX    8
 
 int pkt_mnglr_rw_nxt_lck = 0;
 void* pkt_mnglr_rw_lock_history[PKT_MNGLR_RW_LCK_MAX];
@@ -111,10 +112,8 @@ void* pkt_mnglr_rw_lock_history[PKT_MNGLR_RW_LCK_MAX];
 int pkt_mnglr_rw_nxt_unlck = 0;
 void* pkt_mnglr_rw_unlock_history[PKT_MNGLR_RW_LCK_MAX];
 
-
-#define        PACKET_MANGLER_ZONE_NAME        "packet_mangler"
-#define        PACKET_MANGLER_ZONE_MAX         10
-static struct zone *packet_mangler_zone = NULL;        /* zone for packet_mangler */
+static ZONE_DECLARE(packet_mangler_zone, "packet_mangler",
+    sizeof(struct packet_mangler), ZC_NONE);
 
 /*
  * For troubleshooting
@@ -131,13 +130,25 @@ static void pkt_mnglr_rw_lock_shared(lck_rw_t *);
 static void pkt_mnglr_rw_unlock_shared(lck_rw_t *);
 
 static errno_t pktmnglr_ipfilter_output(void *cookie, mbuf_t *data,
-               ipf_pktopts_t options);
+    ipf_pktopts_t options);
 static errno_t pktmnglr_ipfilter_input(void *cookie, mbuf_t *data,
-               int offset, u_int8_t protocol);
+    int offset, u_int8_t protocol);
 static void pktmnglr_ipfilter_detach(void *cookie);
 
 static void chksm_update(mbuf_t data);
 
+#define TCP_OPT_MULTIPATH_TCP   30
+#define MPTCP_SBT_VER_OFFSET    2
+
+#define MPTCP_SUBTYPE_MPCAPABLE         0x0
+#define MPTCP_SUBTYPE_MPJOIN            0x1
+#define MPTCP_SUBTYPE_DSS               0x2
+#define MPTCP_SUBTYPE_ADD_ADDR          0x3
+#define MPTCP_SUBTYPE_REM_ADDR          0x4
+#define MPTCP_SUBTYPE_MP_PRIO           0x5
+#define MPTCP_SUBTYPE_MP_FAIL           0x6
+#define MPTCP_SUBTYPE_MP_FASTCLOSE      0x7
+
 /*
  * packet filter global read write lock
  */
@@ -201,9 +212,9 @@ pkt_mnglr_rw_unlock_shared(lck_rw_t *lck)
  */
 static errno_t
 pkt_mnglr_ctl_connect(kern_ctl_ref kctlref, struct sockaddr_ctl *sac,
-               void **unitinfo)
+    void **unitinfo)
 {
-       errno_t error = 0;
+       errno_t error = 0;
        struct packet_mangler *p_pkt_mnglr = NULL;
 
        PKT_MNGLR_LOG(LOG_NOTICE, "Connecting packet mangler filter.");
@@ -237,10 +248,11 @@ pkt_mnglr_ctl_connect(kern_ctl_ref kctlref, struct sockaddr_ctl *sac,
                        goto done;
                }
                /* Another thread may have won the race */
-               if (packet_manglers != NULL)
+               if (packet_manglers != NULL) {
                        FREE(tmp, M_TEMP);
-               else
+               } else {
                        packet_manglers = tmp;
+               }
        }
 
        if (sac->sc_unit == 0 || sac->sc_unit > MAX_PACKET_MANGLER) {
@@ -280,24 +292,25 @@ pkt_mnglr_ctl_connect(kern_ctl_ref kctlref, struct sockaddr_ctl *sac,
        }
 
        PKT_MNGLR_LOG(LOG_INFO, "Registered packet mangler's IP Filters");
-       p_pkt_mnglr->pkt_mnglr_flags |= PKT_MNGLR_FLG_IPFILTER_ATTACHED;
+       p_pkt_mnglr->pkt_mnglr_flags |= PKT_MNGLR_FLG_IPFILTER_ATTACHED;
        pkt_mnglr_rw_unlock_exclusive(&pkt_mnglr_lck_rw);
 
 done:
-       if (error != 0 && p_pkt_mnglr != NULL)
+       if (error != 0 && p_pkt_mnglr != NULL) {
                zfree(packet_mangler_zone, p_pkt_mnglr);
+       }
 
        PKT_MNGLR_LOG(LOG_INFO, "return %d pkt_mnglr_active_count %u kcunit %u",
            error, pkt_mnglr_active_count, sac->sc_unit);
 
-       return (error);
+       return error;
 }
 
 static errno_t
 pkt_mnglr_ctl_disconnect(kern_ctl_ref kctlref, u_int32_t kcunit, void *unitinfo)
 {
 #pragma unused(kctlref)
-       errno_t error = 0;
+       errno_t error = 0;
        struct packet_mangler *p_pkt_mnglr;
 
        PKT_MNGLR_LOG(LOG_INFO, "Disconnecting packet mangler kernel control");
@@ -343,15 +356,15 @@ done:
        PKT_MNGLR_LOG(LOG_INFO, "return %d pkt_mnglr_active_count %u kcunit %u",
            error, pkt_mnglr_active_count, kcunit);
 
-       return (error);
+       return error;
 }
 
 static errno_t
 pkt_mnglr_ctl_getopt(kern_ctl_ref kctlref, u_int32_t kcunit, void *unitinfo,
-               int opt, void *data, size_t *len)
+    int opt, void *data, size_t *len)
 {
 #pragma unused(kctlref, opt)
-       errno_t error = 0;
+       errno_t error = 0;
        struct packet_mangler *p_pkt_mnglr = (struct packet_mangler *)unitinfo;
 
        PKT_MNGLR_LOG(LOG_NOTICE, "");
@@ -376,128 +389,128 @@ pkt_mnglr_ctl_getopt(kern_ctl_ref kctlref, u_int32_t kcunit, void *unitinfo,
                goto done;
        }
        switch (opt) {
-               case PKT_MNGLR_OPT_PROTO_ACT_MASK:
-                       if (*len < sizeof(uint32_t)) {
-                               PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_PROTO_ACT_MASK "
-                                   "len too small %lu", *len);
-                               error = EINVAL;
-                               goto done;
-                       }
+       case PKT_MNGLR_OPT_PROTO_ACT_MASK:
+               if (*len < sizeof(uint32_t)) {
+                       PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_PROTO_ACT_MASK "
+                           "len too small %lu", *len);
+                       error = EINVAL;
+                       goto done;
+               }
 
-                       if (data != NULL) {
-                               *(uint32_t *)data = p_pkt_mnglr->proto_action_mask;
-                       }
-                       break;
-               case PKT_MNGLR_OPT_IP_ACT_MASK:
-                       if (*len < sizeof(uint32_t)) {
-                               PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_IP_ACT_MASK "
-                                   "len too small %lu", *len);
-                               error = EINVAL;
-                               goto done;
-                       }
+               if (data != NULL) {
+                       *(uint32_t *)data = p_pkt_mnglr->proto_action_mask;
+               }
+               break;
+       case PKT_MNGLR_OPT_IP_ACT_MASK:
+               if (*len < sizeof(uint32_t)) {
+                       PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_IP_ACT_MASK "
+                           "len too small %lu", *len);
+                       error = EINVAL;
+                       goto done;
+               }
 
-                       if (data != NULL) {
-                               *(uint32_t *)data = p_pkt_mnglr->ip_action_mask;
-                       }
-                       break;
-               case PKT_MNGLR_OPT_LOCAL_IP:
-                       if (*len < sizeof(struct sockaddr_storage)) {
-                               PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_LOCAL_IP "
-                                   "len too small %lu", *len);
-                               error = EINVAL;
-                               goto done;
-                       }
+               if (data != NULL) {
+                       *(uint32_t *)data = p_pkt_mnglr->ip_action_mask;
+               }
+               break;
+       case PKT_MNGLR_OPT_LOCAL_IP:
+               if (*len < sizeof(struct sockaddr_storage)) {
+                       PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_LOCAL_IP "
+                           "len too small %lu", *len);
+                       error = EINVAL;
+                       goto done;
+               }
 
-                       if (data != NULL) {
-                               *(struct sockaddr_storage *)data = p_pkt_mnglr->lsaddr;
-                       }
-                       break;
-               case PKT_MNGLR_OPT_REMOTE_IP:
-                       if (*len < sizeof(struct sockaddr_storage)) {
-                               PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_REMOTE_IP "
-                                   "len too small %lu", *len);
-                               error = EINVAL;
-                               goto done;
-                       }
+               if (data != NULL) {
+                       *(struct sockaddr_storage *)data = p_pkt_mnglr->lsaddr;
+               }
+               break;
+       case PKT_MNGLR_OPT_REMOTE_IP:
+               if (*len < sizeof(struct sockaddr_storage)) {
+                       PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_REMOTE_IP "
+                           "len too small %lu", *len);
+                       error = EINVAL;
+                       goto done;
+               }
 
-                       if (data != NULL) {
-                               *(struct sockaddr_storage *)data = p_pkt_mnglr->rsaddr;
-                       }
-                       break;
-               case PKT_MNGLR_OPT_LOCAL_PORT:
-                       if (*len < sizeof(uint16_t)) {
-                               PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_LOCAL_PORT "
-                                   "len too small %lu", *len);
-                               error = EINVAL;
-                               goto done;
-                       }
+               if (data != NULL) {
+                       *(struct sockaddr_storage *)data = p_pkt_mnglr->rsaddr;
+               }
+               break;
+       case PKT_MNGLR_OPT_LOCAL_PORT:
+               if (*len < sizeof(uint16_t)) {
+                       PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_LOCAL_PORT "
+                           "len too small %lu", *len);
+                       error = EINVAL;
+                       goto done;
+               }
 
-                       if (data != NULL) {
-                               *(uint16_t *)data = p_pkt_mnglr->lport;
-                       }
-                       break;
-               case PKT_MNGLR_OPT_REMOTE_PORT:
-                       if (*len < sizeof(uint16_t)) {
-                               PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_REMOTE_PORT "
-                                   "len too small %lu", *len);
-                               error = EINVAL;
-                               goto done;
-                       }
+               if (data != NULL) {
+                       *(uint16_t *)data = p_pkt_mnglr->lport;
+               }
+               break;
+       case PKT_MNGLR_OPT_REMOTE_PORT:
+               if (*len < sizeof(uint16_t)) {
+                       PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_REMOTE_PORT "
+                           "len too small %lu", *len);
+                       error = EINVAL;
+                       goto done;
+               }
 
-                       if (data != NULL) {
-                               *(uint16_t *)data = p_pkt_mnglr->rport;
-                       }
-                       break;
-               case PKT_MNGLR_OPT_DIRECTION:
-                       if (*len < sizeof(uint32_t)) {
-                               PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_DIRECTION "
-                                   "len too small %lu", *len);
-                               error = EINVAL;
-                               goto done;
-                       }
-                       if (data != NULL) {
-                               *(uint32_t *)data = p_pkt_mnglr->dir;
-                       }
-                       break;
-               case PKT_MNGLR_OPT_PROTOCOL:
-                       if (*len < sizeof(uint32_t)) {
-                               PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_PROTOCOL "
-                                   "len too small %lu", *len);
-                               error = EINVAL;
-                               goto done;
-                       }
-                       if (data != NULL) {
-                               *(uint32_t *)data = p_pkt_mnglr->proto;
-                       }
-                       break;
-               case PKT_MNGLR_OPT_ACTIVATE:
-                       if (*len < sizeof(uint8_t)) {
-                               PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_ACTIVATE "
-                                   "len too small %lu", *len);
-                               error = EINVAL;
-                               goto done;
-                       }
+               if (data != NULL) {
+                       *(uint16_t *)data = p_pkt_mnglr->rport;
+               }
+               break;
+       case PKT_MNGLR_OPT_DIRECTION:
+               if (*len < sizeof(uint32_t)) {
+                       PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_DIRECTION "
+                           "len too small %lu", *len);
+                       error = EINVAL;
+                       goto done;
+               }
+               if (data != NULL) {
+                       *(uint32_t *)data = p_pkt_mnglr->dir;
+               }
+               break;
+       case PKT_MNGLR_OPT_PROTOCOL:
+               if (*len < sizeof(uint32_t)) {
+                       PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_PROTOCOL "
+                           "len too small %lu", *len);
+                       error = EINVAL;
+                       goto done;
+               }
+               if (data != NULL) {
+                       *(uint32_t *)data = p_pkt_mnglr->proto;
+               }
+               break;
+       case PKT_MNGLR_OPT_ACTIVATE:
+               if (*len < sizeof(uint8_t)) {
+                       PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_ACTIVATE "
+                           "len too small %lu", *len);
+                       error = EINVAL;
+                       goto done;
+               }
 
-                       if (data != NULL) {
-                               *(uint8_t *)data = p_pkt_mnglr->activate;
-                       }
-                       break;
-               default:
-                       error = ENOPROTOOPT;
-                       break;
+               if (data != NULL) {
+                       *(uint8_t *)data = p_pkt_mnglr->activate;
+               }
+               break;
+       default:
+               error = ENOPROTOOPT;
+               break;
        }
 done:
        pkt_mnglr_rw_unlock_shared(&pkt_mnglr_lck_rw);
 
-       return (error);
+       return error;
 }
 
 static errno_t
 pkt_mnglr_ctl_setopt(kern_ctl_ref kctlref, u_int32_t kcunit, void *unitinfo,
-               int opt, void *data, size_t len)
+    int opt, void *data, size_t len)
 {
 #pragma unused(kctlref, opt)
-       errno_t error = 0;
+       errno_t error = 0;
        struct packet_mangler *p_pkt_mnglr = (struct packet_mangler *)unitinfo;
 
        PKT_MNGLR_LOG(LOG_NOTICE, "");
@@ -522,171 +535,170 @@ pkt_mnglr_ctl_setopt(kern_ctl_ref kctlref, u_int32_t kcunit, void *unitinfo,
                goto done;
        }
        switch (opt) {
-               case PKT_MNGLR_OPT_PROTO_ACT_MASK:
-                       if (len < sizeof(uint32_t)) {
-                               PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_PROTO_ACT_MASK "
-                                   "len too small %lu", len);
-                               error = EINVAL;
-                               goto done;
-                       }
-                       if (p_pkt_mnglr->proto_action_mask != 0) {
-                               PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_PROTO_ACT_MASK "
-                                   "already set %u",
-                                   p_pkt_mnglr->proto_action_mask);
-                               error = EINVAL;
-                               goto done;
-                       }
-                       p_pkt_mnglr->proto_action_mask = *(uint32_t *)data;
-                       PKT_MNGLR_LOG(LOG_INFO, "p_pkt_mnglr->proto_action_mask set to :%d", p_pkt_mnglr->proto_action_mask);
-                       break;
-               case PKT_MNGLR_OPT_IP_ACT_MASK:
-                       if (len < sizeof(uint32_t)) {
-                               PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_IP_ACT_MASK "
-                                   "len too small %lu", len);
-                               error = EINVAL;
-                               goto done;
-                       }
-                       if (p_pkt_mnglr->ip_action_mask != 0) {
-                               PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_IP_ACT_MASK "
-                                   "already set %u",
-                                   p_pkt_mnglr->ip_action_mask);
-                               error = EINVAL;
-                               goto done;
-                       }
-                       p_pkt_mnglr->ip_action_mask = *(uint32_t *)data;
-                       break;
-               case PKT_MNGLR_OPT_LOCAL_IP:
-                       if (len < sizeof(struct sockaddr_storage)) {
-                               PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_LOCAL_IP "
-                                   "len too small %lu", len);
-                               error = EINVAL;
-                               goto done;
-                       }
-                       if (p_pkt_mnglr->lsaddr.ss_family) {
-                               PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_LOCAL_IP "
-                                   "already set");
-                               error = EINVAL;
-                               goto done;
-                       }
-                       p_pkt_mnglr->lsaddr = *(struct sockaddr_storage *)data;
-                       break;
-               case PKT_MNGLR_OPT_REMOTE_IP:
-                       if (len < sizeof(struct sockaddr_storage)) {
-                               PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_REMOTE_IP "
-                                   "len too small %lu", len);
-                               error = EINVAL;
-                               goto done;
-                       }
-                       if (p_pkt_mnglr->rsaddr.ss_family) {
-                               PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_REMOTE_IP "
-                                   "already set");
-                               error = EINVAL;
-                               goto done;
-                       }
+       case PKT_MNGLR_OPT_PROTO_ACT_MASK:
+               if (len < sizeof(uint32_t)) {
+                       PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_PROTO_ACT_MASK "
+                           "len too small %lu", len);
+                       error = EINVAL;
+                       goto done;
+               }
+               if (p_pkt_mnglr->proto_action_mask != 0) {
+                       PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_PROTO_ACT_MASK "
+                           "already set %u",
+                           p_pkt_mnglr->proto_action_mask);
+                       error = EINVAL;
+                       goto done;
+               }
+               p_pkt_mnglr->proto_action_mask = *(uint32_t *)data;
+               PKT_MNGLR_LOG(LOG_INFO, "p_pkt_mnglr->proto_action_mask set to :%d", p_pkt_mnglr->proto_action_mask);
+               break;
+       case PKT_MNGLR_OPT_IP_ACT_MASK:
+               if (len < sizeof(uint32_t)) {
+                       PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_IP_ACT_MASK "
+                           "len too small %lu", len);
+                       error = EINVAL;
+                       goto done;
+               }
+               if (p_pkt_mnglr->ip_action_mask != 0) {
+                       PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_IP_ACT_MASK "
+                           "already set %u",
+                           p_pkt_mnglr->ip_action_mask);
+                       error = EINVAL;
+                       goto done;
+               }
+               p_pkt_mnglr->ip_action_mask = *(uint32_t *)data;
+               break;
+       case PKT_MNGLR_OPT_LOCAL_IP:
+               if (len < sizeof(struct sockaddr_storage)) {
+                       PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_LOCAL_IP "
+                           "len too small %lu", len);
+                       error = EINVAL;
+                       goto done;
+               }
+               if (p_pkt_mnglr->lsaddr.ss_family) {
+                       PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_LOCAL_IP "
+                           "already set");
+                       error = EINVAL;
+                       goto done;
+               }
+               p_pkt_mnglr->lsaddr = *(struct sockaddr_storage *)data;
+               break;
+       case PKT_MNGLR_OPT_REMOTE_IP:
+               if (len < sizeof(struct sockaddr_storage)) {
+                       PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_REMOTE_IP "
+                           "len too small %lu", len);
+                       error = EINVAL;
+                       goto done;
+               }
+               if (p_pkt_mnglr->rsaddr.ss_family) {
+                       PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_REMOTE_IP "
+                           "already set");
+                       error = EINVAL;
+                       goto done;
+               }
 
-                       p_pkt_mnglr->rsaddr = *(struct sockaddr_storage *)data;
-                       PKT_MNGLR_LOG(LOG_INFO,
-                           "Remote IP registered for address family: %d",
-                           p_pkt_mnglr->rsaddr.ss_family);
-                       break;
-               case PKT_MNGLR_OPT_LOCAL_PORT:
-                       if (len < sizeof(uint16_t)) {
-                               PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_LOCAL_PORT "
-                                   "len too small %lu", len);
-                               error = EINVAL;
-                               goto done;
-                       }
-                       if (p_pkt_mnglr->lport != 0) {
-                               PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_LOCAL_PORT "
-                                   "already set %d",
-                                   p_pkt_mnglr->lport);
-                               error = EINVAL;
-                               goto done;
-                       }
-                       p_pkt_mnglr->lport = *(uint16_t *)data;
-                       break;
-               case PKT_MNGLR_OPT_REMOTE_PORT:
-                       if (len < sizeof(uint16_t)) {
-                               PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_REMOTE_PORT "
-                                   "len too small %lu", len);
-                               error = EINVAL;
-                               goto done;
-                       }
-                       if (p_pkt_mnglr->rport != 0) {
-                               PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_REMOTE_PORT "
-                                   "already set %d",
-                                   p_pkt_mnglr->rport);
-                               error = EINVAL;
-                               goto done;
-                       }
-                       p_pkt_mnglr->rport = *(uint16_t *)data;
-                       break;
-               case PKT_MNGLR_OPT_DIRECTION:
-                       if (len < sizeof(uint32_t)) {
-                               PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_DIRECTION "
-                                   "len too small %lu", len);
-                               error = EINVAL;
-                               goto done;
-                       }
-                       if (p_pkt_mnglr->dir != 0) {
-                               PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_DIRECTION "
-                                   "already set %u",
-                                   p_pkt_mnglr->dir);
-                               error = EINVAL;
-                               goto done;
-                       }
-                       p_pkt_mnglr->dir = *(uint32_t *)data;
-                       break;
-               case PKT_MNGLR_OPT_PROTOCOL:
-                       if (len < sizeof(uint32_t)) {
-                               PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_PROTOCOL "
-                                   "len too small %lu", len);
-                               error = EINVAL;
-                               goto done;
-                       }
-                       if (p_pkt_mnglr->proto != 0) {
-                               PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_PROTOCOL "
-                                   "already set %u",
-                                   p_pkt_mnglr->proto);
-                               error = EINVAL;
-                               goto done;
-                       }
-                       p_pkt_mnglr->proto = *(uint32_t *)data;
-                       break;
-               case PKT_MNGLR_OPT_ACTIVATE:
-                       if (len < sizeof(uint8_t)) {
-                               PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_ACTIVATE "
-                                   "len too small %lu", len);
-                               error = EINVAL;
-                               goto done;
-                       }
-                       if (p_pkt_mnglr->activate != 0) {
-                               PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_ACTIVATE "
-                                   "already set %u",
-                                   p_pkt_mnglr->activate);
-                               error = EINVAL;
-                               goto done;
-                       }
-                       p_pkt_mnglr->activate = *(uint8_t *)data;
-                       PKT_MNGLR_LOG(LOG_ERR, "p_pkt_mnglr->activate set to :%d",
+               p_pkt_mnglr->rsaddr = *(struct sockaddr_storage *)data;
+               PKT_MNGLR_LOG(LOG_INFO,
+                   "Remote IP registered for address family: %d",
+                   p_pkt_mnglr->rsaddr.ss_family);
+               break;
+       case PKT_MNGLR_OPT_LOCAL_PORT:
+               if (len < sizeof(uint16_t)) {
+                       PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_LOCAL_PORT "
+                           "len too small %lu", len);
+                       error = EINVAL;
+                       goto done;
+               }
+               if (p_pkt_mnglr->lport != 0) {
+                       PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_LOCAL_PORT "
+                           "already set %d",
+                           p_pkt_mnglr->lport);
+                       error = EINVAL;
+                       goto done;
+               }
+               p_pkt_mnglr->lport = *(uint16_t *)data;
+               break;
+       case PKT_MNGLR_OPT_REMOTE_PORT:
+               if (len < sizeof(uint16_t)) {
+                       PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_REMOTE_PORT "
+                           "len too small %lu", len);
+                       error = EINVAL;
+                       goto done;
+               }
+               if (p_pkt_mnglr->rport != 0) {
+                       PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_REMOTE_PORT "
+                           "already set %d",
+                           p_pkt_mnglr->rport);
+                       error = EINVAL;
+                       goto done;
+               }
+               p_pkt_mnglr->rport = *(uint16_t *)data;
+               break;
+       case PKT_MNGLR_OPT_DIRECTION:
+               if (len < sizeof(uint32_t)) {
+                       PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_DIRECTION "
+                           "len too small %lu", len);
+                       error = EINVAL;
+                       goto done;
+               }
+               if (p_pkt_mnglr->dir != 0) {
+                       PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_DIRECTION "
+                           "already set %u",
+                           p_pkt_mnglr->dir);
+                       error = EINVAL;
+                       goto done;
+               }
+               p_pkt_mnglr->dir = *(uint32_t *)data;
+               break;
+       case PKT_MNGLR_OPT_PROTOCOL:
+               if (len < sizeof(uint32_t)) {
+                       PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_PROTOCOL "
+                           "len too small %lu", len);
+                       error = EINVAL;
+                       goto done;
+               }
+               if (p_pkt_mnglr->proto != 0) {
+                       PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_PROTOCOL "
+                           "already set %u",
+                           p_pkt_mnglr->proto);
+                       error = EINVAL;
+                       goto done;
+               }
+               p_pkt_mnglr->proto = *(uint32_t *)data;
+               break;
+       case PKT_MNGLR_OPT_ACTIVATE:
+               if (len < sizeof(uint8_t)) {
+                       PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_ACTIVATE "
+                           "len too small %lu", len);
+                       error = EINVAL;
+                       goto done;
+               }
+               if (p_pkt_mnglr->activate != 0) {
+                       PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_ACTIVATE "
+                           "already set %u",
                            p_pkt_mnglr->activate);
-                       break;
-               default:
-                       error = ENOPROTOOPT;
-                       break;
+                       error = EINVAL;
+                       goto done;
+               }
+               p_pkt_mnglr->activate = *(uint8_t *)data;
+               PKT_MNGLR_LOG(LOG_ERR, "p_pkt_mnglr->activate set to :%d",
+                   p_pkt_mnglr->activate);
+               break;
+       default:
+               error = ENOPROTOOPT;
+               break;
        }
 done:
        pkt_mnglr_rw_unlock_exclusive(&pkt_mnglr_lck_rw);
 
-       return (error);
+       return error;
 }
 
 void
 pkt_mnglr_init(void)
 {
        struct kern_ctl_reg kern_ctl;
-       errno_t error = 0;
-       vm_size_t pkt_mnglr_size = 0;
+       errno_t error = 0;
 
        PKT_MNGLR_LOG(LOG_NOTICE, "");
 
@@ -695,23 +707,6 @@ pkt_mnglr_init(void)
         */
        _CASSERT(PKT_MNGLR_MAX_FILTER_COUNT == MAX_PACKET_MANGLER);
 
-       /*
-        * Zone for packet mangler kernel control sockets
-        */
-       pkt_mnglr_size = sizeof(struct packet_mangler);
-       packet_mangler_zone = zinit(pkt_mnglr_size,
-           PACKET_MANGLER_ZONE_MAX * pkt_mnglr_size,
-           0,
-           PACKET_MANGLER_ZONE_NAME);
-
-       if (packet_mangler_zone == NULL) {
-               panic("%s: zinit(%s) failed", __func__,
-                   PACKET_MANGLER_ZONE_NAME);
-               /* NOTREACHED */
-       }
-       zone_change(packet_mangler_zone, Z_CALLERACCT, FALSE);
-       zone_change(packet_mangler_zone, Z_EXPAND, TRUE);
-
        /*
         * Allocate locks
         */
@@ -752,74 +747,84 @@ pkt_mnglr_init(void)
        }
 }
 
-static errno_t pktmnglr_ipfilter_output(void *cookie, mbuf_t *data, ipf_pktopts_t options)
+static errno_t
+pktmnglr_ipfilter_output(void *cookie, mbuf_t *data, ipf_pktopts_t options)
 {
        struct packet_mangler *p_pkt_mnglr = (struct packet_mangler *)cookie;
-       unsigned char *ptr = (unsigned char *)mbuf_data(*data);
-       struct ip *ip = (struct ip *)(void *)ptr;
-       struct tcphdr *tcp;
+       struct ip ip;
+       struct tcphdr tcp;
        int optlen = 0;
+       errno_t error = 0;
 
 #pragma unused(tcp, optlen, options)
-
        if (p_pkt_mnglr == NULL) {
-               return 0;
+               goto output_done;
        }
 
        if (!p_pkt_mnglr->activate) {
-               return 0;
+               goto output_done;
+       }
+
+       if (p_pkt_mnglr->dir == IN) {
+               goto output_done;
        }
 
        if (data == NULL) {
-               PKT_MNGLR_LOG(LOG_INFO, "%s:%d Data pointer is NULL\n", __FILE__, __LINE__);
-               return 0;
+               PKT_MNGLR_LOG(LOG_ERR, "Data pointer is NULL");
+               goto output_done;
        }
 
-       if (p_pkt_mnglr->dir == IN) {
-               return 0;
+       /* Check for IP filter options */
+       error = mbuf_copydata(*data, 0, sizeof(ip), &ip);
+       if (error) {
+               PKT_MNGLR_LOG(LOG_ERR, "Could not make local IP header copy");
+               goto output_done;
        }
 
-       if ((p_pkt_mnglr->lsaddr.ss_family == AF_INET6) && (ip->ip_v == 4)) {
-               return 0;
+       if ((p_pkt_mnglr->lsaddr.ss_family == AF_INET6) && (ip.ip_v == 4)) {
+               goto output_done;
        }
 
-       if ((p_pkt_mnglr->lsaddr.ss_family == AF_INET) && (ip->ip_v == 6)) {
-               return 0;
+       if ((p_pkt_mnglr->lsaddr.ss_family == AF_INET) && (ip.ip_v == 6)) {
+               goto output_done;
        }
 
        if (p_pkt_mnglr->lsaddr.ss_family == AF_INET) {
                struct sockaddr_in laddr = *(struct sockaddr_in *)(&(p_pkt_mnglr->lsaddr));
-               if (ip->ip_src.s_addr != laddr.sin_addr.s_addr) {
-                       return 0;
+               if (ip.ip_src.s_addr != laddr.sin_addr.s_addr) {
+                       goto output_done;
                }
        }
 
        if (p_pkt_mnglr->rsaddr.ss_family == AF_INET) {
                struct sockaddr_in raddr = *(struct sockaddr_in *)(&(p_pkt_mnglr->rsaddr));
-               if (ip->ip_dst.s_addr != raddr.sin_addr.s_addr) {
-                       return 0;
+               if (ip.ip_dst.s_addr != raddr.sin_addr.s_addr) {
+                       goto output_done;
                }
        }
 
-       if (ip->ip_v != 4) {
-               PKT_MNGLR_LOG(LOG_INFO, "%s:%d Not handling IP version %d\n", __FILE__, __LINE__, ip->ip_v);
-               return 0;
+       if (ip.ip_v != 4) {
+               PKT_MNGLR_LOG(LOG_INFO,
+                   "%s:%d Not handling IP version %d\n",
+                   __func__, __LINE__, ip.ip_v);
+               goto output_done;
        }
 
+output_done:
        /* Not handling output flow */
        return 0;
 }
 
-#define        TCP_MAX_OPTLEN  40
+#define TCP_MAX_OPTLEN  40
 
-static errno_t pktmnglr_ipfilter_input(void *cookie, mbuf_t *data, int offset, u_int8_t protocol)
+static errno_t
+pktmnglr_ipfilter_input(void *cookie, mbuf_t *data, int offset, u_int8_t protocol)
 {
        struct packet_mangler *p_pkt_mnglr = (struct packet_mangler *)cookie;
+       struct ip6_hdr ip6;
        struct ip ip;
        struct tcphdr tcp;
-       char tcp_opt_buf[TCP_MAX_OPTLEN] = {0};
-       int orig_tcp_optlen;
-       int tcp_optlen = 0;
+       int ip_pld_len;
        errno_t error = 0;
 
        if (p_pkt_mnglr == NULL) {
@@ -832,12 +837,12 @@ static errno_t pktmnglr_ipfilter_input(void *cookie, mbuf_t *data, int offset, u
                goto input_done;
        }
 
-       if (data == NULL) {
-               PKT_MNGLR_LOG(LOG_ERR, "Data pointer is NULL");
+       if (p_pkt_mnglr->dir == OUT) {
                goto input_done;
        }
 
-       if (p_pkt_mnglr->dir == OUT) {
+       if (data == NULL) {
+               PKT_MNGLR_LOG(LOG_ERR, "Data pointer is NULL");
                goto input_done;
        }
 
@@ -848,6 +853,14 @@ static errno_t pktmnglr_ipfilter_input(void *cookie, mbuf_t *data, int offset, u
                goto input_done;
        }
 
+       if (ip.ip_v == 6) {
+               error = mbuf_copydata(*data, 0, sizeof(ip6), &ip6);
+               if (error) {
+                       PKT_MNGLR_LOG(LOG_ERR, "Could not make local IPv6 header copy");
+                       goto input_done;
+               }
+       }
+
        if ((p_pkt_mnglr->lsaddr.ss_family == AF_INET6) && (ip.ip_v == 4)) {
                PKT_MNGLR_LOG(LOG_INFO, "Skipping filtering as address family of packet is IPv4 but local "
                    "address is set to IPv6");
@@ -865,6 +878,11 @@ static errno_t pktmnglr_ipfilter_input(void *cookie, mbuf_t *data, int offset, u
                if (ip.ip_dst.s_addr != laddr.sin_addr.s_addr) {
                        goto input_done;
                }
+       } else if (p_pkt_mnglr->lsaddr.ss_family == AF_INET6) {
+               struct sockaddr_in6 laddr = *(struct sockaddr_in6 *)(&(p_pkt_mnglr->lsaddr));
+               if (!IN6_ARE_ADDR_EQUAL(&ip6.ip6_dst, &laddr.sin6_addr)) {
+                       goto input_done;
+               }
        }
 
        if (p_pkt_mnglr->rsaddr.ss_family == AF_INET) {
@@ -875,47 +893,62 @@ static errno_t pktmnglr_ipfilter_input(void *cookie, mbuf_t *data, int offset, u
                PKT_MNGLR_LOG(LOG_INFO, "Remote IP: %x Source IP: %x in input path",
                    raddr.sin_addr.s_addr,
                    ip.ip_src.s_addr);
+       } else if (p_pkt_mnglr->rsaddr.ss_family == AF_INET6) {
+               struct sockaddr_in6 raddr = *(struct sockaddr_in6 *)(&(p_pkt_mnglr->rsaddr));
+               if (!IN6_ARE_ADDR_EQUAL(&ip6.ip6_src, &raddr.sin6_addr)) {
+                       goto input_done;
+               }
        }
 
-       if (ip.ip_v != 4) {
+       if (ip.ip_v == 4) {
+               ip_pld_len = ntohs(ip.ip_len) - (ip.ip_hl << 2);
+       } else if (ip.ip_v == 6) {
+               if (ip6.ip6_nxt != p_pkt_mnglr->proto) {
+                       /* Don't support IPv6 extension headers */
+                       goto input_done;
+               }
+               ip_pld_len = ntohs(ip6.ip6_plen) + sizeof(struct ip6_hdr);
+       } else {
                goto input_done;
        }
 
+
        if (protocol != p_pkt_mnglr->proto) {
                PKT_MNGLR_LOG(LOG_INFO, "Skip: Protocol mismatch");
                goto input_done;
        }
 
        switch (protocol) {
-               case IPPROTO_TCP:
-                       error = mbuf_copydata(*data, offset, sizeof(tcp), &tcp);
-                       if (error) {
-                               PKT_MNGLR_LOG(LOG_ERR, "Could not make local TCP header copy");
-                               goto input_done;
-                       }
-
-                       if (p_pkt_mnglr->lport && (p_pkt_mnglr->lport != tcp.th_dport)) {
-                               PKT_MNGLR_LOG(LOG_INFO, "Local port and IP des port do not match");
-                               goto input_done;
-                       }
+       case IPPROTO_TCP:
+               if (ip_pld_len < (int) sizeof(tcp)) {
+                       PKT_MNGLR_LOG(LOG_ERR, "IP total len not big enough for TCP: %d", ip_pld_len);
+                       goto drop_it;
+               }
 
-                       if (p_pkt_mnglr->rport && (p_pkt_mnglr->rport != tcp.th_sport)) {
-                               PKT_MNGLR_LOG(LOG_INFO, "Remote port and IP src port do not match");
-                               goto input_done;
-                       }
-                       break;
-               case IPPROTO_UDP:
-                       goto input_done;
-                       break;
-               case IPPROTO_ICMP:
+               error = mbuf_copydata(*data, offset, sizeof(tcp), &tcp);
+               if (error) {
+                       PKT_MNGLR_LOG(LOG_ERR, "Could not make local TCP header copy");
                        goto input_done;
-                       break;
-               case IPPROTO_ICMPV6:
+               }
+
+               if (p_pkt_mnglr->lport && (p_pkt_mnglr->lport != tcp.th_dport)) {
+                       PKT_MNGLR_LOG(LOG_INFO, "Local port and IP des port do not match");
                        goto input_done;
-                       break;
-               default:
+               }
+
+               if (p_pkt_mnglr->rport && (p_pkt_mnglr->rport != tcp.th_sport)) {
+                       PKT_MNGLR_LOG(LOG_INFO, "Remote port and IP src port do not match");
                        goto input_done;
-                       break;
+               }
+               break;
+       case IPPROTO_UDP:
+               goto input_done;
+       case IPPROTO_ICMP:
+               goto input_done;
+       case IPPROTO_ICMPV6:
+               goto input_done;
+       default:
+               goto input_done;
        }
 
        /* XXX Do IP actions here */
@@ -923,85 +956,132 @@ static errno_t pktmnglr_ipfilter_input(void *cookie, mbuf_t *data, int offset, u
 
        /* Protocol actions */
        switch (protocol) {
-               case IPPROTO_TCP:
-                       if (p_pkt_mnglr->proto_action_mask & PKT_MNGLR_TCP_ACT_NOP_MPTCP) {
-                               int i = 0;
-                               tcp_optlen = (tcp.th_off << 2)-sizeof(struct tcphdr);
-                               PKT_MNGLR_LOG(LOG_INFO, "Packet from F5 is TCP\n");
-                               PKT_MNGLR_LOG(LOG_INFO, "Optlen: %d\n", tcp_optlen);
-                               orig_tcp_optlen = tcp_optlen;
-                               if (orig_tcp_optlen) {
-                                       error = mbuf_copydata(*data, offset+sizeof(struct tcphdr), orig_tcp_optlen, tcp_opt_buf);
-                                       if (error) {
-                                               PKT_MNGLR_LOG(LOG_ERR, "Failed to copy tcp options");
-                                               goto input_done;
-                                       }
+       case IPPROTO_TCP:
+               if (p_pkt_mnglr->proto_action_mask) {
+                       char tcp_opt_buf[TCP_MAX_OPTLEN] = {0};
+                       int orig_tcp_optlen;
+                       int tcp_optlen = 0;
+                       int i = 0, off;
+
+                       off = (tcp.th_off << 2);
+
+                       if (off < (int) sizeof(struct tcphdr) || off > ip_pld_len) {
+                               PKT_MNGLR_LOG(LOG_ERR, "TCP header offset is wrong: %d", off);
+                               goto drop_it;
+                       }
+
+
+                       tcp_optlen = off - sizeof(struct tcphdr);
+
+                       PKT_MNGLR_LOG(LOG_INFO, "Packet from F5 is TCP\n");
+                       PKT_MNGLR_LOG(LOG_INFO, "Optlen: %d\n", tcp_optlen);
+                       orig_tcp_optlen = tcp_optlen;
+                       if (orig_tcp_optlen) {
+                               error = mbuf_copydata(*data, offset + sizeof(struct tcphdr), orig_tcp_optlen, tcp_opt_buf);
+                               if (error) {
+                                       PKT_MNGLR_LOG(LOG_ERR, "Failed to copy tcp options: error %d offset %d optlen %d", error, offset, orig_tcp_optlen);
+                                       goto input_done;
                                }
+                       }
 
-                               while (tcp_optlen) {
-                                       if (tcp_opt_buf[i] == 0x1) {
-                                               PKT_MNGLR_LOG(LOG_INFO, "Skipping NOP\n");
-                                               tcp_optlen--;
-                                               i++;
-                                               continue;
-                                       } else if ((tcp_opt_buf[i] != 0) && (tcp_opt_buf[i] != 0x1e)) {
-                                               PKT_MNGLR_LOG(LOG_INFO, "Skipping option %x\n", tcp_opt_buf[i]);
-                                               tcp_optlen -= tcp_opt_buf[i+1];
-                                               i += tcp_opt_buf[i+1];
-                                               continue;
-                                       } else if (tcp_opt_buf[i] == 0x1e) {
-                                               int j = 0;
-                                               int mptcpoptlen = tcp_opt_buf[i+1];
-                                               PKT_MNGLR_LOG(LOG_INFO, "Got MPTCP option %x\n", tcp_opt_buf[i]);
-                                               PKT_MNGLR_LOG(LOG_INFO, "Overwriting with NOP\n");
-                                               for (; j < mptcpoptlen; j++) {
-                                                       tcp_opt_buf[i+j] = 0x1;
+                       while (tcp_optlen > 0) {
+                               if (tcp_opt_buf[i] == 0x1) {
+                                       PKT_MNGLR_LOG(LOG_INFO, "Skipping NOP\n");
+                                       tcp_optlen--;
+                                       i++;
+                                       continue;
+                               } else if ((tcp_opt_buf[i] != 0) && (tcp_opt_buf[i] != TCP_OPT_MULTIPATH_TCP)) {
+                                       PKT_MNGLR_LOG(LOG_INFO, "Skipping option %x\n", tcp_opt_buf[i]);
+
+                                       /* Minimum TCP option size is 2 */
+                                       if (tcp_opt_buf[i + 1] < 2) {
+                                               PKT_MNGLR_LOG(LOG_ERR, "Received suspicious TCP option");
+                                               goto drop_it;
+                                       }
+                                       tcp_optlen -= tcp_opt_buf[i + 1];
+                                       i += tcp_opt_buf[i + 1];
+                                       continue;
+                               } else if (tcp_opt_buf[i] == TCP_OPT_MULTIPATH_TCP) {
+                                       int j = 0;
+                                       unsigned char mptcpoptlen = tcp_opt_buf[i + 1];
+                                       uint8_t sbtver = tcp_opt_buf[i + MPTCP_SBT_VER_OFFSET];
+                                       uint8_t subtype = sbtver >> 4;
+
+                                       PKT_MNGLR_LOG(LOG_INFO, "Got MPTCP option %x\n", tcp_opt_buf[i]);
+                                       PKT_MNGLR_LOG(LOG_INFO, "Got MPTCP subtype %x\n", subtype);
+                                       if (subtype == MPTCP_SUBTYPE_DSS) {
+                                               PKT_MNGLR_LOG(LOG_INFO, "Got DSS option\n");
+                                               PKT_MNGLR_LOG(LOG_INFO, "Protocol option mask: %d\n", p_pkt_mnglr->proto_action_mask);
+                                               if (p_pkt_mnglr->proto_action_mask &
+                                                   PKT_MNGLR_TCP_ACT_DSS_DROP) {
+                                                       goto drop_it;
                                                }
-                                               tcp_optlen -= mptcpoptlen;
-                                               i += mptcpoptlen;
-                                       } else {
-                                               tcp_optlen--;
-                                               i++;
                                        }
+
+                                       PKT_MNGLR_LOG(LOG_INFO, "Got MPTCP option %x\n", tcp_opt_buf[i]);
+                                       for (; j < mptcpoptlen && j < tcp_optlen; j++) {
+                                               if (p_pkt_mnglr->proto_action_mask &
+                                                   PKT_MNGLR_TCP_ACT_NOP_MPTCP) {
+                                                       tcp_opt_buf[i + j] = 0x1;
+                                               }
+                                       }
+                                       tcp_optlen -= mptcpoptlen;
+                                       i += mptcpoptlen;
+                               } else {
+                                       tcp_optlen--;
+                                       i++;
                                }
+                       }
+
+                       if (orig_tcp_optlen) {
                                error = mbuf_copyback(*data,
-                                   offset+sizeof(struct tcphdr),
+                                   offset + sizeof(struct tcphdr),
                                    orig_tcp_optlen, tcp_opt_buf, MBUF_WAITOK);
 
                                if (error) {
                                        PKT_MNGLR_LOG(LOG_ERR,
-                                           "Failed to copy tcp options");
+                                           "Failed to copy tcp options back: error %d offset %d optlen %d",
+                                           error, offset, orig_tcp_optlen);
                                        goto input_done;
                                }
                        }
-                       break;
-               case IPPROTO_UDP:
-                       /* Don't handle UDP */
-                       break;
-               case IPPROTO_ICMP:
-                       break;
-               case IPPROTO_ICMPV6:
-                       break;
-               default:
-                       break;
+               }
+               break;
+       case IPPROTO_UDP:
+               /* Don't handle UDP */
+               break;
+       case IPPROTO_ICMP:
+               break;
+       case IPPROTO_ICMPV6:
+               break;
+       default:
+               break;
        }
        chksm_update(*data);
 input_done:
        return 0;
+
+drop_it:
+       PKT_MNGLR_LOG(LOG_INFO, "Dropping packet\n");
+       mbuf_freem(*data);
+       return EJUSTRETURN;
 }
 
-static void pktmnglr_ipfilter_detach(void *cookie)
+static void
+pktmnglr_ipfilter_detach(void *cookie)
 {
 #pragma unused(cookie)
        return;
 }
 
 /* XXX Still need to modify this to use mbuf_copy* macros */
-static void chksm_update(mbuf_t data)
+static void
+chksm_update(mbuf_t data)
 {
        u_int16_t ip_sum;
        u_int16_t tsum;
        struct tcphdr *tcp;
+       errno_t err;
 
        unsigned char *ptr = (unsigned char *)mbuf_data(data);
        struct ip *ip = (struct ip *)(void *)ptr;
@@ -1010,26 +1090,29 @@ static void chksm_update(mbuf_t data)
        }
 
        ip->ip_sum = 0;
-       mbuf_inet_cksum(data, 0, 0, ip->ip_hl << 2, &ip_sum); // ip sum
-
-       ip->ip_sum = ip_sum;
+       err = mbuf_inet_cksum(data, 0, 0, ip->ip_hl << 2, &ip_sum); // ip sum
+       if (err == 0) {
+               ip->ip_sum = ip_sum;
+       }
        switch (ip->ip_p) {
-               case IPPROTO_TCP:
-                       tcp = (struct tcphdr *)(void *)(ptr + (ip->ip_hl << 2));
-                       tcp->th_sum = 0;
-                       mbuf_inet_cksum(data, IPPROTO_TCP, ip->ip_hl << 2,
-                           ntohs(ip->ip_len) - (ip->ip_hl << 2), &tsum);
+       case IPPROTO_TCP:
+               tcp = (struct tcphdr *)(void *)(ptr + (ip->ip_hl << 2));
+               tcp->th_sum = 0;
+               err = mbuf_inet_cksum(data, IPPROTO_TCP, ip->ip_hl << 2,
+                       ntohs(ip->ip_len) - (ip->ip_hl << 2), &tsum);
+               if (err == 0) {
                        tcp->th_sum = tsum;
-                       break;
-               case IPPROTO_UDP:
-                       /* Don't handle UDP */
-                       break;
-               case IPPROTO_ICMP:
-                       break;
-               case IPPROTO_ICMPV6:
-                       break;
-               default:
-                       break;
+               }
+               break;
+       case IPPROTO_UDP:
+               /* Don't handle UDP */
+               break;
+       case IPPROTO_ICMP:
+               break;
+       case IPPROTO_ICMPV6:
+               break;
+       default:
+               break;
        }
 
        mbuf_clear_csum_performed(data);