blob: 2e0bb40a69a81174944e939633b0742c339a15a5 [file] [log] [blame]
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001/*
2 * sfe-cm.c
3 * Shortcut forwarding engine connection manager.
4 *
Xiaoping Fand44a5b42015-05-26 17:37:37 -07005 * Copyright (c) 2013-2015 Qualcomm Atheros, Inc.
Matthew McClintocka3221942014-01-16 11:44:26 -06006 *
7 * All Rights Reserved.
8 * Qualcomm Atheros Confidential and Proprietary.
Dave Hudsondcd08fb2013-11-22 09:25:16 -06009 */
Matthew McClintocka3221942014-01-16 11:44:26 -060010
Dave Hudsondcd08fb2013-11-22 09:25:16 -060011#include <linux/module.h>
12#include <linux/sysfs.h>
13#include <linux/skbuff.h>
14#include <net/route.h>
Xiaoping Fan978b3772015-05-27 14:15:18 -070015#include <net/ip6_route.h>
16#include <net/addrconf.h>
Dave Hudsondcd08fb2013-11-22 09:25:16 -060017#include <linux/inetdevice.h>
18#include <linux/netfilter_bridge.h>
Xiaoping Fan978b3772015-05-27 14:15:18 -070019#include <linux/netfilter_ipv6.h>
Dave Hudsondcd08fb2013-11-22 09:25:16 -060020#include <net/netfilter/nf_conntrack_acct.h>
21#include <net/netfilter/nf_conntrack_helper.h>
22#include <net/netfilter/nf_conntrack_zones.h>
23#include <net/netfilter/nf_conntrack_core.h>
Matthew McClintockbf6b5bc2014-02-24 12:27:14 -060024#include <linux/if_bridge.h>
Dave Hudsondcd08fb2013-11-22 09:25:16 -060025
26#include "sfe.h"
Xiaoping Fand44a5b42015-05-26 17:37:37 -070027#include "sfe_cm.h"
Xiaoping Fan3f1fe512014-11-05 12:14:57 -080028#include "sfe_backport.h"
Dave Hudsondcd08fb2013-11-22 09:25:16 -060029
Xiaoping Fan82c21512015-06-30 01:15:23 -070030typedef enum sfe_cm_exception {
31 SFE_CM_EXCEPTION_PACKET_BROADCAST,
32 SFE_CM_EXCEPTION_PACKET_MULTICAST,
33 SFE_CM_EXCEPTION_NO_IIF,
34 SFE_CM_EXCEPTION_NO_CT,
35 SFE_CM_EXCEPTION_CT_NO_TRACK,
36 SFE_CM_EXCEPTION_CT_NO_CONFIRM,
37 SFE_CM_EXCEPTION_CT_IS_ALG,
38 SFE_CM_EXCEPTION_IS_IPV4_MCAST,
39 SFE_CM_EXCEPTION_IS_IPV6_MCAST,
40 SFE_CM_EXCEPTION_TCP_NOT_ASSURED,
41 SFE_CM_EXCEPTION_TCP_NOT_ESTABLISHED,
42 SFE_CM_EXCEPTION_UNKNOW_PROTOCOL,
43 SFE_CM_EXCEPTION_NO_SRC_DEV,
44 SFE_CM_EXCEPTION_NO_SRC_XLATE_DEV,
45 SFE_CM_EXCEPTION_NO_DEST_DEV,
46 SFE_CM_EXCEPTION_NO_DEST_XLATE_DEV,
47 SFE_CM_EXCEPTION_NO_BRIDGE,
48 SFE_CM_EXCEPTION_MAX
49} sfe_cm_exception_t;
50
51static char *sfe_cm_exception_events_string[SFE_CM_EXCEPTION_MAX] = {
52 "PACKET_BROADCAST",
53 "PACKET_MULTICAST",
54 "NO_IIF",
55 "NO_CT",
56 "CT_NO_TRACK",
57 "CT_NO_CONFIRM",
58 "CT_IS_ALG",
59 "IS_IPV4_MCAST",
60 "IS_IPV6_MCAST",
61 "TCP_NOT_ASSURED",
62 "TCP_NOT_ESTABLISHED",
63 "UNKNOW_PROTOCOL",
64 "NO_SRC_DEV",
65 "NO_SRC_XLATE_DEV",
66 "NO_DEST_DEV",
67 "NO_DEST_XLATE_DEV",
68 "NO_BRIDGE"
69};
70
Dave Hudsondcd08fb2013-11-22 09:25:16 -060071/*
72 * Per-module structure.
73 */
74struct sfe_cm {
75 spinlock_t lock; /* Lock for SMP correctness */
76
77 /*
78 * Control state.
79 */
80 struct kobject *sys_sfe_cm; /* sysfs linkage */
81
82 /*
83 * Callback notifiers.
84 */
85 struct notifier_block dev_notifier;
86 /* Device notifier */
87 struct notifier_block inet_notifier;
Xiaoping Fan978b3772015-05-27 14:15:18 -070088 /* IPv4 notifier */
89 struct notifier_block inet6_notifier;
90 /* IPv6 notifier */
Xiaoping Fan82c21512015-06-30 01:15:23 -070091 uint32_t exceptions[SFE_CM_EXCEPTION_MAX];
Dave Hudsondcd08fb2013-11-22 09:25:16 -060092};
93
94struct sfe_cm __sc;
95
96/*
97 * Expose the hook for the receive processing.
98 */
99extern int (*athrs_fast_nat_recv)(struct sk_buff *skb);
100
101/*
102 * Expose what should be a static flag in the TCP connection tracker.
103 */
104extern int nf_ct_tcp_no_window_check;
105
106/*
Xiaoping Fan82c21512015-06-30 01:15:23 -0700107 * sfe_cm_incr_exceptions()
108 * increase an exception counter.
109 */
110static inline void sfe_cm_incr_exceptions(sfe_cm_exception_t except)
111{
112 struct sfe_cm *sc = &__sc;
113
114 spin_lock_bh(&sc->lock);
115 sc->exceptions[except]++;
116 spin_unlock_bh(&sc->lock);
117}
118
119/*
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600120 * sfe_cm_recv()
121 * Handle packet receives.
122 *
123 * Returns 1 if the packet is forwarded or 0 if it isn't.
124 */
125int sfe_cm_recv(struct sk_buff *skb)
126{
127 struct net_device *dev;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600128
129 /*
130 * We know that for the vast majority of packets we need the transport
131 * layer header so we may as well start to fetch it now!
132 */
133 prefetch(skb->data + 32);
134 barrier();
135
136 dev = skb->dev;
137
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600138 /*
Xiaoping Fan978b3772015-05-27 14:15:18 -0700139 * We're only interested in IPv4 and IPv6 packets.
Xiaoping Fan59176422015-05-22 15:58:10 -0700140 */
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600141 if (likely(htons(ETH_P_IP) == skb->protocol)) {
Xiaoping Fan978b3772015-05-27 14:15:18 -0700142#if (SFE_HOOK_ABOVE_BRIDGE)
143 struct in_device *in_dev;
144
145 /*
146 * Does our input device support IP processing?
147 */
148 in_dev = (struct in_device *)dev->ip_ptr;
149 if (unlikely(!in_dev)) {
150 DEBUG_TRACE("no IP processing for device: %s\n", dev->name);
151 return 0;
152 }
153
154 /*
155 * Does it have an IP address? If it doesn't then we can't do anything
156 * interesting here!
157 */
158 if (unlikely(!in_dev->ifa_list)) {
159 DEBUG_TRACE("no IP address for device: %s\n", dev->name);
160 return 0;
161 }
162#endif
163
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600164 return sfe_ipv4_recv(dev, skb);
165 }
166
Xiaoping Fan978b3772015-05-27 14:15:18 -0700167 if (likely(htons(ETH_P_IPV6) == skb->protocol)) {
168#if (SFE_HOOK_ABOVE_BRIDGE)
169 struct inet6_dev *in_dev;
170
171 /*
172 * Does our input device support IPv6 processing?
173 */
174 in_dev = (struct inet6_dev *)dev->ip6_ptr;
175 if (unlikely(!in_dev)) {
176 DEBUG_TRACE("no IPv6 processing for device: %s\n", dev->name);
177 return 0;
178 }
179
180 /*
181 * Does it have an IPv6 address? If it doesn't then we can't do anything
182 * interesting here!
183 */
184 if (unlikely(list_empty(&in_dev->addr_list))) {
185 DEBUG_TRACE("no IPv6 address for device: %s\n", dev->name);
186 return 0;
187 }
188#endif
189
190 return sfe_ipv6_recv(dev, skb);
191 }
192
Matthew McClintocka8ad7962014-01-16 16:49:30 -0600193 DEBUG_TRACE("not IP packet\n");
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600194 return 0;
195}
196
197/*
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600198 * sfe_cm_find_dev_and_mac_addr()
Xiaoping Fan978b3772015-05-27 14:15:18 -0700199 * Find the device and MAC address for a given IPv4/IPv6 address.
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600200 *
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600201 * Returns true if we find the device and MAC address, otherwise false.
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600202 *
203 * We look up the rtable entry for the address and, from its neighbour
204 * structure, obtain the hardware address. This means this function also
205 * works if the neighbours are routers too.
206 */
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700207static bool sfe_cm_find_dev_and_mac_addr(sfe_ip_addr_t *addr, struct net_device **dev, uint8_t *mac_addr, int is_v4)
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600208{
209 struct neighbour *neigh;
210 struct rtable *rt;
Xiaoping Fan978b3772015-05-27 14:15:18 -0700211 struct rt6_info *rt6;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600212 struct dst_entry *dst;
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600213 struct net_device *mac_dev;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600214
215 /*
216 * Look up the rtable entry for the IP address then get the hardware
217 * address from its neighbour structure. This means this work when the
218 * neighbours are routers too.
219 */
Xiaoping Fan978b3772015-05-27 14:15:18 -0700220 if (likely(is_v4)) {
221 rt = ip_route_output(&init_net, addr->ip, 0, 0, 0);
222 if (unlikely(IS_ERR(rt))) {
223 goto ret_fail;
224 }
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600225
Xiaoping Fan978b3772015-05-27 14:15:18 -0700226 dst = (struct dst_entry *)rt;
227 } else {
228 rt6 = rt6_lookup(&init_net, (struct in6_addr *)addr->ip6, 0, 0, 0);
229 if (!rt6) {
230 goto ret_fail;
231 }
232
233 dst = (struct dst_entry *)rt6;
234 }
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600235
236 rcu_read_lock();
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700237 neigh = dst_neigh_lookup(dst, addr);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600238 if (unlikely(!neigh)) {
239 rcu_read_unlock();
240 dst_release(dst);
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700241 goto ret_fail;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600242 }
243
244 if (unlikely(!(neigh->nud_state & NUD_VALID))) {
245 rcu_read_unlock();
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700246 neigh_release(neigh);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600247 dst_release(dst);
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700248 goto ret_fail;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600249 }
250
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600251 mac_dev = neigh->dev;
252 if (!mac_dev) {
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600253 rcu_read_unlock();
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700254 neigh_release(neigh);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600255 dst_release(dst);
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700256 goto ret_fail;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600257 }
258
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600259 memcpy(mac_addr, neigh->ha, (size_t)mac_dev->addr_len);
260
261 dev_hold(mac_dev);
262 *dev = mac_dev;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600263 rcu_read_unlock();
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700264 neigh_release(neigh);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600265 dst_release(dst);
266
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600267 return true;
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700268
269ret_fail:
270 if (is_v4) {
271 DEBUG_TRACE("failed to find MAC address for IP: %pI4\n", &addr->ip);
272
273 } else {
274 DEBUG_TRACE("failed to find MAC address for IP: %pI6\n", addr->ip6);
275 }
276
277 return false;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600278}
279
280/*
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700281 * sfe_cm_post_routing()
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600282 * Called for packets about to leave the box - either locally generated or forwarded from another interface
283 */
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700284static unsigned int sfe_cm_post_routing(struct sk_buff *skb, int is_v4)
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600285{
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700286 struct sfe_connection_create sic;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600287 struct net_device *in;
288 struct nf_conn *ct;
289 enum ip_conntrack_info ctinfo;
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600290 struct net_device *dev;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600291 struct net_device *src_dev;
292 struct net_device *dest_dev;
293 struct net_device *src_br_dev = NULL;
294 struct net_device *dest_br_dev = NULL;
295 struct nf_conntrack_tuple orig_tuple;
296 struct nf_conntrack_tuple reply_tuple;
297
298 /*
299 * Don't process broadcast or multicast packets.
300 */
301 if (unlikely(skb->pkt_type == PACKET_BROADCAST)) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700302 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_PACKET_BROADCAST);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600303 DEBUG_TRACE("broadcast, ignoring\n");
304 return NF_ACCEPT;
305 }
306 if (unlikely(skb->pkt_type == PACKET_MULTICAST)) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700307 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_PACKET_MULTICAST);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600308 DEBUG_TRACE("multicast, ignoring\n");
309 return NF_ACCEPT;
310 }
311
Zhi Chen8748eb32015-06-18 12:58:48 -0700312#ifdef CONFIG_XFRM
313 /*
314 * Packet to xfrm for encapsulation, we can't process it
315 */
316 if (unlikely(skb_dst(skb)->xfrm)) {
317 DEBUG_TRACE("packet to xfrm, ignoring\n");
318 return NF_ACCEPT;
319 }
320#endif
321
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600322 /*
323 * Don't process packets that are not being forwarded.
324 */
325 in = dev_get_by_index(&init_net, skb->skb_iif);
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600326 if (!in) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700327 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_IIF);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600328 DEBUG_TRACE("packet not forwarding\n");
329 return NF_ACCEPT;
330 }
331
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600332 dev_put(in);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600333
334 /*
335 * Don't process packets that aren't being tracked by conntrack.
336 */
337 ct = nf_ct_get(skb, &ctinfo);
338 if (unlikely(!ct)) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700339 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_CT);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600340 DEBUG_TRACE("no conntrack connection, ignoring\n");
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600341 return NF_ACCEPT;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600342 }
343
344 /*
345 * Don't process untracked connections.
346 */
347 if (unlikely(ct == &nf_conntrack_untracked)) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700348 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_CT_NO_TRACK);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600349 DEBUG_TRACE("untracked connection\n");
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600350 return NF_ACCEPT;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600351 }
352
353 /*
Xiaoping Fan956461e2015-06-25 17:35:13 -0700354 * Unconfirmed connection may be dropped by Linux at the final step,
355 * So we don't process unconfirmed connections.
356 */
357 if (!nf_ct_is_confirmed(ct)) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700358 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_CT_NO_CONFIRM);
Xiaoping Fan956461e2015-06-25 17:35:13 -0700359 DEBUG_TRACE("unconfirmed connection\n");
360 return NF_ACCEPT;
361 }
362
363 /*
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600364 * Don't process connections that require support from a 'helper' (typically a NAT ALG).
365 */
366 if (unlikely(nfct_help(ct))) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700367 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_CT_IS_ALG);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600368 DEBUG_TRACE("connection has helper\n");
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600369 return NF_ACCEPT;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600370 }
371
372 /*
373 * Look up the details of our connection in conntrack.
374 *
375 * Note that the data we get from conntrack is for the "ORIGINAL" direction
376 * but our packet may actually be in the "REPLY" direction.
377 */
378 orig_tuple = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
379 reply_tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
380 sic.protocol = (int32_t)orig_tuple.dst.protonum;
381
382 /*
383 * Get addressing information, non-NAT first
384 */
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700385 if (likely(is_v4)) {
386 sic.src_ip.ip = (__be32)orig_tuple.src.u3.ip;
387 sic.dest_ip.ip = (__be32)orig_tuple.dst.u3.ip;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600388
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700389 if (ipv4_is_multicast(sic.src_ip.ip) || ipv4_is_multicast(sic.dest_ip.ip)) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700390 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_IS_IPV4_MCAST);
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700391 DEBUG_TRACE("multicast address\n");
392 return NF_ACCEPT;
393 }
394
395 /*
396 * NAT'ed addresses - note these are as seen from the 'reply' direction
397 * When NAT does not apply to this connection these will be identical to the above.
398 */
399 sic.src_ip_xlate.ip = (__be32)reply_tuple.dst.u3.ip;
400 sic.dest_ip_xlate.ip = (__be32)reply_tuple.src.u3.ip;
401 } else {
Xiaoping Fan978b3772015-05-27 14:15:18 -0700402 sic.src_ip.ip6[0] = *((struct sfe_ipv6_addr *)&orig_tuple.src.u3.in6);
403 sic.dest_ip.ip6[0] = *((struct sfe_ipv6_addr *)&orig_tuple.dst.u3.in6);
404
405 if (ipv6_addr_is_multicast((struct in6_addr *)sic.src_ip.ip6) ||
406 ipv6_addr_is_multicast((struct in6_addr *)sic.dest_ip.ip6)) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700407 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_IS_IPV6_MCAST);
Xiaoping Fan978b3772015-05-27 14:15:18 -0700408 DEBUG_TRACE("multicast address\n");
409 return NF_ACCEPT;
410 }
411
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700412 /*
Xiaoping Fan978b3772015-05-27 14:15:18 -0700413 * NAT'ed addresses - note these are as seen from the 'reply' direction
414 * When NAT does not apply to this connection these will be identical to the above.
415 */
416 sic.src_ip_xlate.ip6[0] = *((struct sfe_ipv6_addr *)&reply_tuple.dst.u3.in6);
417 sic.dest_ip_xlate.ip6[0] = *((struct sfe_ipv6_addr *)&reply_tuple.src.u3.in6);
Matthew McClintocka11c7cd2014-08-06 16:41:30 -0500418 }
419
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600420 sic.flags = 0;
421
422 switch (sic.protocol) {
423 case IPPROTO_TCP:
424 sic.src_port = orig_tuple.src.u.tcp.port;
425 sic.dest_port = orig_tuple.dst.u.tcp.port;
426 sic.src_port_xlate = reply_tuple.dst.u.tcp.port;
427 sic.dest_port_xlate = reply_tuple.src.u.tcp.port;
428 sic.src_td_window_scale = ct->proto.tcp.seen[0].td_scale;
429 sic.src_td_max_window = ct->proto.tcp.seen[0].td_maxwin;
430 sic.src_td_end = ct->proto.tcp.seen[0].td_end;
431 sic.src_td_max_end = ct->proto.tcp.seen[0].td_maxend;
432 sic.dest_td_window_scale = ct->proto.tcp.seen[1].td_scale;
433 sic.dest_td_max_window = ct->proto.tcp.seen[1].td_maxwin;
434 sic.dest_td_end = ct->proto.tcp.seen[1].td_end;
435 sic.dest_td_max_end = ct->proto.tcp.seen[1].td_maxend;
436 if (nf_ct_tcp_no_window_check
437 || (ct->proto.tcp.seen[0].flags & IP_CT_TCP_FLAG_BE_LIBERAL)
438 || (ct->proto.tcp.seen[1].flags & IP_CT_TCP_FLAG_BE_LIBERAL)) {
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700439 sic.flags |= SFE_CREATE_FLAG_NO_SEQ_CHECK;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600440 }
441
442 /*
443 * Don't try to manage a non-established connection.
444 */
445 if (!test_bit(IPS_ASSURED_BIT, &ct->status)) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700446 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_TCP_NOT_ASSURED);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600447 DEBUG_TRACE("non-established connection\n");
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600448 return NF_ACCEPT;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600449 }
450
451 /*
452 * If the connection is shutting down do not manage it.
453 * state can not be SYN_SENT, SYN_RECV because connection is assured
454 * Not managed states: FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE.
455 */
456 spin_lock_bh(&ct->lock);
457 if (ct->proto.tcp.state != TCP_CONNTRACK_ESTABLISHED) {
458 spin_unlock_bh(&ct->lock);
Xiaoping Fan82c21512015-06-30 01:15:23 -0700459 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_TCP_NOT_ESTABLISHED);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600460 DEBUG_TRACE("connection in termination state: %#x, s: %pI4:%u, d: %pI4:%u\n",
461 ct->proto.tcp.state, &sic.src_ip, ntohs(sic.src_port),
462 &sic.dest_ip, ntohs(sic.dest_port));
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600463 return NF_ACCEPT;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600464 }
465 spin_unlock_bh(&ct->lock);
466 break;
467
468 case IPPROTO_UDP:
469 sic.src_port = orig_tuple.src.u.udp.port;
470 sic.dest_port = orig_tuple.dst.u.udp.port;
471 sic.src_port_xlate = reply_tuple.dst.u.udp.port;
472 sic.dest_port_xlate = reply_tuple.src.u.udp.port;
473 break;
474
475 default:
Xiaoping Fan82c21512015-06-30 01:15:23 -0700476 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_UNKNOW_PROTOCOL);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600477 DEBUG_TRACE("unhandled protocol %d\n", sic.protocol);
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600478 return NF_ACCEPT;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600479 }
480
Zhi Chen8748eb32015-06-18 12:58:48 -0700481#ifdef CONFIG_XFRM
482 sic.original_accel = 1;
483 sic.reply_accel = 1;
484
485 /*
486 * For packets de-capsulated from xfrm, we still can accelerate it
487 * on the direction we just received the packet.
488 */
489 if (unlikely(skb->sp)) {
490 if (sic.protocol == IPPROTO_TCP &&
491 !(sic.flags & SFE_CREATE_FLAG_NO_SEQ_CHECK)) {
492 return NF_ACCEPT;
493 }
494
495 if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) {
496 sic.reply_accel = 0;
497 } else {
498 sic.original_accel = 0;
499 }
500 }
501#endif
502
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600503 /*
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600504 * Get the net device and MAC addresses that correspond to the various source and
505 * destination host addresses.
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600506 */
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700507 if (!sfe_cm_find_dev_and_mac_addr(&sic.src_ip, &src_dev, sic.src_mac, is_v4)) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700508 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_SRC_DEV);
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600509 return NF_ACCEPT;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600510 }
511
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700512 if (!sfe_cm_find_dev_and_mac_addr(&sic.src_ip_xlate, &dev, sic.src_mac_xlate, is_v4)) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700513 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_SRC_XLATE_DEV);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600514 goto done1;
515 }
516
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600517 dev_put(dev);
518
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700519 if (!sfe_cm_find_dev_and_mac_addr(&sic.dest_ip, &dev, sic.dest_mac, is_v4)) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700520 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_DEST_DEV);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600521 goto done1;
522 }
523
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600524 dev_put(dev);
525
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700526 if (!sfe_cm_find_dev_and_mac_addr(&sic.dest_ip_xlate, &dest_dev, sic.dest_mac_xlate, is_v4)) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700527 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_DEST_XLATE_DEV);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600528 goto done1;
529 }
530
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600531#if (!SFE_HOOK_ABOVE_BRIDGE)
532 /*
533 * Now our devices may actually be a bridge interface. If that's
534 * the case then we need to hunt down the underlying interface.
535 */
536 if (src_dev->priv_flags & IFF_EBRIDGE) {
537 src_br_dev = br_port_dev_get(src_dev, sic.src_mac);
538 if (!src_br_dev) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700539 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_BRIDGE);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600540 DEBUG_TRACE("no port found on bridge\n");
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600541 goto done2;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600542 }
543
544 src_dev = src_br_dev;
545 }
546
547 if (dest_dev->priv_flags & IFF_EBRIDGE) {
548 dest_br_dev = br_port_dev_get(dest_dev, sic.dest_mac_xlate);
549 if (!dest_br_dev) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700550 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_BRIDGE);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600551 DEBUG_TRACE("no port found on bridge\n");
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600552 goto done3;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600553 }
554
555 dest_dev = dest_br_dev;
556 }
557#else
558 /*
559 * Our devices may actually be part of a bridge interface. If that's
560 * the case then find the bridge interface instead.
561 */
562 if (src_dev->priv_flags & IFF_BRIDGE_PORT) {
Xiaoping Fan79ed7292015-03-27 16:47:19 -0700563 src_br_dev = sfe_dev_get_master(src_dev);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600564 if (!src_br_dev) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700565 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_BRIDGE);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600566 DEBUG_TRACE("no bridge found for: %s\n", src_dev->name);
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600567 goto done2;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600568 }
569
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600570 src_dev = src_br_dev;
571 }
572
573 if (dest_dev->priv_flags & IFF_BRIDGE_PORT) {
Xiaoping Fan79ed7292015-03-27 16:47:19 -0700574 dest_br_dev = sfe_dev_get_master(dest_dev);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600575 if (!dest_br_dev) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700576 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_BRIDGE);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600577 DEBUG_TRACE("no bridge found for: %s\n", dest_dev->name);
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600578 goto done3;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600579 }
580
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600581 dest_dev = dest_br_dev;
582 }
583#endif
584
585 sic.src_dev = src_dev;
586 sic.dest_dev = dest_dev;
587
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600588 sic.src_mtu = src_dev->mtu;
589 sic.dest_mtu = dest_dev->mtu;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600590
Xiaoping Fan978b3772015-05-27 14:15:18 -0700591 if (likely(is_v4)) {
592 sfe_ipv4_create_rule(&sic);
593 } else {
594 sfe_ipv6_create_rule(&sic);
595 }
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600596
597 /*
598 * If we had bridge ports then release them too.
599 */
600 if (dest_br_dev) {
601 dev_put(dest_br_dev);
602 }
603
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600604done3:
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600605 if (src_br_dev) {
606 dev_put(src_br_dev);
607 }
608
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600609done2:
610 dev_put(dest_dev);
611
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600612done1:
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600613 dev_put(src_dev);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600614
615 return NF_ACCEPT;
616}
617
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700618/*
619 * sfe_cm_ipv4_post_routing_hook()
620 * Called for packets about to leave the box - either locally generated or forwarded from another interface
621 */
622sfe_cm_ipv4_post_routing_hook(hooknum, ops, skb, in_unused, out, okfn)
623{
624 return sfe_cm_post_routing(skb, true);
625}
626
Xiaoping Fan978b3772015-05-27 14:15:18 -0700627/*
628 * sfe_cm_ipv6_post_routing_hook()
629 * Called for packets about to leave the box - either locally generated or forwarded from another interface
630 */
631sfe_cm_ipv6_post_routing_hook(hooknum, ops, skb, in_unused, out, okfn)
632{
633 return sfe_cm_post_routing(skb, false);
634}
635
636
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600637#ifdef CONFIG_NF_CONNTRACK_EVENTS
638/*
639 * sfe_cm_conntrack_event()
640 * Callback event invoked when a conntrack connection's state changes.
641 */
Matthew McClintock0680e9f2013-11-26 15:43:10 -0600642#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
643static int sfe_cm_conntrack_event(struct notifier_block *this,
Matthew McClintock0f5c0592014-02-12 11:17:11 -0600644 unsigned long events, void *ptr)
Matthew McClintock0680e9f2013-11-26 15:43:10 -0600645#else
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600646static int sfe_cm_conntrack_event(unsigned int events, struct nf_ct_event *item)
Matthew McClintock0680e9f2013-11-26 15:43:10 -0600647#endif
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600648{
Matthew McClintock0f5c0592014-02-12 11:17:11 -0600649#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
650 struct nf_ct_event *item = ptr;
651#endif
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700652 struct sfe_connection_destroy sid;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600653 struct nf_conn *ct = item->ct;
654 struct nf_conntrack_tuple orig_tuple;
655
656 /*
657 * If we don't have a conntrack entry then we're done.
658 */
659 if (unlikely(!ct)) {
660 DEBUG_WARN("no ct in conntrack event callback\n");
661 return NOTIFY_DONE;
662 }
663
664 /*
665 * If this is an untracked connection then we can't have any state either.
666 */
667 if (unlikely(ct == &nf_conntrack_untracked)) {
668 DEBUG_TRACE("ignoring untracked conn\n");
669 return NOTIFY_DONE;
670 }
671
672 /*
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600673 * We're only interested in destroy events.
674 */
675 if (unlikely(!(events & (1 << IPCT_DESTROY)))) {
676 DEBUG_TRACE("ignoring non-destroy event\n");
677 return NOTIFY_DONE;
678 }
679
680 orig_tuple = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
681 sid.protocol = (int32_t)orig_tuple.dst.protonum;
682
683 /*
684 * Extract information from the conntrack connection. We're only interested
685 * in nominal connection information (i.e. we're ignoring any NAT information).
686 */
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600687 switch (sid.protocol) {
688 case IPPROTO_TCP:
689 sid.src_port = orig_tuple.src.u.tcp.port;
690 sid.dest_port = orig_tuple.dst.u.tcp.port;
691 break;
692
693 case IPPROTO_UDP:
694 sid.src_port = orig_tuple.src.u.udp.port;
695 sid.dest_port = orig_tuple.dst.u.udp.port;
696 break;
697
698 default:
699 DEBUG_TRACE("unhandled protocol: %d\n", sid.protocol);
700 return NOTIFY_DONE;
701 }
702
Xiaoping Fan978b3772015-05-27 14:15:18 -0700703 if (likely(nf_ct_l3num(ct) == AF_INET)) {
704 sid.src_ip.ip = (__be32)orig_tuple.src.u3.ip;
705 sid.dest_ip.ip = (__be32)orig_tuple.dst.u3.ip;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600706
Xiaoping Fan978b3772015-05-27 14:15:18 -0700707 sfe_ipv4_destroy_rule(&sid);
708 } else if (likely(nf_ct_l3num(ct) == AF_INET6)) {
709 sid.src_ip.ip6[0] = *((struct sfe_ipv6_addr *)&orig_tuple.src.u3.in6);
710 sid.dest_ip.ip6[0] = *((struct sfe_ipv6_addr *)&orig_tuple.dst.u3.in6);
711
712 sfe_ipv6_destroy_rule(&sid);
713 } else {
714 DEBUG_TRACE("ignoring non-IPv4 and non-IPv6 connection\n");
715 }
716
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600717 return NOTIFY_DONE;
718}
719
720/*
721 * Netfilter conntrack event system to monitor connection tracking changes
722 */
Matthew McClintock0680e9f2013-11-26 15:43:10 -0600723#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
724static struct notifier_block sfe_cm_conntrack_notifier = {
725 .notifier_call = sfe_cm_conntrack_event,
726};
727#else
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600728static struct nf_ct_event_notifier sfe_cm_conntrack_notifier = {
729 .fcn = sfe_cm_conntrack_event,
730};
731#endif
Matthew McClintock0680e9f2013-11-26 15:43:10 -0600732#endif
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600733
734/*
735 * Structure to establish a hook into the post routing netfilter point - this
736 * will pick up local outbound and packets going from one interface to another.
737 *
738 * Note: see include/linux/netfilter_ipv4.h for info related to priority levels.
739 * We want to examine packets after NAT translation and any ALG processing.
740 */
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700741static struct nf_hook_ops sfe_cm_ops_post_routing[] __read_mostly = {
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600742 {
Xiaoping Fan3f1fe512014-11-05 12:14:57 -0800743 .hook = __sfe_cm_ipv4_post_routing_hook,
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600744 .owner = THIS_MODULE,
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700745 .pf = NFPROTO_IPV4,
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600746 .hooknum = NF_INET_POST_ROUTING,
747 .priority = NF_IP_PRI_NAT_SRC + 1,
748 },
Xiaoping Fan978b3772015-05-27 14:15:18 -0700749#ifdef SFE_SUPPORT_IPV6
750 {
751 .hook = __sfe_cm_ipv6_post_routing_hook,
752 .owner = THIS_MODULE,
753 .pf = NFPROTO_IPV6,
754 .hooknum = NF_INET_POST_ROUTING,
755 .priority = NF_IP6_PRI_NAT_SRC + 1,
756 },
757#endif
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600758};
759
760/*
761 * sfe_cm_sync_rule()
762 * Synchronize a connection's state.
763 */
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700764static void sfe_cm_sync_rule(struct sfe_connection_sync *sis)
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600765{
766 struct nf_conntrack_tuple_hash *h;
767 struct nf_conntrack_tuple tuple;
768 struct nf_conn *ct;
Xiaoping Fan3f1fe512014-11-05 12:14:57 -0800769 SFE_NF_CONN_ACCT(acct);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600770
771 /*
772 * Create a tuple so as to be able to look up a connection
773 */
774 memset(&tuple, 0, sizeof(tuple));
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600775 tuple.src.u.all = (__be16)sis->src_port;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600776 tuple.dst.dir = IP_CT_DIR_ORIGINAL;
777 tuple.dst.protonum = (uint8_t)sis->protocol;
778 tuple.dst.u.all = (__be16)sis->dest_port;
779
Xiaoping Fan978b3772015-05-27 14:15:18 -0700780 if (sis->is_v6) {
781 tuple.src.u3.in6 = *((struct in6_addr *)sis->src_ip.ip6);
782 tuple.dst.u3.in6 = *((struct in6_addr *)sis->dest_ip.ip6);
783 tuple.src.l3num = AF_INET6;
784
785 DEBUG_TRACE("update connection - p: %d, s: %pI6:%u, d: %pI6:%u\n",
786 (int)tuple.dst.protonum,
787 &tuple.src.u3.in6, (unsigned int)ntohs(tuple.src.u.all),
788 &tuple.dst.u3.in6, (unsigned int)ntohs(tuple.dst.u.all));
789 } else {
790 tuple.src.u3.ip = sis->src_ip.ip;
791 tuple.dst.u3.ip = sis->dest_ip.ip;
792 tuple.src.l3num = AF_INET;
793
794 DEBUG_TRACE("update connection - p: %d, s: %pI4:%u, d: %pI4:%u\n",
795 (int)tuple.dst.protonum,
796 &tuple.src.u3.ip, (unsigned int)ntohs(tuple.src.u.all),
797 &tuple.dst.u3.ip, (unsigned int)ntohs(tuple.dst.u.all));
798 }
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600799
800 /*
801 * Look up conntrack connection
802 */
803 h = nf_conntrack_find_get(&init_net, NF_CT_DEFAULT_ZONE, &tuple);
804 if (unlikely(!h)) {
805 DEBUG_TRACE("no connection found\n");
806 return;
807 }
808
809 ct = nf_ct_tuplehash_to_ctrack(h);
810 NF_CT_ASSERT(ct->timeout.data == (unsigned long)ct);
811
812 /*
813 * Only update if this is not a fixed timeout
814 */
815 if (!test_bit(IPS_FIXED_TIMEOUT_BIT, &ct->status)) {
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700816 spin_lock_bh(&ct->lock);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600817 ct->timeout.expires += sis->delta_jiffies;
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700818 spin_unlock_bh(&ct->lock);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600819 }
820
821 acct = nf_conn_acct_find(ct);
822 if (acct) {
823 spin_lock_bh(&ct->lock);
Xiaoping Fan3f1fe512014-11-05 12:14:57 -0800824 atomic64_set(&SFE_ACCT_COUNTER(acct)[IP_CT_DIR_ORIGINAL].packets, sis->src_packet_count);
825 atomic64_set(&SFE_ACCT_COUNTER(acct)[IP_CT_DIR_ORIGINAL].bytes, sis->src_byte_count);
826 atomic64_set(&SFE_ACCT_COUNTER(acct)[IP_CT_DIR_REPLY].packets, sis->dest_packet_count);
827 atomic64_set(&SFE_ACCT_COUNTER(acct)[IP_CT_DIR_REPLY].bytes, sis->dest_byte_count);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600828 spin_unlock_bh(&ct->lock);
829 }
830
831 switch (sis->protocol) {
832 case IPPROTO_TCP:
833 spin_lock_bh(&ct->lock);
834 if (ct->proto.tcp.seen[0].td_maxwin < sis->src_td_max_window) {
835 ct->proto.tcp.seen[0].td_maxwin = sis->src_td_max_window;
836 }
837 if ((int32_t)(ct->proto.tcp.seen[0].td_end - sis->src_td_end) < 0) {
838 ct->proto.tcp.seen[0].td_end = sis->src_td_end;
839 }
840 if ((int32_t)(ct->proto.tcp.seen[0].td_maxend - sis->src_td_max_end) < 0) {
841 ct->proto.tcp.seen[0].td_maxend = sis->src_td_max_end;
842 }
843 if (ct->proto.tcp.seen[1].td_maxwin < sis->dest_td_max_window) {
844 ct->proto.tcp.seen[1].td_maxwin = sis->dest_td_max_window;
845 }
846 if ((int32_t)(ct->proto.tcp.seen[1].td_end - sis->dest_td_end) < 0) {
847 ct->proto.tcp.seen[1].td_end = sis->dest_td_end;
848 }
849 if ((int32_t)(ct->proto.tcp.seen[1].td_maxend - sis->dest_td_max_end) < 0) {
850 ct->proto.tcp.seen[1].td_maxend = sis->dest_td_max_end;
851 }
852 spin_unlock_bh(&ct->lock);
853 break;
854 }
855
856 /*
857 * Release connection
858 */
859 nf_ct_put(ct);
860}
861
862/*
863 * sfe_cm_device_event()
864 */
865static int sfe_cm_device_event(struct notifier_block *this, unsigned long event, void *ptr)
866{
867 struct net_device *dev = (struct net_device *)ptr;
868
869 switch (event) {
870 case NETDEV_DOWN:
871 if (dev) {
872 sfe_ipv4_destroy_all_rules_for_dev(dev);
Xiaoping Fan978b3772015-05-27 14:15:18 -0700873 sfe_ipv6_destroy_all_rules_for_dev(dev);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600874 }
875 break;
876 }
877
878 return NOTIFY_DONE;
879}
880
881/*
882 * sfe_cm_inet_event()
883 */
884static int sfe_cm_inet_event(struct notifier_block *this, unsigned long event, void *ptr)
885{
886 struct net_device *dev = ((struct in_ifaddr *)ptr)->ifa_dev->dev;
887 return sfe_cm_device_event(this, event, dev);
888}
889
890/*
Xiaoping Fan978b3772015-05-27 14:15:18 -0700891 * sfe_cm_inet6_event()
892 */
893static int sfe_cm_inet6_event(struct notifier_block *this, unsigned long event, void *ptr)
894{
895 struct net_device *dev = ((struct inet6_ifaddr *)ptr)->idev->dev;
896 return sfe_cm_device_event(this, event, dev);
897}
898
899/*
Xiaoping Fan82c21512015-06-30 01:15:23 -0700900 * sfe_cm_get_exceptions
901 * dump exception counters
902 */
903static ssize_t sfe_cm_get_exceptions(struct device *dev,
904 struct device_attribute *attr,
905 char *buf)
906{
907 int idx, len;
908 struct sfe_cm *sc = &__sc;
909
910 spin_lock_bh(&sc->lock);
911 for (len = 0, idx = 0; idx < SFE_CM_EXCEPTION_MAX; idx++) {
912 if (sc->exceptions[idx]) {
913 len += sprintf(buf + len, "%s = %d\n", sfe_cm_exception_events_string[idx], sc->exceptions[idx]);
914 }
915 }
916 spin_unlock_bh(&sc->lock);
917
918 return len;
919}
920
921/*
922 * sysfs attributes.
923 */
924static const struct device_attribute sfe_cm_exceptions_attr =
925 __ATTR(exceptions, S_IRUGO, sfe_cm_get_exceptions, NULL);
926
927/*
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600928 * sfe_cm_init()
929 */
930static int __init sfe_cm_init(void)
931{
932 struct sfe_cm *sc = &__sc;
933 int result = -1;
934
935 DEBUG_INFO("SFE CM init\n");
936
937 /*
938 * Create sys/sfe_cm
939 */
940 sc->sys_sfe_cm = kobject_create_and_add("sfe_cm", NULL);
941 if (!sc->sys_sfe_cm) {
942 DEBUG_ERROR("failed to register sfe_cm\n");
943 goto exit1;
944 }
945
Xiaoping Fan82c21512015-06-30 01:15:23 -0700946 /*
947 * Create sys/sfe_cm/exceptions
948 */
949 result = sysfs_create_file(sc->sys_sfe_cm, &sfe_cm_exceptions_attr.attr);
950 if (result) {
951 DEBUG_ERROR("failed to register exceptions file: %d\n", result);
952 goto exit2;
953 }
954
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600955 sc->dev_notifier.notifier_call = sfe_cm_device_event;
956 sc->dev_notifier.priority = 1;
957 register_netdevice_notifier(&sc->dev_notifier);
958
959 sc->inet_notifier.notifier_call = sfe_cm_inet_event;
960 sc->inet_notifier.priority = 1;
961 register_inetaddr_notifier(&sc->inet_notifier);
962
Xiaoping Fan978b3772015-05-27 14:15:18 -0700963 sc->inet6_notifier.notifier_call = sfe_cm_inet6_event;
964 sc->inet6_notifier.priority = 1;
965 register_inet6addr_notifier(&sc->inet6_notifier);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600966 /*
967 * Register our netfilter hooks.
968 */
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700969 result = nf_register_hooks(sfe_cm_ops_post_routing, ARRAY_SIZE(sfe_cm_ops_post_routing));
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600970 if (result < 0) {
971 DEBUG_ERROR("can't register nf post routing hook: %d\n", result);
Xiaoping Fan82c21512015-06-30 01:15:23 -0700972 goto exit3;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600973 }
974
975#ifdef CONFIG_NF_CONNTRACK_EVENTS
976 /*
977 * Register a notifier hook to get fast notifications of expired connections.
978 */
979 result = nf_conntrack_register_notifier(&init_net, &sfe_cm_conntrack_notifier);
980 if (result < 0) {
981 DEBUG_ERROR("can't register nf notifier hook: %d\n", result);
Xiaoping Fan82c21512015-06-30 01:15:23 -0700982 goto exit4;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600983 }
984#endif
985
986 spin_lock_init(&sc->lock);
987
988 /*
989 * Hook the receive path in the network stack.
990 */
991 BUG_ON(athrs_fast_nat_recv != NULL);
992 RCU_INIT_POINTER(athrs_fast_nat_recv, sfe_cm_recv);
993
994 /*
995 * Hook the shortcut sync callback.
996 */
997 sfe_ipv4_register_sync_rule_callback(sfe_cm_sync_rule);
Xiaoping Fan978b3772015-05-27 14:15:18 -0700998 sfe_ipv6_register_sync_rule_callback(sfe_cm_sync_rule);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600999 return 0;
1000
1001#ifdef CONFIG_NF_CONNTRACK_EVENTS
Xiaoping Fan82c21512015-06-30 01:15:23 -07001002exit4:
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001003#endif
Xiaoping Fand44a5b42015-05-26 17:37:37 -07001004 nf_unregister_hooks(sfe_cm_ops_post_routing, ARRAY_SIZE(sfe_cm_ops_post_routing));
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001005
Xiaoping Fan82c21512015-06-30 01:15:23 -07001006exit3:
Xiaoping Fan978b3772015-05-27 14:15:18 -07001007 unregister_inet6addr_notifier(&sc->inet6_notifier);
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001008 unregister_inetaddr_notifier(&sc->inet_notifier);
1009 unregister_netdevice_notifier(&sc->dev_notifier);
Xiaoping Fan82c21512015-06-30 01:15:23 -07001010exit2:
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001011 kobject_put(sc->sys_sfe_cm);
1012
1013exit1:
1014 return result;
1015}
1016
1017/*
1018 * sfe_cm_exit()
1019 */
1020static void __exit sfe_cm_exit(void)
1021{
1022 struct sfe_cm *sc = &__sc;
1023
1024 DEBUG_INFO("SFE CM exit\n");
1025
1026 /*
1027 * Unregister our sync callback.
1028 */
1029 sfe_ipv4_register_sync_rule_callback(NULL);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001030 sfe_ipv6_register_sync_rule_callback(NULL);
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001031
1032 /*
1033 * Unregister our receive callback.
1034 */
1035 RCU_INIT_POINTER(athrs_fast_nat_recv, NULL);
1036
1037 /*
1038 * Wait for all callbacks to complete.
1039 */
1040 rcu_barrier();
1041
1042 /*
1043 * Destroy all connections.
1044 */
1045 sfe_ipv4_destroy_all_rules_for_dev(NULL);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001046 sfe_ipv6_destroy_all_rules_for_dev(NULL);
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001047
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001048#ifdef CONFIG_NF_CONNTRACK_EVENTS
1049 nf_conntrack_unregister_notifier(&init_net, &sfe_cm_conntrack_notifier);
1050
1051#endif
Xiaoping Fand44a5b42015-05-26 17:37:37 -07001052 nf_unregister_hooks(sfe_cm_ops_post_routing, ARRAY_SIZE(sfe_cm_ops_post_routing));
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001053
Xiaoping Fan978b3772015-05-27 14:15:18 -07001054 unregister_inet6addr_notifier(&sc->inet6_notifier);
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001055 unregister_inetaddr_notifier(&sc->inet_notifier);
1056 unregister_netdevice_notifier(&sc->dev_notifier);
1057
1058 kobject_put(sc->sys_sfe_cm);
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001059}
1060
1061module_init(sfe_cm_init)
1062module_exit(sfe_cm_exit)
1063
1064MODULE_AUTHOR("Qualcomm Atheros Inc.");
1065MODULE_DESCRIPTION("Shortcut Forwarding Engine - Connection Manager");
Matthew McClintocka3221942014-01-16 11:44:26 -06001066MODULE_LICENSE("Dual BSD/GPL");
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001067