blob: 2e7e5d5ea454dd3166518b325292474f65916d31 [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"
25
26/*
27 * Per-module structure.
28 */
29struct sfe_cm {
30 spinlock_t lock; /* Lock for SMP correctness */
31
32 /*
33 * Control state.
34 */
35 struct kobject *sys_sfe_cm; /* sysfs linkage */
36
37 /*
38 * Callback notifiers.
39 */
40 struct notifier_block dev_notifier;
41 /* Device notifier */
42 struct notifier_block inet_notifier;
43 /* IP notifier */
44};
45
46struct sfe_cm __sc;
47
48/*
49 * Expose the hook for the receive processing.
50 */
51extern int (*athrs_fast_nat_recv)(struct sk_buff *skb);
52
53/*
54 * Expose what should be a static flag in the TCP connection tracker.
55 */
56extern int nf_ct_tcp_no_window_check;
57
58/*
59 * sfe_cm_recv()
60 * Handle packet receives.
61 *
62 * Returns 1 if the packet is forwarded or 0 if it isn't.
63 */
64int sfe_cm_recv(struct sk_buff *skb)
65{
66 struct net_device *dev;
67#if (SFE_HOOK_ABOVE_BRIDGE)
68 struct in_device *in_dev;
69#endif
70
71 /*
72 * We know that for the vast majority of packets we need the transport
73 * layer header so we may as well start to fetch it now!
74 */
75 prefetch(skb->data + 32);
76 barrier();
77
78 dev = skb->dev;
79
80#if (SFE_HOOK_ABOVE_BRIDGE)
81 /*
82 * Does our input device support IP processing?
83 */
84 in_dev = (struct in_device *)dev->ip_ptr;
85 if (unlikely(!in_dev)) {
86 DEBUG_TRACE("no IP processing for device: %s\n", dev->name);
87 return 0;
88 }
89
90 /*
91 * Does it have an IP address? If it doesn't then we can't do anything
92 * interesting here!
93 */
94 if (unlikely(!in_dev->ifa_list)) {
95 DEBUG_TRACE("no IP address for device: %s\n", dev->name);
96 return 0;
97 }
98#endif
99
100 /*
101 * We're only interested in IP packets.
102 */
103 if (likely(htons(ETH_P_IP) == skb->protocol)) {
104 return sfe_ipv4_recv(dev, skb);
105 }
106
Matthew McClintocka8ad7962014-01-16 16:49:30 -0600107 DEBUG_TRACE("not IP packet\n");
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600108 return 0;
109}
110
111/*
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600112 * sfe_cm_find_dev_and_mac_addr()
113 * Find the device and MAC address for a given IPv4 address.
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600114 *
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600115 * Returns true if we find the device and MAC address, otherwise false.
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600116 *
117 * We look up the rtable entry for the address and, from its neighbour
118 * structure, obtain the hardware address. This means this function also
119 * works if the neighbours are routers too.
120 */
Matthew McClintock0d37fe72014-08-06 16:42:08 -0500121static 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 -0600122{
123 struct neighbour *neigh;
124 struct rtable *rt;
125 struct dst_entry *dst;
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600126 struct net_device *mac_dev;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600127
128 /*
129 * Look up the rtable entry for the IP address then get the hardware
130 * address from its neighbour structure. This means this work when the
131 * neighbours are routers too.
132 */
Matthew McClintock0d37fe72014-08-06 16:42:08 -0500133 rt = ip_route_output(&init_net, addr, 0, 0, 0);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600134 if (unlikely(IS_ERR(rt))) {
135 return false;
136 }
137
138 dst = (struct dst_entry *)rt;
139
140 rcu_read_lock();
141 neigh = dst_get_neighbour_noref(dst);
142 if (unlikely(!neigh)) {
143 rcu_read_unlock();
144 dst_release(dst);
145 return false;
146 }
147
148 if (unlikely(!(neigh->nud_state & NUD_VALID))) {
149 rcu_read_unlock();
150 dst_release(dst);
151 return false;
152 }
153
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600154 mac_dev = neigh->dev;
155 if (!mac_dev) {
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600156 rcu_read_unlock();
157 dst_release(dst);
158 return false;
159 }
160
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600161 memcpy(mac_addr, neigh->ha, (size_t)mac_dev->addr_len);
162
163 dev_hold(mac_dev);
164 *dev = mac_dev;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600165 rcu_read_unlock();
166
167 dst_release(dst);
168
169 /*
170 * We're only interested in unicast MAC addresses - if it's not a unicast
171 * address then our IP address mustn't be unicast either.
172 */
173 if (is_multicast_ether_addr(mac_addr)) {
174 DEBUG_TRACE("MAC is non-unicast - ignoring\n");
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600175 dev_put(mac_dev);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600176 return false;
177 }
178
179 return true;
180}
181
182/*
183 * sfe_cm_ipv4_post_routing_hook()
184 * Called for packets about to leave the box - either locally generated or forwarded from another interface
185 */
186static unsigned int sfe_cm_ipv4_post_routing_hook(unsigned int hooknum,
187 struct sk_buff *skb,
188 const struct net_device *in_unused,
189 const struct net_device *out,
190 int (*okfn)(struct sk_buff *))
191{
192 struct sfe_ipv4_create sic;
193 struct net_device *in;
194 struct nf_conn *ct;
195 enum ip_conntrack_info ctinfo;
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600196 struct net_device *dev;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600197 struct net_device *src_dev;
198 struct net_device *dest_dev;
199 struct net_device *src_br_dev = NULL;
200 struct net_device *dest_br_dev = NULL;
201 struct nf_conntrack_tuple orig_tuple;
202 struct nf_conntrack_tuple reply_tuple;
203
204 /*
205 * Don't process broadcast or multicast packets.
206 */
207 if (unlikely(skb->pkt_type == PACKET_BROADCAST)) {
208 DEBUG_TRACE("broadcast, ignoring\n");
209 return NF_ACCEPT;
210 }
211 if (unlikely(skb->pkt_type == PACKET_MULTICAST)) {
212 DEBUG_TRACE("multicast, ignoring\n");
213 return NF_ACCEPT;
214 }
215
216 /*
217 * Don't process packets that are not being forwarded.
218 */
219 in = dev_get_by_index(&init_net, skb->skb_iif);
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600220 if (!in) {
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600221 DEBUG_TRACE("packet not forwarding\n");
222 return NF_ACCEPT;
223 }
224
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600225 dev_put(in);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600226
227 /*
228 * Don't process packets that aren't being tracked by conntrack.
229 */
230 ct = nf_ct_get(skb, &ctinfo);
231 if (unlikely(!ct)) {
232 DEBUG_TRACE("no conntrack connection, ignoring\n");
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600233 return NF_ACCEPT;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600234 }
235
236 /*
237 * Don't process untracked connections.
238 */
239 if (unlikely(ct == &nf_conntrack_untracked)) {
240 DEBUG_TRACE("untracked connection\n");
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600241 return NF_ACCEPT;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600242 }
243
244 /*
245 * Don't process connections that require support from a 'helper' (typically a NAT ALG).
246 */
247 if (unlikely(nfct_help(ct))) {
248 DEBUG_TRACE("connection has helper\n");
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600249 return NF_ACCEPT;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600250 }
251
252 /*
253 * Look up the details of our connection in conntrack.
254 *
255 * Note that the data we get from conntrack is for the "ORIGINAL" direction
256 * but our packet may actually be in the "REPLY" direction.
257 */
258 orig_tuple = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
259 reply_tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
260 sic.protocol = (int32_t)orig_tuple.dst.protonum;
261
262 /*
263 * Get addressing information, non-NAT first
264 */
265 sic.src_ip = (__be32)orig_tuple.src.u3.ip;
266 sic.dest_ip = (__be32)orig_tuple.dst.u3.ip;
267
Matthew McClintocka11c7cd2014-08-06 16:41:30 -0500268 if (ipv4_is_multicast(sic.src_ip) || ipv4_is_multicast(sic.dest_ip)) {
269 DEBUG_TRACE("multicast address\n");
270 return NF_ACCEPT;
271 }
272
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600273 /*
274 * NAT'ed addresses - note these are as seen from the 'reply' direction
275 * When NAT does not apply to this connection these will be identical to the above.
276 */
277 sic.src_ip_xlate = (__be32)reply_tuple.dst.u3.ip;
278 sic.dest_ip_xlate = (__be32)reply_tuple.src.u3.ip;
279
280 sic.flags = 0;
281
282 switch (sic.protocol) {
283 case IPPROTO_TCP:
284 sic.src_port = orig_tuple.src.u.tcp.port;
285 sic.dest_port = orig_tuple.dst.u.tcp.port;
286 sic.src_port_xlate = reply_tuple.dst.u.tcp.port;
287 sic.dest_port_xlate = reply_tuple.src.u.tcp.port;
288 sic.src_td_window_scale = ct->proto.tcp.seen[0].td_scale;
289 sic.src_td_max_window = ct->proto.tcp.seen[0].td_maxwin;
290 sic.src_td_end = ct->proto.tcp.seen[0].td_end;
291 sic.src_td_max_end = ct->proto.tcp.seen[0].td_maxend;
292 sic.dest_td_window_scale = ct->proto.tcp.seen[1].td_scale;
293 sic.dest_td_max_window = ct->proto.tcp.seen[1].td_maxwin;
294 sic.dest_td_end = ct->proto.tcp.seen[1].td_end;
295 sic.dest_td_max_end = ct->proto.tcp.seen[1].td_maxend;
296 if (nf_ct_tcp_no_window_check
297 || (ct->proto.tcp.seen[0].flags & IP_CT_TCP_FLAG_BE_LIBERAL)
298 || (ct->proto.tcp.seen[1].flags & IP_CT_TCP_FLAG_BE_LIBERAL)) {
299 sic.flags |= SFE_IPV4_CREATE_FLAG_NO_SEQ_CHECK;
300 }
301
302 /*
303 * Don't try to manage a non-established connection.
304 */
305 if (!test_bit(IPS_ASSURED_BIT, &ct->status)) {
306 DEBUG_TRACE("non-established connection\n");
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600307 return NF_ACCEPT;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600308 }
309
310 /*
311 * If the connection is shutting down do not manage it.
312 * state can not be SYN_SENT, SYN_RECV because connection is assured
313 * Not managed states: FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE.
314 */
315 spin_lock_bh(&ct->lock);
316 if (ct->proto.tcp.state != TCP_CONNTRACK_ESTABLISHED) {
317 spin_unlock_bh(&ct->lock);
318 DEBUG_TRACE("connection in termination state: %#x, s: %pI4:%u, d: %pI4:%u\n",
319 ct->proto.tcp.state, &sic.src_ip, ntohs(sic.src_port),
320 &sic.dest_ip, ntohs(sic.dest_port));
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600321 return NF_ACCEPT;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600322 }
323 spin_unlock_bh(&ct->lock);
324 break;
325
326 case IPPROTO_UDP:
327 sic.src_port = orig_tuple.src.u.udp.port;
328 sic.dest_port = orig_tuple.dst.u.udp.port;
329 sic.src_port_xlate = reply_tuple.dst.u.udp.port;
330 sic.dest_port_xlate = reply_tuple.src.u.udp.port;
331 break;
332
333 default:
334 DEBUG_TRACE("unhandled protocol %d\n", sic.protocol);
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600335 return NF_ACCEPT;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600336 }
337
338 /*
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600339 * Get the net device and MAC addresses that correspond to the various source and
340 * destination host addresses.
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600341 */
Matthew McClintock0d37fe72014-08-06 16:42:08 -0500342 if (!sfe_cm_find_dev_and_mac_addr(sic.src_ip, &src_dev, sic.src_mac)) {
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600343 DEBUG_TRACE("failed to find MAC address for src IP: %pI4\n", &sic.src_ip);
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600344 return NF_ACCEPT;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600345 }
346
Matthew McClintock0d37fe72014-08-06 16:42:08 -0500347 if (!sfe_cm_find_dev_and_mac_addr(sic.src_ip_xlate, &dev, sic.src_mac_xlate)) {
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600348 DEBUG_TRACE("failed to find MAC address for xlate src IP: %pI4\n", &sic.src_ip_xlate);
349 goto done1;
350 }
351
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600352 dev_put(dev);
353
Matthew McClintock0d37fe72014-08-06 16:42:08 -0500354 if (!sfe_cm_find_dev_and_mac_addr(sic.dest_ip, &dev, sic.dest_mac)) {
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600355 DEBUG_TRACE("failed to find MAC address for dest IP: %pI4\n", &sic.dest_ip);
356 goto done1;
357 }
358
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600359 dev_put(dev);
360
Matthew McClintock0d37fe72014-08-06 16:42:08 -0500361 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 -0600362 DEBUG_TRACE("failed to find MAC address for xlate dest IP: %pI4\n", &sic.dest_ip_xlate);
363 goto done1;
364 }
365
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600366#if (!SFE_HOOK_ABOVE_BRIDGE)
367 /*
368 * Now our devices may actually be a bridge interface. If that's
369 * the case then we need to hunt down the underlying interface.
370 */
371 if (src_dev->priv_flags & IFF_EBRIDGE) {
372 src_br_dev = br_port_dev_get(src_dev, sic.src_mac);
373 if (!src_br_dev) {
374 DEBUG_TRACE("no port found on bridge\n");
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600375 goto done2;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600376 }
377
378 src_dev = src_br_dev;
379 }
380
381 if (dest_dev->priv_flags & IFF_EBRIDGE) {
382 dest_br_dev = br_port_dev_get(dest_dev, sic.dest_mac_xlate);
383 if (!dest_br_dev) {
384 DEBUG_TRACE("no port found on bridge\n");
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600385 goto done3;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600386 }
387
388 dest_dev = dest_br_dev;
389 }
390#else
391 /*
392 * Our devices may actually be part of a bridge interface. If that's
393 * the case then find the bridge interface instead.
394 */
395 if (src_dev->priv_flags & IFF_BRIDGE_PORT) {
396 src_br_dev = src_dev->master;
397 if (!src_br_dev) {
398 DEBUG_TRACE("no bridge found for: %s\n", src_dev->name);
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600399 goto done2;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600400 }
401
402 dev_hold(src_br_dev);
403 src_dev = src_br_dev;
404 }
405
406 if (dest_dev->priv_flags & IFF_BRIDGE_PORT) {
407 dest_br_dev = dest_dev->master;
408 if (!dest_br_dev) {
409 DEBUG_TRACE("no bridge found for: %s\n", dest_dev->name);
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600410 goto done3;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600411 }
412
413 dev_hold(dest_br_dev);
414 dest_dev = dest_br_dev;
415 }
416#endif
417
418 sic.src_dev = src_dev;
419 sic.dest_dev = dest_dev;
420
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600421 sic.src_mtu = src_dev->mtu;
422 sic.dest_mtu = dest_dev->mtu;
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600423
424 sfe_ipv4_create_rule(&sic);
425
426 /*
427 * If we had bridge ports then release them too.
428 */
429 if (dest_br_dev) {
430 dev_put(dest_br_dev);
431 }
432
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600433done3:
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600434 if (src_br_dev) {
435 dev_put(src_br_dev);
436 }
437
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600438done2:
439 dev_put(dest_dev);
440
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600441done1:
Matthew McClintockdb5ac512014-01-16 17:01:40 -0600442 dev_put(src_dev);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600443
444 return NF_ACCEPT;
445}
446
447#ifdef CONFIG_NF_CONNTRACK_EVENTS
448/*
449 * sfe_cm_conntrack_event()
450 * Callback event invoked when a conntrack connection's state changes.
451 */
Matthew McClintock0680e9f2013-11-26 15:43:10 -0600452#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
453static int sfe_cm_conntrack_event(struct notifier_block *this,
Matthew McClintock0f5c0592014-02-12 11:17:11 -0600454 unsigned long events, void *ptr)
Matthew McClintock0680e9f2013-11-26 15:43:10 -0600455#else
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600456static int sfe_cm_conntrack_event(unsigned int events, struct nf_ct_event *item)
Matthew McClintock0680e9f2013-11-26 15:43:10 -0600457#endif
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600458{
Matthew McClintock0f5c0592014-02-12 11:17:11 -0600459#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
460 struct nf_ct_event *item = ptr;
461#endif
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600462 struct sfe_ipv4_destroy sid;
463 struct nf_conn *ct = item->ct;
464 struct nf_conntrack_tuple orig_tuple;
465
466 /*
467 * If we don't have a conntrack entry then we're done.
468 */
469 if (unlikely(!ct)) {
470 DEBUG_WARN("no ct in conntrack event callback\n");
471 return NOTIFY_DONE;
472 }
473
474 /*
475 * If this is an untracked connection then we can't have any state either.
476 */
477 if (unlikely(ct == &nf_conntrack_untracked)) {
478 DEBUG_TRACE("ignoring untracked conn\n");
479 return NOTIFY_DONE;
480 }
481
482 /*
483 * Ignore anything other than IPv4 connections.
484 */
485 if (unlikely(nf_ct_l3num(ct) != AF_INET)) {
486 DEBUG_TRACE("ignoring non-IPv4 conn\n");
487 return NOTIFY_DONE;
488 }
489
490 /*
491 * We're only interested in destroy events.
492 */
493 if (unlikely(!(events & (1 << IPCT_DESTROY)))) {
494 DEBUG_TRACE("ignoring non-destroy event\n");
495 return NOTIFY_DONE;
496 }
497
498 orig_tuple = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
499 sid.protocol = (int32_t)orig_tuple.dst.protonum;
500
501 /*
502 * Extract information from the conntrack connection. We're only interested
503 * in nominal connection information (i.e. we're ignoring any NAT information).
504 */
505 sid.src_ip = (__be32)orig_tuple.src.u3.ip;
506 sid.dest_ip = (__be32)orig_tuple.dst.u3.ip;
507
508 switch (sid.protocol) {
509 case IPPROTO_TCP:
510 sid.src_port = orig_tuple.src.u.tcp.port;
511 sid.dest_port = orig_tuple.dst.u.tcp.port;
512 break;
513
514 case IPPROTO_UDP:
515 sid.src_port = orig_tuple.src.u.udp.port;
516 sid.dest_port = orig_tuple.dst.u.udp.port;
517 break;
518
519 default:
520 DEBUG_TRACE("unhandled protocol: %d\n", sid.protocol);
521 return NOTIFY_DONE;
522 }
523
524
525 sfe_ipv4_destroy_rule(&sid);
526 return NOTIFY_DONE;
527}
528
529/*
530 * Netfilter conntrack event system to monitor connection tracking changes
531 */
Matthew McClintock0680e9f2013-11-26 15:43:10 -0600532#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
533static struct notifier_block sfe_cm_conntrack_notifier = {
534 .notifier_call = sfe_cm_conntrack_event,
535};
536#else
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600537static struct nf_ct_event_notifier sfe_cm_conntrack_notifier = {
538 .fcn = sfe_cm_conntrack_event,
539};
540#endif
Matthew McClintock0680e9f2013-11-26 15:43:10 -0600541#endif
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600542
543/*
544 * Structure to establish a hook into the post routing netfilter point - this
545 * will pick up local outbound and packets going from one interface to another.
546 *
547 * Note: see include/linux/netfilter_ipv4.h for info related to priority levels.
548 * We want to examine packets after NAT translation and any ALG processing.
549 */
550static struct nf_hook_ops sfe_cm_ipv4_ops_post_routing[] __read_mostly = {
551 {
552 .hook = sfe_cm_ipv4_post_routing_hook,
553 .owner = THIS_MODULE,
554 .pf = PF_INET,
555 .hooknum = NF_INET_POST_ROUTING,
556 .priority = NF_IP_PRI_NAT_SRC + 1,
557 },
558};
559
560/*
561 * sfe_cm_sync_rule()
562 * Synchronize a connection's state.
563 */
564static void sfe_cm_sync_rule(struct sfe_ipv4_sync *sis)
565{
566 struct nf_conntrack_tuple_hash *h;
567 struct nf_conntrack_tuple tuple;
568 struct nf_conn *ct;
569 struct nf_conn_counter *acct;
570
571 /*
572 * Create a tuple so as to be able to look up a connection
573 */
574 memset(&tuple, 0, sizeof(tuple));
575 tuple.src.u3.ip = sis->src_ip;
576 tuple.src.u.all = (__be16)sis->src_port;
577 tuple.src.l3num = AF_INET;
578
579 tuple.dst.u3.ip = sis->dest_ip;
580 tuple.dst.dir = IP_CT_DIR_ORIGINAL;
581 tuple.dst.protonum = (uint8_t)sis->protocol;
582 tuple.dst.u.all = (__be16)sis->dest_port;
583
584 DEBUG_TRACE("update connection - p: %d, s: %pI4:%u, d: %pI4:%u\n",
585 (int)tuple.dst.protonum,
586 &tuple.src.u3.ip, (unsigned int)ntohs(tuple.src.u.all),
587 &tuple.dst.u3.ip, (unsigned int)ntohs(tuple.dst.u.all));
588
589 /*
590 * Look up conntrack connection
591 */
592 h = nf_conntrack_find_get(&init_net, NF_CT_DEFAULT_ZONE, &tuple);
593 if (unlikely(!h)) {
594 DEBUG_TRACE("no connection found\n");
595 return;
596 }
597
598 ct = nf_ct_tuplehash_to_ctrack(h);
599 NF_CT_ASSERT(ct->timeout.data == (unsigned long)ct);
600
601 /*
602 * Only update if this is not a fixed timeout
603 */
604 if (!test_bit(IPS_FIXED_TIMEOUT_BIT, &ct->status)) {
605 ct->timeout.expires += sis->delta_jiffies;
606 }
607
608 acct = nf_conn_acct_find(ct);
609 if (acct) {
610 spin_lock_bh(&ct->lock);
Matthew McClintock704b7a62013-12-19 16:13:01 -0600611 atomic64_set(&acct[IP_CT_DIR_ORIGINAL].packets, sis->src_packet_count);
612 atomic64_set(&acct[IP_CT_DIR_ORIGINAL].bytes, sis->src_byte_count);
613 atomic64_set(&acct[IP_CT_DIR_REPLY].packets, sis->dest_packet_count);
614 atomic64_set(&acct[IP_CT_DIR_REPLY].bytes, sis->dest_byte_count);
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600615 spin_unlock_bh(&ct->lock);
616 }
617
618 switch (sis->protocol) {
619 case IPPROTO_TCP:
620 spin_lock_bh(&ct->lock);
621 if (ct->proto.tcp.seen[0].td_maxwin < sis->src_td_max_window) {
622 ct->proto.tcp.seen[0].td_maxwin = sis->src_td_max_window;
623 }
624 if ((int32_t)(ct->proto.tcp.seen[0].td_end - sis->src_td_end) < 0) {
625 ct->proto.tcp.seen[0].td_end = sis->src_td_end;
626 }
627 if ((int32_t)(ct->proto.tcp.seen[0].td_maxend - sis->src_td_max_end) < 0) {
628 ct->proto.tcp.seen[0].td_maxend = sis->src_td_max_end;
629 }
630 if (ct->proto.tcp.seen[1].td_maxwin < sis->dest_td_max_window) {
631 ct->proto.tcp.seen[1].td_maxwin = sis->dest_td_max_window;
632 }
633 if ((int32_t)(ct->proto.tcp.seen[1].td_end - sis->dest_td_end) < 0) {
634 ct->proto.tcp.seen[1].td_end = sis->dest_td_end;
635 }
636 if ((int32_t)(ct->proto.tcp.seen[1].td_maxend - sis->dest_td_max_end) < 0) {
637 ct->proto.tcp.seen[1].td_maxend = sis->dest_td_max_end;
638 }
639 spin_unlock_bh(&ct->lock);
640 break;
641 }
642
643 /*
644 * Release connection
645 */
646 nf_ct_put(ct);
647}
648
649/*
650 * sfe_cm_device_event()
651 */
652static int sfe_cm_device_event(struct notifier_block *this, unsigned long event, void *ptr)
653{
654 struct net_device *dev = (struct net_device *)ptr;
655
656 switch (event) {
657 case NETDEV_DOWN:
658 if (dev) {
659 sfe_ipv4_destroy_all_rules_for_dev(dev);
660 }
661 break;
662 }
663
664 return NOTIFY_DONE;
665}
666
667/*
668 * sfe_cm_inet_event()
669 */
670static int sfe_cm_inet_event(struct notifier_block *this, unsigned long event, void *ptr)
671{
672 struct net_device *dev = ((struct in_ifaddr *)ptr)->ifa_dev->dev;
673 return sfe_cm_device_event(this, event, dev);
674}
675
676/*
677 * sfe_cm_init()
678 */
679static int __init sfe_cm_init(void)
680{
681 struct sfe_cm *sc = &__sc;
682 int result = -1;
683
684 DEBUG_INFO("SFE CM init\n");
685
686 /*
687 * Create sys/sfe_cm
688 */
689 sc->sys_sfe_cm = kobject_create_and_add("sfe_cm", NULL);
690 if (!sc->sys_sfe_cm) {
691 DEBUG_ERROR("failed to register sfe_cm\n");
692 goto exit1;
693 }
694
695 sc->dev_notifier.notifier_call = sfe_cm_device_event;
696 sc->dev_notifier.priority = 1;
697 register_netdevice_notifier(&sc->dev_notifier);
698
699 sc->inet_notifier.notifier_call = sfe_cm_inet_event;
700 sc->inet_notifier.priority = 1;
701 register_inetaddr_notifier(&sc->inet_notifier);
702
703 /*
704 * Register our netfilter hooks.
705 */
706 result = nf_register_hooks(sfe_cm_ipv4_ops_post_routing, ARRAY_SIZE(sfe_cm_ipv4_ops_post_routing));
707 if (result < 0) {
708 DEBUG_ERROR("can't register nf post routing hook: %d\n", result);
709 goto exit6;
710 }
711
712#ifdef CONFIG_NF_CONNTRACK_EVENTS
713 /*
714 * Register a notifier hook to get fast notifications of expired connections.
715 */
716 result = nf_conntrack_register_notifier(&init_net, &sfe_cm_conntrack_notifier);
717 if (result < 0) {
718 DEBUG_ERROR("can't register nf notifier hook: %d\n", result);
719 goto exit7;
720 }
721#endif
722
723 spin_lock_init(&sc->lock);
724
725 /*
726 * Hook the receive path in the network stack.
727 */
728 BUG_ON(athrs_fast_nat_recv != NULL);
729 RCU_INIT_POINTER(athrs_fast_nat_recv, sfe_cm_recv);
730
731 /*
732 * Hook the shortcut sync callback.
733 */
734 sfe_ipv4_register_sync_rule_callback(sfe_cm_sync_rule);
735 return 0;
736
737#ifdef CONFIG_NF_CONNTRACK_EVENTS
738exit7:
739#endif
740 nf_unregister_hooks(sfe_cm_ipv4_ops_post_routing, ARRAY_SIZE(sfe_cm_ipv4_ops_post_routing));
741
742exit6:
743 unregister_inetaddr_notifier(&sc->inet_notifier);
744 unregister_netdevice_notifier(&sc->dev_notifier);
745 kobject_put(sc->sys_sfe_cm);
746
747exit1:
748 return result;
749}
750
751/*
752 * sfe_cm_exit()
753 */
754static void __exit sfe_cm_exit(void)
755{
756 struct sfe_cm *sc = &__sc;
757
758 DEBUG_INFO("SFE CM exit\n");
759
760 /*
761 * Unregister our sync callback.
762 */
763 sfe_ipv4_register_sync_rule_callback(NULL);
764
765 /*
766 * Unregister our receive callback.
767 */
768 RCU_INIT_POINTER(athrs_fast_nat_recv, NULL);
769
770 /*
771 * Wait for all callbacks to complete.
772 */
773 rcu_barrier();
774
775 /*
776 * Destroy all connections.
777 */
778 sfe_ipv4_destroy_all_rules_for_dev(NULL);
779
780// XXX - this is where we need to unregister with any lower level offload services.
781
782#ifdef CONFIG_NF_CONNTRACK_EVENTS
783 nf_conntrack_unregister_notifier(&init_net, &sfe_cm_conntrack_notifier);
784
785#endif
786 nf_unregister_hooks(sfe_cm_ipv4_ops_post_routing, ARRAY_SIZE(sfe_cm_ipv4_ops_post_routing));
787
788 unregister_inetaddr_notifier(&sc->inet_notifier);
789 unregister_netdevice_notifier(&sc->dev_notifier);
790
791 kobject_put(sc->sys_sfe_cm);
792
793}
794
795module_init(sfe_cm_init)
796module_exit(sfe_cm_exit)
797
798MODULE_AUTHOR("Qualcomm Atheros Inc.");
799MODULE_DESCRIPTION("Shortcut Forwarding Engine - Connection Manager");
Matthew McClintocka3221942014-01-16 11:44:26 -0600800MODULE_LICENSE("Dual BSD/GPL");
Dave Hudsondcd08fb2013-11-22 09:25:16 -0600801