blob: 8539ca1ecf55f33aa2a3852e625bae3f972fab9c [file] [log] [blame]
Ben Menchaca84f36632014-02-28 20:57:38 +00001/*
2 **************************************************************************
Tushar Mathurcccbf282015-01-13 01:22:44 +05303 * Copyright (c) 2014,2015 The Linux Foundation. All rights reserved.
Ben Menchaca84f36632014-02-28 20:57:38 +00004 * Permission to use, copy, modify, and/or distribute this software for
5 * any purpose with or without fee is hereby granted, provided that the
6 * above copyright notice and this permission notice appear in all copies.
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
13 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 **************************************************************************
15 */
16
Murat Sezginb3731e82014-11-26 12:20:59 -080017#include <linux/version.h>
Ben Menchaca84f36632014-02-28 20:57:38 +000018#include <linux/types.h>
19#include <linux/ip.h>
20#include <linux/tcp.h>
21#include <linux/module.h>
22#include <linux/skbuff.h>
23#include <linux/icmp.h>
24#include <linux/sysctl.h>
25#include <linux/kthread.h>
Murat Sezgin1f381852014-11-20 09:51:07 -080026#include <linux/device.h>
Ben Menchaca84f36632014-02-28 20:57:38 +000027#include <linux/fs.h>
28#include <linux/pkt_sched.h>
29#include <linux/string.h>
30#include <net/ip6_route.h>
31#include <net/ip6_fib.h>
32#include <net/ipv6.h>
33#include <net/route.h>
Gareth Williams46f4b5f2014-06-01 23:35:23 +010034#include <net/ip_fib.h>
Ben Menchaca84f36632014-02-28 20:57:38 +000035#include <net/ip.h>
36#include <net/tcp.h>
37#include <asm/unaligned.h>
38#include <asm/uaccess.h> /* for put_user */
39#include <linux/inet.h>
40#include <linux/in6.h>
41#include <linux/in.h>
42#include <linux/udp.h>
43#include <linux/tcp.h>
44
45
46#include <linux/inetdevice.h>
Murat Sezginc1402562015-03-12 12:32:20 -070047#if defined(ECM_INTERFACE_TUNIPIP6_ENABLE) || defined(ECM_INTERFACE_SIT_ENABLE)
Ben Menchaca84f36632014-02-28 20:57:38 +000048#include <net/ipip.h>
Murat Sezginb3731e82014-11-26 12:20:59 -080049#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000050#include <net/ip6_tunnel.h>
Gareth Williams43fc0852014-05-26 19:10:00 +010051#include <net/addrconf.h>
Ben Menchaca84f36632014-02-28 20:57:38 +000052#include <linux/if_arp.h>
53#include <linux/netfilter_ipv4.h>
54#include <linux/netfilter_bridge.h>
55#include <linux/if_bridge.h>
56#include <net/arp.h>
57#include <net/netfilter/nf_conntrack.h>
58#include <net/netfilter/nf_conntrack_acct.h>
59#include <net/netfilter/nf_conntrack_helper.h>
60#include <net/netfilter/nf_conntrack_l4proto.h>
61#include <net/netfilter/nf_conntrack_l3proto.h>
62#include <net/netfilter/nf_conntrack_zones.h>
63#include <net/netfilter/nf_conntrack_core.h>
64#include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
65#include <net/netfilter/ipv4/nf_defrag_ipv4.h>
Gareth Williams141d2382014-11-25 11:35:19 -080066#ifdef ECM_INTERFACE_VLAN_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +000067#include <linux/../../net/8021q/vlan.h>
68#include <linux/if_vlan.h>
Gareth Williams141d2382014-11-25 11:35:19 -080069#endif
Murat Sezgina683edd2015-01-20 10:48:30 -080070#ifdef ECM_INTERFACE_PPP_ENABLE
71#include <linux/if_pppox.h>
72#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000073
74/*
75 * Debug output levels
76 * 0 = OFF
77 * 1 = ASSERTS / ERRORS
78 * 2 = 1 + WARN
79 * 3 = 2 + INFO
80 * 4 = 3 + TRACE
81 */
82#define DEBUG_LEVEL ECM_INTERFACE_DEBUG_LEVEL
83
84#include <nss_api_if.h>
85
86#include "ecm_types.h"
87#include "ecm_db_types.h"
88#include "ecm_tracker.h"
89#include "ecm_classifier.h"
90#include "ecm_front_end_types.h"
91#include "ecm_tracker_datagram.h"
92#include "ecm_tracker_udp.h"
93#include "ecm_tracker_tcp.h"
94#include "ecm_db.h"
95#include "ecm_interface.h"
96
Murat Sezgin49465a42014-11-24 15:37:48 -080097#ifdef ECM_FRONT_END_IPV6_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +000098/*
Gareth Williamsadf425f2014-05-26 19:29:02 +010099 * TODO: Remove once the Linux image and headers get propogated.
100 */
101struct net_device *ipv6_dev_find(struct net *net, struct in6_addr *addr, int strict);
Murat Sezgin49465a42014-11-24 15:37:48 -0800102#endif
Gareth Williamsadf425f2014-05-26 19:29:02 +0100103
104/*
Ben Menchaca84f36632014-02-28 20:57:38 +0000105 * Locking - concurrency control
106 */
107static spinlock_t ecm_interface_lock; /* Protect against SMP access between netfilter, events and private threaded function. */
108
109/*
Murat Sezgin1f381852014-11-20 09:51:07 -0800110 * System device linkage
Ben Menchaca84f36632014-02-28 20:57:38 +0000111 */
Murat Sezgin1f381852014-11-20 09:51:07 -0800112static struct device ecm_interface_dev; /* System device linkage */
Ben Menchaca84f36632014-02-28 20:57:38 +0000113
114/*
115 * General operational control
116 */
117static int ecm_interface_stopped = 0; /* When non-zero further traffic will not be processed */
118
119/*
120 * Management thread control
121 */
122static bool ecm_interface_terminate_pending = false; /* True when the user has signalled we should quit */
Ben Menchaca84f36632014-02-28 20:57:38 +0000123
124/*
Murat Sezginb3731e82014-11-26 12:20:59 -0800125 * ecm_interface_get_and_hold_dev_master()
126 * Returns the master device of a net device if any.
127 */
128struct net_device *ecm_interface_get_and_hold_dev_master(struct net_device *dev)
129{
130 struct net_device *master;
131#if (LINUX_VERSION_CODE > KERNEL_VERSION(3,6,0))
132 rcu_read_lock();
133 master = netdev_master_upper_dev_get_rcu(dev);
134 if (!master) {
135 rcu_read_unlock();
136 return NULL;
137 }
138 dev_hold(master);
139 rcu_read_unlock();
140#else
141 master = dev->master;
142 if (!master) {
143 return NULL;
144 }
145 dev_hold(master);
146#endif
147 return master;
148}
149EXPORT_SYMBOL(ecm_interface_get_and_hold_dev_master);
150
151/*
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100152 * ecm_interface_dev_find_by_local_addr_ipv4()
153 * Return a hold to the device for the given local IP address. Returns NULL on failure.
Gareth Williamsadf425f2014-05-26 19:29:02 +0100154 */
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100155static struct net_device *ecm_interface_dev_find_by_local_addr_ipv4(ip_addr_t addr)
Gareth Williamsadf425f2014-05-26 19:29:02 +0100156{
157 __be32 be_addr;
158 struct net_device *dev;
159
160 ECM_IP_ADDR_TO_NIN4_ADDR(be_addr, addr);
161 dev = ip_dev_find(&init_net, be_addr);
162 return dev;
163}
164
Murat Sezgin49465a42014-11-24 15:37:48 -0800165#ifdef ECM_FRONT_END_IPV6_ENABLE
Gareth Williamsadf425f2014-05-26 19:29:02 +0100166/*
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100167 * ecm_interface_dev_find_by_local_addr_ipv6()
168 * Return a hold to the device for the given local IP address. Returns NULL on failure.
Gareth Williamsadf425f2014-05-26 19:29:02 +0100169 */
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100170static struct net_device *ecm_interface_dev_find_by_local_addr_ipv6(ip_addr_t addr)
Gareth Williamsadf425f2014-05-26 19:29:02 +0100171{
172 struct in6_addr addr6;
173 struct net_device *dev;
174
175 ECM_IP_ADDR_TO_NIN6_ADDR(addr6, addr);
176 dev = (struct net_device *)ipv6_dev_find(&init_net, &addr6, 1);
177 return dev;
178}
Murat Sezgin49465a42014-11-24 15:37:48 -0800179#endif
Gareth Williamsadf425f2014-05-26 19:29:02 +0100180
181/*
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100182 * ecm_interface_dev_find_by_local_addr()
183 * Return the device on which the local address resides.
Gareth Williamsadf425f2014-05-26 19:29:02 +0100184 *
185 * Returns a hold to the device or NULL on failure.
186 */
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100187struct net_device *ecm_interface_dev_find_by_local_addr(ip_addr_t addr)
Gareth Williamsadf425f2014-05-26 19:29:02 +0100188{
189 char __attribute__((unused)) addr_str[40];
190
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100191 DEBUG_ECM_IP_ADDR_TO_STRING(addr_str, addr);
Gareth Williamsadf425f2014-05-26 19:29:02 +0100192 DEBUG_TRACE("Locate dev for: %s\n", addr_str);
193
194 if (ECM_IP_ADDR_IS_V4(addr)) {
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100195 return ecm_interface_dev_find_by_local_addr_ipv4(addr);
Gareth Williamsadf425f2014-05-26 19:29:02 +0100196 }
197
Murat Sezgin49465a42014-11-24 15:37:48 -0800198#ifdef ECM_FRONT_END_IPV6_ENABLE
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100199 return ecm_interface_dev_find_by_local_addr_ipv6(addr);
Murat Sezgin49465a42014-11-24 15:37:48 -0800200#else
201 return NULL;
202#endif
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100203}
204EXPORT_SYMBOL(ecm_interface_dev_find_by_local_addr);
205
206/*
207 * ecm_interface_dev_find_by_addr()
208 * Return the net device on which the given IP address resides. Returns NULL on faiure.
209 *
210 * NOTE: The device may be the device upon which has a default gateway to reach the address.
211 * from_local_addr is true when the device was found by a local address search.
212 */
213struct net_device *ecm_interface_dev_find_by_addr(ip_addr_t addr, bool *from_local_addr)
214{
215 char __attribute__((unused)) addr_str[40];
216 struct ecm_interface_route ecm_rt;
217 struct net_device *dev;
218 struct dst_entry *dst;
219
220 DEBUG_ECM_IP_ADDR_TO_STRING(addr_str, addr);
221
222 /*
223 * Is the address a local IP?
224 */
225 DEBUG_TRACE("find net device for address: %s\n", addr_str);
226 dev = ecm_interface_dev_find_by_local_addr(addr);
227 if (dev) {
228 *from_local_addr = true;
229 DEBUG_TRACE("addr: %s is local: %p (%s)\n", addr_str, dev, dev->name);
230 return dev;
231 }
232
233 DEBUG_TRACE("addr: %s is not local\n", addr_str);
234
235 /*
236 * Try a route to the address instead
237 * NOTE: This will locate a route entry in the route destination *cache*.
238 */
239 if (!ecm_interface_find_route_by_addr(addr, &ecm_rt)) {
240 DEBUG_WARN("addr: %s - no dev locatable\n", addr_str);
241 return NULL;
242 }
243
244 *from_local_addr = false;
245 dst = ecm_rt.dst;
246 dev = dst->dev;
247 dev_hold(dev);
248 ecm_interface_route_release(&ecm_rt);
249 DEBUG_TRACE("dest_addr: %s uses dev: %p(%s)\n", addr_str, dev, dev->name);
250 return dev;
Gareth Williamsadf425f2014-05-26 19:29:02 +0100251}
252EXPORT_SYMBOL(ecm_interface_dev_find_by_addr);
253
Murat Sezgin49465a42014-11-24 15:37:48 -0800254#ifdef ECM_FRONT_END_IPV6_ENABLE
Gareth Williamsadf425f2014-05-26 19:29:02 +0100255/*
Ben Menchaca84f36632014-02-28 20:57:38 +0000256 * ecm_interface_mac_addr_get_ipv6()
257 * Return mac for an IPv6 address
258 *
259 * GGG TODO Need to make sure this also works for local IP addresses too.
260 */
261static bool ecm_interface_mac_addr_get_ipv6(ip_addr_t addr, uint8_t *mac_addr, bool *on_link, ip_addr_t gw_addr)
262{
263 struct in6_addr daddr;
264 struct ecm_interface_route ecm_rt;
265 struct neighbour *neigh;
266 struct rt6_info *rt;
267 struct dst_entry *dst;
268
269 /*
270 * Get the MAC address that corresponds to IP address given.
271 * We look up the rt6_info entries and, from its neighbour structure, obtain the hardware address.
272 * This means we will also work if the neighbours are routers too.
273 */
274 ECM_IP_ADDR_TO_NIN6_ADDR(daddr, addr);
275 if (!ecm_interface_find_route_by_addr(addr, &ecm_rt)) {
Kiran Kumar C. S. K7d178222014-06-27 18:47:29 +0530276 *on_link = false;
Ben Menchaca84f36632014-02-28 20:57:38 +0000277 return false;
278 }
279 DEBUG_ASSERT(!ecm_rt.v4_route, "Did not locate a v6 route!\n");
280
281 /*
282 * Is this destination on link or off-link via a gateway?
283 */
284 rt = ecm_rt.rt.rtv6;
285 if (!ECM_IP_ADDR_MATCH(rt->rt6i_dst.addr.in6_u.u6_addr32, rt->rt6i_gateway.in6_u.u6_addr32) || (rt->rt6i_flags & RTF_GATEWAY)) {
286 *on_link = false;
287 ECM_NIN6_ADDR_TO_IP_ADDR(gw_addr, rt->rt6i_gateway)
288 } else {
289 *on_link = true;
290 }
291
292 rcu_read_lock();
293 dst = ecm_rt.dst;
Murat Sezgine9b84582015-01-27 17:34:14 -0800294#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3,6,0))
Ben Menchaca84f36632014-02-28 20:57:38 +0000295 neigh = dst_get_neighbour_noref(dst);
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700296 if (neigh) {
297 neigh_hold(neigh);
Murat Sezgine9b84582015-01-27 17:34:14 -0800298 }
299#else
300 neigh = dst_neigh_lookup(dst, &daddr);
301#endif
302 if (!neigh) {
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700303 neigh = neigh_lookup(&nd_tbl, &daddr, dst->dev);
304 }
Murat Sezgine9b84582015-01-27 17:34:14 -0800305
Ben Menchaca84f36632014-02-28 20:57:38 +0000306 if (!neigh) {
307 rcu_read_unlock();
308 ecm_interface_route_release(&ecm_rt);
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700309 DEBUG_WARN("No neigh reference\n");
Ben Menchaca84f36632014-02-28 20:57:38 +0000310 return false;
311 }
312 if (!(neigh->nud_state & NUD_VALID)) {
313 rcu_read_unlock();
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700314 neigh_release(neigh);
Ben Menchaca84f36632014-02-28 20:57:38 +0000315 ecm_interface_route_release(&ecm_rt);
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700316 DEBUG_WARN("NUD invalid\n");
Ben Menchaca84f36632014-02-28 20:57:38 +0000317 return false;
318 }
319 if (!neigh->dev) {
320 rcu_read_unlock();
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700321 neigh_release(neigh);
Ben Menchaca84f36632014-02-28 20:57:38 +0000322 ecm_interface_route_release(&ecm_rt);
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700323 DEBUG_WARN("Neigh dev invalid\n");
Ben Menchaca84f36632014-02-28 20:57:38 +0000324 return false;
325 }
326
327 /*
328 * If neigh->dev is a loopback then addr is a local address in which case we take the MAC from given device
329 */
330 if (neigh->dev->flags & IFF_LOOPBACK) {
331 // GGG TODO Create an equivalent logic to that for ipv4, maybe need to create an ip6_dev_find()?
332 DEBUG_TRACE("local address " ECM_IP_ADDR_OCTAL_FMT " (found loopback)\n", ECM_IP_ADDR_TO_OCTAL(addr));
333 memset(mac_addr, 0, 6);
334 } else {
335 memcpy(mac_addr, neigh->ha, 6);
336 }
337 rcu_read_unlock();
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700338 neigh_release(neigh);
Ben Menchaca84f36632014-02-28 20:57:38 +0000339 ecm_interface_route_release(&ecm_rt);
340
341 DEBUG_TRACE(ECM_IP_ADDR_OCTAL_FMT " maps to %pM\n", ECM_IP_ADDR_TO_OCTAL(addr), mac_addr);
342 return true;
343}
Murat Sezgin49465a42014-11-24 15:37:48 -0800344#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000345
346/*
347 * ecm_interface_mac_addr_get_ipv4()
348 * Return mac for an IPv4 address
349 */
350static bool ecm_interface_mac_addr_get_ipv4(ip_addr_t addr, uint8_t *mac_addr, bool *on_link, ip_addr_t gw_addr)
351{
352 struct neighbour *neigh;
353 struct ecm_interface_route ecm_rt;
354 struct rtable *rt;
355 struct dst_entry *dst;
356 __be32 ipv4_addr;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530357
Ben Menchaca84f36632014-02-28 20:57:38 +0000358 /*
359 * Get the MAC address that corresponds to IP address given.
360 * We look up the rtable entries and, from its neighbour structure, obtain the hardware address.
361 * This means we will also work if the neighbours are routers too.
362 * We also locate the MAC if the address is a local host address.
363 */
364 ECM_IP_ADDR_TO_NIN4_ADDR(ipv4_addr, addr);
365 if (!ecm_interface_find_route_by_addr(addr, &ecm_rt)) {
Kiran Kumar C. S. K7d178222014-06-27 18:47:29 +0530366 *on_link = false;
Ben Menchaca84f36632014-02-28 20:57:38 +0000367 return false;
368 }
369 DEBUG_ASSERT(ecm_rt.v4_route, "Did not locate a v4 route!\n");
Murat Sezginb3731e82014-11-26 12:20:59 -0800370 DEBUG_TRACE("Found route\n");
Ben Menchaca84f36632014-02-28 20:57:38 +0000371
372 /*
373 * Is this destination on link or off-link via a gateway?
374 */
375 rt = ecm_rt.rt.rtv4;
Murat Sezginb3731e82014-11-26 12:20:59 -0800376#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3,6,0))
Ben Menchaca84f36632014-02-28 20:57:38 +0000377 if ((rt->rt_dst != rt->rt_gateway) || (rt->rt_flags & RTF_GATEWAY)) {
Murat Sezginb3731e82014-11-26 12:20:59 -0800378#else
379 if (rt->rt_uses_gateway || (rt->rt_flags & RTF_GATEWAY)) {
380#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000381 *on_link = false;
382 ECM_NIN4_ADDR_TO_IP_ADDR(gw_addr, rt->rt_gateway)
383 } else {
384 *on_link = true;
385 }
386
387 /*
388 * Get the neighbour entry for the address
389 */
390 rcu_read_lock();
391 dst = ecm_rt.dst;
Murat Sezginb3731e82014-11-26 12:20:59 -0800392#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3,6,0))
Ben Menchaca84f36632014-02-28 20:57:38 +0000393 neigh = dst_get_neighbour_noref(dst);
394 if (neigh) {
395 neigh_hold(neigh);
Murat Sezginb3731e82014-11-26 12:20:59 -0800396 }
397#else
398 neigh = dst_neigh_lookup(dst, &ipv4_addr);
399#endif
400 if (!neigh) {
Ben Menchaca84f36632014-02-28 20:57:38 +0000401 neigh = neigh_lookup(&arp_tbl, &ipv4_addr, dst->dev);
402 }
403 if (!neigh) {
404 rcu_read_unlock();
405 ecm_interface_route_release(&ecm_rt);
Murat Sezginb3731e82014-11-26 12:20:59 -0800406 DEBUG_WARN("no neigh\n");
Ben Menchaca84f36632014-02-28 20:57:38 +0000407 return false;
408 }
409 if (!(neigh->nud_state & NUD_VALID)) {
410 rcu_read_unlock();
411 neigh_release(neigh);
412 ecm_interface_route_release(&ecm_rt);
Murat Sezginb3731e82014-11-26 12:20:59 -0800413 DEBUG_WARN("neigh nud state is not valid\n");
Ben Menchaca84f36632014-02-28 20:57:38 +0000414 return false;
415 }
416 if (!neigh->dev) {
417 rcu_read_unlock();
418 neigh_release(neigh);
419 ecm_interface_route_release(&ecm_rt);
Murat Sezginb3731e82014-11-26 12:20:59 -0800420 DEBUG_WARN("neigh has no device\n");
Ben Menchaca84f36632014-02-28 20:57:38 +0000421 return false;
422 }
423
424 /*
425 * If the device is loopback this will be because the address is a local address
426 * In this case locate the device that has this local address and get its mac.
427 */
428 if (neigh->dev->type == ARPHRD_LOOPBACK) {
429 struct net_device *dev;
430
431 DEBUG_TRACE("%pI4 finds loopback device, dev: %p (%s)\n", &ipv4_addr, neigh->dev, neigh->dev->name);
432 rcu_read_unlock();
433 neigh_release(neigh);
434 ecm_interface_route_release(&ecm_rt);
435
436 /*
437 * Lookup the device that has this IP address assigned
438 */
439 dev = ip_dev_find(&init_net, ipv4_addr);
440 if (!dev) {
441 DEBUG_WARN("Unable to locate dev for: %pI4\n", &ipv4_addr);
442 return false;
443 }
444 memcpy(mac_addr, dev->dev_addr, (size_t)dev->addr_len);
445 DEBUG_TRACE("is local addr: %pI4, mac: %pM, dev ifindex: %d, dev: %p (%s), dev_type: %d\n",
446 &ipv4_addr, mac_addr, dev->ifindex, dev, dev->name, dev->type);
447 dev_put(dev);
448 return true;
449 }
450
451 if (!(neigh->dev->flags & IFF_NOARP)) {
452 memcpy(mac_addr, neigh->ha, (size_t)neigh->dev->addr_len);
453 } else {
454 DEBUG_TRACE("non-arp device: %p (%s, type: %d) to reach %pI4\n", neigh->dev, neigh->dev->name, neigh->dev->type, &ipv4_addr);
455 memset(mac_addr, 0, 6);
456 }
457 DEBUG_TRACE("addr: %pI4, mac: %pM, iif: %d, neigh dev ifindex: %d, dev: %p (%s), dev_type: %d\n",
458 &ipv4_addr, mac_addr, rt->rt_iif, neigh->dev->ifindex, neigh->dev, neigh->dev->name, neigh->dev->type);
459
460 rcu_read_unlock();
461 neigh_release(neigh);
462 ecm_interface_route_release(&ecm_rt);
463 return true;
464}
465
466/*
467 * ecm_interface_mac_addr_get()
468 * Return the mac address for the given IP address. Returns false on failure.
469 *
470 * dev is the device on which the addr was sent/received. If addr is a local address then mac shall be the given dev mac.
471 *
472 * GGG TODO Make this function work for IPv6!!!!!!!!!!!!!!
473 */
474bool ecm_interface_mac_addr_get(ip_addr_t addr, uint8_t *mac_addr, bool *on_link, ip_addr_t gw_addr)
475{
476 if (ECM_IP_ADDR_IS_V4(addr)) {
477 return ecm_interface_mac_addr_get_ipv4(addr, mac_addr, on_link, gw_addr);
478 }
479
Murat Sezgin49465a42014-11-24 15:37:48 -0800480#ifdef ECM_FRONT_END_IPV6_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000481 return ecm_interface_mac_addr_get_ipv6(addr, mac_addr, on_link, gw_addr);
Murat Sezgin49465a42014-11-24 15:37:48 -0800482#else
483 return false;
484#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000485}
486EXPORT_SYMBOL(ecm_interface_mac_addr_get);
487
488/*
489 * ecm_interface_addr_find_route_by_addr_ipv4()
490 * Return the route for the given IP address. Returns NULL on failure.
491 */
492static bool ecm_interface_find_route_by_addr_ipv4(ip_addr_t addr, struct ecm_interface_route *ecm_rt)
493{
494 __be32 be_addr;
495
496 /*
497 * Get a route to the given IP address, this will allow us to also find the interface
498 * it is using to communicate with that IP address.
499 */
500 ECM_IP_ADDR_TO_NIN4_ADDR(be_addr, addr);
501 ecm_rt->rt.rtv4 = ip_route_output(&init_net, be_addr, 0, 0, 0);
502 if (IS_ERR(ecm_rt->rt.rtv4)) {
503 DEBUG_TRACE("No output route to: %pI4n\n", &be_addr);
504 return false;
505 }
506 DEBUG_TRACE("Output route to: %pI4n is: %p\n", &be_addr, ecm_rt->rt.rtv4);
507 ecm_rt->dst = (struct dst_entry *)ecm_rt->rt.rtv4;
508 ecm_rt->v4_route = true;
509 return true;
510}
511
Murat Sezgin49465a42014-11-24 15:37:48 -0800512#ifdef ECM_FRONT_END_IPV6_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000513/*
514 * ecm_interface_addr_find_route_by_addr_ipv6()
515 * Return the route for the given IP address. Returns NULL on failure.
516 */
517static bool ecm_interface_find_route_by_addr_ipv6(ip_addr_t addr, struct ecm_interface_route *ecm_rt)
518{
519 struct in6_addr naddr;
520
521 ECM_IP_ADDR_TO_NIN6_ADDR(naddr, addr);
522
523 /*
524 * Get a route to the given IP address, this will allow us to also find the interface
525 * it is using to communicate with that IP address.
526 */
527 ecm_rt->rt.rtv6 = rt6_lookup(&init_net, &naddr, NULL, 0, 0);
528 if (!ecm_rt->rt.rtv6) {
529 DEBUG_TRACE("No output route to: " ECM_IP_ADDR_OCTAL_FMT "\n", ECM_IP_ADDR_TO_OCTAL(addr));
530 return NULL;
531 }
532 DEBUG_TRACE("Output route to: " ECM_IP_ADDR_OCTAL_FMT " is: %p\n", ECM_IP_ADDR_TO_OCTAL(addr), ecm_rt->rt.rtv6);
533 ecm_rt->dst = (struct dst_entry *)ecm_rt->rt.rtv6;
534 ecm_rt->v4_route = false;
535 return true;
536}
Murat Sezgin49465a42014-11-24 15:37:48 -0800537#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000538
539/*
540 * ecm_interface_addr_find_route_by_addr()
541 * Return the route (in the given parameter) for the given IP address. Returns false on failure.
542 *
543 * Route is the device on which the addr is reachable, which may be loopback for local addresses.
544 *
545 * Returns true if the route was able to be located. The route must be released using ecm_interface_route_release().
546 */
547bool ecm_interface_find_route_by_addr(ip_addr_t addr, struct ecm_interface_route *ecm_rt)
548{
549 char __attribute__((unused)) addr_str[40];
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530550
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100551 DEBUG_ECM_IP_ADDR_TO_STRING(addr_str, addr);
Ben Menchaca84f36632014-02-28 20:57:38 +0000552 DEBUG_TRACE("Locate route to: %s\n", addr_str);
553
554 if (ECM_IP_ADDR_IS_V4(addr)) {
555 return ecm_interface_find_route_by_addr_ipv4(addr, ecm_rt);
556 }
557
Murat Sezgin49465a42014-11-24 15:37:48 -0800558#ifdef ECM_FRONT_END_IPV6_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000559 return ecm_interface_find_route_by_addr_ipv6(addr, ecm_rt);
Murat Sezgin49465a42014-11-24 15:37:48 -0800560#else
561 return false;
562#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000563}
564EXPORT_SYMBOL(ecm_interface_find_route_by_addr);
565
566/*
567 * ecm_interface_route_release()
568 * Release an ecm route
569 */
570void ecm_interface_route_release(struct ecm_interface_route *rt)
571{
572 dst_release(rt->dst);
573}
574EXPORT_SYMBOL(ecm_interface_route_release);
575
Xiaoping Fan80e406b2015-01-29 16:15:31 -0800576#ifdef ECM_INTERFACE_PPP_ENABLE
577/*
578 * ecm_interface_skip_l2tp_pptp()
579 * skip l2tp/pptp tunnel encapsulated traffic
580 *
581 * ECM does not handle L2TP or PPTP encapsulated packets,
582 * this function detects packets of that type so they can be skipped over to improve their throughput.
583 */
584bool ecm_interface_skip_l2tp_pptp(struct sk_buff *skb, const struct net_device *out)
585{
586 struct ppp_channel *ppp_chan[1];
587 int px_proto;
588
589 /*
590 * skip first pass of l2tp/pptp tunnel encapsulated traffic
591 */
592 if (out->type == ARPHRD_PPP) {
593 if (ppp_hold_channels((struct net_device *)out, ppp_chan, 1) == 1) {
594 px_proto = ppp_channel_get_protocol(ppp_chan[0]);
595 ppp_release_channels(ppp_chan, 1);
596 return ((px_proto == PX_PROTO_OL2TP) || (px_proto == PX_PROTO_PPTP));
597 }
598 }
599
600 /*
601 * skip second pass of l2tp tunnel encapsulated traffic
602 */
603 if (!skb->sk) {
604 return false;
605 }
606
607 if (skb->sk->sk_protocol != IPPROTO_UDP) {
608 return false;
609 }
610
611 if (unlikely(udp_sk(skb->sk)->encap_type == UDP_ENCAP_L2TPINUDP)) {
612 return true;
613 }
614
615 return false;
616}
617#endif
618
Gareth Williams141d2382014-11-25 11:35:19 -0800619#ifdef ECM_INTERFACE_VLAN_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000620/*
Ben Menchaca84f36632014-02-28 20:57:38 +0000621 * ecm_interface_vlan_interface_establish()
622 * Returns a reference to a iface of the VLAN type, possibly creating one if necessary.
623 * Returns NULL on failure or a reference to interface.
624 */
625static struct ecm_db_iface_instance *ecm_interface_vlan_interface_establish(struct ecm_db_interface_info_vlan *type_info,
626 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
627{
628 struct ecm_db_iface_instance *nii;
629 struct ecm_db_iface_instance *ii;
630
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530631 DEBUG_INFO("Establish VLAN iface: %s with address: %pM, vlan tag: %u, vlan_tpid: %x MTU: %d, if num: %d, nss if id: %d\n",
632 dev_name, type_info->address, type_info->vlan_tag, type_info->vlan_tpid, mtu, dev_interface_num, nss_interface_num);
Ben Menchaca84f36632014-02-28 20:57:38 +0000633
634 /*
635 * Locate the iface
636 */
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530637 ii = ecm_db_iface_find_and_ref_vlan(type_info->address, type_info->vlan_tag, type_info->vlan_tpid);
Ben Menchaca84f36632014-02-28 20:57:38 +0000638 if (ii) {
639 DEBUG_TRACE("%p: iface established\n", ii);
640 return ii;
641 }
642
643 /*
644 * No iface - create one
645 */
646 nii = ecm_db_iface_alloc();
647 if (!nii) {
648 DEBUG_WARN("Failed to establish iface\n");
649 return NULL;
650 }
651
652 /*
653 * Add iface into the database, atomically to avoid races creating the same thing
654 */
655 spin_lock_bh(&ecm_interface_lock);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530656 ii = ecm_db_iface_find_and_ref_vlan(type_info->address, type_info->vlan_tag, type_info->vlan_tpid);
Ben Menchaca84f36632014-02-28 20:57:38 +0000657 if (ii) {
658 spin_unlock_bh(&ecm_interface_lock);
659 ecm_db_iface_deref(nii);
660 return ii;
661 }
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530662 ecm_db_iface_add_vlan(nii, type_info->address, type_info->vlan_tag, type_info->vlan_tpid, dev_name,
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500663 mtu, dev_interface_num, nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000664 spin_unlock_bh(&ecm_interface_lock);
665
666 DEBUG_TRACE("%p: vlan iface established\n", nii);
667 return nii;
668}
Gareth Williams141d2382014-11-25 11:35:19 -0800669#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000670
671/*
672 * ecm_interface_bridge_interface_establish()
673 * Returns a reference to a iface of the BRIDGE type, possibly creating one if necessary.
674 * Returns NULL on failure or a reference to interface.
675 */
676static struct ecm_db_iface_instance *ecm_interface_bridge_interface_establish(struct ecm_db_interface_info_bridge *type_info,
677 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
678{
679 struct ecm_db_iface_instance *nii;
680 struct ecm_db_iface_instance *ii;
681
682 DEBUG_INFO("Establish BRIDGE iface: %s with address: %pM, MTU: %d, if num: %d, nss if id: %d\n",
683 dev_name, type_info->address, mtu, dev_interface_num, nss_interface_num);
684
685 /*
686 * Locate the iface
687 */
688 ii = ecm_db_iface_find_and_ref_bridge(type_info->address);
689 if (ii) {
690 DEBUG_TRACE("%p: iface established\n", ii);
691 return ii;
692 }
693
694 /*
695 * No iface - create one
696 */
697 nii = ecm_db_iface_alloc();
698 if (!nii) {
699 DEBUG_WARN("Failed to establish iface\n");
700 return NULL;
701 }
702
703 /*
704 * Add iface into the database, atomically to avoid races creating the same thing
705 */
706 spin_lock_bh(&ecm_interface_lock);
707 ii = ecm_db_iface_find_and_ref_bridge(type_info->address);
708 if (ii) {
709 spin_unlock_bh(&ecm_interface_lock);
710 ecm_db_iface_deref(nii);
711 return ii;
712 }
713 ecm_db_iface_add_bridge(nii, type_info->address, dev_name,
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500714 mtu, dev_interface_num, nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000715 spin_unlock_bh(&ecm_interface_lock);
716
717 DEBUG_TRACE("%p: bridge iface established\n", nii);
718 return nii;
719}
720
Murat Sezgin910c9662015-03-11 16:15:06 -0700721#ifdef ECM_INTERFACE_BOND_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000722/*
723 * ecm_interface_lag_interface_establish()
724 * Returns a reference to a iface of the LAG type, possibly creating one if necessary.
725 * Returns NULL on failure or a reference to interface.
726 */
727static struct ecm_db_iface_instance *ecm_interface_lag_interface_establish(struct ecm_db_interface_info_lag *type_info,
728 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
729{
730 struct ecm_db_iface_instance *nii;
731 struct ecm_db_iface_instance *ii;
732
733 DEBUG_INFO("Establish LAG iface: %s with address: %pM, MTU: %d, if num: %d, nss if id: %d\n",
734 dev_name, type_info->address, mtu, dev_interface_num, nss_interface_num);
735
736 /*
737 * Locate the iface
738 */
739 ii = ecm_db_iface_find_and_ref_lag(type_info->address);
740 if (ii) {
741 DEBUG_TRACE("%p: iface established\n", ii);
742 return ii;
743 }
744
745 /*
746 * No iface - create one
747 */
748 nii = ecm_db_iface_alloc();
749 if (!nii) {
750 DEBUG_WARN("Failed to establish iface\n");
751 return NULL;
752 }
753
754 /*
755 * Add iface into the database, atomically to avoid races creating the same thing
756 */
757 spin_lock_bh(&ecm_interface_lock);
758 ii = ecm_db_iface_find_and_ref_lag(type_info->address);
759 if (ii) {
760 spin_unlock_bh(&ecm_interface_lock);
761 ecm_db_iface_deref(nii);
762 return ii;
763 }
764 ecm_db_iface_add_lag(nii, type_info->address, dev_name,
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500765 mtu, dev_interface_num, nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000766 spin_unlock_bh(&ecm_interface_lock);
767
768 DEBUG_TRACE("%p: lag iface established\n", nii);
769 return nii;
770}
Murat Sezgin910c9662015-03-11 16:15:06 -0700771#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000772
773/*
774 * ecm_interface_ethernet_interface_establish()
775 * Returns a reference to a iface of the ETHERNET type, possibly creating one if necessary.
776 * Returns NULL on failure or a reference to interface.
777 */
778static struct ecm_db_iface_instance *ecm_interface_ethernet_interface_establish(struct ecm_db_interface_info_ethernet *type_info,
779 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
780{
781 struct ecm_db_iface_instance *nii;
782 struct ecm_db_iface_instance *ii;
783
784 DEBUG_INFO("Establish ETHERNET iface: %s with address: %pM, MTU: %d, if num: %d, nss if id: %d\n",
785 dev_name, type_info->address, mtu, dev_interface_num, nss_interface_num);
786
787 /*
788 * Locate the iface
789 */
Tushar Mathur4ab0bf92014-06-10 20:37:07 +0530790 ii = ecm_db_iface_ifidx_find_and_ref_ethernet(type_info->address, dev_interface_num);
791
Ben Menchaca84f36632014-02-28 20:57:38 +0000792 if (ii) {
793 DEBUG_TRACE("%p: iface established\n", ii);
794 return ii;
795 }
796
797 /*
798 * No iface - create one
799 */
800 nii = ecm_db_iface_alloc();
801 if (!nii) {
802 DEBUG_WARN("Failed to establish iface\n");
803 return NULL;
804 }
805
806 /*
807 * Add iface into the database, atomically to avoid races creating the same thing
808 */
809 spin_lock_bh(&ecm_interface_lock);
Tushar Mathur4ab0bf92014-06-10 20:37:07 +0530810 ii = ecm_db_iface_ifidx_find_and_ref_ethernet(type_info->address, dev_interface_num);
Ben Menchaca84f36632014-02-28 20:57:38 +0000811 if (ii) {
812 spin_unlock_bh(&ecm_interface_lock);
813 ecm_db_iface_deref(nii);
814 return ii;
815 }
816 ecm_db_iface_add_ethernet(nii, type_info->address, dev_name,
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500817 mtu, dev_interface_num, nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000818 spin_unlock_bh(&ecm_interface_lock);
819
820 DEBUG_TRACE("%p: ethernet iface established\n", nii);
821 return nii;
822}
823
Gareth Williamsdbb2bfd2014-11-20 16:42:09 -0800824#ifdef ECM_INTERFACE_PPP_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000825/*
826 * ecm_interface_pppoe_interface_establish()
827 * Returns a reference to a iface of the PPPoE type, possibly creating one if necessary.
828 * Returns NULL on failure or a reference to interface.
829 */
830static struct ecm_db_iface_instance *ecm_interface_pppoe_interface_establish(struct ecm_db_interface_info_pppoe *type_info,
831 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
832{
833 struct ecm_db_iface_instance *nii;
834 struct ecm_db_iface_instance *ii;
835
836 DEBUG_INFO("Establish PPPoE iface: %s with session id: %u, remote mac: %pM, MTU: %d, if num: %d, nss if id: %d\n",
837 dev_name, type_info->pppoe_session_id, type_info->remote_mac, mtu, dev_interface_num, nss_interface_num);
838
839 /*
840 * Locate the iface
841 */
842 ii = ecm_db_iface_find_and_ref_pppoe(type_info->pppoe_session_id, type_info->remote_mac);
843 if (ii) {
844 DEBUG_TRACE("%p: iface established\n", ii);
845 return ii;
846 }
847
848 /*
849 * No iface - create one
850 */
851 nii = ecm_db_iface_alloc();
852 if (!nii) {
853 DEBUG_WARN("Failed to establish iface\n");
854 return NULL;
855 }
856
857 /*
858 * Add iface into the database, atomically to avoid races creating the same thing
859 */
860 spin_lock_bh(&ecm_interface_lock);
861 ii = ecm_db_iface_find_and_ref_pppoe(type_info->pppoe_session_id, type_info->remote_mac);
862 if (ii) {
863 spin_unlock_bh(&ecm_interface_lock);
864 ecm_db_iface_deref(nii);
865 return ii;
866 }
867 ecm_db_iface_add_pppoe(nii, type_info->pppoe_session_id, type_info->remote_mac, dev_name,
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500868 mtu, dev_interface_num, nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000869 spin_unlock_bh(&ecm_interface_lock);
870
871 DEBUG_TRACE("%p: pppoe iface established\n", nii);
872 return nii;
873}
Gareth Williamsc5b9d712014-05-09 20:40:07 +0100874#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000875
876/*
877 * ecm_interface_unknown_interface_establish()
878 * Returns a reference to a iface of the UNKNOWN type, possibly creating one if necessary.
879 * Returns NULL on failure or a reference to interface.
880 */
881static struct ecm_db_iface_instance *ecm_interface_unknown_interface_establish(struct ecm_db_interface_info_unknown *type_info,
882 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
883{
884 struct ecm_db_iface_instance *nii;
885 struct ecm_db_iface_instance *ii;
886
887 DEBUG_INFO("Establish UNKNOWN iface: %s with os_specific_ident: %u, MTU: %d, if num: %d, nss if id: %d\n",
888 dev_name, type_info->os_specific_ident, mtu, dev_interface_num, nss_interface_num);
889
890 /*
891 * Locate the iface
892 */
893 ii = ecm_db_iface_find_and_ref_unknown(type_info->os_specific_ident);
894 if (ii) {
895 DEBUG_TRACE("%p: iface established\n", ii);
896 return ii;
897 }
898
899 /*
900 * No iface - create one
901 */
902 nii = ecm_db_iface_alloc();
903 if (!nii) {
904 DEBUG_WARN("Failed to establish iface\n");
905 return NULL;
906 }
907
908 /*
909 * Add iface into the database, atomically to avoid races creating the same thing
910 */
911 spin_lock_bh(&ecm_interface_lock);
912 ii = ecm_db_iface_find_and_ref_unknown(type_info->os_specific_ident);
913 if (ii) {
914 spin_unlock_bh(&ecm_interface_lock);
915 ecm_db_iface_deref(nii);
916 return ii;
917 }
918 ecm_db_iface_add_unknown(nii, type_info->os_specific_ident, dev_name,
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500919 mtu, dev_interface_num, nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000920 spin_unlock_bh(&ecm_interface_lock);
921
922 DEBUG_TRACE("%p: unknown iface established\n", nii);
923 return nii;
924}
925
926/*
927 * ecm_interface_loopback_interface_establish()
928 * Returns a reference to a iface of the LOOPBACK type, possibly creating one if necessary.
929 * Returns NULL on failure or a reference to interface.
930 */
931static struct ecm_db_iface_instance *ecm_interface_loopback_interface_establish(struct ecm_db_interface_info_loopback *type_info,
932 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
933{
934 struct ecm_db_iface_instance *nii;
935 struct ecm_db_iface_instance *ii;
936
937 DEBUG_INFO("Establish LOOPBACK iface: %s with os_specific_ident: %u, MTU: %d, if num: %d, nss if id: %d\n",
938 dev_name, type_info->os_specific_ident, mtu, dev_interface_num, nss_interface_num);
939
940 /*
941 * Locate the iface
942 */
943 ii = ecm_db_iface_find_and_ref_loopback(type_info->os_specific_ident);
944 if (ii) {
945 DEBUG_TRACE("%p: iface established\n", ii);
946 return ii;
947 }
948
949 /*
950 * No iface - create one
951 */
952 nii = ecm_db_iface_alloc();
953 if (!nii) {
954 DEBUG_WARN("Failed to establish iface\n");
955 return NULL;
956 }
957
958 /*
959 * Add iface into the database, atomically to avoid races creating the same thing
960 */
961 spin_lock_bh(&ecm_interface_lock);
962 ii = ecm_db_iface_find_and_ref_loopback(type_info->os_specific_ident);
963 if (ii) {
964 spin_unlock_bh(&ecm_interface_lock);
965 ecm_db_iface_deref(nii);
966 return ii;
967 }
968 ecm_db_iface_add_loopback(nii, type_info->os_specific_ident, dev_name,
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500969 mtu, dev_interface_num, nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000970 spin_unlock_bh(&ecm_interface_lock);
971
972 DEBUG_TRACE("%p: loopback iface established\n", nii);
973 return nii;
974}
975
976/*
977 * ecm_interface_ipsec_tunnel_interface_establish()
978 * Returns a reference to a iface of the IPSEC_TUNNEL type, possibly creating one if necessary.
979 * Returns NULL on failure or a reference to interface.
980 *
981 * NOTE: GGG TODO THIS NEEDS TO TAKE A PROPER APPROACH TO IPSEC TUNNELS USING ENDPOINT ADDRESSING AS THE TYPE INFO KEYS
982 */
983static struct ecm_db_iface_instance *ecm_interface_ipsec_tunnel_interface_establish(struct ecm_db_interface_info_ipsec_tunnel *type_info,
984 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
985{
986 struct ecm_db_iface_instance *nii;
987 struct ecm_db_iface_instance *ii;
988
989 DEBUG_INFO("Establish IPSEC_TUNNEL iface: %s with os_specific_ident: %u, MTU: %d, if num: %d, nss if id: %d\n",
990 dev_name, type_info->os_specific_ident, mtu, dev_interface_num, nss_interface_num);
991
992 /*
993 * Locate the iface
994 */
995 ii = ecm_db_iface_find_and_ref_ipsec_tunnel(type_info->os_specific_ident);
996 if (ii) {
997 DEBUG_TRACE("%p: iface established\n", ii);
998 return ii;
999 }
1000
1001 /*
1002 * No iface - create one
1003 */
1004 nii = ecm_db_iface_alloc();
1005 if (!nii) {
1006 DEBUG_WARN("Failed to establish iface\n");
1007 return NULL;
1008 }
1009
1010 /*
1011 * Add iface into the database, atomically to avoid races creating the same thing
1012 */
1013 spin_lock_bh(&ecm_interface_lock);
1014 ii = ecm_db_iface_find_and_ref_ipsec_tunnel(type_info->os_specific_ident);
1015 if (ii) {
1016 spin_unlock_bh(&ecm_interface_lock);
1017 ecm_db_iface_deref(nii);
1018 return ii;
1019 }
1020 ecm_db_iface_add_ipsec_tunnel(nii, type_info->os_specific_ident, dev_name,
Nicolas Costaf46c33b2014-05-15 10:02:00 -05001021 mtu, dev_interface_num, nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +00001022 spin_unlock_bh(&ecm_interface_lock);
1023
1024 DEBUG_TRACE("%p: ipsec_tunnel iface established\n", nii);
1025 return nii;
1026}
1027
Murat Sezginb3731e82014-11-26 12:20:59 -08001028#ifdef ECM_INTERFACE_SIT_ENABLE
Murat Sezginbde55f92015-03-11 16:44:11 -07001029#ifdef CONFIG_IPV6_SIT_6RD
Ben Menchaca84f36632014-02-28 20:57:38 +00001030/*
1031 * ecm_interface_sit_interface_establish()
1032 * Returns a reference to a iface of the SIT type, possibly creating one if necessary.
1033 * Returns NULL on failure or a reference to interface.
1034 */
1035static struct ecm_db_iface_instance *ecm_interface_sit_interface_establish(struct ecm_db_interface_info_sit *type_info,
1036 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
1037{
1038 struct ecm_db_iface_instance *nii;
1039 struct ecm_db_iface_instance *ii;
1040
1041 DEBUG_INFO("Establish SIT iface: %s with saddr: " ECM_IP_ADDR_OCTAL_FMT ", daddr: " ECM_IP_ADDR_OCTAL_FMT ", MTU: %d, if num: %d, nss if id: %d\n",
1042 dev_name, ECM_IP_ADDR_TO_OCTAL(type_info->saddr), ECM_IP_ADDR_TO_OCTAL(type_info->daddr), mtu, dev_interface_num, nss_interface_num);
1043
1044 /*
1045 * Locate the iface
1046 */
1047 ii = ecm_db_iface_find_and_ref_sit(type_info->saddr, type_info->daddr);
1048 if (ii) {
1049 DEBUG_TRACE("%p: iface established\n", ii);
1050 return ii;
1051 }
1052
1053 /*
1054 * No iface - create one
1055 */
1056 nii = ecm_db_iface_alloc();
1057 if (!nii) {
1058 DEBUG_WARN("Failed to establish iface\n");
1059 return NULL;
1060 }
1061
1062 /*
1063 * Add iface into the database, atomically to avoid races creating the same thing
1064 */
1065 spin_lock_bh(&ecm_interface_lock);
1066 ii = ecm_db_iface_find_and_ref_sit(type_info->saddr, type_info->daddr);
1067 if (ii) {
1068 spin_unlock_bh(&ecm_interface_lock);
1069 ecm_db_iface_deref(nii);
1070 return ii;
1071 }
1072 ecm_db_iface_add_sit(nii, type_info, dev_name, mtu, dev_interface_num,
Nicolas Costaf46c33b2014-05-15 10:02:00 -05001073 nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +00001074 spin_unlock_bh(&ecm_interface_lock);
1075
1076 DEBUG_TRACE("%p: sit iface established\n", nii);
1077 return nii;
1078}
Murat Sezgincc6eedf2014-05-09 23:59:19 -07001079#endif
Murat Sezginb3731e82014-11-26 12:20:59 -08001080#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001081
Murat Sezginc1402562015-03-12 12:32:20 -07001082#ifdef ECM_INTERFACE_TUNIPIP6_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001083/*
1084 * ecm_interface_tunipip6_interface_establish()
1085 * Returns a reference to a iface of the TUNIPIP6 type, possibly creating one if necessary.
1086 * Returns NULL on failure or a reference to interface.
1087 */
1088static struct ecm_db_iface_instance *ecm_interface_tunipip6_interface_establish(struct ecm_db_interface_info_tunipip6 *type_info,
1089 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
1090{
1091 struct ecm_db_iface_instance *nii;
1092 struct ecm_db_iface_instance *ii;
1093
1094 DEBUG_INFO("Establish TUNIPIP6 iface: %s with saddr: " ECM_IP_ADDR_OCTAL_FMT ", daddr: " ECM_IP_ADDR_OCTAL_FMT ", MTU: %d, if num: %d, nss if id: %d\n",
1095 dev_name, ECM_IP_ADDR_TO_OCTAL(type_info->saddr), ECM_IP_ADDR_TO_OCTAL(type_info->daddr), mtu, dev_interface_num, nss_interface_num);
1096
1097 /*
1098 * Locate the iface
1099 */
1100 ii = ecm_db_iface_find_and_ref_tunipip6(type_info->saddr, type_info->daddr);
1101 if (ii) {
1102 DEBUG_TRACE("%p: iface established\n", ii);
1103 return ii;
1104 }
1105
1106 /*
1107 * No iface - create one
1108 */
1109 nii = ecm_db_iface_alloc();
1110 if (!nii) {
1111 DEBUG_WARN("Failed to establish iface\n");
1112 return NULL;
1113 }
1114
1115 /*
1116 * Add iface into the database, atomically to avoid races creating the same thing
1117 */
1118 spin_lock_bh(&ecm_interface_lock);
1119 ii = ecm_db_iface_find_and_ref_tunipip6(type_info->saddr, type_info->daddr);
1120 if (ii) {
1121 spin_unlock_bh(&ecm_interface_lock);
1122 ecm_db_iface_deref(nii);
1123 return ii;
1124 }
1125 ecm_db_iface_add_tunipip6(nii, type_info, dev_name, mtu, dev_interface_num,
Nicolas Costaf46c33b2014-05-15 10:02:00 -05001126 nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +00001127 spin_unlock_bh(&ecm_interface_lock);
1128
1129 DEBUG_TRACE("%p: tunipip6 iface established\n", nii);
1130 return nii;
1131}
Murat Sezginc1402562015-03-12 12:32:20 -07001132#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001133
1134/*
1135 * ecm_interface_establish_and_ref()
1136 * Establish an interface instance for the given interface detail.
1137 */
1138struct ecm_db_iface_instance *ecm_interface_establish_and_ref(struct net_device *dev)
1139{
1140 int32_t dev_interface_num;
1141 char *dev_name;
1142 int32_t dev_type;
1143 int32_t dev_mtu;
1144 int32_t nss_interface_num;
1145 struct ecm_db_iface_instance *ii;
1146 union {
1147 struct ecm_db_interface_info_ethernet ethernet; /* type == ECM_DB_IFACE_TYPE_ETHERNET */
Gareth Williams141d2382014-11-25 11:35:19 -08001148#ifdef ECM_INTERFACE_VLAN_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001149 struct ecm_db_interface_info_vlan vlan; /* type == ECM_DB_IFACE_TYPE_VLAN */
Gareth Williams141d2382014-11-25 11:35:19 -08001150#endif
Murat Sezgin910c9662015-03-11 16:15:06 -07001151#ifdef ECM_INTERFACE_BOND_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001152 struct ecm_db_interface_info_lag lag; /* type == ECM_DB_IFACE_TYPE_LAG */
Murat Sezgin910c9662015-03-11 16:15:06 -07001153#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001154 struct ecm_db_interface_info_bridge bridge; /* type == ECM_DB_IFACE_TYPE_BRIDGE */
Murat Sezginaad635c2015-03-06 16:11:41 -08001155#ifdef ECM_INTERFACE_PPP_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001156 struct ecm_db_interface_info_pppoe pppoe; /* type == ECM_DB_IFACE_TYPE_PPPOE */
Murat Sezginaad635c2015-03-06 16:11:41 -08001157#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001158 struct ecm_db_interface_info_unknown unknown; /* type == ECM_DB_IFACE_TYPE_UNKNOWN */
1159 struct ecm_db_interface_info_loopback loopback; /* type == ECM_DB_IFACE_TYPE_LOOPBACK */
1160 struct ecm_db_interface_info_ipsec_tunnel ipsec_tunnel; /* type == ECM_DB_IFACE_TYPE_IPSEC_TUNNEL */
Murat Sezginbde55f92015-03-11 16:44:11 -07001161#ifdef ECM_INTERFACE_SIT_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001162 struct ecm_db_interface_info_sit sit; /* type == ECM_DB_IFACE_TYPE_SIT */
Murat Sezginbde55f92015-03-11 16:44:11 -07001163#endif
Murat Sezginc1402562015-03-12 12:32:20 -07001164#ifdef ECM_INTERFACE_TUNIPIP6_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001165 struct ecm_db_interface_info_tunipip6 tunipip6; /* type == ECM_DB_IFACE_TYPE_TUNIPIP6 */
Murat Sezginc1402562015-03-12 12:32:20 -07001166#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001167 } type_info;
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001168
Gareth Williamsdbb2bfd2014-11-20 16:42:09 -08001169#ifdef ECM_INTERFACE_PPP_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001170 int channel_count;
1171 struct ppp_channel *ppp_chan[1];
Ben Menchaca84f36632014-02-28 20:57:38 +00001172 int channel_protocol;
Ben Menchaca84f36632014-02-28 20:57:38 +00001173 struct pppoe_opt addressing;
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001174#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001175
1176 /*
1177 * Get basic information about the given device
1178 */
1179 dev_interface_num = dev->ifindex;
1180 dev_name = dev->name;
1181 dev_type = dev->type;
1182 dev_mtu = dev->mtu;
1183
1184 /*
1185 * Does the NSS recognise this interface?
1186 */
1187 nss_interface_num = nss_cmn_get_interface_number_by_dev(dev);
1188
1189 DEBUG_TRACE("Establish interface instance for device: %p is type: %d, name: %s, ifindex: %d, nss_if: %d, mtu: %d\n",
1190 dev, dev_type, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1191
1192 /*
1193 * Extract from the device more type-specific information
1194 */
1195 if (dev_type == ARPHRD_ETHER) {
1196 /*
1197 * Ethernet - but what sub type?
1198 */
1199
Gareth Williams141d2382014-11-25 11:35:19 -08001200#ifdef ECM_INTERFACE_VLAN_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001201 /*
1202 * VLAN?
1203 */
1204 if (is_vlan_dev(dev)) {
1205 /*
1206 * VLAN master
1207 * GGG No locking needed here, ASSUMPTION is that real_dev is held for as long as we have dev.
1208 */
1209 memcpy(type_info.vlan.address, dev->dev_addr, 6);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301210 type_info.vlan.vlan_tag = vlan_dev_vlan_id(dev);
1211 type_info.vlan.vlan_tpid = VLAN_CTAG_TPID;
1212 DEBUG_TRACE("Net device: %p is VLAN, mac: %pM, vlan_id: %x vlan_tpid: %x\n",
1213 dev, type_info.vlan.address, type_info.vlan.vlan_tag, type_info.vlan.vlan_tpid);
Ben Menchaca84f36632014-02-28 20:57:38 +00001214
1215 /*
1216 * Establish this type of interface
1217 */
1218 ii = ecm_interface_vlan_interface_establish(&type_info.vlan, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1219 return ii;
1220 }
Gareth Williams141d2382014-11-25 11:35:19 -08001221#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001222
1223 /*
1224 * BRIDGE?
1225 */
1226 if (ecm_front_end_is_bridge_device(dev)) {
1227 /*
1228 * Bridge
1229 */
1230 memcpy(type_info.bridge.address, dev->dev_addr, 6);
1231
1232 DEBUG_TRACE("Net device: %p is BRIDGE, mac: %pM\n",
1233 dev, type_info.bridge.address);
1234
1235 /*
1236 * Establish this type of interface
1237 */
1238 ii = ecm_interface_bridge_interface_establish(&type_info.bridge, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1239 return ii;
1240 }
1241
Murat Sezgin910c9662015-03-11 16:15:06 -07001242#ifdef ECM_INTERFACE_BOND_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001243 /*
1244 * LAG?
1245 */
1246 if (ecm_front_end_is_lag_master(dev)) {
1247 /*
1248 * Link aggregation
1249 */
1250 memcpy(type_info.lag.address, dev->dev_addr, 6);
1251
1252 DEBUG_TRACE("Net device: %p is LAG, mac: %pM\n",
1253 dev, type_info.lag.address);
1254
1255 /*
1256 * Establish this type of interface
1257 */
1258 ii = ecm_interface_lag_interface_establish(&type_info.lag, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1259 return ii;
1260 }
Murat Sezgin910c9662015-03-11 16:15:06 -07001261#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001262
1263 /*
1264 * ETHERNET!
1265 * Just plain ethernet it seems
1266 */
1267 memcpy(type_info.ethernet.address, dev->dev_addr, 6);
1268 DEBUG_TRACE("Net device: %p is ETHERNET, mac: %pM\n",
1269 dev, type_info.ethernet.address);
1270
1271 /*
1272 * Establish this type of interface
1273 */
1274 ii = ecm_interface_ethernet_interface_establish(&type_info.ethernet, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1275 return ii;
1276 }
1277
1278 /*
1279 * LOOPBACK?
1280 */
1281 if (dev_type == ARPHRD_LOOPBACK) {
1282 DEBUG_TRACE("Net device: %p is LOOPBACK type: %d\n", dev, dev_type);
1283 type_info.loopback.os_specific_ident = dev_interface_num;
1284 ii = ecm_interface_loopback_interface_establish(&type_info.loopback, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1285 return ii;
1286 }
1287
1288 /*
1289 * IPSEC?
1290 */
1291 if (dev_type == ECM_ARPHRD_IPSEC_TUNNEL_TYPE) {
1292 DEBUG_TRACE("Net device: %p is IPSec tunnel type: %d\n", dev, dev_type);
1293 type_info.ipsec_tunnel.os_specific_ident = dev_interface_num;
Ankit Dhanuka6d5014a2014-06-22 17:21:44 +05301294
1295 /*
1296 * nss_interface_num for all IPsec tunnels will always be NSS_C2C_TX_INTERFACE
1297 */
1298 nss_interface_num = NSS_C2C_TX_INTERFACE;
1299
Ben Menchaca84f36632014-02-28 20:57:38 +00001300 // GGG TODO Flesh this out with tunnel endpoint addressing detail
1301 ii = ecm_interface_ipsec_tunnel_interface_establish(&type_info.ipsec_tunnel, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1302 return ii;
1303 }
1304
Murat Sezginb3731e82014-11-26 12:20:59 -08001305#ifdef ECM_INTERFACE_SIT_ENABLE
Murat Sezginbde55f92015-03-11 16:44:11 -07001306#ifdef CONFIG_IPV6_SIT_6RD
Ben Menchaca84f36632014-02-28 20:57:38 +00001307 /*
1308 * SIT (6-in-4)?
1309 */
1310 if (dev_type == ARPHRD_SIT) {
1311 struct ip_tunnel *tunnel;
1312 struct ip_tunnel_6rd_parm *ip6rd;
1313 const struct iphdr *tiph;
1314
1315 DEBUG_TRACE("Net device: %p is SIT (6-in-4) type: %d\n", dev, dev_type);
1316
1317 tunnel = (struct ip_tunnel*)netdev_priv(dev);
1318 ip6rd = &tunnel->ip6rd;
1319
1320 /*
1321 * Get the Tunnel device IP header info
1322 */
1323 tiph = &tunnel->parms.iph ;
1324
1325 type_info.sit.prefixlen = ip6rd->prefixlen;
1326 type_info.sit.relay_prefix = ip6rd->relay_prefix;
1327 type_info.sit.relay_prefixlen = ip6rd->relay_prefixlen;
1328 ECM_NIN4_ADDR_TO_IP_ADDR(type_info.sit.saddr, tiph->saddr);
1329 ECM_NIN4_ADDR_TO_IP_ADDR(type_info.sit.daddr, tiph->daddr);
1330 type_info.sit.prefix[0] = ntohl(ip6rd->prefix.s6_addr32[0]);
1331 type_info.sit.prefix[1] = ntohl(ip6rd->prefix.s6_addr32[1]);
1332 type_info.sit.prefix[2] = ntohl(ip6rd->prefix.s6_addr32[2]);
1333 type_info.sit.prefix[3] = ntohl(ip6rd->prefix.s6_addr32[3]);
1334 type_info.sit.ttl = tiph->ttl;
1335 type_info.sit.tos = tiph->tos;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301336
Ben Menchaca84f36632014-02-28 20:57:38 +00001337 ii = ecm_interface_sit_interface_establish(&type_info.sit, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1338 return ii;
1339 }
Murat Sezgincc6eedf2014-05-09 23:59:19 -07001340#endif
Murat Sezginb3731e82014-11-26 12:20:59 -08001341#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001342
Murat Sezginc1402562015-03-12 12:32:20 -07001343#ifdef ECM_INTERFACE_TUNIPIP6_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001344 /*
1345 * IPIP6 Tunnel?
1346 */
1347 if (dev_type == ARPHRD_TUNNEL6) {
1348 struct ip6_tnl *tunnel;
1349 struct flowi6 *fl6;
1350
1351 DEBUG_TRACE("Net device: %p is TUNIPIP6 type: %d\n", dev, dev_type);
1352
1353 /*
1354 * Get the tunnel device flow information (discover the output path of the tunnel)
1355 */
1356 tunnel = (struct ip6_tnl *)netdev_priv(dev);
1357 fl6 = &tunnel->fl.u.ip6;
1358
1359 ECM_NIN6_ADDR_TO_IP_ADDR(type_info.tunipip6.saddr, fl6->saddr);
1360 ECM_NIN6_ADDR_TO_IP_ADDR(type_info.tunipip6.daddr, fl6->daddr);
1361 type_info.tunipip6.hop_limit = tunnel->parms.hop_limit;
1362 type_info.tunipip6.flags = ntohl(tunnel->parms.flags);
1363 type_info.tunipip6.flowlabel = fl6->flowlabel; /* flow Label In kernel is stored in big endian format */
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301364
Ben Menchaca84f36632014-02-28 20:57:38 +00001365 ii = ecm_interface_tunipip6_interface_establish(&type_info.tunipip6, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1366 return ii;
1367 }
Murat Sezginc1402562015-03-12 12:32:20 -07001368#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001369 /*
1370 * If this is NOT PPP then it is unknown to the ecm
1371 */
1372 if (dev_type != ARPHRD_PPP) {
1373 DEBUG_TRACE("Net device: %p is UNKNOWN type: %d\n", dev, dev_type);
1374 type_info.unknown.os_specific_ident = dev_interface_num;
1375
1376 /*
1377 * Establish this type of interface
1378 */
1379 ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1380 return ii;
1381 }
1382
Gareth Williamsdbb2bfd2014-11-20 16:42:09 -08001383#ifndef ECM_INTERFACE_PPP_ENABLE
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001384 /*
1385 * PPP support is NOT provided for.
1386 * Interface is therefore unknown
1387 */
1388 DEBUG_TRACE("Net device: %p is UNKNOWN (PPP Unsupported) type: %d\n", dev, dev_type);
1389 type_info.unknown.os_specific_ident = dev_interface_num;
1390
1391 /*
1392 * Establish this type of interface
1393 */
1394 ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1395 return ii;
1396#else
Ben Menchaca84f36632014-02-28 20:57:38 +00001397 /*
1398 * PPP - but what is the channel type?
1399 * First: If this is multi-link then we do not support it
1400 */
1401 if (ppp_is_multilink(dev) > 0) {
1402 DEBUG_TRACE("Net device: %p is MULTILINK PPP - Unknown to the ECM\n", dev);
1403 type_info.unknown.os_specific_ident = dev_interface_num;
1404
1405 /*
1406 * Establish this type of interface
1407 */
1408 ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1409 return ii;
1410 }
1411
1412 DEBUG_TRACE("Net device: %p is PPP\n", dev);
1413
1414 /*
1415 * Get the PPP channel and then enquire what kind of channel it is
1416 * NOTE: Not multilink so only one channel to get.
1417 */
1418 channel_count = ppp_hold_channels(dev, ppp_chan, 1);
1419 if (channel_count != 1) {
Gareth Williams6f96a4b2014-05-29 19:41:21 +01001420 DEBUG_TRACE("Net device: %p PPP has %d channels - ECM cannot handle this (interface becomes Unknown type)\n",
1421 dev, channel_count);
Ben Menchaca84f36632014-02-28 20:57:38 +00001422 type_info.unknown.os_specific_ident = dev_interface_num;
1423
1424 /*
1425 * Establish this type of interface
1426 */
1427 ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1428 return ii;
1429 }
1430
1431 /*
1432 * Get channel protocol type
Gareth Williams6f96a4b2014-05-29 19:41:21 +01001433 * NOTE: Not all PPP channels support channel specific methods.
Ben Menchaca84f36632014-02-28 20:57:38 +00001434 */
Gareth Williams6f96a4b2014-05-29 19:41:21 +01001435 channel_protocol = ppp_channel_get_protocol(ppp_chan[0]);
Ben Menchaca84f36632014-02-28 20:57:38 +00001436 if (channel_protocol != PX_PROTO_OE) {
1437 DEBUG_TRACE("Net device: %p PPP channel protocol: %d - Unknown to the ECM\n", dev, channel_protocol);
1438 type_info.unknown.os_specific_ident = dev_interface_num;
1439
1440 /*
1441 * Release the channel
1442 */
1443 ppp_release_channels(ppp_chan, 1);
1444
1445 /*
1446 * Establish this type of interface
1447 */
1448 ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1449 return ii;
1450 }
1451
1452 /*
1453 * PPPoE channel
1454 */
1455 DEBUG_TRACE("Net device: %p PPP channel is PPPoE\n", dev);
1456
1457 /*
1458 * Get PPPoE session information and the underlying device it is using.
Ben Menchaca84f36632014-02-28 20:57:38 +00001459 */
Gareth Williams6f96a4b2014-05-29 19:41:21 +01001460 pppoe_channel_addressing_get(ppp_chan[0], &addressing);
1461 type_info.pppoe.pppoe_session_id = (uint16_t)ntohs((uint16_t)addressing.pa.sid);
Ben Menchaca84f36632014-02-28 20:57:38 +00001462 memcpy(type_info.pppoe.remote_mac, addressing.pa.remote, ETH_ALEN);
Gareth Williams6f96a4b2014-05-29 19:41:21 +01001463 dev_put(addressing.dev);
Ben Menchaca84f36632014-02-28 20:57:38 +00001464
1465 /*
1466 * Release the channel. Note that next_dev is still (correctly) held.
1467 */
1468 ppp_release_channels(ppp_chan, 1);
1469
1470 DEBUG_TRACE("Net device: %p PPPoE session: %x, remote mac: %pM\n",
1471 dev, type_info.pppoe.pppoe_session_id, type_info.pppoe.remote_mac);
1472
1473 /*
1474 * Establish this type of interface
1475 */
1476 ii = ecm_interface_pppoe_interface_establish(&type_info.pppoe, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1477 return ii;
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001478#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001479}
1480EXPORT_SYMBOL(ecm_interface_establish_and_ref);
1481
1482/*
1483 * ecm_interface_heirarchy_construct()
1484 * Construct an interface heirarchy.
1485 *
1486 * Using the given addressing, locate the interface heirarchy used to emit packets to that destination.
1487 * This is the heirarchy of interfaces a packet would transit to emit from the device.
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001488 *
1489 * We will use the given src/dest devices when is_routed is false.
1490 * When is_routed is true we will try routing tables first, failing back to any given.
1491 *
Ben Menchaca84f36632014-02-28 20:57:38 +00001492 * For example, with this network arrangement:
1493 *
1494 * PPPoE--VLAN--BRIDGE--BRIDGE_PORT(LAG_MASTER)--LAG_SLAVE_0--10.22.33.11
1495 *
Gareth Williams43fc0852014-05-26 19:10:00 +01001496 * Given the packet_dest_addr IP address 10.22.33.11 this will create an interface heirarchy (in interracfes[]) of:
Ben Menchaca84f36632014-02-28 20:57:38 +00001497 * LAG_SLAVE_0 @ [ECM_DB_IFACE_HEIRARCHY_MAX - 5]
1498 * LAG_MASTER @ [ECM_DB_IFACE_HEIRARCHY_MAX - 4]
1499 * BRIDGE @ [ECM_DB_IFACE_HEIRARCHY_MAX - 3]
1500 * VLAN @ [ECM_DB_IFACE_HEIRARCHY_MAX - 2]
1501 * PPPOE @ [ECM_DB_IFACE_HEIRARCHY_MAX - 1]
1502 * The value returned is (ECM_DB_IFACE_HEIRARCHY_MAX - 5)
1503 *
1504 * IMPORTANT: This function will return any known interfaces in the database, when interfaces do not exist in the database
1505 * they will be created and added automatically to the database.
1506 *
1507 * GGG TODO Make this function work for IPv6!!!!!!!!!!!!!!
1508 */
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001509int32_t ecm_interface_heirarchy_construct(struct ecm_db_iface_instance *interfaces[], ip_addr_t packet_src_addr, ip_addr_t packet_dest_addr, int packet_protocol,
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05301510 struct net_device *given_dest_dev, bool is_routed, struct net_device *given_src_dev, uint8_t *dest_node_addr, uint8_t *src_node_addr)
Ben Menchaca84f36632014-02-28 20:57:38 +00001511{
Ben Menchaca84f36632014-02-28 20:57:38 +00001512 int protocol;
1513 ip_addr_t src_addr;
1514 ip_addr_t dest_addr;
Ben Menchaca84f36632014-02-28 20:57:38 +00001515 struct net_device *dest_dev;
Ben Menchaca84f36632014-02-28 20:57:38 +00001516 char *dest_dev_name;
Ben Menchaca84f36632014-02-28 20:57:38 +00001517 int32_t dest_dev_type;
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001518 struct net_device *src_dev;
1519 char *src_dev_name;
1520 int32_t src_dev_type;
Ben Menchaca84f36632014-02-28 20:57:38 +00001521 int32_t current_interface_index;
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001522 bool from_local_addr;
Ben Menchaca84f36632014-02-28 20:57:38 +00001523
1524 /*
1525 * Get a big endian of the IPv4 address we have been given as our starting point.
1526 */
1527 protocol = packet_protocol;
1528 ECM_IP_ADDR_COPY(src_addr, packet_src_addr);
1529 ECM_IP_ADDR_COPY(dest_addr, packet_dest_addr);
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001530 DEBUG_TRACE("Construct interface heirarchy for from src_addr: " ECM_IP_ADDR_DOT_FMT " to dest_addr: " ECM_IP_ADDR_DOT_FMT ", protocol: %d\n",
1531 ECM_IP_ADDR_TO_DOT(src_addr), ECM_IP_ADDR_TO_DOT(dest_addr), protocol);
Ben Menchaca84f36632014-02-28 20:57:38 +00001532
1533 /*
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001534 * Get device to reach the given destination address.
1535 * If the heirarchy is for a routed connection we must try route lookup first, falling back to any given_dest_dev.
1536 * If the heirarchy is NOT for a routed connection we try the given_dest_dev first, followed by routed lookup.
Ben Menchaca84f36632014-02-28 20:57:38 +00001537 */
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001538 from_local_addr = false;
1539 if (is_routed) {
1540 dest_dev = ecm_interface_dev_find_by_addr(dest_addr, &from_local_addr);
1541 if (!dest_dev && given_dest_dev) {
1542 /*
1543 * Fall back to any given
1544 */
1545 dest_dev = given_dest_dev;
1546 dev_hold(dest_dev);
Gareth Williams43fc0852014-05-26 19:10:00 +01001547 }
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001548 } else if (given_dest_dev) {
1549 dest_dev = given_dest_dev;
1550 dev_hold(dest_dev);
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05301551 } else {
1552 /*
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001553 * Fall back to routed look up
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05301554 */
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001555 dest_dev = ecm_interface_dev_find_by_addr(dest_addr, &from_local_addr);
Gareth Williams43fc0852014-05-26 19:10:00 +01001556 }
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05301557
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001558 /*
1559 * GGG ALERT: If the address is a local address and protocol is an IP tunnel
1560 * then this connection is a tunnel endpoint made to this device.
1561 * In which case we circumvent all proper procedure and just hack the devices to make stuff work.
1562 * GGG TODO THIS MUST BE FIXED - WE MUST USE THE INTERFACE HIERARCHY FOR ITS INTENDED PURPOSE TO
1563 * PARSE THE DEVICES AND WORK OUT THE PROPER INTERFACES INVOLVED.
1564 * E.G. IF WE TRIED TO RUN A TUNNEL OVER A VLAN OR QINQ THIS WILL BREAK AS WE DON'T DISCOVER THAT HIERARCHY
1565 */
1566 if (dest_dev && from_local_addr && (protocol == IPPROTO_IPV6)) {
1567 dev_put(dest_dev);
1568 dest_dev = given_dest_dev;
1569 if (dest_dev) {
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05301570 dev_hold(dest_dev);
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001571 DEBUG_TRACE("HACK: IPV6 tunnel packet with dest_addr: " ECM_IP_ADDR_OCTAL_FMT " uses dev: %p(%s)\n", ECM_IP_ADDR_TO_OCTAL(dest_addr), dest_dev, dest_dev->name);
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05301572 }
Gareth Williams43fc0852014-05-26 19:10:00 +01001573 }
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001574 if (!dest_dev) {
1575 DEBUG_WARN("dest_addr: " ECM_IP_ADDR_OCTAL_FMT " - cannot locate device\n", ECM_IP_ADDR_TO_OCTAL(dest_addr));
1576 return ECM_DB_IFACE_HEIRARCHY_MAX;
1577 }
Ben Menchaca84f36632014-02-28 20:57:38 +00001578 dest_dev_name = dest_dev->name;
1579 dest_dev_type = dest_dev->type;
1580
1581 /*
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001582 * Get device to reach the given source address.
1583 * If the heirarchy is for a routed connection we must try route lookup first, falling back to any given_src_dev.
1584 * If the heirarchy is NOT for a routed connection we try the given_src_dev first, followed by routed lookup.
1585 */
1586 from_local_addr = false;
1587 if (is_routed) {
1588 src_dev = ecm_interface_dev_find_by_addr(src_addr, &from_local_addr);
1589 if (!src_dev && given_src_dev) {
1590 /*
1591 * Fall back to any given
1592 */
1593 src_dev = given_src_dev;
1594 dev_hold(src_dev);
1595 }
1596 } else if (given_src_dev) {
1597 src_dev = given_src_dev;
1598 dev_hold(src_dev);
1599 } else {
1600 /*
1601 * Fall back to routed look up
1602 */
1603 src_dev = ecm_interface_dev_find_by_addr(src_addr, &from_local_addr);
1604 }
1605
1606 /*
1607 * GGG ALERT: If the address is a local address and protocol is an IP tunnel
1608 * then this connection is a tunnel endpoint made to this device.
1609 * In which case we circumvent all proper procedure and just hack the devices to make stuff work.
1610 * GGG TODO THIS MUST BE FIXED - WE MUST USE THE INTERFACE HIERARCHY FOR ITS INTENDED PURPOSE TO
1611 * PARSE THE DEVICES AND WORK OUT THE PROPER INTERFACES INVOLVED.
1612 * E.G. IF WE TRIED TO RUN A TUNNEL OVER A VLAN OR QINQ THIS WILL BREAK AS WE DON'T DISCOVER THAT HIERARCHY
1613 */
1614 if (src_dev && from_local_addr && (protocol == IPPROTO_IPV6)) {
1615 dev_put(src_dev);
1616 src_dev = given_src_dev;
1617 if (src_dev) {
1618 dev_hold(src_dev);
1619 DEBUG_TRACE("HACK: IPV6 tunnel packet with src_addr: " ECM_IP_ADDR_OCTAL_FMT " uses dev: %p(%s)\n", ECM_IP_ADDR_TO_OCTAL(src_addr), src_dev, src_dev->name);
1620 }
1621 }
1622 if (!src_dev) {
1623 DEBUG_WARN("src_addr: " ECM_IP_ADDR_OCTAL_FMT " - cannot locate device\n", ECM_IP_ADDR_TO_OCTAL(src_addr));
1624 dev_put(dest_dev);
1625 return ECM_DB_IFACE_HEIRARCHY_MAX;
1626 }
1627 src_dev_name = src_dev->name;
1628 src_dev_type = src_dev->type;
1629
1630 /*
1631 * Check if source and dest dev are same.
1632 * For the forwarded flows which involve tunnels this will happen when called from input hook.
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05301633 */
1634 if (src_dev == dest_dev) {
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001635 DEBUG_TRACE("Protocol is :%d source dev and dest dev are same\n", protocol);
Ankit Dhanuka60683c52014-06-09 17:43:38 +05301636 if ((protocol == IPPROTO_IPV6) || (protocol == IPPROTO_ESP)) {
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05301637 /*
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001638 * This happens from the input hook
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05301639 * We do not want to create a connection entry for this
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001640 * GGG TODO YES WE DO.
1641 * GGG TODO THIS CONCERNS ME AS THIS SHOULD BE CAUGHT MUCH
1642 * EARLIER IN THE FRONT END IF POSSIBLE TO AVOID PERFORMANCE PENALTIES.
1643 * WE HAVE DONE A TREMENDOUS AMOUT OF WORK TO GET TO THIS POINT.
1644 * WE WILL ABORT HERE AND THIS WILL BE REPEATED FOR EVERY PACKET.
1645 * IN KEEPING WITH THE ECM DESIGN IT IS BETTER TO CREATE A CONNECTION AND RECORD IN THE HIERARCHY
1646 * ENOUGH INFORMATION TO ENSURE THAT ACCELERATION IS NOT BROKEN / DOES NOT OCCUR AT ALL.
1647 * THAT WAY WE DO A HEAVYWEIGHT ESTABLISHING OF A CONNECTION ONCE AND NEVER AGAIN...
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05301648 */
1649 dev_put(src_dev);
1650 dev_put(dest_dev);
1651 return ECM_DB_IFACE_HEIRARCHY_MAX;
1652 }
1653 }
1654
1655 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00001656 * Iterate until we are done or get to the max number of interfaces we can record.
1657 * NOTE: current_interface_index tracks the position of the first interface position in interfaces[]
1658 * because we add from the end first_interface grows downwards.
1659 */
1660 current_interface_index = ECM_DB_IFACE_HEIRARCHY_MAX;
1661 while (current_interface_index > 0) {
1662 struct ecm_db_iface_instance *ii;
1663 struct net_device *next_dev;
1664
1665 /*
1666 * Get the ecm db interface instance for the device at hand
1667 */
1668 ii = ecm_interface_establish_and_ref(dest_dev);
1669
1670 /*
1671 * If the interface could not be established then we abort
1672 */
1673 if (!ii) {
1674 DEBUG_WARN("Failed to establish interface: %p, name: %s\n", dest_dev, dest_dev_name);
1675 dev_put(src_dev);
1676 dev_put(dest_dev);
1677
1678 /*
1679 * Release the interfaces heirarchy we constructed to this point.
1680 */
1681 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1682 return ECM_DB_IFACE_HEIRARCHY_MAX;
1683 }
1684
1685 /*
1686 * Record the interface instance into the interfaces[]
1687 */
1688 current_interface_index--;
1689 interfaces[current_interface_index] = ii;
1690
1691 /*
1692 * Now we have to figure out what the next device will be (in the transmission path) the skb
1693 * will use to emit to the destination address.
1694 */
1695 do {
Gareth Williamsdbb2bfd2014-11-20 16:42:09 -08001696#ifdef ECM_INTERFACE_PPP_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001697 int channel_count;
1698 struct ppp_channel *ppp_chan[1];
Ben Menchaca84f36632014-02-28 20:57:38 +00001699 int channel_protocol;
Ben Menchaca84f36632014-02-28 20:57:38 +00001700 struct pppoe_opt addressing;
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001701#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001702
1703 DEBUG_TRACE("Net device: %p is type: %d, name: %s\n", dest_dev, dest_dev_type, dest_dev_name);
1704 next_dev = NULL;
1705
1706 if (dest_dev_type == ARPHRD_ETHER) {
1707 /*
1708 * Ethernet - but what sub type?
1709 */
1710
Gareth Williams141d2382014-11-25 11:35:19 -08001711#ifdef ECM_INTERFACE_VLAN_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001712 /*
1713 * VLAN?
1714 */
1715 if (is_vlan_dev(dest_dev)) {
1716 /*
1717 * VLAN master
1718 * No locking needed here, ASSUMPTION is that real_dev is held for as long as we have dev.
1719 */
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301720 next_dev = vlan_dev_real_dev(dest_dev);
Ben Menchaca84f36632014-02-28 20:57:38 +00001721 dev_hold(next_dev);
1722 DEBUG_TRACE("Net device: %p is VLAN, slave dev: %p (%s)\n",
1723 dest_dev, next_dev, next_dev->name);
1724 break;
1725 }
Gareth Williams141d2382014-11-25 11:35:19 -08001726#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001727
1728 /*
1729 * BRIDGE?
1730 */
1731 if (ecm_front_end_is_bridge_device(dest_dev)) {
1732 /*
1733 * Bridge
1734 * Figure out which port device the skb will go to using the dest_addr.
1735 */
1736 bool on_link;
Murat Sezginebf8a642014-06-06 12:51:43 -07001737 ip_addr_t gw_addr = ECM_IP_ADDR_NULL;
Ben Menchaca84f36632014-02-28 20:57:38 +00001738 uint8_t mac_addr[ETH_ALEN];
1739 if (!ecm_interface_mac_addr_get(dest_addr, mac_addr, &on_link, gw_addr)) {
1740 /*
1741 * Possible ARP does not know the address yet
1742 */
Gareth Williams9e1d17a2014-05-26 19:40:10 +01001743 DEBUG_INFO("Unable to obtain MAC address for " ECM_IP_ADDR_DOT_FMT "\n", ECM_IP_ADDR_TO_DOT(dest_addr));
1744 if (ECM_IP_ADDR_IS_V4(dest_addr)) {
1745 __be32 ipv4_addr;
1746 __be32 src_ip;
1747
1748 /*
1749 * Issue an ARP request for it, select the src_ip from which to issue the request.
1750 */
1751 ECM_IP_ADDR_TO_NIN4_ADDR(ipv4_addr, dest_addr);
1752 src_ip = inet_select_addr(dest_dev, ipv4_addr, RT_SCOPE_LINK);
1753 if (!src_ip) {
1754 DEBUG_TRACE("failed to lookup IP for %pI4\n", &ipv4_addr);
1755
1756 dev_put(src_dev);
1757 dev_put(dest_dev);
1758
1759 /*
1760 * Release the interfaces heirarchy we constructed to this point.
1761 */
1762 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1763 return ECM_DB_IFACE_HEIRARCHY_MAX;
1764 }
1765
1766 /*
1767 * If we have a GW for this address, then we have to send ARP request to the GW
1768 */
Murat Sezginebf8a642014-06-06 12:51:43 -07001769 if (!on_link && !ECM_IP_ADDR_IS_NULL(gw_addr)) {
Sol Kavyd3fd5d82014-06-05 19:27:04 -07001770 ECM_IP_ADDR_TO_NIN4_ADDR(ipv4_addr, gw_addr);
Gareth Williams9e1d17a2014-05-26 19:40:10 +01001771 }
1772
1773 DEBUG_TRACE("Send ARP for %pI4 using src_ip as %pI4\n", &ipv4_addr, &src_ip);
1774 arp_send(ARPOP_REQUEST, ETH_P_ARP, ipv4_addr, dest_dev, src_ip, NULL, NULL, NULL);
1775 }
1776
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001777 DEBUG_WARN("Unable to obtain MAC address for " ECM_IP_ADDR_DOT_FMT "\n", ECM_IP_ADDR_TO_DOT(dest_addr));
Ben Menchaca84f36632014-02-28 20:57:38 +00001778 dev_put(src_dev);
1779 dev_put(dest_dev);
1780
1781 /*
1782 * Release the interfaces heirarchy we constructed to this point.
1783 */
1784 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1785 return ECM_DB_IFACE_HEIRARCHY_MAX;
1786 }
1787 next_dev = br_port_dev_get(dest_dev, mac_addr);
1788 if (!next_dev) {
1789 DEBUG_WARN("Unable to obtain output port for: %pM\n", mac_addr);
1790 dev_put(src_dev);
1791 dev_put(dest_dev);
1792
1793 /*
1794 * Release the interfaces heirarchy we constructed to this point.
1795 */
1796 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1797 return ECM_DB_IFACE_HEIRARCHY_MAX;
1798 }
1799 DEBUG_TRACE("Net device: %p is BRIDGE, next_dev: %p (%s)\n", dest_dev, next_dev, next_dev->name);
1800 break;
1801 }
Murat Sezginb3731e82014-11-26 12:20:59 -08001802#ifdef ECM_INTERFACE_BOND_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001803 /*
1804 * LAG?
1805 */
1806 if (ecm_front_end_is_lag_master(dest_dev)) {
1807 /*
1808 * Link aggregation
Murat Sezginb3731e82014-11-26 12:20:59 -08001809 * Figure out whiich slave device of the link aggregation will be used to reach the destination.
Ben Menchaca84f36632014-02-28 20:57:38 +00001810 */
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05301811 bool dest_on_link = false;
1812 ip_addr_t dest_gw_addr = ECM_IP_ADDR_NULL;
1813 uint32_t src_addr_32 = 0;
1814 uint32_t dest_addr_32 = 0;
Ben Menchaca84f36632014-02-28 20:57:38 +00001815 uint8_t src_mac_addr[ETH_ALEN];
1816 uint8_t dest_mac_addr[ETH_ALEN];
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05301817 struct net_device *master_dev = NULL;
Ben Menchaca84f36632014-02-28 20:57:38 +00001818
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05301819 memset(src_mac_addr, 0, ETH_ALEN);
1820 memset(dest_mac_addr, 0, ETH_ALEN);
Ben Menchaca84f36632014-02-28 20:57:38 +00001821
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05301822 ECM_IP_ADDR_TO_NIN4_ADDR(src_addr_32, src_addr);
1823 ECM_IP_ADDR_TO_NIN4_ADDR(dest_addr_32, dest_addr);
1824
1825 if (!is_routed) {
1826 memcpy(src_mac_addr, src_node_addr, ETH_ALEN);
1827 memcpy(dest_mac_addr, dest_node_addr, ETH_ALEN);
1828 } else {
Murat Sezginb3731e82014-11-26 12:20:59 -08001829 struct net_device *dest_dev_master;
1830
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05301831 /*
1832 * Use appropriate source MAC address for routed packets
1833 */
Murat Sezginb3731e82014-11-26 12:20:59 -08001834 dest_dev_master = ecm_interface_get_and_hold_dev_master(dest_dev);
1835 if (dest_dev_master) {
1836 memcpy(src_mac_addr, dest_dev_master->dev_addr, ETH_ALEN);
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05301837 } else {
1838 memcpy(src_mac_addr, dest_dev->dev_addr, ETH_ALEN);
1839 }
1840
1841 /*
1842 * Determine destination MAC address for this routed packet
1843 */
1844 if (!ecm_interface_mac_addr_get(dest_addr, dest_mac_addr,
1845 &dest_on_link, dest_gw_addr)) {
1846 __be32 ipv4_addr = 0;
1847 __be32 src_ip = 0;
1848 DEBUG_WARN("Unable to obtain MAC address for "
1849 ECM_IP_ADDR_DOT_FMT "\n", ECM_IP_ADDR_TO_DOT(dest_addr));
1850
1851
1852 /*
1853 * Issue an ARP request, select the src_ip from which to issue the request.
1854 */
1855
1856 /*
1857 * find proper interfce from which to issue ARP
1858 */
Murat Sezginb3731e82014-11-26 12:20:59 -08001859 if (dest_dev_master) {
1860 master_dev = dest_dev_master;
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05301861 } else {
1862 master_dev = dest_dev;
1863 }
1864
1865 dev_hold(master_dev);
1866
Murat Sezginb3731e82014-11-26 12:20:59 -08001867 if (dest_dev_master) {
1868 dev_put(dest_dev_master);
1869 }
1870
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05301871 ECM_IP_ADDR_TO_NIN4_ADDR(ipv4_addr, dest_addr);
1872 src_ip = inet_select_addr(master_dev, ipv4_addr, RT_SCOPE_LINK);
1873 if (!src_ip) {
1874 DEBUG_TRACE("failed to lookup IP for %pI4\n", &ipv4_addr);
1875
1876 dev_put(src_dev);
1877 dev_put(dest_dev);
1878 dev_put(master_dev);
1879
1880 /*
1881 * Release the interfaces heirarchy we constructed to this point.
1882 */
1883 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1884 return ECM_DB_IFACE_HEIRARCHY_MAX;
1885 }
1886
1887 /*
1888 * If we have a GW for this address, then we have to send ARP request to the GW
1889 */
1890 if (!dest_on_link && !ECM_IP_ADDR_IS_NULL(dest_gw_addr)) {
1891 ECM_IP_ADDR_TO_NIN4_ADDR(ipv4_addr, dest_gw_addr);
1892 }
1893
1894 DEBUG_TRACE("Send ARP for %pI4 using src_ip as %pI4\n", &ipv4_addr, &src_ip);
1895 arp_send(ARPOP_REQUEST, ETH_P_ARP, ipv4_addr, master_dev, src_ip, NULL, NULL, NULL);
1896
1897
1898 dev_put(src_dev);
1899 dev_put(dest_dev);
1900 dev_put(master_dev);
1901 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1902 return ECM_DB_IFACE_HEIRARCHY_MAX;
1903 }
Murat Sezginb3731e82014-11-26 12:20:59 -08001904
1905 if (dest_dev_master) {
1906 dev_put(dest_dev_master);
1907 }
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05301908 }
1909
1910 next_dev = bond_get_tx_dev(NULL, src_mac_addr, dest_mac_addr,
1911 &src_addr_32, &dest_addr_32,
1912 htons((uint16_t)ETH_P_IP), dest_dev);
Tushar Mathur933907c2014-06-24 17:06:14 +05301913 if (next_dev && netif_carrier_ok(next_dev)) {
Ben Menchaca84f36632014-02-28 20:57:38 +00001914 dev_hold(next_dev);
1915 } else {
1916 DEBUG_WARN("Unable to obtain LAG output slave device\n");
1917 dev_put(src_dev);
1918 dev_put(dest_dev);
1919
1920 /*
1921 * Release the interfaces heirarchy we constructed to this point.
1922 */
1923 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1924 return ECM_DB_IFACE_HEIRARCHY_MAX;
1925 }
1926
1927 DEBUG_TRACE("Net device: %p is LAG, slave dev: %p (%s)\n", dest_dev, next_dev, next_dev->name);
Ben Menchaca84f36632014-02-28 20:57:38 +00001928 break;
1929 }
Murat Sezginb3731e82014-11-26 12:20:59 -08001930#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001931
1932 /*
1933 * ETHERNET!
1934 * Just plain ethernet it seems.
1935 */
1936 DEBUG_TRACE("Net device: %p is ETHERNET\n", dest_dev);
1937 break;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301938 }
Ben Menchaca84f36632014-02-28 20:57:38 +00001939
1940 /*
1941 * LOOPBACK?
1942 */
1943 if (dest_dev_type == ARPHRD_LOOPBACK) {
1944 DEBUG_TRACE("Net device: %p is LOOPBACK type: %d\n", dest_dev, dest_dev_type);
1945 break;
1946 }
1947
1948 /*
1949 * IPSEC?
1950 */
1951 if (dest_dev_type == ECM_ARPHRD_IPSEC_TUNNEL_TYPE) {
1952 DEBUG_TRACE("Net device: %p is IPSec tunnel type: %d\n", dest_dev, dest_dev_type);
1953 // GGG TODO Figure out the next device the tunnel is using...
1954 break;
1955 }
1956
1957 /*
1958 * SIT (6-in-4)?
1959 */
1960 if (dest_dev_type == ARPHRD_SIT) {
1961 DEBUG_TRACE("Net device: %p is SIT (6-in-4) type: %d\n", dest_dev, dest_dev_type);
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001962 // GGG TODO Figure out the next device the tunnel is using...
Ben Menchaca84f36632014-02-28 20:57:38 +00001963 break;
1964 }
1965
1966 /*
1967 * IPIP6 Tunnel?
1968 */
1969 if (dest_dev_type == ARPHRD_TUNNEL6) {
1970 DEBUG_TRACE("Net device: %p is TUNIPIP6 type: %d\n", dest_dev, dest_dev_type);
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001971 // GGG TODO Figure out the next device the tunnel is using...
Ben Menchaca84f36632014-02-28 20:57:38 +00001972 break;
1973 }
1974
1975 /*
1976 * If this is NOT PPP then it is unknown to the ecm and we cannot figure out it's next device.
1977 */
1978 if (dest_dev_type != ARPHRD_PPP) {
1979 DEBUG_TRACE("Net device: %p is UNKNOWN type: %d\n", dest_dev, dest_dev_type);
1980 break;
1981 }
1982
Gareth Williamsdbb2bfd2014-11-20 16:42:09 -08001983#ifndef ECM_INTERFACE_PPP_ENABLE
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001984 DEBUG_TRACE("Net device: %p is UNKNOWN (PPP Unsupported) type: %d\n", dest_dev, dest_dev_type);
1985#else
Ben Menchaca84f36632014-02-28 20:57:38 +00001986 /*
1987 * PPP - but what is the channel type?
1988 * First: If this is multi-link then we do not support it
1989 */
1990 if (ppp_is_multilink(dest_dev) > 0) {
1991 DEBUG_TRACE("Net device: %p is MULTILINK PPP - Unknown to the ECM\n", dest_dev);
1992 break;
1993 }
1994
1995 DEBUG_TRACE("Net device: %p is PPP\n", dest_dev);
1996
1997 /*
1998 * Get the PPP channel and then enquire what kind of channel it is
1999 * NOTE: Not multilink so only one channel to get.
2000 */
2001 channel_count = ppp_hold_channels(dest_dev, ppp_chan, 1);
2002 if (channel_count != 1) {
2003 DEBUG_TRACE("Net device: %p PPP has %d channels - Unknown to the ECM\n",
2004 dest_dev, channel_count);
2005 break;
2006 }
2007
2008 /*
2009 * Get channel protocol type
Gareth Williams6f96a4b2014-05-29 19:41:21 +01002010 * NOTE: Not all PPP channels support channel specific methods.
Ben Menchaca84f36632014-02-28 20:57:38 +00002011 */
Gareth Williams6f96a4b2014-05-29 19:41:21 +01002012 channel_protocol = ppp_channel_get_protocol(ppp_chan[0]);
Ben Menchaca84f36632014-02-28 20:57:38 +00002013 if (channel_protocol != PX_PROTO_OE) {
2014 DEBUG_TRACE("Net device: %p PPP channel protocol: %d - Unknown to the ECM\n",
2015 dest_dev, channel_protocol);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302016
Ben Menchaca84f36632014-02-28 20:57:38 +00002017 /*
2018 * Release the channel
2019 */
2020 ppp_release_channels(ppp_chan, 1);
2021
2022 break;
2023 }
2024
2025 /*
2026 * PPPoE channel
2027 */
2028 DEBUG_TRACE("Net device: %p PPP channel is PPPoE\n", dest_dev);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302029
Ben Menchaca84f36632014-02-28 20:57:38 +00002030 /*
2031 * Get PPPoE session information and the underlying device it is using.
Ben Menchaca84f36632014-02-28 20:57:38 +00002032 */
Gareth Williams6f96a4b2014-05-29 19:41:21 +01002033 pppoe_channel_addressing_get(ppp_chan[0], &addressing);
Ben Menchaca84f36632014-02-28 20:57:38 +00002034
2035 /*
2036 * Copy the dev hold into this, we will release the hold later
2037 */
2038 next_dev = addressing.dev;
2039
2040 DEBUG_TRACE("Net device: %p, next device: %p (%s)\n", dest_dev, next_dev, next_dev->name);
2041
2042 /*
2043 * Release the channel. Note that next_dev is still (correctly) held.
2044 */
2045 ppp_release_channels(ppp_chan, 1);
Gareth Williamsc5b9d712014-05-09 20:40:07 +01002046#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00002047 } while (false);
2048
2049 /*
Gareth Williamsa11d4352014-05-14 18:25:49 +01002050 * No longer need dest_dev as it may become next_dev
Ben Menchaca84f36632014-02-28 20:57:38 +00002051 */
Ben Menchaca84f36632014-02-28 20:57:38 +00002052 dev_put(dest_dev);
2053
2054 /*
2055 * Check out the next_dev, if any
2056 */
2057 if (!next_dev) {
2058 int32_t i __attribute__((unused));
2059 DEBUG_INFO("Completed interface heirarchy construct with first interface @: %d\n", current_interface_index);
2060#if DEBUG_LEVEL > 1
2061 for (i = current_interface_index; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
2062 DEBUG_TRACE("\tInterface @ %d: %p, type: %d, name: %s\n",
2063 i, interfaces[i], ecm_db_connection_iface_type_get(interfaces[i]), ecm_db_interface_type_to_string(ecm_db_connection_iface_type_get(interfaces[i])));
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05302064
Ben Menchaca84f36632014-02-28 20:57:38 +00002065 }
2066#endif
Gareth Williamsa11d4352014-05-14 18:25:49 +01002067
2068 /*
2069 * Release src_dev now
2070 */
2071 dev_put(src_dev);
Ben Menchaca84f36632014-02-28 20:57:38 +00002072 return current_interface_index;
2073 }
2074
Gareth Williamsa11d4352014-05-14 18:25:49 +01002075 /*
2076 * dest_dev becomes next_dev
2077 */
Ben Menchaca84f36632014-02-28 20:57:38 +00002078 dest_dev = next_dev;
2079 dest_dev_name = dest_dev->name;
2080 dest_dev_type = dest_dev->type;
2081 }
2082
2083 DEBUG_WARN("Too many interfaces: %d\n", current_interface_index);
2084 DEBUG_ASSERT(current_interface_index == 0, "Bad logic handling current_interface_index: %d\n", current_interface_index);
2085 dev_put(src_dev);
2086 dev_put(dest_dev);
2087
2088 /*
2089 * Release the interfaces heirarchy we constructed to this point.
2090 */
2091 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
2092 return ECM_DB_IFACE_HEIRARCHY_MAX;
2093}
2094EXPORT_SYMBOL(ecm_interface_heirarchy_construct);
2095
2096/*
Gareth Williamsadf425f2014-05-26 19:29:02 +01002097 * ecm_interface_list_stats_update()
2098 * Given an interface list, walk the interfaces and update the stats for certain types.
2099 */
2100static void ecm_interface_list_stats_update(int iface_list_first, struct ecm_db_iface_instance *iface_list[], uint8_t *mac_addr,
2101 uint32_t tx_packets, uint32_t tx_bytes, uint32_t rx_packets, uint32_t rx_bytes)
2102{
2103 int list_index;
2104
2105 for (list_index = iface_list_first; (list_index < ECM_DB_IFACE_HEIRARCHY_MAX); list_index++) {
2106 struct ecm_db_iface_instance *ii;
2107 ecm_db_iface_type_t ii_type;
2108 char *ii_name;
2109 struct net_device *dev;
2110
2111 ii = iface_list[list_index];
2112 ii_type = ecm_db_connection_iface_type_get(ii);
2113 ii_name = ecm_db_interface_type_to_string(ii_type);
2114 DEBUG_TRACE("list_index: %d, ii: %p, type: %d (%s)\n", list_index, ii, ii_type, ii_name);
2115
2116 /*
2117 * Locate real device in system
2118 */
2119 dev = dev_get_by_index(&init_net, ecm_db_iface_interface_identifier_get(ii));
2120 if (!dev) {
2121 DEBUG_WARN("Could not locate interface\n");
2122 continue;
2123 }
2124 DEBUG_TRACE("found dev: %p (%s)\n", dev, dev->name);
2125
Selin Dag1af781a2014-06-10 10:37:54 -07002126 /*
2127 * Refresh the bridge forward table entry if the port is a bridge port
2128 * Note: A bridge port can be of different interface type, e.g VLAN, ethernet.
2129 * This check, therefore, should be performed for all interface types.
2130 */
2131 if (is_valid_ether_addr(mac_addr) && ecm_front_end_is_bridge_port(dev)) {
2132 DEBUG_TRACE("Update bridge fdb entry for mac: %pM\n", mac_addr);
2133 br_refresh_fdb_entry(dev, mac_addr);
2134 }
2135
Gareth Williamsadf425f2014-05-26 19:29:02 +01002136 switch (ii_type) {
2137 struct rtnl_link_stats64 stats;
2138
Gareth Williams141d2382014-11-25 11:35:19 -08002139#ifdef ECM_INTERFACE_VLAN_ENABLE
Gareth Williamsadf425f2014-05-26 19:29:02 +01002140 case ECM_DB_IFACE_TYPE_VLAN:
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05302141 DEBUG_INFO("VLAN\n");
Gareth Williamsadf425f2014-05-26 19:29:02 +01002142 stats.rx_packets = rx_packets;
2143 stats.rx_bytes = rx_bytes;
2144 stats.tx_packets = tx_packets;
2145 stats.tx_bytes = tx_bytes;
2146 __vlan_dev_update_accel_stats(dev, &stats);
2147 break;
Gareth Williams141d2382014-11-25 11:35:19 -08002148#endif
Gareth Williamsadf425f2014-05-26 19:29:02 +01002149 case ECM_DB_IFACE_TYPE_BRIDGE:
2150 DEBUG_INFO("BRIDGE\n");
2151 stats.rx_packets = rx_packets;
2152 stats.rx_bytes = rx_bytes;
2153 stats.tx_packets = tx_packets;
2154 stats.tx_bytes = tx_bytes;
2155 br_dev_update_stats(dev, &stats);
Gareth Williamsadf425f2014-05-26 19:29:02 +01002156 break;
Murat Sezgina683edd2015-01-20 10:48:30 -08002157
2158#ifdef ECM_INTERFACE_PPP_ENABLE
2159 case ECM_DB_IFACE_TYPE_PPPOE:
2160 DEBUG_INFO("PPPOE\n");
2161 ppp_update_stats(dev, rx_packets, rx_bytes, tx_packets, tx_bytes);
2162 break;
2163#endif
Gareth Williamsadf425f2014-05-26 19:29:02 +01002164 default:
2165 /*
2166 * TODO: Extend it accordingly
2167 */
2168 break;
2169 }
2170
2171 dev_put(dev);
2172 }
2173}
2174
2175/*
2176 * ecm_interface_stats_update()
2177 * Using the interface lists for the given connection, update the interface statistics for each.
2178 *
2179 * 'from' here is wrt the connection 'from' side. Likewise with 'to'.
2180 * TX is wrt what the interface has transmitted. RX is what the interface has received.
2181 */
2182void ecm_interface_stats_update(struct ecm_db_connection_instance *ci,
2183 uint32_t from_tx_packets, uint32_t from_tx_bytes, uint32_t from_rx_packets, uint32_t from_rx_bytes,
2184 uint32_t to_tx_packets, uint32_t to_tx_bytes, uint32_t to_rx_packets, uint32_t to_rx_bytes)
2185{
2186 struct ecm_db_iface_instance *from_ifaces[ECM_DB_IFACE_HEIRARCHY_MAX];
2187 struct ecm_db_iface_instance *to_ifaces[ECM_DB_IFACE_HEIRARCHY_MAX];
2188 int from_ifaces_first;
2189 int to_ifaces_first;
2190 uint8_t mac_addr[ETH_ALEN];
2191
2192 /*
2193 * Iterate the 'from' side interfaces and update statistics and state for the real HLOS interfaces
2194 * from_tx_packets / bytes: the amount transmitted by the 'from' interface
2195 * from_rx_packets / bytes: the amount received by the 'from' interface
2196 */
2197 DEBUG_INFO("%p: Update from interface stats\n", ci);
2198 from_ifaces_first = ecm_db_connection_from_interfaces_get_and_ref(ci, from_ifaces);
2199 ecm_db_connection_from_node_address_get(ci, mac_addr);
2200 ecm_interface_list_stats_update(from_ifaces_first, from_ifaces, mac_addr, from_tx_packets, from_tx_bytes, from_rx_packets, from_rx_bytes);
2201 ecm_db_connection_interfaces_deref(from_ifaces, from_ifaces_first);
2202
2203 /*
2204 * Iterate the 'to' side interfaces and update statistics and state for the real HLOS interfaces
2205 * to_tx_packets / bytes: the amount transmitted by the 'to' interface
2206 * to_rx_packets / bytes: the amount received by the 'to' interface
2207 */
2208 DEBUG_INFO("%p: Update to interface stats\n", ci);
2209 to_ifaces_first = ecm_db_connection_to_interfaces_get_and_ref(ci, to_ifaces);
2210 ecm_db_connection_to_node_address_get(ci, mac_addr);
2211 ecm_interface_list_stats_update(to_ifaces_first, to_ifaces, mac_addr, to_tx_packets, to_tx_bytes, to_rx_packets, to_rx_bytes);
2212 ecm_db_connection_interfaces_deref(to_ifaces, to_ifaces_first);
2213}
2214EXPORT_SYMBOL(ecm_interface_stats_update);
2215
2216/*
Gareth Williams3cb1ffc2014-09-19 16:04:35 +01002217 * ecm_interface_regenerate_connection()
2218 * Re-generate a specific connection
2219 */
2220void ecm_interface_regenerate_connection(struct ecm_db_connection_instance *ci)
2221{
2222 struct ecm_front_end_connection_instance *feci;
2223
2224 DEBUG_TRACE("Regenerate connection: %p\n", ci);
2225
2226 /*
2227 * Flag the connection as needing re-generation.
2228 * Re-generation occurs when we next see traffic OR an acceleration engine sync for this connection.
2229 * Refer to front end protocol specific process() functions.
2230 */
2231 ecm_db_connection_classifier_generation_change(ci);
2232
2233 /*
2234 * If the connection is accelerated then force deceleration.
2235 * Under normal circumstances deceleration would occur on the next sync received,
2236 * however, there is a situation where a sync may not occur if, say, a cable has been pulled.
2237 * The acceleration engine would see no further traffic to trigger sending a sync and so
2238 * re-generation would not occur.
2239 * The connection would stall and no-regeneration would happen leaving the connection in bad state.
2240 * NOTE: We can just call decelerate() upon the front end - if its not accelerated this will have no effect.
2241 */
2242 feci = ecm_db_connection_front_end_get_and_ref(ci);
2243 feci->decelerate(feci);
2244 feci->deref(feci);
2245}
2246
2247/*
Ben Menchaca84f36632014-02-28 20:57:38 +00002248 * ecm_interface_regenerate_connections()
2249 * Cause regeneration of all connections that are using the specified interface.
2250 */
2251static void ecm_interface_regenerate_connections(struct ecm_db_iface_instance *ii)
2252{
2253 struct ecm_db_connection_instance *ci;
2254
2255 DEBUG_TRACE("Regenerate connections using interface: %p\n", ii);
2256
2257 /*
2258 * Iterate the connections of this interface and cause each one to be re-generated.
2259 * GGG TODO NOTE: If this proves slow (need metrics here) we could just regenerate the "lot" with one very simple call.
2260 * But this would cause re-gen of every connection which may not be appropriate, this here at least keeps things in scope of the interface
2261 * but at the cost of performance.
2262 */
2263 DEBUG_TRACE("%p: Regenerate 'from' connections\n", ii);
2264 ci = ecm_db_iface_connections_from_get_and_ref_first(ii);
2265 while (ci) {
2266 struct ecm_db_connection_instance *cin;
2267 cin = ecm_db_connection_iface_from_get_and_ref_next(ci);
2268
2269 DEBUG_TRACE("%p: Regenerate: %p", ii, ci);
Gareth Williams3cb1ffc2014-09-19 16:04:35 +01002270 ecm_interface_regenerate_connection(ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00002271 ecm_db_connection_deref(ci);
2272 ci = cin;
2273 }
2274
2275 DEBUG_TRACE("%p: Regenerate 'to' connections\n", ii);
2276 ci = ecm_db_iface_connections_to_get_and_ref_first(ii);
2277 while (ci) {
2278 struct ecm_db_connection_instance *cin;
2279 cin = ecm_db_connection_iface_to_get_and_ref_next(ci);
2280
2281 DEBUG_TRACE("%p: Regenerate: %p", ii, ci);
Gareth Williams3cb1ffc2014-09-19 16:04:35 +01002282 ecm_interface_regenerate_connection(ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00002283 ecm_db_connection_deref(ci);
2284 ci = cin;
2285 }
2286
2287 DEBUG_TRACE("%p: Regenerate 'from_nat' connections\n", ii);
2288 ci = ecm_db_iface_connections_nat_from_get_and_ref_first(ii);
2289 while (ci) {
2290 struct ecm_db_connection_instance *cin;
2291 cin = ecm_db_connection_iface_nat_from_get_and_ref_next(ci);
2292
2293 DEBUG_TRACE("%p: Regenerate: %p", ii, ci);
Gareth Williams3cb1ffc2014-09-19 16:04:35 +01002294 ecm_interface_regenerate_connection(ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00002295 ecm_db_connection_deref(ci);
2296 ci = cin;
2297 }
2298
2299 DEBUG_TRACE("%p: Regenerate 'to_nat' connections\n", ii);
2300 ci = ecm_db_iface_connections_nat_to_get_and_ref_first(ii);
2301 while (ci) {
2302 struct ecm_db_connection_instance *cin;
2303 cin = ecm_db_connection_iface_nat_to_get_and_ref_next(ci);
2304
2305 DEBUG_TRACE("%p: Regenerate: %p", ii, ci);
Gareth Williams3cb1ffc2014-09-19 16:04:35 +01002306 ecm_interface_regenerate_connection(ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00002307 ecm_db_connection_deref(ci);
2308 ci = cin;
2309 }
2310
2311 DEBUG_TRACE("%p: Regenerate COMPLETE\n", ii);
2312}
2313
2314/*
2315 * ecm_interface_dev_regenerate_connections()
2316 * Cause regeneration of all connections that are using the specified interface.
2317 */
Tushar Mathurcccbf282015-01-13 01:22:44 +05302318void ecm_interface_dev_regenerate_connections(struct net_device *dev)
Ben Menchaca84f36632014-02-28 20:57:38 +00002319{
2320 struct ecm_db_iface_instance *ii;
2321
2322 DEBUG_INFO("Regenerate connections for: %p (%s)\n", dev, dev->name);
2323
2324 /*
2325 * Establish the interface for the given device.
2326 * NOTE: The cute thing here is even if dev is previously unknown to us this will create an interface instance
2327 * but it will have no connections to regen and will be destroyed at the end of the function when we deref - so no harm done.
2328 * However if the interface is known to us then we will get it returned by this function and process it accordingly.
2329 */
2330 ii = ecm_interface_establish_and_ref(dev);
2331 if (!ii) {
2332 DEBUG_WARN("%p: No interface instance could be established for this dev\n", dev);
2333 return;
2334 }
2335 ecm_interface_regenerate_connections(ii);
2336 DEBUG_TRACE("%p: Regenerate for %p: COMPLETE\n", dev, ii);
2337 ecm_db_iface_deref(ii);
2338}
2339
2340/*
2341 * ecm_interface_mtu_change()
2342 * MTU of interface has changed
2343 */
2344static void ecm_interface_mtu_change(struct net_device *dev)
2345{
2346 int mtu;
2347 struct ecm_db_iface_instance *ii;
2348
2349 mtu = dev->mtu;
2350 DEBUG_INFO("%p (%s): MTU Change to: %d\n", dev, dev->name, mtu);
2351
2352 /*
2353 * Establish the interface for the given device.
2354 */
2355 ii = ecm_interface_establish_and_ref(dev);
2356 if (!ii) {
2357 DEBUG_WARN("%p: No interface instance could be established for this dev\n", dev);
2358 return;
2359 }
2360
2361 /*
2362 * Change the mtu
2363 */
2364 ecm_db_iface_mtu_reset(ii, mtu);
2365 DEBUG_TRACE("%p (%s): MTU Changed to: %d\n", dev, dev->name, mtu);
2366 ecm_interface_regenerate_connections(ii);
2367 DEBUG_TRACE("%p: Regenerate for %p: COMPLETE\n", dev, ii);
2368 ecm_db_iface_deref(ii);
2369}
2370
2371/*
2372 * ecm_interface_netdev_notifier_callback()
2373 * Netdevice notifier callback to inform us of change of state of a netdevice
2374 */
2375static int ecm_interface_netdev_notifier_callback(struct notifier_block *this, unsigned long event, void *ptr)
2376{
Stephen Wang69379c32015-02-04 18:37:13 -08002377#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 10, 0))
Ben Menchaca84f36632014-02-28 20:57:38 +00002378 struct net_device *dev __attribute__ ((unused)) = (struct net_device *)ptr;
Stephen Wang69379c32015-02-04 18:37:13 -08002379#else
2380 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
2381#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00002382
2383 DEBUG_INFO("Net device notifier for: %p, name: %s, event: %lx\n", dev, dev->name, event);
2384
2385 switch (event) {
2386 case NETDEV_DOWN:
2387 DEBUG_INFO("Net device: %p, DOWN\n", dev);
2388 ecm_interface_dev_regenerate_connections(dev);
2389 break;
2390
2391 case NETDEV_CHANGE:
2392 DEBUG_INFO("Net device: %p, CHANGE\n", dev);
2393 if (!netif_carrier_ok(dev)) {
2394 DEBUG_INFO("Net device: %p, CARRIER BAD\n", dev);
Tushar Mathur933907c2014-06-24 17:06:14 +05302395 if (netif_is_bond_slave(dev)) {
Murat Sezginb3731e82014-11-26 12:20:59 -08002396 struct net_device *master;
2397 master = ecm_interface_get_and_hold_dev_master(dev);
2398 DEBUG_ASSERT(master, "Expected a master\n");
2399 ecm_interface_dev_regenerate_connections(master);
2400 dev_put(master);
Tushar Mathur933907c2014-06-24 17:06:14 +05302401 } else {
2402 ecm_interface_dev_regenerate_connections(dev);
2403 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002404 }
2405 break;
2406
2407 case NETDEV_CHANGEMTU:
2408 DEBUG_INFO("Net device: %p, MTU CHANGE\n", dev);
2409 ecm_interface_mtu_change(dev);
2410 break;
2411
2412 default:
2413 DEBUG_TRACE("Net device: %p, UNHANDLED: %lx\n", dev, event);
2414 break;
2415 }
2416
2417 return NOTIFY_DONE;
2418}
2419
2420/*
2421 * struct notifier_block ecm_interface_netdev_notifier
2422 * Registration for net device changes of state.
2423 */
2424static struct notifier_block ecm_interface_netdev_notifier __read_mostly = {
2425 .notifier_call = ecm_interface_netdev_notifier_callback,
2426};
2427
2428/*
Ben Menchaca84f36632014-02-28 20:57:38 +00002429 * ecm_interface_get_stop()
2430 */
Murat Sezgin1f381852014-11-20 09:51:07 -08002431static ssize_t ecm_interface_get_stop(struct device *dev,
2432 struct device_attribute *attr,
Ben Menchaca84f36632014-02-28 20:57:38 +00002433 char *buf)
2434{
2435 ssize_t count;
2436 int num;
2437
2438 /*
2439 * Operate under our locks
2440 */
2441 spin_lock_bh(&ecm_interface_lock);
2442 num = ecm_interface_stopped;
2443 spin_unlock_bh(&ecm_interface_lock);
2444
2445 count = snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", num);
2446 return count;
2447}
2448
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002449void ecm_interface_stop(int num)
2450{
2451 /*
2452 * Operate under our locks and stop further processing of packets
2453 */
2454 spin_lock_bh(&ecm_interface_lock);
2455 ecm_interface_stopped = num;
2456 spin_unlock_bh(&ecm_interface_lock);
2457
2458}
2459EXPORT_SYMBOL(ecm_interface_stop);
2460
2461
Ben Menchaca84f36632014-02-28 20:57:38 +00002462/*
2463 * ecm_interface_set_stop()
2464 */
Murat Sezgin1f381852014-11-20 09:51:07 -08002465static ssize_t ecm_interface_set_stop(struct device *dev,
2466 struct device_attribute *attr,
Ben Menchaca84f36632014-02-28 20:57:38 +00002467 const char *buf, size_t count)
2468{
2469 char num_buf[12];
2470 int num;
2471
2472 /*
2473 * Get the number from buf into a properly z-termed number buffer
2474 */
2475 if (count > 11) {
2476 return 0;
2477 }
2478 memcpy(num_buf, buf, count);
2479 num_buf[count] = '\0';
2480 sscanf(num_buf, "%d", &num);
2481 DEBUG_TRACE("ecm_interface_stop = %d\n", num);
2482
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002483 ecm_interface_stop(num);
Ben Menchaca84f36632014-02-28 20:57:38 +00002484
2485 return count;
2486}
2487
2488/*
Murat Sezgin1f381852014-11-20 09:51:07 -08002489 * System device attributes for the ECM interface.
Ben Menchaca84f36632014-02-28 20:57:38 +00002490 */
Murat Sezgin1f381852014-11-20 09:51:07 -08002491static DEVICE_ATTR(stop, 0644, ecm_interface_get_stop, ecm_interface_set_stop);
Ben Menchaca84f36632014-02-28 20:57:38 +00002492
2493/*
Murat Sezgin1f381852014-11-20 09:51:07 -08002494 * Sub system node.
2495 * Sys device control points can be found at /sys/devices/system/ecm_interface/ecm_interfaceX/
Ben Menchaca84f36632014-02-28 20:57:38 +00002496 */
Murat Sezgin1f381852014-11-20 09:51:07 -08002497static struct bus_type ecm_interface_subsys = {
Ben Menchaca84f36632014-02-28 20:57:38 +00002498 .name = "ecm_interface",
Murat Sezgin1f381852014-11-20 09:51:07 -08002499 .dev_name = "ecm_interface",
Ben Menchaca84f36632014-02-28 20:57:38 +00002500};
2501
2502/*
Murat Sezgin1f381852014-11-20 09:51:07 -08002503 * ecm_interface_dev_release()
2504 * This is a dummy release function for device.
2505 */
2506static void ecm_interface_dev_release(struct device *dev)
2507{
2508
2509}
2510
2511/*
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002512 * ecm_interface_init()
Ben Menchaca84f36632014-02-28 20:57:38 +00002513 */
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002514int ecm_interface_init(void)
Ben Menchaca84f36632014-02-28 20:57:38 +00002515{
2516 int result;
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002517 DEBUG_INFO("ECM Interface init\n");
Ben Menchaca84f36632014-02-28 20:57:38 +00002518
2519 /*
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002520 * Initialise our global lock
Ben Menchaca84f36632014-02-28 20:57:38 +00002521 */
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002522 spin_lock_init(&ecm_interface_lock);
Ben Menchaca84f36632014-02-28 20:57:38 +00002523
2524 /*
Murat Sezgin1f381852014-11-20 09:51:07 -08002525 * Register the sub system
Ben Menchaca84f36632014-02-28 20:57:38 +00002526 */
Murat Sezgin1f381852014-11-20 09:51:07 -08002527 result = subsys_system_register(&ecm_interface_subsys, NULL);
Ben Menchaca84f36632014-02-28 20:57:38 +00002528 if (result) {
Murat Sezgin1f381852014-11-20 09:51:07 -08002529 DEBUG_ERROR("Failed to register sub system %d\n", result);
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002530 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00002531 }
2532
2533 /*
Murat Sezgin1f381852014-11-20 09:51:07 -08002534 * Register system device control
Ben Menchaca84f36632014-02-28 20:57:38 +00002535 */
Murat Sezgin1f381852014-11-20 09:51:07 -08002536 memset(&ecm_interface_dev, 0, sizeof(ecm_interface_dev));
2537 ecm_interface_dev.id = 0;
2538 ecm_interface_dev.bus = &ecm_interface_subsys;
2539 ecm_interface_dev.release = &ecm_interface_dev_release;
2540 result = device_register(&ecm_interface_dev);
Ben Menchaca84f36632014-02-28 20:57:38 +00002541 if (result) {
Murat Sezgin1f381852014-11-20 09:51:07 -08002542 DEBUG_ERROR("Failed to register system device %d\n", result);
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002543 goto task_cleanup_1;
Ben Menchaca84f36632014-02-28 20:57:38 +00002544 }
2545
2546 /*
2547 * Create files, one for each parameter supported by this module
2548 */
Murat Sezgin1f381852014-11-20 09:51:07 -08002549 result = device_create_file(&ecm_interface_dev, &dev_attr_stop);
Ben Menchaca84f36632014-02-28 20:57:38 +00002550 if (result) {
2551 DEBUG_ERROR("Failed to register stop file %d\n", result);
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002552 goto task_cleanup_2;
Ben Menchaca84f36632014-02-28 20:57:38 +00002553 }
2554
2555 result = register_netdevice_notifier(&ecm_interface_netdev_notifier);
2556 if (result != 0) {
2557 DEBUG_ERROR("Failed to register netdevice notifier %d\n", result);
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002558 goto task_cleanup_2;
Ben Menchaca84f36632014-02-28 20:57:38 +00002559 }
2560
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002561 return 0;
Ben Menchaca84f36632014-02-28 20:57:38 +00002562
Ben Menchaca84f36632014-02-28 20:57:38 +00002563task_cleanup_2:
Murat Sezgin1f381852014-11-20 09:51:07 -08002564 device_unregister(&ecm_interface_dev);
Ben Menchaca84f36632014-02-28 20:57:38 +00002565task_cleanup_1:
Murat Sezgin1f381852014-11-20 09:51:07 -08002566 bus_unregister(&ecm_interface_subsys);
Ben Menchaca84f36632014-02-28 20:57:38 +00002567
Ben Menchaca84f36632014-02-28 20:57:38 +00002568 return result;
2569}
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002570EXPORT_SYMBOL(ecm_interface_init);
Ben Menchaca84f36632014-02-28 20:57:38 +00002571
2572/*
2573 * ecm_interface_exit()
2574 */
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002575void ecm_interface_exit(void)
Ben Menchaca84f36632014-02-28 20:57:38 +00002576{
2577 DEBUG_INFO("ECM Interface exit\n");
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002578
2579 spin_lock_bh(&ecm_interface_lock);
2580 ecm_interface_terminate_pending = true;
2581 spin_unlock_bh(&ecm_interface_lock);
2582
2583 unregister_netdevice_notifier(&ecm_interface_netdev_notifier);
Murat Sezgin1f381852014-11-20 09:51:07 -08002584
2585 device_remove_file(&ecm_interface_dev, &dev_attr_stop);
2586 device_unregister(&ecm_interface_dev);
2587 bus_unregister(&ecm_interface_subsys);
Ben Menchaca84f36632014-02-28 20:57:38 +00002588}
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002589EXPORT_SYMBOL(ecm_interface_exit);