blob: 1ca09a188b090b5331a5dd2dc0004028ee56d82e [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,
Xiaoping Fan1d8d69d2015-08-03 13:36:01 -070048 SFE_CM_EXCEPTION_LOCAL_OUT,
Xiaoping Fan82c21512015-06-30 01:15:23 -070049 SFE_CM_EXCEPTION_MAX
50} sfe_cm_exception_t;
51
52static char *sfe_cm_exception_events_string[SFE_CM_EXCEPTION_MAX] = {
53 "PACKET_BROADCAST",
54 "PACKET_MULTICAST",
55 "NO_IIF",
56 "NO_CT",
57 "CT_NO_TRACK",
58 "CT_NO_CONFIRM",
59 "CT_IS_ALG",
60 "IS_IPV4_MCAST",
61 "IS_IPV6_MCAST",
62 "TCP_NOT_ASSURED",
63 "TCP_NOT_ESTABLISHED",
64 "UNKNOW_PROTOCOL",
65 "NO_SRC_DEV",
66 "NO_SRC_XLATE_DEV",
67 "NO_DEST_DEV",
68 "NO_DEST_XLATE_DEV",
Xiaoping Fan1d8d69d2015-08-03 13:36:01 -070069 "NO_BRIDGE",
70 "LOCAL_OUT"
Xiaoping Fan82c21512015-06-30 01:15:23 -070071};
72
Dave Hudsondcd08fb2013-11-22 09:25:16 -060073/*
74 * Per-module structure.
75 */
76struct sfe_cm {
77 spinlock_t lock; /* Lock for SMP correctness */
78
79 /*
80 * Control state.
81 */
82 struct kobject *sys_sfe_cm; /* sysfs linkage */
83
84 /*
85 * Callback notifiers.
86 */
87 struct notifier_block dev_notifier;
88 /* Device notifier */
89 struct notifier_block inet_notifier;
Xiaoping Fan978b3772015-05-27 14:15:18 -070090 /* IPv4 notifier */
91 struct notifier_block inet6_notifier;
92 /* IPv6 notifier */
Xiaoping Fan82c21512015-06-30 01:15:23 -070093 uint32_t exceptions[SFE_CM_EXCEPTION_MAX];
Dave Hudsondcd08fb2013-11-22 09:25:16 -060094};
95
96struct sfe_cm __sc;
97
98/*
99 * Expose the hook for the receive processing.
100 */
101extern int (*athrs_fast_nat_recv)(struct sk_buff *skb);
102
103/*
104 * Expose what should be a static flag in the TCP connection tracker.
105 */
106extern int nf_ct_tcp_no_window_check;
107
108/*
Xiaoping Fan82c21512015-06-30 01:15:23 -0700109 * sfe_cm_incr_exceptions()
110 * increase an exception counter.
111 */
112static inline void sfe_cm_incr_exceptions(sfe_cm_exception_t except)
113{
114 struct sfe_cm *sc = &__sc;
115
116 spin_lock_bh(&sc->lock);
117 sc->exceptions[except]++;
118 spin_unlock_bh(&sc->lock);
119}
120
121/*
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600122 * sfe_cm_recv()
123 * Handle packet receives.
124 *
125 * Returns 1 if the packet is forwarded or 0 if it isn't.
126 */
127int sfe_cm_recv(struct sk_buff *skb)
128{
129 struct net_device *dev;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600130
131 /*
132 * We know that for the vast majority of packets we need the transport
133 * layer header so we may as well start to fetch it now!
134 */
135 prefetch(skb->data + 32);
136 barrier();
137
138 dev = skb->dev;
139
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600140 /*
Xiaoping Fan978b3772015-05-27 14:15:18 -0700141 * We're only interested in IPv4 and IPv6 packets.
Xiaoping Fan59176422015-05-22 15:58:10 -0700142 */
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600143 if (likely(htons(ETH_P_IP) == skb->protocol)) {
Xiaoping Fan978b3772015-05-27 14:15:18 -0700144#if (SFE_HOOK_ABOVE_BRIDGE)
145 struct in_device *in_dev;
146
147 /*
148 * Does our input device support IP processing?
149 */
150 in_dev = (struct in_device *)dev->ip_ptr;
151 if (unlikely(!in_dev)) {
152 DEBUG_TRACE("no IP processing for device: %s\n", dev->name);
153 return 0;
154 }
155
156 /*
157 * Does it have an IP address? If it doesn't then we can't do anything
158 * interesting here!
159 */
160 if (unlikely(!in_dev->ifa_list)) {
161 DEBUG_TRACE("no IP address for device: %s\n", dev->name);
162 return 0;
163 }
164#endif
165
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600166 return sfe_ipv4_recv(dev, skb);
167 }
168
Xiaoping Fan978b3772015-05-27 14:15:18 -0700169 if (likely(htons(ETH_P_IPV6) == skb->protocol)) {
170#if (SFE_HOOK_ABOVE_BRIDGE)
171 struct inet6_dev *in_dev;
172
173 /*
174 * Does our input device support IPv6 processing?
175 */
176 in_dev = (struct inet6_dev *)dev->ip6_ptr;
177 if (unlikely(!in_dev)) {
178 DEBUG_TRACE("no IPv6 processing for device: %s\n", dev->name);
179 return 0;
180 }
181
182 /*
183 * Does it have an IPv6 address? If it doesn't then we can't do anything
184 * interesting here!
185 */
186 if (unlikely(list_empty(&in_dev->addr_list))) {
187 DEBUG_TRACE("no IPv6 address for device: %s\n", dev->name);
188 return 0;
189 }
190#endif
191
192 return sfe_ipv6_recv(dev, skb);
193 }
194
Matthew McClintocka8ad7962014-01-16 16:49:30 -0600195 DEBUG_TRACE("not IP packet\n");
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600196 return 0;
197}
198
199/*
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600200 * sfe_cm_find_dev_and_mac_addr()
Xiaoping Fan978b3772015-05-27 14:15:18 -0700201 * Find the device and MAC address for a given IPv4/IPv6 address.
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600202 *
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600203 * Returns true if we find the device and MAC address, otherwise false.
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600204 *
205 * We look up the rtable entry for the address and, from its neighbour
206 * structure, obtain the hardware address. This means this function also
207 * works if the neighbours are routers too.
208 */
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700209static 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 -0600210{
211 struct neighbour *neigh;
212 struct rtable *rt;
Xiaoping Fan978b3772015-05-27 14:15:18 -0700213 struct rt6_info *rt6;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600214 struct dst_entry *dst;
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600215 struct net_device *mac_dev;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600216
217 /*
218 * Look up the rtable entry for the IP address then get the hardware
219 * address from its neighbour structure. This means this work when the
220 * neighbours are routers too.
221 */
Xiaoping Fan978b3772015-05-27 14:15:18 -0700222 if (likely(is_v4)) {
223 rt = ip_route_output(&init_net, addr->ip, 0, 0, 0);
224 if (unlikely(IS_ERR(rt))) {
225 goto ret_fail;
226 }
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600227
Xiaoping Fan978b3772015-05-27 14:15:18 -0700228 dst = (struct dst_entry *)rt;
229 } else {
230 rt6 = rt6_lookup(&init_net, (struct in6_addr *)addr->ip6, 0, 0, 0);
231 if (!rt6) {
232 goto ret_fail;
233 }
234
235 dst = (struct dst_entry *)rt6;
236 }
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600237
238 rcu_read_lock();
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700239 neigh = dst_neigh_lookup(dst, addr);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600240 if (unlikely(!neigh)) {
241 rcu_read_unlock();
242 dst_release(dst);
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700243 goto ret_fail;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600244 }
245
246 if (unlikely(!(neigh->nud_state & NUD_VALID))) {
247 rcu_read_unlock();
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700248 neigh_release(neigh);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600249 dst_release(dst);
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700250 goto ret_fail;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600251 }
252
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600253 mac_dev = neigh->dev;
254 if (!mac_dev) {
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600255 rcu_read_unlock();
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700256 neigh_release(neigh);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600257 dst_release(dst);
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700258 goto ret_fail;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600259 }
260
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600261 memcpy(mac_addr, neigh->ha, (size_t)mac_dev->addr_len);
262
263 dev_hold(mac_dev);
264 *dev = mac_dev;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600265 rcu_read_unlock();
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700266 neigh_release(neigh);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600267 dst_release(dst);
268
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600269 return true;
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700270
271ret_fail:
272 if (is_v4) {
273 DEBUG_TRACE("failed to find MAC address for IP: %pI4\n", &addr->ip);
274
275 } else {
276 DEBUG_TRACE("failed to find MAC address for IP: %pI6\n", addr->ip6);
277 }
278
279 return false;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600280}
281
282/*
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700283 * sfe_cm_post_routing()
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600284 * Called for packets about to leave the box - either locally generated or forwarded from another interface
285 */
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700286static unsigned int sfe_cm_post_routing(struct sk_buff *skb, int is_v4)
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600287{
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700288 struct sfe_connection_create sic;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600289 struct net_device *in;
290 struct nf_conn *ct;
291 enum ip_conntrack_info ctinfo;
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600292 struct net_device *dev;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600293 struct net_device *src_dev;
294 struct net_device *dest_dev;
295 struct net_device *src_br_dev = NULL;
296 struct net_device *dest_br_dev = NULL;
297 struct nf_conntrack_tuple orig_tuple;
298 struct nf_conntrack_tuple reply_tuple;
299
300 /*
301 * Don't process broadcast or multicast packets.
302 */
303 if (unlikely(skb->pkt_type == PACKET_BROADCAST)) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700304 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_PACKET_BROADCAST);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600305 DEBUG_TRACE("broadcast, ignoring\n");
306 return NF_ACCEPT;
307 }
308 if (unlikely(skb->pkt_type == PACKET_MULTICAST)) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700309 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_PACKET_MULTICAST);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600310 DEBUG_TRACE("multicast, ignoring\n");
311 return NF_ACCEPT;
312 }
313
Zhi Chen8748eb32015-06-18 12:58:48 -0700314#ifdef CONFIG_XFRM
315 /*
316 * Packet to xfrm for encapsulation, we can't process it
317 */
318 if (unlikely(skb_dst(skb)->xfrm)) {
319 DEBUG_TRACE("packet to xfrm, ignoring\n");
320 return NF_ACCEPT;
321 }
322#endif
323
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600324 /*
Xiaoping Fan1d8d69d2015-08-03 13:36:01 -0700325 * Don't process locally generated packets.
326 */
327 if (skb->sk) {
328 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_LOCAL_OUT);
329 DEBUG_TRACE("skip local out packet\n");
330 return NF_ACCEPT;
331 }
332
333 /*
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600334 * Don't process packets that are not being forwarded.
335 */
336 in = dev_get_by_index(&init_net, skb->skb_iif);
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600337 if (!in) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700338 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_IIF);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600339 DEBUG_TRACE("packet not forwarding\n");
340 return NF_ACCEPT;
341 }
342
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600343 dev_put(in);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600344
345 /*
346 * Don't process packets that aren't being tracked by conntrack.
347 */
348 ct = nf_ct_get(skb, &ctinfo);
349 if (unlikely(!ct)) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700350 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_CT);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600351 DEBUG_TRACE("no conntrack connection, ignoring\n");
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600352 return NF_ACCEPT;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600353 }
354
355 /*
356 * Don't process untracked connections.
357 */
358 if (unlikely(ct == &nf_conntrack_untracked)) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700359 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_CT_NO_TRACK);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600360 DEBUG_TRACE("untracked connection\n");
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600361 return NF_ACCEPT;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600362 }
363
364 /*
Xiaoping Fan956461e2015-06-25 17:35:13 -0700365 * Unconfirmed connection may be dropped by Linux at the final step,
366 * So we don't process unconfirmed connections.
367 */
368 if (!nf_ct_is_confirmed(ct)) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700369 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_CT_NO_CONFIRM);
Xiaoping Fan956461e2015-06-25 17:35:13 -0700370 DEBUG_TRACE("unconfirmed connection\n");
371 return NF_ACCEPT;
372 }
373
374 /*
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600375 * Don't process connections that require support from a 'helper' (typically a NAT ALG).
376 */
377 if (unlikely(nfct_help(ct))) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700378 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_CT_IS_ALG);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600379 DEBUG_TRACE("connection has helper\n");
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600380 return NF_ACCEPT;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600381 }
382
383 /*
384 * Look up the details of our connection in conntrack.
385 *
386 * Note that the data we get from conntrack is for the "ORIGINAL" direction
387 * but our packet may actually be in the "REPLY" direction.
388 */
389 orig_tuple = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
390 reply_tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
391 sic.protocol = (int32_t)orig_tuple.dst.protonum;
392
393 /*
394 * Get addressing information, non-NAT first
395 */
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700396 if (likely(is_v4)) {
397 sic.src_ip.ip = (__be32)orig_tuple.src.u3.ip;
398 sic.dest_ip.ip = (__be32)orig_tuple.dst.u3.ip;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600399
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700400 if (ipv4_is_multicast(sic.src_ip.ip) || ipv4_is_multicast(sic.dest_ip.ip)) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700401 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_IS_IPV4_MCAST);
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700402 DEBUG_TRACE("multicast address\n");
403 return NF_ACCEPT;
404 }
405
406 /*
407 * NAT'ed addresses - note these are as seen from the 'reply' direction
408 * When NAT does not apply to this connection these will be identical to the above.
409 */
410 sic.src_ip_xlate.ip = (__be32)reply_tuple.dst.u3.ip;
411 sic.dest_ip_xlate.ip = (__be32)reply_tuple.src.u3.ip;
412 } else {
Xiaoping Fan978b3772015-05-27 14:15:18 -0700413 sic.src_ip.ip6[0] = *((struct sfe_ipv6_addr *)&orig_tuple.src.u3.in6);
414 sic.dest_ip.ip6[0] = *((struct sfe_ipv6_addr *)&orig_tuple.dst.u3.in6);
415
416 if (ipv6_addr_is_multicast((struct in6_addr *)sic.src_ip.ip6) ||
417 ipv6_addr_is_multicast((struct in6_addr *)sic.dest_ip.ip6)) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700418 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_IS_IPV6_MCAST);
Xiaoping Fan978b3772015-05-27 14:15:18 -0700419 DEBUG_TRACE("multicast address\n");
420 return NF_ACCEPT;
421 }
422
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700423 /*
Xiaoping Fan978b3772015-05-27 14:15:18 -0700424 * NAT'ed addresses - note these are as seen from the 'reply' direction
425 * When NAT does not apply to this connection these will be identical to the above.
426 */
427 sic.src_ip_xlate.ip6[0] = *((struct sfe_ipv6_addr *)&reply_tuple.dst.u3.in6);
428 sic.dest_ip_xlate.ip6[0] = *((struct sfe_ipv6_addr *)&reply_tuple.src.u3.in6);
Matthew McClintocka11c7cd2014-08-06 16:41:30 -0500429 }
430
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600431 sic.flags = 0;
432
433 switch (sic.protocol) {
434 case IPPROTO_TCP:
435 sic.src_port = orig_tuple.src.u.tcp.port;
436 sic.dest_port = orig_tuple.dst.u.tcp.port;
437 sic.src_port_xlate = reply_tuple.dst.u.tcp.port;
438 sic.dest_port_xlate = reply_tuple.src.u.tcp.port;
439 sic.src_td_window_scale = ct->proto.tcp.seen[0].td_scale;
440 sic.src_td_max_window = ct->proto.tcp.seen[0].td_maxwin;
441 sic.src_td_end = ct->proto.tcp.seen[0].td_end;
442 sic.src_td_max_end = ct->proto.tcp.seen[0].td_maxend;
443 sic.dest_td_window_scale = ct->proto.tcp.seen[1].td_scale;
444 sic.dest_td_max_window = ct->proto.tcp.seen[1].td_maxwin;
445 sic.dest_td_end = ct->proto.tcp.seen[1].td_end;
446 sic.dest_td_max_end = ct->proto.tcp.seen[1].td_maxend;
447 if (nf_ct_tcp_no_window_check
448 || (ct->proto.tcp.seen[0].flags & IP_CT_TCP_FLAG_BE_LIBERAL)
449 || (ct->proto.tcp.seen[1].flags & IP_CT_TCP_FLAG_BE_LIBERAL)) {
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700450 sic.flags |= SFE_CREATE_FLAG_NO_SEQ_CHECK;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600451 }
452
453 /*
454 * Don't try to manage a non-established connection.
455 */
456 if (!test_bit(IPS_ASSURED_BIT, &ct->status)) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700457 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_TCP_NOT_ASSURED);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600458 DEBUG_TRACE("non-established connection\n");
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600459 return NF_ACCEPT;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600460 }
461
462 /*
463 * If the connection is shutting down do not manage it.
464 * state can not be SYN_SENT, SYN_RECV because connection is assured
465 * Not managed states: FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE.
466 */
467 spin_lock_bh(&ct->lock);
468 if (ct->proto.tcp.state != TCP_CONNTRACK_ESTABLISHED) {
469 spin_unlock_bh(&ct->lock);
Xiaoping Fan82c21512015-06-30 01:15:23 -0700470 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_TCP_NOT_ESTABLISHED);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600471 DEBUG_TRACE("connection in termination state: %#x, s: %pI4:%u, d: %pI4:%u\n",
472 ct->proto.tcp.state, &sic.src_ip, ntohs(sic.src_port),
473 &sic.dest_ip, ntohs(sic.dest_port));
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600474 return NF_ACCEPT;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600475 }
476 spin_unlock_bh(&ct->lock);
477 break;
478
479 case IPPROTO_UDP:
480 sic.src_port = orig_tuple.src.u.udp.port;
481 sic.dest_port = orig_tuple.dst.u.udp.port;
482 sic.src_port_xlate = reply_tuple.dst.u.udp.port;
483 sic.dest_port_xlate = reply_tuple.src.u.udp.port;
484 break;
485
486 default:
Xiaoping Fan82c21512015-06-30 01:15:23 -0700487 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_UNKNOW_PROTOCOL);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600488 DEBUG_TRACE("unhandled protocol %d\n", sic.protocol);
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600489 return NF_ACCEPT;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600490 }
491
Zhi Chen8748eb32015-06-18 12:58:48 -0700492#ifdef CONFIG_XFRM
493 sic.original_accel = 1;
494 sic.reply_accel = 1;
495
496 /*
497 * For packets de-capsulated from xfrm, we still can accelerate it
498 * on the direction we just received the packet.
499 */
500 if (unlikely(skb->sp)) {
501 if (sic.protocol == IPPROTO_TCP &&
502 !(sic.flags & SFE_CREATE_FLAG_NO_SEQ_CHECK)) {
503 return NF_ACCEPT;
504 }
505
506 if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) {
507 sic.reply_accel = 0;
508 } else {
509 sic.original_accel = 0;
510 }
511 }
512#endif
513
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600514 /*
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600515 * Get the net device and MAC addresses that correspond to the various source and
516 * destination host addresses.
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600517 */
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700518 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 -0700519 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_SRC_DEV);
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600520 return NF_ACCEPT;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600521 }
522
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700523 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 -0700524 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_SRC_XLATE_DEV);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600525 goto done1;
526 }
527
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600528 dev_put(dev);
529
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700530 if (!sfe_cm_find_dev_and_mac_addr(&sic.dest_ip, &dev, sic.dest_mac, is_v4)) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700531 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_DEST_DEV);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600532 goto done1;
533 }
534
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600535 dev_put(dev);
536
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700537 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 -0700538 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_DEST_XLATE_DEV);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600539 goto done1;
540 }
541
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600542#if (!SFE_HOOK_ABOVE_BRIDGE)
543 /*
544 * Now our devices may actually be a bridge interface. If that's
545 * the case then we need to hunt down the underlying interface.
546 */
547 if (src_dev->priv_flags & IFF_EBRIDGE) {
548 src_br_dev = br_port_dev_get(src_dev, sic.src_mac);
549 if (!src_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 done2;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600553 }
554
555 src_dev = src_br_dev;
556 }
557
558 if (dest_dev->priv_flags & IFF_EBRIDGE) {
559 dest_br_dev = br_port_dev_get(dest_dev, sic.dest_mac_xlate);
560 if (!dest_br_dev) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700561 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_BRIDGE);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600562 DEBUG_TRACE("no port found on bridge\n");
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600563 goto done3;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600564 }
565
566 dest_dev = dest_br_dev;
567 }
568#else
569 /*
570 * Our devices may actually be part of a bridge interface. If that's
571 * the case then find the bridge interface instead.
572 */
573 if (src_dev->priv_flags & IFF_BRIDGE_PORT) {
Xiaoping Fan79ed7292015-03-27 16:47:19 -0700574 src_br_dev = sfe_dev_get_master(src_dev);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600575 if (!src_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", src_dev->name);
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600578 goto done2;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600579 }
580
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600581 src_dev = src_br_dev;
582 }
583
584 if (dest_dev->priv_flags & IFF_BRIDGE_PORT) {
Xiaoping Fan79ed7292015-03-27 16:47:19 -0700585 dest_br_dev = sfe_dev_get_master(dest_dev);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600586 if (!dest_br_dev) {
Xiaoping Fan82c21512015-06-30 01:15:23 -0700587 sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_BRIDGE);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600588 DEBUG_TRACE("no bridge found for: %s\n", dest_dev->name);
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600589 goto done3;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600590 }
591
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600592 dest_dev = dest_br_dev;
593 }
594#endif
595
596 sic.src_dev = src_dev;
597 sic.dest_dev = dest_dev;
598
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600599 sic.src_mtu = src_dev->mtu;
600 sic.dest_mtu = dest_dev->mtu;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600601
Xiaoping Fan978b3772015-05-27 14:15:18 -0700602 if (likely(is_v4)) {
603 sfe_ipv4_create_rule(&sic);
604 } else {
605 sfe_ipv6_create_rule(&sic);
606 }
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600607
608 /*
609 * If we had bridge ports then release them too.
610 */
611 if (dest_br_dev) {
612 dev_put(dest_br_dev);
613 }
614
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600615done3:
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600616 if (src_br_dev) {
617 dev_put(src_br_dev);
618 }
619
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600620done2:
621 dev_put(dest_dev);
622
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600623done1:
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600624 dev_put(src_dev);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600625
626 return NF_ACCEPT;
627}
628
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700629/*
630 * sfe_cm_ipv4_post_routing_hook()
631 * Called for packets about to leave the box - either locally generated or forwarded from another interface
632 */
633sfe_cm_ipv4_post_routing_hook(hooknum, ops, skb, in_unused, out, okfn)
634{
635 return sfe_cm_post_routing(skb, true);
636}
637
Xiaoping Fan978b3772015-05-27 14:15:18 -0700638/*
639 * sfe_cm_ipv6_post_routing_hook()
640 * Called for packets about to leave the box - either locally generated or forwarded from another interface
641 */
642sfe_cm_ipv6_post_routing_hook(hooknum, ops, skb, in_unused, out, okfn)
643{
644 return sfe_cm_post_routing(skb, false);
645}
646
647
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600648#ifdef CONFIG_NF_CONNTRACK_EVENTS
649/*
650 * sfe_cm_conntrack_event()
651 * Callback event invoked when a conntrack connection's state changes.
652 */
Matthew McClintock0680e9f2013-11-26 15:43:10 -0600653#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
654static int sfe_cm_conntrack_event(struct notifier_block *this,
Matthew McClintock0f5c0592014-02-12 11:17:11 -0600655 unsigned long events, void *ptr)
Matthew McClintock0680e9f2013-11-26 15:43:10 -0600656#else
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600657static int sfe_cm_conntrack_event(unsigned int events, struct nf_ct_event *item)
Matthew McClintock0680e9f2013-11-26 15:43:10 -0600658#endif
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600659{
Matthew McClintock0f5c0592014-02-12 11:17:11 -0600660#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
661 struct nf_ct_event *item = ptr;
662#endif
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700663 struct sfe_connection_destroy sid;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600664 struct nf_conn *ct = item->ct;
665 struct nf_conntrack_tuple orig_tuple;
666
667 /*
668 * If we don't have a conntrack entry then we're done.
669 */
670 if (unlikely(!ct)) {
671 DEBUG_WARN("no ct in conntrack event callback\n");
672 return NOTIFY_DONE;
673 }
674
675 /*
676 * If this is an untracked connection then we can't have any state either.
677 */
678 if (unlikely(ct == &nf_conntrack_untracked)) {
679 DEBUG_TRACE("ignoring untracked conn\n");
680 return NOTIFY_DONE;
681 }
682
683 /*
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600684 * We're only interested in destroy events.
685 */
686 if (unlikely(!(events & (1 << IPCT_DESTROY)))) {
687 DEBUG_TRACE("ignoring non-destroy event\n");
688 return NOTIFY_DONE;
689 }
690
691 orig_tuple = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
692 sid.protocol = (int32_t)orig_tuple.dst.protonum;
693
694 /*
695 * Extract information from the conntrack connection. We're only interested
696 * in nominal connection information (i.e. we're ignoring any NAT information).
697 */
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600698 switch (sid.protocol) {
699 case IPPROTO_TCP:
700 sid.src_port = orig_tuple.src.u.tcp.port;
701 sid.dest_port = orig_tuple.dst.u.tcp.port;
702 break;
703
704 case IPPROTO_UDP:
705 sid.src_port = orig_tuple.src.u.udp.port;
706 sid.dest_port = orig_tuple.dst.u.udp.port;
707 break;
708
709 default:
710 DEBUG_TRACE("unhandled protocol: %d\n", sid.protocol);
711 return NOTIFY_DONE;
712 }
713
Xiaoping Fan978b3772015-05-27 14:15:18 -0700714 if (likely(nf_ct_l3num(ct) == AF_INET)) {
715 sid.src_ip.ip = (__be32)orig_tuple.src.u3.ip;
716 sid.dest_ip.ip = (__be32)orig_tuple.dst.u3.ip;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600717
Xiaoping Fan978b3772015-05-27 14:15:18 -0700718 sfe_ipv4_destroy_rule(&sid);
719 } else if (likely(nf_ct_l3num(ct) == AF_INET6)) {
720 sid.src_ip.ip6[0] = *((struct sfe_ipv6_addr *)&orig_tuple.src.u3.in6);
721 sid.dest_ip.ip6[0] = *((struct sfe_ipv6_addr *)&orig_tuple.dst.u3.in6);
722
723 sfe_ipv6_destroy_rule(&sid);
724 } else {
725 DEBUG_TRACE("ignoring non-IPv4 and non-IPv6 connection\n");
726 }
727
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600728 return NOTIFY_DONE;
729}
730
731/*
732 * Netfilter conntrack event system to monitor connection tracking changes
733 */
Matthew McClintock0680e9f2013-11-26 15:43:10 -0600734#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
735static struct notifier_block sfe_cm_conntrack_notifier = {
736 .notifier_call = sfe_cm_conntrack_event,
737};
738#else
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600739static struct nf_ct_event_notifier sfe_cm_conntrack_notifier = {
740 .fcn = sfe_cm_conntrack_event,
741};
742#endif
Matthew McClintock0680e9f2013-11-26 15:43:10 -0600743#endif
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600744
745/*
746 * Structure to establish a hook into the post routing netfilter point - this
747 * will pick up local outbound and packets going from one interface to another.
748 *
749 * Note: see include/linux/netfilter_ipv4.h for info related to priority levels.
750 * We want to examine packets after NAT translation and any ALG processing.
751 */
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700752static struct nf_hook_ops sfe_cm_ops_post_routing[] __read_mostly = {
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600753 {
Xiaoping Fan3f1fe512014-11-05 12:14:57 -0800754 .hook = __sfe_cm_ipv4_post_routing_hook,
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600755 .owner = THIS_MODULE,
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700756 .pf = NFPROTO_IPV4,
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600757 .hooknum = NF_INET_POST_ROUTING,
758 .priority = NF_IP_PRI_NAT_SRC + 1,
759 },
Xiaoping Fan978b3772015-05-27 14:15:18 -0700760#ifdef SFE_SUPPORT_IPV6
761 {
762 .hook = __sfe_cm_ipv6_post_routing_hook,
763 .owner = THIS_MODULE,
764 .pf = NFPROTO_IPV6,
765 .hooknum = NF_INET_POST_ROUTING,
766 .priority = NF_IP6_PRI_NAT_SRC + 1,
767 },
768#endif
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600769};
770
771/*
772 * sfe_cm_sync_rule()
773 * Synchronize a connection's state.
774 */
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700775static void sfe_cm_sync_rule(struct sfe_connection_sync *sis)
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600776{
777 struct nf_conntrack_tuple_hash *h;
778 struct nf_conntrack_tuple tuple;
779 struct nf_conn *ct;
Xiaoping Fan3f1fe512014-11-05 12:14:57 -0800780 SFE_NF_CONN_ACCT(acct);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600781
782 /*
783 * Create a tuple so as to be able to look up a connection
784 */
785 memset(&tuple, 0, sizeof(tuple));
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600786 tuple.src.u.all = (__be16)sis->src_port;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600787 tuple.dst.dir = IP_CT_DIR_ORIGINAL;
788 tuple.dst.protonum = (uint8_t)sis->protocol;
789 tuple.dst.u.all = (__be16)sis->dest_port;
790
Xiaoping Fan978b3772015-05-27 14:15:18 -0700791 if (sis->is_v6) {
792 tuple.src.u3.in6 = *((struct in6_addr *)sis->src_ip.ip6);
793 tuple.dst.u3.in6 = *((struct in6_addr *)sis->dest_ip.ip6);
794 tuple.src.l3num = AF_INET6;
795
796 DEBUG_TRACE("update connection - p: %d, s: %pI6:%u, d: %pI6:%u\n",
797 (int)tuple.dst.protonum,
798 &tuple.src.u3.in6, (unsigned int)ntohs(tuple.src.u.all),
799 &tuple.dst.u3.in6, (unsigned int)ntohs(tuple.dst.u.all));
800 } else {
801 tuple.src.u3.ip = sis->src_ip.ip;
802 tuple.dst.u3.ip = sis->dest_ip.ip;
803 tuple.src.l3num = AF_INET;
804
805 DEBUG_TRACE("update connection - p: %d, s: %pI4:%u, d: %pI4:%u\n",
806 (int)tuple.dst.protonum,
807 &tuple.src.u3.ip, (unsigned int)ntohs(tuple.src.u.all),
808 &tuple.dst.u3.ip, (unsigned int)ntohs(tuple.dst.u.all));
809 }
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600810
811 /*
812 * Look up conntrack connection
813 */
814 h = nf_conntrack_find_get(&init_net, NF_CT_DEFAULT_ZONE, &tuple);
815 if (unlikely(!h)) {
816 DEBUG_TRACE("no connection found\n");
817 return;
818 }
819
820 ct = nf_ct_tuplehash_to_ctrack(h);
821 NF_CT_ASSERT(ct->timeout.data == (unsigned long)ct);
822
823 /*
824 * Only update if this is not a fixed timeout
825 */
826 if (!test_bit(IPS_FIXED_TIMEOUT_BIT, &ct->status)) {
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700827 spin_lock_bh(&ct->lock);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600828 ct->timeout.expires += sis->delta_jiffies;
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700829 spin_unlock_bh(&ct->lock);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600830 }
831
832 acct = nf_conn_acct_find(ct);
833 if (acct) {
834 spin_lock_bh(&ct->lock);
Xiaoping Fan3f1fe512014-11-05 12:14:57 -0800835 atomic64_set(&SFE_ACCT_COUNTER(acct)[IP_CT_DIR_ORIGINAL].packets, sis->src_packet_count);
836 atomic64_set(&SFE_ACCT_COUNTER(acct)[IP_CT_DIR_ORIGINAL].bytes, sis->src_byte_count);
837 atomic64_set(&SFE_ACCT_COUNTER(acct)[IP_CT_DIR_REPLY].packets, sis->dest_packet_count);
838 atomic64_set(&SFE_ACCT_COUNTER(acct)[IP_CT_DIR_REPLY].bytes, sis->dest_byte_count);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600839 spin_unlock_bh(&ct->lock);
840 }
841
842 switch (sis->protocol) {
843 case IPPROTO_TCP:
844 spin_lock_bh(&ct->lock);
845 if (ct->proto.tcp.seen[0].td_maxwin < sis->src_td_max_window) {
846 ct->proto.tcp.seen[0].td_maxwin = sis->src_td_max_window;
847 }
848 if ((int32_t)(ct->proto.tcp.seen[0].td_end - sis->src_td_end) < 0) {
849 ct->proto.tcp.seen[0].td_end = sis->src_td_end;
850 }
851 if ((int32_t)(ct->proto.tcp.seen[0].td_maxend - sis->src_td_max_end) < 0) {
852 ct->proto.tcp.seen[0].td_maxend = sis->src_td_max_end;
853 }
854 if (ct->proto.tcp.seen[1].td_maxwin < sis->dest_td_max_window) {
855 ct->proto.tcp.seen[1].td_maxwin = sis->dest_td_max_window;
856 }
857 if ((int32_t)(ct->proto.tcp.seen[1].td_end - sis->dest_td_end) < 0) {
858 ct->proto.tcp.seen[1].td_end = sis->dest_td_end;
859 }
860 if ((int32_t)(ct->proto.tcp.seen[1].td_maxend - sis->dest_td_max_end) < 0) {
861 ct->proto.tcp.seen[1].td_maxend = sis->dest_td_max_end;
862 }
863 spin_unlock_bh(&ct->lock);
864 break;
865 }
866
867 /*
868 * Release connection
869 */
870 nf_ct_put(ct);
871}
872
873/*
874 * sfe_cm_device_event()
875 */
Xiaoping Fan20f04cc2015-03-30 10:14:20 -0700876int sfe_cm_device_event(struct notifier_block *this, unsigned long event, void *ptr)
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600877{
Xiaoping Fan20f04cc2015-03-30 10:14:20 -0700878 struct net_device *dev = SFE_DEV_EVENT_PTR(ptr);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600879
880 switch (event) {
881 case NETDEV_DOWN:
882 if (dev) {
883 sfe_ipv4_destroy_all_rules_for_dev(dev);
Xiaoping Fan978b3772015-05-27 14:15:18 -0700884 sfe_ipv6_destroy_all_rules_for_dev(dev);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600885 }
886 break;
887 }
888
889 return NOTIFY_DONE;
890}
891
892/*
893 * sfe_cm_inet_event()
894 */
895static int sfe_cm_inet_event(struct notifier_block *this, unsigned long event, void *ptr)
896{
897 struct net_device *dev = ((struct in_ifaddr *)ptr)->ifa_dev->dev;
Xiaoping Fan20f04cc2015-03-30 10:14:20 -0700898 return sfe_cm_propagate_event(this, event, dev);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600899}
900
901/*
Xiaoping Fan978b3772015-05-27 14:15:18 -0700902 * sfe_cm_inet6_event()
903 */
904static int sfe_cm_inet6_event(struct notifier_block *this, unsigned long event, void *ptr)
905{
906 struct net_device *dev = ((struct inet6_ifaddr *)ptr)->idev->dev;
Xiaoping Fan20f04cc2015-03-30 10:14:20 -0700907 return sfe_cm_propagate_event(this, event, dev);
Xiaoping Fan978b3772015-05-27 14:15:18 -0700908}
909
910/*
Xiaoping Fan82c21512015-06-30 01:15:23 -0700911 * sfe_cm_get_exceptions
912 * dump exception counters
913 */
914static ssize_t sfe_cm_get_exceptions(struct device *dev,
915 struct device_attribute *attr,
916 char *buf)
917{
918 int idx, len;
919 struct sfe_cm *sc = &__sc;
920
921 spin_lock_bh(&sc->lock);
922 for (len = 0, idx = 0; idx < SFE_CM_EXCEPTION_MAX; idx++) {
923 if (sc->exceptions[idx]) {
924 len += sprintf(buf + len, "%s = %d\n", sfe_cm_exception_events_string[idx], sc->exceptions[idx]);
925 }
926 }
927 spin_unlock_bh(&sc->lock);
928
929 return len;
930}
931
932/*
933 * sysfs attributes.
934 */
935static const struct device_attribute sfe_cm_exceptions_attr =
936 __ATTR(exceptions, S_IRUGO, sfe_cm_get_exceptions, NULL);
937
938/*
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600939 * sfe_cm_init()
940 */
941static int __init sfe_cm_init(void)
942{
943 struct sfe_cm *sc = &__sc;
944 int result = -1;
945
946 DEBUG_INFO("SFE CM init\n");
947
948 /*
949 * Create sys/sfe_cm
950 */
951 sc->sys_sfe_cm = kobject_create_and_add("sfe_cm", NULL);
952 if (!sc->sys_sfe_cm) {
953 DEBUG_ERROR("failed to register sfe_cm\n");
954 goto exit1;
955 }
956
Xiaoping Fan82c21512015-06-30 01:15:23 -0700957 /*
958 * Create sys/sfe_cm/exceptions
959 */
960 result = sysfs_create_file(sc->sys_sfe_cm, &sfe_cm_exceptions_attr.attr);
961 if (result) {
962 DEBUG_ERROR("failed to register exceptions file: %d\n", result);
963 goto exit2;
964 }
965
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600966 sc->dev_notifier.notifier_call = sfe_cm_device_event;
967 sc->dev_notifier.priority = 1;
968 register_netdevice_notifier(&sc->dev_notifier);
969
970 sc->inet_notifier.notifier_call = sfe_cm_inet_event;
971 sc->inet_notifier.priority = 1;
972 register_inetaddr_notifier(&sc->inet_notifier);
973
Xiaoping Fan978b3772015-05-27 14:15:18 -0700974 sc->inet6_notifier.notifier_call = sfe_cm_inet6_event;
975 sc->inet6_notifier.priority = 1;
976 register_inet6addr_notifier(&sc->inet6_notifier);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600977 /*
978 * Register our netfilter hooks.
979 */
Xiaoping Fand44a5b42015-05-26 17:37:37 -0700980 result = nf_register_hooks(sfe_cm_ops_post_routing, ARRAY_SIZE(sfe_cm_ops_post_routing));
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600981 if (result < 0) {
982 DEBUG_ERROR("can't register nf post routing hook: %d\n", result);
Xiaoping Fan82c21512015-06-30 01:15:23 -0700983 goto exit3;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600984 }
985
986#ifdef CONFIG_NF_CONNTRACK_EVENTS
987 /*
988 * Register a notifier hook to get fast notifications of expired connections.
989 */
990 result = nf_conntrack_register_notifier(&init_net, &sfe_cm_conntrack_notifier);
991 if (result < 0) {
992 DEBUG_ERROR("can't register nf notifier hook: %d\n", result);
Xiaoping Fan82c21512015-06-30 01:15:23 -0700993 goto exit4;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600994 }
995#endif
996
997 spin_lock_init(&sc->lock);
998
999 /*
1000 * Hook the receive path in the network stack.
1001 */
1002 BUG_ON(athrs_fast_nat_recv != NULL);
1003 RCU_INIT_POINTER(athrs_fast_nat_recv, sfe_cm_recv);
1004
1005 /*
1006 * Hook the shortcut sync callback.
1007 */
1008 sfe_ipv4_register_sync_rule_callback(sfe_cm_sync_rule);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001009 sfe_ipv6_register_sync_rule_callback(sfe_cm_sync_rule);
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001010 return 0;
1011
1012#ifdef CONFIG_NF_CONNTRACK_EVENTS
Xiaoping Fan82c21512015-06-30 01:15:23 -07001013exit4:
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001014#endif
Xiaoping Fand44a5b42015-05-26 17:37:37 -07001015 nf_unregister_hooks(sfe_cm_ops_post_routing, ARRAY_SIZE(sfe_cm_ops_post_routing));
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001016
Xiaoping Fan82c21512015-06-30 01:15:23 -07001017exit3:
Xiaoping Fan978b3772015-05-27 14:15:18 -07001018 unregister_inet6addr_notifier(&sc->inet6_notifier);
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001019 unregister_inetaddr_notifier(&sc->inet_notifier);
1020 unregister_netdevice_notifier(&sc->dev_notifier);
Xiaoping Fan82c21512015-06-30 01:15:23 -07001021exit2:
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001022 kobject_put(sc->sys_sfe_cm);
1023
1024exit1:
1025 return result;
1026}
1027
1028/*
1029 * sfe_cm_exit()
1030 */
1031static void __exit sfe_cm_exit(void)
1032{
1033 struct sfe_cm *sc = &__sc;
1034
1035 DEBUG_INFO("SFE CM exit\n");
1036
1037 /*
1038 * Unregister our sync callback.
1039 */
1040 sfe_ipv4_register_sync_rule_callback(NULL);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001041 sfe_ipv6_register_sync_rule_callback(NULL);
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001042
1043 /*
1044 * Unregister our receive callback.
1045 */
1046 RCU_INIT_POINTER(athrs_fast_nat_recv, NULL);
1047
1048 /*
1049 * Wait for all callbacks to complete.
1050 */
1051 rcu_barrier();
1052
1053 /*
1054 * Destroy all connections.
1055 */
1056 sfe_ipv4_destroy_all_rules_for_dev(NULL);
Xiaoping Fan978b3772015-05-27 14:15:18 -07001057 sfe_ipv6_destroy_all_rules_for_dev(NULL);
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001058
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001059#ifdef CONFIG_NF_CONNTRACK_EVENTS
1060 nf_conntrack_unregister_notifier(&init_net, &sfe_cm_conntrack_notifier);
1061
1062#endif
Xiaoping Fand44a5b42015-05-26 17:37:37 -07001063 nf_unregister_hooks(sfe_cm_ops_post_routing, ARRAY_SIZE(sfe_cm_ops_post_routing));
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001064
Xiaoping Fan978b3772015-05-27 14:15:18 -07001065 unregister_inet6addr_notifier(&sc->inet6_notifier);
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001066 unregister_inetaddr_notifier(&sc->inet_notifier);
1067 unregister_netdevice_notifier(&sc->dev_notifier);
1068
1069 kobject_put(sc->sys_sfe_cm);
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001070}
1071
1072module_init(sfe_cm_init)
1073module_exit(sfe_cm_exit)
1074
1075MODULE_AUTHOR("Qualcomm Atheros Inc.");
1076MODULE_DESCRIPTION("Shortcut Forwarding Engine - Connection Manager");
Matthew McClintocka3221942014-01-16 11:44:26 -06001077MODULE_LICENSE("Dual BSD/GPL");
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001078