blob: 601749d5bcbb05514155a1aae8b79bb45b36b928 [file] [log] [blame]
Dave Hudsondcd08fb2013-11-22 09:25:16 -06001/*
2 * sfe-cm.c
3 * Shortcut forwarding engine connection manager.
4 *
Matthew McClintocka3221942014-01-16 11:44:26 -06005 * Copyright (c) 2013 Qualcomm Atheros, Inc.
6 *
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>
15#include <linux/inetdevice.h>
16#include <linux/netfilter_bridge.h>
17#include <net/netfilter/nf_conntrack_acct.h>
18#include <net/netfilter/nf_conntrack_helper.h>
19#include <net/netfilter/nf_conntrack_zones.h>
20#include <net/netfilter/nf_conntrack_core.h>
Matthew McClintockbf6b5bc2014-02-24 12:27:14 -060021#include <linux/if_bridge.h>
Dave Hudsondcd08fb2013-11-22 09:25:16 -060022
23#include "sfe.h"
24#include "sfe_ipv4.h"
Xiaoping Fan3f1fe512014-11-05 12:14:57 -080025#include "sfe_backport.h"
Dave Hudsondcd08fb2013-11-22 09:25:16 -060026
27/*
28 * Per-module structure.
29 */
30struct sfe_cm {
31 spinlock_t lock; /* Lock for SMP correctness */
32
33 /*
34 * Control state.
35 */
36 struct kobject *sys_sfe_cm; /* sysfs linkage */
37
38 /*
39 * Callback notifiers.
40 */
41 struct notifier_block dev_notifier;
42 /* Device notifier */
43 struct notifier_block inet_notifier;
44 /* IP notifier */
45};
46
47struct sfe_cm __sc;
48
49/*
50 * Expose the hook for the receive processing.
51 */
52extern int (*athrs_fast_nat_recv)(struct sk_buff *skb);
53
54/*
55 * Expose what should be a static flag in the TCP connection tracker.
56 */
57extern int nf_ct_tcp_no_window_check;
58
59/*
60 * sfe_cm_recv()
61 * Handle packet receives.
62 *
63 * Returns 1 if the packet is forwarded or 0 if it isn't.
64 */
65int sfe_cm_recv(struct sk_buff *skb)
66{
67 struct net_device *dev;
68#if (SFE_HOOK_ABOVE_BRIDGE)
69 struct in_device *in_dev;
70#endif
71
72 /*
73 * We know that for the vast majority of packets we need the transport
74 * layer header so we may as well start to fetch it now!
75 */
76 prefetch(skb->data + 32);
77 barrier();
78
79 dev = skb->dev;
80
81#if (SFE_HOOK_ABOVE_BRIDGE)
82 /*
83 * Does our input device support IP processing?
84 */
85 in_dev = (struct in_device *)dev->ip_ptr;
86 if (unlikely(!in_dev)) {
87 DEBUG_TRACE("no IP processing for device: %s\n", dev->name);
88 return 0;
89 }
90
91 /*
92 * Does it have an IP address? If it doesn't then we can't do anything
93 * interesting here!
94 */
95 if (unlikely(!in_dev->ifa_list)) {
96 DEBUG_TRACE("no IP address for device: %s\n", dev->name);
97 return 0;
98 }
99#endif
100
101 /*
102 * We're only interested in IP packets.
Xiaoping Fan59176422015-05-22 15:58:10 -0700103 */
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600104 if (likely(htons(ETH_P_IP) == skb->protocol)) {
105 return sfe_ipv4_recv(dev, skb);
106 }
107
Matthew McClintocka8ad7962014-01-16 16:49:30 -0600108 DEBUG_TRACE("not IP packet\n");
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600109 return 0;
110}
111
112/*
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600113 * sfe_cm_find_dev_and_mac_addr()
114 * Find the device and MAC address for a given IPv4 address.
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600115 *
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600116 * Returns true if we find the device and MAC address, otherwise false.
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600117 *
118 * We look up the rtable entry for the address and, from its neighbour
119 * structure, obtain the hardware address. This means this function also
120 * works if the neighbours are routers too.
121 */
Matthew McClintock0d37fe72014-08-06 16:42:08 -0500122static bool sfe_cm_find_dev_and_mac_addr(uint32_t addr, struct net_device **dev, uint8_t *mac_addr)
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600123{
124 struct neighbour *neigh;
125 struct rtable *rt;
126 struct dst_entry *dst;
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600127 struct net_device *mac_dev;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600128
129 /*
130 * Look up the rtable entry for the IP address then get the hardware
131 * address from its neighbour structure. This means this work when the
132 * neighbours are routers too.
133 */
Matthew McClintock0d37fe72014-08-06 16:42:08 -0500134 rt = ip_route_output(&init_net, addr, 0, 0, 0);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600135 if (unlikely(IS_ERR(rt))) {
136 return false;
137 }
138
139 dst = (struct dst_entry *)rt;
140
141 rcu_read_lock();
Xiaoping Fan3f1fe512014-11-05 12:14:57 -0800142 neigh = dst_neigh_lookup(dst, &addr);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600143 if (unlikely(!neigh)) {
144 rcu_read_unlock();
145 dst_release(dst);
Xiaoping Fan59176422015-05-22 15:58:10 -0700146 return false;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600147 }
148
149 if (unlikely(!(neigh->nud_state & NUD_VALID))) {
Xiaoping Fan3f1fe512014-11-05 12:14:57 -0800150 neigh_release(neigh);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600151 rcu_read_unlock();
152 dst_release(dst);
153 return false;
154 }
155
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600156 mac_dev = neigh->dev;
157 if (!mac_dev) {
Xiaoping Fan3f1fe512014-11-05 12:14:57 -0800158 neigh_release(neigh);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600159 rcu_read_unlock();
160 dst_release(dst);
161 return false;
162 }
163
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600164 memcpy(mac_addr, neigh->ha, (size_t)mac_dev->addr_len);
165
166 dev_hold(mac_dev);
167 *dev = mac_dev;
Xiaoping Fan3f1fe512014-11-05 12:14:57 -0800168 neigh_release(neigh);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600169 rcu_read_unlock();
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600170 dst_release(dst);
171
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600172 return true;
173}
174
175/*
176 * sfe_cm_ipv4_post_routing_hook()
177 * Called for packets about to leave the box - either locally generated or forwarded from another interface
178 */
Xiaoping Fan3f1fe512014-11-05 12:14:57 -0800179sfe_cm_ipv4_post_routing_hook(hooknum, ops, skb, in_unused, out, okfn)
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600180{
181 struct sfe_ipv4_create sic;
182 struct net_device *in;
183 struct nf_conn *ct;
184 enum ip_conntrack_info ctinfo;
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600185 struct net_device *dev;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600186 struct net_device *src_dev;
187 struct net_device *dest_dev;
188 struct net_device *src_br_dev = NULL;
189 struct net_device *dest_br_dev = NULL;
190 struct nf_conntrack_tuple orig_tuple;
191 struct nf_conntrack_tuple reply_tuple;
192
193 /*
194 * Don't process broadcast or multicast packets.
195 */
196 if (unlikely(skb->pkt_type == PACKET_BROADCAST)) {
197 DEBUG_TRACE("broadcast, ignoring\n");
198 return NF_ACCEPT;
199 }
200 if (unlikely(skb->pkt_type == PACKET_MULTICAST)) {
201 DEBUG_TRACE("multicast, ignoring\n");
202 return NF_ACCEPT;
203 }
204
205 /*
206 * Don't process packets that are not being forwarded.
207 */
208 in = dev_get_by_index(&init_net, skb->skb_iif);
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600209 if (!in) {
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600210 DEBUG_TRACE("packet not forwarding\n");
211 return NF_ACCEPT;
212 }
213
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600214 dev_put(in);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600215
216 /*
217 * Don't process packets that aren't being tracked by conntrack.
218 */
219 ct = nf_ct_get(skb, &ctinfo);
220 if (unlikely(!ct)) {
221 DEBUG_TRACE("no conntrack connection, ignoring\n");
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600222 return NF_ACCEPT;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600223 }
224
225 /*
226 * Don't process untracked connections.
227 */
228 if (unlikely(ct == &nf_conntrack_untracked)) {
229 DEBUG_TRACE("untracked connection\n");
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600230 return NF_ACCEPT;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600231 }
232
233 /*
234 * Don't process connections that require support from a 'helper' (typically a NAT ALG).
235 */
236 if (unlikely(nfct_help(ct))) {
237 DEBUG_TRACE("connection has helper\n");
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600238 return NF_ACCEPT;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600239 }
240
241 /*
242 * Look up the details of our connection in conntrack.
243 *
244 * Note that the data we get from conntrack is for the "ORIGINAL" direction
245 * but our packet may actually be in the "REPLY" direction.
246 */
247 orig_tuple = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
248 reply_tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
249 sic.protocol = (int32_t)orig_tuple.dst.protonum;
250
251 /*
252 * Get addressing information, non-NAT first
253 */
254 sic.src_ip = (__be32)orig_tuple.src.u3.ip;
255 sic.dest_ip = (__be32)orig_tuple.dst.u3.ip;
256
Matthew McClintocka11c7cd2014-08-06 16:41:30 -0500257 if (ipv4_is_multicast(sic.src_ip) || ipv4_is_multicast(sic.dest_ip)) {
258 DEBUG_TRACE("multicast address\n");
259 return NF_ACCEPT;
260 }
261
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600262 /*
263 * NAT'ed addresses - note these are as seen from the 'reply' direction
264 * When NAT does not apply to this connection these will be identical to the above.
265 */
266 sic.src_ip_xlate = (__be32)reply_tuple.dst.u3.ip;
267 sic.dest_ip_xlate = (__be32)reply_tuple.src.u3.ip;
268
269 sic.flags = 0;
270
271 switch (sic.protocol) {
272 case IPPROTO_TCP:
273 sic.src_port = orig_tuple.src.u.tcp.port;
274 sic.dest_port = orig_tuple.dst.u.tcp.port;
275 sic.src_port_xlate = reply_tuple.dst.u.tcp.port;
276 sic.dest_port_xlate = reply_tuple.src.u.tcp.port;
277 sic.src_td_window_scale = ct->proto.tcp.seen[0].td_scale;
278 sic.src_td_max_window = ct->proto.tcp.seen[0].td_maxwin;
279 sic.src_td_end = ct->proto.tcp.seen[0].td_end;
280 sic.src_td_max_end = ct->proto.tcp.seen[0].td_maxend;
281 sic.dest_td_window_scale = ct->proto.tcp.seen[1].td_scale;
282 sic.dest_td_max_window = ct->proto.tcp.seen[1].td_maxwin;
283 sic.dest_td_end = ct->proto.tcp.seen[1].td_end;
284 sic.dest_td_max_end = ct->proto.tcp.seen[1].td_maxend;
285 if (nf_ct_tcp_no_window_check
286 || (ct->proto.tcp.seen[0].flags & IP_CT_TCP_FLAG_BE_LIBERAL)
287 || (ct->proto.tcp.seen[1].flags & IP_CT_TCP_FLAG_BE_LIBERAL)) {
288 sic.flags |= SFE_IPV4_CREATE_FLAG_NO_SEQ_CHECK;
289 }
290
291 /*
292 * Don't try to manage a non-established connection.
293 */
294 if (!test_bit(IPS_ASSURED_BIT, &ct->status)) {
295 DEBUG_TRACE("non-established connection\n");
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600296 return NF_ACCEPT;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600297 }
298
299 /*
300 * If the connection is shutting down do not manage it.
301 * state can not be SYN_SENT, SYN_RECV because connection is assured
302 * Not managed states: FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE.
303 */
304 spin_lock_bh(&ct->lock);
305 if (ct->proto.tcp.state != TCP_CONNTRACK_ESTABLISHED) {
306 spin_unlock_bh(&ct->lock);
307 DEBUG_TRACE("connection in termination state: %#x, s: %pI4:%u, d: %pI4:%u\n",
308 ct->proto.tcp.state, &sic.src_ip, ntohs(sic.src_port),
309 &sic.dest_ip, ntohs(sic.dest_port));
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600310 return NF_ACCEPT;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600311 }
312 spin_unlock_bh(&ct->lock);
313 break;
314
315 case IPPROTO_UDP:
316 sic.src_port = orig_tuple.src.u.udp.port;
317 sic.dest_port = orig_tuple.dst.u.udp.port;
318 sic.src_port_xlate = reply_tuple.dst.u.udp.port;
319 sic.dest_port_xlate = reply_tuple.src.u.udp.port;
320 break;
321
322 default:
323 DEBUG_TRACE("unhandled protocol %d\n", sic.protocol);
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600324 return NF_ACCEPT;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600325 }
326
327 /*
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600328 * Get the net device and MAC addresses that correspond to the various source and
329 * destination host addresses.
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600330 */
Matthew McClintock0d37fe72014-08-06 16:42:08 -0500331 if (!sfe_cm_find_dev_and_mac_addr(sic.src_ip, &src_dev, sic.src_mac)) {
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600332 DEBUG_TRACE("failed to find MAC address for src IP: %pI4\n", &sic.src_ip);
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600333 return NF_ACCEPT;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600334 }
335
Matthew McClintock0d37fe72014-08-06 16:42:08 -0500336 if (!sfe_cm_find_dev_and_mac_addr(sic.src_ip_xlate, &dev, sic.src_mac_xlate)) {
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600337 DEBUG_TRACE("failed to find MAC address for xlate src IP: %pI4\n", &sic.src_ip_xlate);
338 goto done1;
339 }
340
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600341 dev_put(dev);
342
Matthew McClintock0d37fe72014-08-06 16:42:08 -0500343 if (!sfe_cm_find_dev_and_mac_addr(sic.dest_ip, &dev, sic.dest_mac)) {
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600344 DEBUG_TRACE("failed to find MAC address for dest IP: %pI4\n", &sic.dest_ip);
345 goto done1;
346 }
347
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600348 dev_put(dev);
349
Matthew McClintock0d37fe72014-08-06 16:42:08 -0500350 if (!sfe_cm_find_dev_and_mac_addr(sic.dest_ip_xlate, &dest_dev, sic.dest_mac_xlate)) {
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600351 DEBUG_TRACE("failed to find MAC address for xlate dest IP: %pI4\n", &sic.dest_ip_xlate);
352 goto done1;
353 }
354
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600355#if (!SFE_HOOK_ABOVE_BRIDGE)
356 /*
357 * Now our devices may actually be a bridge interface. If that's
358 * the case then we need to hunt down the underlying interface.
359 */
360 if (src_dev->priv_flags & IFF_EBRIDGE) {
361 src_br_dev = br_port_dev_get(src_dev, sic.src_mac);
362 if (!src_br_dev) {
363 DEBUG_TRACE("no port found on bridge\n");
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600364 goto done2;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600365 }
366
367 src_dev = src_br_dev;
368 }
369
370 if (dest_dev->priv_flags & IFF_EBRIDGE) {
371 dest_br_dev = br_port_dev_get(dest_dev, sic.dest_mac_xlate);
372 if (!dest_br_dev) {
373 DEBUG_TRACE("no port found on bridge\n");
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600374 goto done3;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600375 }
376
377 dest_dev = dest_br_dev;
378 }
379#else
380 /*
381 * Our devices may actually be part of a bridge interface. If that's
382 * the case then find the bridge interface instead.
383 */
384 if (src_dev->priv_flags & IFF_BRIDGE_PORT) {
Xiaoping Fan3f1fe512014-11-05 12:14:57 -0800385 src_br_dev = SFE_DEV_MASTER(src_dev);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600386 if (!src_br_dev) {
387 DEBUG_TRACE("no bridge found for: %s\n", src_dev->name);
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600388 goto done2;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600389 }
390
391 dev_hold(src_br_dev);
392 src_dev = src_br_dev;
393 }
394
395 if (dest_dev->priv_flags & IFF_BRIDGE_PORT) {
Xiaoping Fan3f1fe512014-11-05 12:14:57 -0800396 dest_br_dev = SFE_DEV_MASTER(dest_dev);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600397 if (!dest_br_dev) {
398 DEBUG_TRACE("no bridge found for: %s\n", dest_dev->name);
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600399 goto done3;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600400 }
401
402 dev_hold(dest_br_dev);
403 dest_dev = dest_br_dev;
404 }
405#endif
406
407 sic.src_dev = src_dev;
408 sic.dest_dev = dest_dev;
409
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600410 sic.src_mtu = src_dev->mtu;
411 sic.dest_mtu = dest_dev->mtu;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600412
413 sfe_ipv4_create_rule(&sic);
414
415 /*
416 * If we had bridge ports then release them too.
417 */
418 if (dest_br_dev) {
419 dev_put(dest_br_dev);
420 }
421
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600422done3:
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600423 if (src_br_dev) {
424 dev_put(src_br_dev);
425 }
426
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600427done2:
428 dev_put(dest_dev);
429
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600430done1:
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600431 dev_put(src_dev);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600432
433 return NF_ACCEPT;
434}
435
436#ifdef CONFIG_NF_CONNTRACK_EVENTS
437/*
438 * sfe_cm_conntrack_event()
439 * Callback event invoked when a conntrack connection's state changes.
440 */
Matthew McClintock0680e9f2013-11-26 15:43:10 -0600441#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
442static int sfe_cm_conntrack_event(struct notifier_block *this,
Matthew McClintock0f5c0592014-02-12 11:17:11 -0600443 unsigned long events, void *ptr)
Matthew McClintock0680e9f2013-11-26 15:43:10 -0600444#else
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600445static int sfe_cm_conntrack_event(unsigned int events, struct nf_ct_event *item)
Matthew McClintock0680e9f2013-11-26 15:43:10 -0600446#endif
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600447{
Matthew McClintock0f5c0592014-02-12 11:17:11 -0600448#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
449 struct nf_ct_event *item = ptr;
450#endif
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600451 struct sfe_ipv4_destroy sid;
452 struct nf_conn *ct = item->ct;
453 struct nf_conntrack_tuple orig_tuple;
454
455 /*
456 * If we don't have a conntrack entry then we're done.
457 */
458 if (unlikely(!ct)) {
459 DEBUG_WARN("no ct in conntrack event callback\n");
460 return NOTIFY_DONE;
461 }
462
463 /*
464 * If this is an untracked connection then we can't have any state either.
465 */
466 if (unlikely(ct == &nf_conntrack_untracked)) {
467 DEBUG_TRACE("ignoring untracked conn\n");
468 return NOTIFY_DONE;
469 }
470
471 /*
472 * Ignore anything other than IPv4 connections.
473 */
474 if (unlikely(nf_ct_l3num(ct) != AF_INET)) {
475 DEBUG_TRACE("ignoring non-IPv4 conn\n");
476 return NOTIFY_DONE;
477 }
478
479 /*
480 * We're only interested in destroy events.
481 */
482 if (unlikely(!(events & (1 << IPCT_DESTROY)))) {
483 DEBUG_TRACE("ignoring non-destroy event\n");
484 return NOTIFY_DONE;
485 }
486
487 orig_tuple = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
488 sid.protocol = (int32_t)orig_tuple.dst.protonum;
489
490 /*
491 * Extract information from the conntrack connection. We're only interested
492 * in nominal connection information (i.e. we're ignoring any NAT information).
493 */
494 sid.src_ip = (__be32)orig_tuple.src.u3.ip;
495 sid.dest_ip = (__be32)orig_tuple.dst.u3.ip;
496
497 switch (sid.protocol) {
498 case IPPROTO_TCP:
499 sid.src_port = orig_tuple.src.u.tcp.port;
500 sid.dest_port = orig_tuple.dst.u.tcp.port;
501 break;
502
503 case IPPROTO_UDP:
504 sid.src_port = orig_tuple.src.u.udp.port;
505 sid.dest_port = orig_tuple.dst.u.udp.port;
506 break;
507
508 default:
509 DEBUG_TRACE("unhandled protocol: %d\n", sid.protocol);
510 return NOTIFY_DONE;
511 }
512
513
514 sfe_ipv4_destroy_rule(&sid);
515 return NOTIFY_DONE;
516}
517
518/*
519 * Netfilter conntrack event system to monitor connection tracking changes
520 */
Matthew McClintock0680e9f2013-11-26 15:43:10 -0600521#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
522static struct notifier_block sfe_cm_conntrack_notifier = {
523 .notifier_call = sfe_cm_conntrack_event,
524};
525#else
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600526static struct nf_ct_event_notifier sfe_cm_conntrack_notifier = {
527 .fcn = sfe_cm_conntrack_event,
528};
529#endif
Matthew McClintock0680e9f2013-11-26 15:43:10 -0600530#endif
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600531
532/*
533 * Structure to establish a hook into the post routing netfilter point - this
534 * will pick up local outbound and packets going from one interface to another.
535 *
536 * Note: see include/linux/netfilter_ipv4.h for info related to priority levels.
537 * We want to examine packets after NAT translation and any ALG processing.
538 */
539static struct nf_hook_ops sfe_cm_ipv4_ops_post_routing[] __read_mostly = {
540 {
Xiaoping Fan3f1fe512014-11-05 12:14:57 -0800541 .hook = __sfe_cm_ipv4_post_routing_hook,
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600542 .owner = THIS_MODULE,
543 .pf = PF_INET,
544 .hooknum = NF_INET_POST_ROUTING,
545 .priority = NF_IP_PRI_NAT_SRC + 1,
546 },
547};
548
549/*
550 * sfe_cm_sync_rule()
551 * Synchronize a connection's state.
552 */
553static void sfe_cm_sync_rule(struct sfe_ipv4_sync *sis)
554{
555 struct nf_conntrack_tuple_hash *h;
556 struct nf_conntrack_tuple tuple;
557 struct nf_conn *ct;
Xiaoping Fan3f1fe512014-11-05 12:14:57 -0800558 SFE_NF_CONN_ACCT(acct);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600559
560 /*
561 * Create a tuple so as to be able to look up a connection
562 */
563 memset(&tuple, 0, sizeof(tuple));
564 tuple.src.u3.ip = sis->src_ip;
565 tuple.src.u.all = (__be16)sis->src_port;
566 tuple.src.l3num = AF_INET;
567
568 tuple.dst.u3.ip = sis->dest_ip;
569 tuple.dst.dir = IP_CT_DIR_ORIGINAL;
570 tuple.dst.protonum = (uint8_t)sis->protocol;
571 tuple.dst.u.all = (__be16)sis->dest_port;
572
573 DEBUG_TRACE("update connection - p: %d, s: %pI4:%u, d: %pI4:%u\n",
574 (int)tuple.dst.protonum,
575 &tuple.src.u3.ip, (unsigned int)ntohs(tuple.src.u.all),
576 &tuple.dst.u3.ip, (unsigned int)ntohs(tuple.dst.u.all));
577
578 /*
579 * Look up conntrack connection
580 */
581 h = nf_conntrack_find_get(&init_net, NF_CT_DEFAULT_ZONE, &tuple);
582 if (unlikely(!h)) {
583 DEBUG_TRACE("no connection found\n");
584 return;
585 }
586
587 ct = nf_ct_tuplehash_to_ctrack(h);
588 NF_CT_ASSERT(ct->timeout.data == (unsigned long)ct);
589
590 /*
591 * Only update if this is not a fixed timeout
592 */
593 if (!test_bit(IPS_FIXED_TIMEOUT_BIT, &ct->status)) {
594 ct->timeout.expires += sis->delta_jiffies;
595 }
596
597 acct = nf_conn_acct_find(ct);
598 if (acct) {
599 spin_lock_bh(&ct->lock);
Xiaoping Fan3f1fe512014-11-05 12:14:57 -0800600 atomic64_set(&SFE_ACCT_COUNTER(acct)[IP_CT_DIR_ORIGINAL].packets, sis->src_packet_count);
601 atomic64_set(&SFE_ACCT_COUNTER(acct)[IP_CT_DIR_ORIGINAL].bytes, sis->src_byte_count);
602 atomic64_set(&SFE_ACCT_COUNTER(acct)[IP_CT_DIR_REPLY].packets, sis->dest_packet_count);
603 atomic64_set(&SFE_ACCT_COUNTER(acct)[IP_CT_DIR_REPLY].bytes, sis->dest_byte_count);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600604 spin_unlock_bh(&ct->lock);
605 }
606
607 switch (sis->protocol) {
608 case IPPROTO_TCP:
609 spin_lock_bh(&ct->lock);
610 if (ct->proto.tcp.seen[0].td_maxwin < sis->src_td_max_window) {
611 ct->proto.tcp.seen[0].td_maxwin = sis->src_td_max_window;
612 }
613 if ((int32_t)(ct->proto.tcp.seen[0].td_end - sis->src_td_end) < 0) {
614 ct->proto.tcp.seen[0].td_end = sis->src_td_end;
615 }
616 if ((int32_t)(ct->proto.tcp.seen[0].td_maxend - sis->src_td_max_end) < 0) {
617 ct->proto.tcp.seen[0].td_maxend = sis->src_td_max_end;
618 }
619 if (ct->proto.tcp.seen[1].td_maxwin < sis->dest_td_max_window) {
620 ct->proto.tcp.seen[1].td_maxwin = sis->dest_td_max_window;
621 }
622 if ((int32_t)(ct->proto.tcp.seen[1].td_end - sis->dest_td_end) < 0) {
623 ct->proto.tcp.seen[1].td_end = sis->dest_td_end;
624 }
625 if ((int32_t)(ct->proto.tcp.seen[1].td_maxend - sis->dest_td_max_end) < 0) {
626 ct->proto.tcp.seen[1].td_maxend = sis->dest_td_max_end;
627 }
628 spin_unlock_bh(&ct->lock);
629 break;
630 }
631
632 /*
633 * Release connection
634 */
635 nf_ct_put(ct);
636}
637
638/*
639 * sfe_cm_device_event()
640 */
641static int sfe_cm_device_event(struct notifier_block *this, unsigned long event, void *ptr)
642{
643 struct net_device *dev = (struct net_device *)ptr;
644
645 switch (event) {
646 case NETDEV_DOWN:
647 if (dev) {
648 sfe_ipv4_destroy_all_rules_for_dev(dev);
649 }
650 break;
651 }
652
653 return NOTIFY_DONE;
654}
655
656/*
657 * sfe_cm_inet_event()
658 */
659static int sfe_cm_inet_event(struct notifier_block *this, unsigned long event, void *ptr)
660{
661 struct net_device *dev = ((struct in_ifaddr *)ptr)->ifa_dev->dev;
662 return sfe_cm_device_event(this, event, dev);
663}
664
665/*
666 * sfe_cm_init()
667 */
668static int __init sfe_cm_init(void)
669{
670 struct sfe_cm *sc = &__sc;
671 int result = -1;
672
673 DEBUG_INFO("SFE CM init\n");
674
675 /*
676 * Create sys/sfe_cm
677 */
678 sc->sys_sfe_cm = kobject_create_and_add("sfe_cm", NULL);
679 if (!sc->sys_sfe_cm) {
680 DEBUG_ERROR("failed to register sfe_cm\n");
681 goto exit1;
682 }
683
684 sc->dev_notifier.notifier_call = sfe_cm_device_event;
685 sc->dev_notifier.priority = 1;
686 register_netdevice_notifier(&sc->dev_notifier);
687
688 sc->inet_notifier.notifier_call = sfe_cm_inet_event;
689 sc->inet_notifier.priority = 1;
690 register_inetaddr_notifier(&sc->inet_notifier);
691
692 /*
693 * Register our netfilter hooks.
694 */
695 result = nf_register_hooks(sfe_cm_ipv4_ops_post_routing, ARRAY_SIZE(sfe_cm_ipv4_ops_post_routing));
696 if (result < 0) {
697 DEBUG_ERROR("can't register nf post routing hook: %d\n", result);
Xiaoping Fan59176422015-05-22 15:58:10 -0700698 goto exit2;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600699 }
700
701#ifdef CONFIG_NF_CONNTRACK_EVENTS
702 /*
703 * Register a notifier hook to get fast notifications of expired connections.
704 */
705 result = nf_conntrack_register_notifier(&init_net, &sfe_cm_conntrack_notifier);
706 if (result < 0) {
707 DEBUG_ERROR("can't register nf notifier hook: %d\n", result);
Xiaoping Fan59176422015-05-22 15:58:10 -0700708 goto exit3;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600709 }
710#endif
711
712 spin_lock_init(&sc->lock);
713
714 /*
715 * Hook the receive path in the network stack.
716 */
717 BUG_ON(athrs_fast_nat_recv != NULL);
718 RCU_INIT_POINTER(athrs_fast_nat_recv, sfe_cm_recv);
719
720 /*
721 * Hook the shortcut sync callback.
722 */
723 sfe_ipv4_register_sync_rule_callback(sfe_cm_sync_rule);
724 return 0;
725
726#ifdef CONFIG_NF_CONNTRACK_EVENTS
Xiaoping Fan59176422015-05-22 15:58:10 -0700727exit3:
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600728#endif
729 nf_unregister_hooks(sfe_cm_ipv4_ops_post_routing, ARRAY_SIZE(sfe_cm_ipv4_ops_post_routing));
730
Xiaoping Fan59176422015-05-22 15:58:10 -0700731exit2:
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600732 unregister_inetaddr_notifier(&sc->inet_notifier);
733 unregister_netdevice_notifier(&sc->dev_notifier);
734 kobject_put(sc->sys_sfe_cm);
735
736exit1:
737 return result;
738}
739
740/*
741 * sfe_cm_exit()
742 */
743static void __exit sfe_cm_exit(void)
744{
745 struct sfe_cm *sc = &__sc;
746
747 DEBUG_INFO("SFE CM exit\n");
748
749 /*
750 * Unregister our sync callback.
751 */
752 sfe_ipv4_register_sync_rule_callback(NULL);
753
754 /*
755 * Unregister our receive callback.
756 */
757 RCU_INIT_POINTER(athrs_fast_nat_recv, NULL);
758
759 /*
760 * Wait for all callbacks to complete.
761 */
762 rcu_barrier();
763
764 /*
765 * Destroy all connections.
766 */
767 sfe_ipv4_destroy_all_rules_for_dev(NULL);
768
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600769#ifdef CONFIG_NF_CONNTRACK_EVENTS
770 nf_conntrack_unregister_notifier(&init_net, &sfe_cm_conntrack_notifier);
771
772#endif
773 nf_unregister_hooks(sfe_cm_ipv4_ops_post_routing, ARRAY_SIZE(sfe_cm_ipv4_ops_post_routing));
774
775 unregister_inetaddr_notifier(&sc->inet_notifier);
776 unregister_netdevice_notifier(&sc->dev_notifier);
777
778 kobject_put(sc->sys_sfe_cm);
779
780}
781
782module_init(sfe_cm_init)
783module_exit(sfe_cm_exit)
784
785MODULE_AUTHOR("Qualcomm Atheros Inc.");
786MODULE_DESCRIPTION("Shortcut Forwarding Engine - Connection Manager");
Matthew McClintocka3221942014-01-16 11:44:26 -0600787MODULE_LICENSE("Dual BSD/GPL");
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600788