1/* 2 ************************************************************************** 3 * Copyright (c) 2015, The Linux Foundation. All rights reserved. 4 * Permission to use, copy, modify, and/or distribute this software for 5 * any purpose with or without fee is hereby granted, provided that the 6 * above copyright notice and this permission notice appear in all copies. 7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 13 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 ************************************************************************** 15 */ 16 17/* 18 * ecm_sfe_conntrack_notifier.c 19 * Conntrack notifier functionality. 20 */ 21 22#include <linux/version.h> 23#include <linux/types.h> 24#include <linux/ip.h> 25#include <linux/tcp.h> 26#include <linux/module.h> 27#include <linux/skbuff.h> 28#include <linux/icmp.h> 29#include <linux/kthread.h> 30#include <linux/debugfs.h> 31#include <linux/pkt_sched.h> 32#include <linux/string.h> 33#include <net/route.h> 34#include <net/ip.h> 35#include <net/tcp.h> 36#include <asm/unaligned.h> 37#include <asm/uaccess.h> /* for put_user */ 38#include <net/ipv6.h> 39#include <linux/inet.h> 40#include <linux/in.h> 41#include <linux/udp.h> 42#include <linux/tcp.h> 43 44#include <linux/inetdevice.h> 45#include <linux/if_arp.h> 46#include <linux/netfilter_ipv4.h> 47#include <linux/netfilter_bridge.h> 48#include <linux/if_bridge.h> 49#include <net/arp.h> 50#include <net/netfilter/nf_conntrack.h> 51#include <net/netfilter/nf_conntrack_acct.h> 52#include <net/netfilter/nf_conntrack_helper.h> 53#include <net/netfilter/nf_conntrack_l4proto.h> 54#include <net/netfilter/nf_conntrack_l3proto.h> 55#include <net/netfilter/nf_conntrack_zones.h> 56#include <net/netfilter/nf_conntrack_core.h> 57#include <net/netfilter/ipv4/nf_conntrack_ipv4.h> 58#include <net/netfilter/ipv4/nf_defrag_ipv4.h> 59 60/* 61 * Debug output levels 62 * 0 = OFF 63 * 1 = ASSERTS / ERRORS 64 * 2 = 1 + WARN 65 * 3 = 2 + INFO 66 * 4 = 3 + TRACE 67 */ 68#define DEBUG_LEVEL ECM_CONNTRACK_NOTIFIER_DEBUG_LEVEL 69 70#include <sfe_drv.h> 71 72#include "ecm_types.h" 73#include "ecm_db_types.h" 74#include "ecm_state.h" 75#include "ecm_tracker.h" 76#include "ecm_classifier.h" 77#include "ecm_front_end_types.h" 78#include "ecm_tracker_udp.h" 79#include "ecm_tracker_tcp.h" 80#include "ecm_tracker_datagram.h" 81#include "ecm_db.h" 82#include "ecm_sfe_ipv4.h" 83#ifdef ECM_IPV6_ENABLE 84#include "ecm_sfe_ipv6.h" 85#endif 86 87/* 88 * Locking of the classifier - concurrency control 89 */ 90static DEFINE_SPINLOCK(ecm_sfe_conntrack_notifier_lock); /* Protect against SMP access between netfilter, events and private threaded function. */ 91 92/* 93 * Debugfs dentry object. 94 */ 95static struct dentry *ecm_sfe_conntrack_notifier_dentry; 96 97/* 98 * General operational control 99 */ 100static int ecm_sfe_conntrack_notifier_stopped = 0; /* When non-zero further traffic will not be processed */ 101 102#ifdef CONFIG_NF_CONNTRACK_EVENTS 103/* 104 * ecm_sfe_conntrack_event() 105 * Callback event invoked when conntrack connection state changes, currently we handle destroy events to quickly release state 106 */ 107#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS 108static int ecm_sfe_conntrack_event(struct notifier_block *this, unsigned long events, void *ptr) 109#else 110static int ecm_sfe_conntrack_event(unsigned int events, struct nf_ct_event *item) 111#endif 112{ 113#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS 114 struct nf_ct_event *item = (struct nf_ct_event *)ptr; 115#endif 116 struct nf_conn *ct = item->ct; 117 118 /* 119 * If operations have stopped then do not process event 120 */ 121 spin_lock_bh(&ecm_sfe_conntrack_notifier_lock); 122 if (unlikely(ecm_sfe_conntrack_notifier_stopped)) { 123 DEBUG_WARN("Ignoring event - stopped\n"); 124 spin_unlock_bh(&ecm_sfe_conntrack_notifier_lock); 125 return NOTIFY_DONE; 126 } 127 spin_unlock_bh(&ecm_sfe_conntrack_notifier_lock); 128 129 if (!ct) { 130 DEBUG_WARN("Error: no ct\n"); 131 return NOTIFY_DONE; 132 } 133 134 /* 135 * Special untracked connection is not monitored 136 */ 137 if (ct == &nf_conntrack_untracked) { 138 DEBUG_TRACE("Fake connection event - ignoring\n"); 139 return NOTIFY_DONE; 140 } 141 142 /* 143 * Only interested if this is IPv4 or IPv6. 144 */ 145 if (nf_ct_l3num(ct) == AF_INET) { 146 return ecm_sfe_ipv4_conntrack_event(events, ct); 147 } 148#ifdef ECM_IPV6_ENABLE 149 if (nf_ct_l3num(ct) == AF_INET6) { 150 return ecm_sfe_ipv6_conntrack_event(events, ct); 151 } 152#endif 153 return NOTIFY_DONE; 154} 155 156#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS 157/* 158 * struct notifier_block ecm_sfe_conntrack_notifier 159 * Netfilter conntrack event system to monitor connection tracking changes 160 */ 161static struct notifier_block ecm_sfe_conntrack_notifier = { 162 .notifier_call = ecm_sfe_conntrack_event, 163}; 164#else 165/* 166 * struct nf_ct_event_notifier ecm_sfe_conntrack_notifier 167 * Netfilter conntrack event system to monitor connection tracking changes 168 */ 169static struct nf_ct_event_notifier ecm_sfe_conntrack_notifier = { 170 .fcn = ecm_sfe_conntrack_event, 171}; 172#endif 173#endif 174 175/* 176 * ecm_sfe_conntrack_notifier_stop() 177 */ 178void ecm_sfe_conntrack_notifier_stop(int num) 179{ 180 ecm_sfe_conntrack_notifier_stopped = num; 181} 182EXPORT_SYMBOL(ecm_sfe_conntrack_notifier_stop); 183 184/* 185 * ecm_sfe_conntrack_notifier_init() 186 */ 187int ecm_sfe_conntrack_notifier_init(struct dentry *dentry) 188{ 189 int result; 190 DEBUG_INFO("ECM Conntrack Notifier init\n"); 191 192 ecm_sfe_conntrack_notifier_dentry = debugfs_create_dir("ecm_sfe_conntrack_notifier", dentry); 193 if (!ecm_sfe_conntrack_notifier_dentry) { 194 DEBUG_ERROR("Failed to create ecm conntrack notifier directory in debugfs\n"); 195 return -1; 196 } 197 198 if (!debugfs_create_u32("stop", S_IRUGO | S_IWUSR, ecm_sfe_conntrack_notifier_dentry, 199 (u32 *)&ecm_sfe_conntrack_notifier_stopped)) { 200 DEBUG_ERROR("Failed to create ecm conntrack notifier stopped file in debugfs\n"); 201 debugfs_remove_recursive(ecm_sfe_conntrack_notifier_dentry); 202 return -1; 203 } 204 205#ifdef CONFIG_NF_CONNTRACK_EVENTS 206 /* 207 * Eventing subsystem is available so we register a notifier hook to get fast notifications of expired connections 208 */ 209 result = nf_conntrack_register_notifier(&init_net, &ecm_sfe_conntrack_notifier); 210 if (result < 0) { 211 DEBUG_ERROR("Can't register nf notifier hook.\n"); 212 debugfs_remove_recursive(ecm_sfe_conntrack_notifier_dentry); 213 return result; 214 } 215#endif 216 217 return 0; 218} 219EXPORT_SYMBOL(ecm_sfe_conntrack_notifier_init); 220 221/* 222 * ecm_sfe_conntrack_notifier_exit() 223 */ 224void ecm_sfe_conntrack_notifier_exit(void) 225{ 226 DEBUG_INFO("ECM Conntrack Notifier exit\n"); 227#ifdef CONFIG_NF_CONNTRACK_EVENTS 228 nf_conntrack_unregister_notifier(&init_net, &ecm_sfe_conntrack_notifier); 229#endif 230 /* 231 * Remove the debugfs files recursively. 232 */ 233 if (ecm_sfe_conntrack_notifier_dentry) { 234 debugfs_remove_recursive(ecm_sfe_conntrack_notifier_dentry); 235 } 236} 237EXPORT_SYMBOL(ecm_sfe_conntrack_notifier_exit); 238