blob: febf03ee68105b37872cf24300c53685d7ea7cf9 [file] [log] [blame]
Ben Menchaca84f36632014-02-28 20:57:38 +00001/*
2 **************************************************************************
3 * Copyright (c) 2014, The Linux Foundation. All rights reserved.
4 * 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 Sezginb3731e82014-11-26 12:20:59 -080047#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3,6,0))
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
Ben Menchaca84f36632014-02-28 20:57:38 +000070
71/*
72 * Debug output levels
73 * 0 = OFF
74 * 1 = ASSERTS / ERRORS
75 * 2 = 1 + WARN
76 * 3 = 2 + INFO
77 * 4 = 3 + TRACE
78 */
79#define DEBUG_LEVEL ECM_INTERFACE_DEBUG_LEVEL
80
81#include <nss_api_if.h>
82
83#include "ecm_types.h"
84#include "ecm_db_types.h"
85#include "ecm_tracker.h"
86#include "ecm_classifier.h"
87#include "ecm_front_end_types.h"
88#include "ecm_tracker_datagram.h"
89#include "ecm_tracker_udp.h"
90#include "ecm_tracker_tcp.h"
91#include "ecm_db.h"
92#include "ecm_interface.h"
93
Murat Sezgin49465a42014-11-24 15:37:48 -080094#ifdef ECM_FRONT_END_IPV6_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +000095/*
Gareth Williamsadf425f2014-05-26 19:29:02 +010096 * TODO: Remove once the Linux image and headers get propogated.
97 */
98struct net_device *ipv6_dev_find(struct net *net, struct in6_addr *addr, int strict);
Murat Sezgin49465a42014-11-24 15:37:48 -080099#endif
Gareth Williamsadf425f2014-05-26 19:29:02 +0100100
101/*
Ben Menchaca84f36632014-02-28 20:57:38 +0000102 * Locking - concurrency control
103 */
104static spinlock_t ecm_interface_lock; /* Protect against SMP access between netfilter, events and private threaded function. */
105
106/*
Murat Sezgin1f381852014-11-20 09:51:07 -0800107 * System device linkage
Ben Menchaca84f36632014-02-28 20:57:38 +0000108 */
Murat Sezgin1f381852014-11-20 09:51:07 -0800109static struct device ecm_interface_dev; /* System device linkage */
Ben Menchaca84f36632014-02-28 20:57:38 +0000110
111/*
112 * General operational control
113 */
114static int ecm_interface_stopped = 0; /* When non-zero further traffic will not be processed */
115
116/*
117 * Management thread control
118 */
119static bool ecm_interface_terminate_pending = false; /* True when the user has signalled we should quit */
Ben Menchaca84f36632014-02-28 20:57:38 +0000120
121/*
Murat Sezginb3731e82014-11-26 12:20:59 -0800122 * ecm_interface_get_and_hold_dev_master()
123 * Returns the master device of a net device if any.
124 */
125struct net_device *ecm_interface_get_and_hold_dev_master(struct net_device *dev)
126{
127 struct net_device *master;
128#if (LINUX_VERSION_CODE > KERNEL_VERSION(3,6,0))
129 rcu_read_lock();
130 master = netdev_master_upper_dev_get_rcu(dev);
131 if (!master) {
132 rcu_read_unlock();
133 return NULL;
134 }
135 dev_hold(master);
136 rcu_read_unlock();
137#else
138 master = dev->master;
139 if (!master) {
140 return NULL;
141 }
142 dev_hold(master);
143#endif
144 return master;
145}
146EXPORT_SYMBOL(ecm_interface_get_and_hold_dev_master);
147
148/*
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100149 * ecm_interface_dev_find_by_local_addr_ipv4()
150 * Return a hold to the device for the given local IP address. Returns NULL on failure.
Gareth Williamsadf425f2014-05-26 19:29:02 +0100151 */
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100152static struct net_device *ecm_interface_dev_find_by_local_addr_ipv4(ip_addr_t addr)
Gareth Williamsadf425f2014-05-26 19:29:02 +0100153{
154 __be32 be_addr;
155 struct net_device *dev;
156
157 ECM_IP_ADDR_TO_NIN4_ADDR(be_addr, addr);
158 dev = ip_dev_find(&init_net, be_addr);
159 return dev;
160}
161
Murat Sezgin49465a42014-11-24 15:37:48 -0800162#ifdef ECM_FRONT_END_IPV6_ENABLE
Gareth Williamsadf425f2014-05-26 19:29:02 +0100163/*
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100164 * ecm_interface_dev_find_by_local_addr_ipv6()
165 * Return a hold to the device for the given local IP address. Returns NULL on failure.
Gareth Williamsadf425f2014-05-26 19:29:02 +0100166 */
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100167static struct net_device *ecm_interface_dev_find_by_local_addr_ipv6(ip_addr_t addr)
Gareth Williamsadf425f2014-05-26 19:29:02 +0100168{
169 struct in6_addr addr6;
170 struct net_device *dev;
171
172 ECM_IP_ADDR_TO_NIN6_ADDR(addr6, addr);
173 dev = (struct net_device *)ipv6_dev_find(&init_net, &addr6, 1);
174 return dev;
175}
Murat Sezgin49465a42014-11-24 15:37:48 -0800176#endif
Gareth Williamsadf425f2014-05-26 19:29:02 +0100177
178/*
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100179 * ecm_interface_dev_find_by_local_addr()
180 * Return the device on which the local address resides.
Gareth Williamsadf425f2014-05-26 19:29:02 +0100181 *
182 * Returns a hold to the device or NULL on failure.
183 */
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100184struct net_device *ecm_interface_dev_find_by_local_addr(ip_addr_t addr)
Gareth Williamsadf425f2014-05-26 19:29:02 +0100185{
186 char __attribute__((unused)) addr_str[40];
187
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100188 DEBUG_ECM_IP_ADDR_TO_STRING(addr_str, addr);
Gareth Williamsadf425f2014-05-26 19:29:02 +0100189 DEBUG_TRACE("Locate dev for: %s\n", addr_str);
190
191 if (ECM_IP_ADDR_IS_V4(addr)) {
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100192 return ecm_interface_dev_find_by_local_addr_ipv4(addr);
Gareth Williamsadf425f2014-05-26 19:29:02 +0100193 }
194
Murat Sezgin49465a42014-11-24 15:37:48 -0800195#ifdef ECM_FRONT_END_IPV6_ENABLE
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100196 return ecm_interface_dev_find_by_local_addr_ipv6(addr);
Murat Sezgin49465a42014-11-24 15:37:48 -0800197#else
198 return NULL;
199#endif
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100200}
201EXPORT_SYMBOL(ecm_interface_dev_find_by_local_addr);
202
203/*
204 * ecm_interface_dev_find_by_addr()
205 * Return the net device on which the given IP address resides. Returns NULL on faiure.
206 *
207 * NOTE: The device may be the device upon which has a default gateway to reach the address.
208 * from_local_addr is true when the device was found by a local address search.
209 */
210struct net_device *ecm_interface_dev_find_by_addr(ip_addr_t addr, bool *from_local_addr)
211{
212 char __attribute__((unused)) addr_str[40];
213 struct ecm_interface_route ecm_rt;
214 struct net_device *dev;
215 struct dst_entry *dst;
216
217 DEBUG_ECM_IP_ADDR_TO_STRING(addr_str, addr);
218
219 /*
220 * Is the address a local IP?
221 */
222 DEBUG_TRACE("find net device for address: %s\n", addr_str);
223 dev = ecm_interface_dev_find_by_local_addr(addr);
224 if (dev) {
225 *from_local_addr = true;
226 DEBUG_TRACE("addr: %s is local: %p (%s)\n", addr_str, dev, dev->name);
227 return dev;
228 }
229
230 DEBUG_TRACE("addr: %s is not local\n", addr_str);
231
232 /*
233 * Try a route to the address instead
234 * NOTE: This will locate a route entry in the route destination *cache*.
235 */
236 if (!ecm_interface_find_route_by_addr(addr, &ecm_rt)) {
237 DEBUG_WARN("addr: %s - no dev locatable\n", addr_str);
238 return NULL;
239 }
240
241 *from_local_addr = false;
242 dst = ecm_rt.dst;
243 dev = dst->dev;
244 dev_hold(dev);
245 ecm_interface_route_release(&ecm_rt);
246 DEBUG_TRACE("dest_addr: %s uses dev: %p(%s)\n", addr_str, dev, dev->name);
247 return dev;
Gareth Williamsadf425f2014-05-26 19:29:02 +0100248}
249EXPORT_SYMBOL(ecm_interface_dev_find_by_addr);
250
Murat Sezgin49465a42014-11-24 15:37:48 -0800251#ifdef ECM_FRONT_END_IPV6_ENABLE
Gareth Williamsadf425f2014-05-26 19:29:02 +0100252/*
Ben Menchaca84f36632014-02-28 20:57:38 +0000253 * ecm_interface_mac_addr_get_ipv6()
254 * Return mac for an IPv6 address
255 *
256 * GGG TODO Need to make sure this also works for local IP addresses too.
257 */
258static bool ecm_interface_mac_addr_get_ipv6(ip_addr_t addr, uint8_t *mac_addr, bool *on_link, ip_addr_t gw_addr)
259{
260 struct in6_addr daddr;
261 struct ecm_interface_route ecm_rt;
262 struct neighbour *neigh;
263 struct rt6_info *rt;
264 struct dst_entry *dst;
265
266 /*
267 * Get the MAC address that corresponds to IP address given.
268 * We look up the rt6_info entries and, from its neighbour structure, obtain the hardware address.
269 * This means we will also work if the neighbours are routers too.
270 */
271 ECM_IP_ADDR_TO_NIN6_ADDR(daddr, addr);
272 if (!ecm_interface_find_route_by_addr(addr, &ecm_rt)) {
Kiran Kumar C. S. K7d178222014-06-27 18:47:29 +0530273 *on_link = false;
Ben Menchaca84f36632014-02-28 20:57:38 +0000274 return false;
275 }
276 DEBUG_ASSERT(!ecm_rt.v4_route, "Did not locate a v6 route!\n");
277
278 /*
279 * Is this destination on link or off-link via a gateway?
280 */
281 rt = ecm_rt.rt.rtv6;
282 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)) {
283 *on_link = false;
284 ECM_NIN6_ADDR_TO_IP_ADDR(gw_addr, rt->rt6i_gateway)
285 } else {
286 *on_link = true;
287 }
288
289 rcu_read_lock();
290 dst = ecm_rt.dst;
291 neigh = dst_get_neighbour_noref(dst);
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700292 if (neigh) {
293 neigh_hold(neigh);
294 } else {
295 neigh = neigh_lookup(&nd_tbl, &daddr, dst->dev);
296 }
Ben Menchaca84f36632014-02-28 20:57:38 +0000297 if (!neigh) {
298 rcu_read_unlock();
299 ecm_interface_route_release(&ecm_rt);
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700300 DEBUG_WARN("No neigh reference\n");
Ben Menchaca84f36632014-02-28 20:57:38 +0000301 return false;
302 }
303 if (!(neigh->nud_state & NUD_VALID)) {
304 rcu_read_unlock();
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700305 neigh_release(neigh);
Ben Menchaca84f36632014-02-28 20:57:38 +0000306 ecm_interface_route_release(&ecm_rt);
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700307 DEBUG_WARN("NUD invalid\n");
Ben Menchaca84f36632014-02-28 20:57:38 +0000308 return false;
309 }
310 if (!neigh->dev) {
311 rcu_read_unlock();
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700312 neigh_release(neigh);
Ben Menchaca84f36632014-02-28 20:57:38 +0000313 ecm_interface_route_release(&ecm_rt);
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700314 DEBUG_WARN("Neigh dev invalid\n");
Ben Menchaca84f36632014-02-28 20:57:38 +0000315 return false;
316 }
317
318 /*
319 * If neigh->dev is a loopback then addr is a local address in which case we take the MAC from given device
320 */
321 if (neigh->dev->flags & IFF_LOOPBACK) {
322 // GGG TODO Create an equivalent logic to that for ipv4, maybe need to create an ip6_dev_find()?
323 DEBUG_TRACE("local address " ECM_IP_ADDR_OCTAL_FMT " (found loopback)\n", ECM_IP_ADDR_TO_OCTAL(addr));
324 memset(mac_addr, 0, 6);
325 } else {
326 memcpy(mac_addr, neigh->ha, 6);
327 }
328 rcu_read_unlock();
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700329 neigh_release(neigh);
Ben Menchaca84f36632014-02-28 20:57:38 +0000330 ecm_interface_route_release(&ecm_rt);
331
332 DEBUG_TRACE(ECM_IP_ADDR_OCTAL_FMT " maps to %pM\n", ECM_IP_ADDR_TO_OCTAL(addr), mac_addr);
333 return true;
334}
Murat Sezgin49465a42014-11-24 15:37:48 -0800335#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000336
337/*
338 * ecm_interface_mac_addr_get_ipv4()
339 * Return mac for an IPv4 address
340 */
341static bool ecm_interface_mac_addr_get_ipv4(ip_addr_t addr, uint8_t *mac_addr, bool *on_link, ip_addr_t gw_addr)
342{
343 struct neighbour *neigh;
344 struct ecm_interface_route ecm_rt;
345 struct rtable *rt;
346 struct dst_entry *dst;
347 __be32 ipv4_addr;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530348
Ben Menchaca84f36632014-02-28 20:57:38 +0000349 /*
350 * Get the MAC address that corresponds to IP address given.
351 * We look up the rtable entries and, from its neighbour structure, obtain the hardware address.
352 * This means we will also work if the neighbours are routers too.
353 * We also locate the MAC if the address is a local host address.
354 */
355 ECM_IP_ADDR_TO_NIN4_ADDR(ipv4_addr, addr);
356 if (!ecm_interface_find_route_by_addr(addr, &ecm_rt)) {
Kiran Kumar C. S. K7d178222014-06-27 18:47:29 +0530357 *on_link = false;
Ben Menchaca84f36632014-02-28 20:57:38 +0000358 return false;
359 }
360 DEBUG_ASSERT(ecm_rt.v4_route, "Did not locate a v4 route!\n");
Murat Sezginb3731e82014-11-26 12:20:59 -0800361 DEBUG_TRACE("Found route\n");
Ben Menchaca84f36632014-02-28 20:57:38 +0000362
363 /*
364 * Is this destination on link or off-link via a gateway?
365 */
366 rt = ecm_rt.rt.rtv4;
Murat Sezginb3731e82014-11-26 12:20:59 -0800367#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3,6,0))
Ben Menchaca84f36632014-02-28 20:57:38 +0000368 if ((rt->rt_dst != rt->rt_gateway) || (rt->rt_flags & RTF_GATEWAY)) {
Murat Sezginb3731e82014-11-26 12:20:59 -0800369#else
370 if (rt->rt_uses_gateway || (rt->rt_flags & RTF_GATEWAY)) {
371#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000372 *on_link = false;
373 ECM_NIN4_ADDR_TO_IP_ADDR(gw_addr, rt->rt_gateway)
374 } else {
375 *on_link = true;
376 }
377
378 /*
379 * Get the neighbour entry for the address
380 */
381 rcu_read_lock();
382 dst = ecm_rt.dst;
Murat Sezginb3731e82014-11-26 12:20:59 -0800383#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3,6,0))
Ben Menchaca84f36632014-02-28 20:57:38 +0000384 neigh = dst_get_neighbour_noref(dst);
385 if (neigh) {
386 neigh_hold(neigh);
Murat Sezginb3731e82014-11-26 12:20:59 -0800387 }
388#else
389 neigh = dst_neigh_lookup(dst, &ipv4_addr);
390#endif
391 if (!neigh) {
Ben Menchaca84f36632014-02-28 20:57:38 +0000392 neigh = neigh_lookup(&arp_tbl, &ipv4_addr, dst->dev);
393 }
394 if (!neigh) {
395 rcu_read_unlock();
396 ecm_interface_route_release(&ecm_rt);
Murat Sezginb3731e82014-11-26 12:20:59 -0800397 DEBUG_WARN("no neigh\n");
Ben Menchaca84f36632014-02-28 20:57:38 +0000398 return false;
399 }
400 if (!(neigh->nud_state & NUD_VALID)) {
401 rcu_read_unlock();
402 neigh_release(neigh);
403 ecm_interface_route_release(&ecm_rt);
Murat Sezginb3731e82014-11-26 12:20:59 -0800404 DEBUG_WARN("neigh nud state is not valid\n");
Ben Menchaca84f36632014-02-28 20:57:38 +0000405 return false;
406 }
407 if (!neigh->dev) {
408 rcu_read_unlock();
409 neigh_release(neigh);
410 ecm_interface_route_release(&ecm_rt);
Murat Sezginb3731e82014-11-26 12:20:59 -0800411 DEBUG_WARN("neigh has no device\n");
Ben Menchaca84f36632014-02-28 20:57:38 +0000412 return false;
413 }
414
415 /*
416 * If the device is loopback this will be because the address is a local address
417 * In this case locate the device that has this local address and get its mac.
418 */
419 if (neigh->dev->type == ARPHRD_LOOPBACK) {
420 struct net_device *dev;
421
422 DEBUG_TRACE("%pI4 finds loopback device, dev: %p (%s)\n", &ipv4_addr, neigh->dev, neigh->dev->name);
423 rcu_read_unlock();
424 neigh_release(neigh);
425 ecm_interface_route_release(&ecm_rt);
426
427 /*
428 * Lookup the device that has this IP address assigned
429 */
430 dev = ip_dev_find(&init_net, ipv4_addr);
431 if (!dev) {
432 DEBUG_WARN("Unable to locate dev for: %pI4\n", &ipv4_addr);
433 return false;
434 }
435 memcpy(mac_addr, dev->dev_addr, (size_t)dev->addr_len);
436 DEBUG_TRACE("is local addr: %pI4, mac: %pM, dev ifindex: %d, dev: %p (%s), dev_type: %d\n",
437 &ipv4_addr, mac_addr, dev->ifindex, dev, dev->name, dev->type);
438 dev_put(dev);
439 return true;
440 }
441
442 if (!(neigh->dev->flags & IFF_NOARP)) {
443 memcpy(mac_addr, neigh->ha, (size_t)neigh->dev->addr_len);
444 } else {
445 DEBUG_TRACE("non-arp device: %p (%s, type: %d) to reach %pI4\n", neigh->dev, neigh->dev->name, neigh->dev->type, &ipv4_addr);
446 memset(mac_addr, 0, 6);
447 }
448 DEBUG_TRACE("addr: %pI4, mac: %pM, iif: %d, neigh dev ifindex: %d, dev: %p (%s), dev_type: %d\n",
449 &ipv4_addr, mac_addr, rt->rt_iif, neigh->dev->ifindex, neigh->dev, neigh->dev->name, neigh->dev->type);
450
451 rcu_read_unlock();
452 neigh_release(neigh);
453 ecm_interface_route_release(&ecm_rt);
454 return true;
455}
456
457/*
458 * ecm_interface_mac_addr_get()
459 * Return the mac address for the given IP address. Returns false on failure.
460 *
461 * 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.
462 *
463 * GGG TODO Make this function work for IPv6!!!!!!!!!!!!!!
464 */
465bool ecm_interface_mac_addr_get(ip_addr_t addr, uint8_t *mac_addr, bool *on_link, ip_addr_t gw_addr)
466{
467 if (ECM_IP_ADDR_IS_V4(addr)) {
468 return ecm_interface_mac_addr_get_ipv4(addr, mac_addr, on_link, gw_addr);
469 }
470
Murat Sezgin49465a42014-11-24 15:37:48 -0800471#ifdef ECM_FRONT_END_IPV6_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000472 return ecm_interface_mac_addr_get_ipv6(addr, mac_addr, on_link, gw_addr);
Murat Sezgin49465a42014-11-24 15:37:48 -0800473#else
474 return false;
475#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000476}
477EXPORT_SYMBOL(ecm_interface_mac_addr_get);
478
479/*
480 * ecm_interface_addr_find_route_by_addr_ipv4()
481 * Return the route for the given IP address. Returns NULL on failure.
482 */
483static bool ecm_interface_find_route_by_addr_ipv4(ip_addr_t addr, struct ecm_interface_route *ecm_rt)
484{
485 __be32 be_addr;
486
487 /*
488 * Get a route to the given IP address, this will allow us to also find the interface
489 * it is using to communicate with that IP address.
490 */
491 ECM_IP_ADDR_TO_NIN4_ADDR(be_addr, addr);
492 ecm_rt->rt.rtv4 = ip_route_output(&init_net, be_addr, 0, 0, 0);
493 if (IS_ERR(ecm_rt->rt.rtv4)) {
494 DEBUG_TRACE("No output route to: %pI4n\n", &be_addr);
495 return false;
496 }
497 DEBUG_TRACE("Output route to: %pI4n is: %p\n", &be_addr, ecm_rt->rt.rtv4);
498 ecm_rt->dst = (struct dst_entry *)ecm_rt->rt.rtv4;
499 ecm_rt->v4_route = true;
500 return true;
501}
502
Murat Sezgin49465a42014-11-24 15:37:48 -0800503#ifdef ECM_FRONT_END_IPV6_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000504/*
505 * ecm_interface_addr_find_route_by_addr_ipv6()
506 * Return the route for the given IP address. Returns NULL on failure.
507 */
508static bool ecm_interface_find_route_by_addr_ipv6(ip_addr_t addr, struct ecm_interface_route *ecm_rt)
509{
510 struct in6_addr naddr;
511
512 ECM_IP_ADDR_TO_NIN6_ADDR(naddr, addr);
513
514 /*
515 * Get a route to the given IP address, this will allow us to also find the interface
516 * it is using to communicate with that IP address.
517 */
518 ecm_rt->rt.rtv6 = rt6_lookup(&init_net, &naddr, NULL, 0, 0);
519 if (!ecm_rt->rt.rtv6) {
520 DEBUG_TRACE("No output route to: " ECM_IP_ADDR_OCTAL_FMT "\n", ECM_IP_ADDR_TO_OCTAL(addr));
521 return NULL;
522 }
523 DEBUG_TRACE("Output route to: " ECM_IP_ADDR_OCTAL_FMT " is: %p\n", ECM_IP_ADDR_TO_OCTAL(addr), ecm_rt->rt.rtv6);
524 ecm_rt->dst = (struct dst_entry *)ecm_rt->rt.rtv6;
525 ecm_rt->v4_route = false;
526 return true;
527}
Murat Sezgin49465a42014-11-24 15:37:48 -0800528#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000529
530/*
531 * ecm_interface_addr_find_route_by_addr()
532 * Return the route (in the given parameter) for the given IP address. Returns false on failure.
533 *
534 * Route is the device on which the addr is reachable, which may be loopback for local addresses.
535 *
536 * Returns true if the route was able to be located. The route must be released using ecm_interface_route_release().
537 */
538bool ecm_interface_find_route_by_addr(ip_addr_t addr, struct ecm_interface_route *ecm_rt)
539{
540 char __attribute__((unused)) addr_str[40];
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530541
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100542 DEBUG_ECM_IP_ADDR_TO_STRING(addr_str, addr);
Ben Menchaca84f36632014-02-28 20:57:38 +0000543 DEBUG_TRACE("Locate route to: %s\n", addr_str);
544
545 if (ECM_IP_ADDR_IS_V4(addr)) {
546 return ecm_interface_find_route_by_addr_ipv4(addr, ecm_rt);
547 }
548
Murat Sezgin49465a42014-11-24 15:37:48 -0800549#ifdef ECM_FRONT_END_IPV6_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000550 return ecm_interface_find_route_by_addr_ipv6(addr, ecm_rt);
Murat Sezgin49465a42014-11-24 15:37:48 -0800551#else
552 return false;
553#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000554}
555EXPORT_SYMBOL(ecm_interface_find_route_by_addr);
556
557/*
558 * ecm_interface_route_release()
559 * Release an ecm route
560 */
561void ecm_interface_route_release(struct ecm_interface_route *rt)
562{
563 dst_release(rt->dst);
564}
565EXPORT_SYMBOL(ecm_interface_route_release);
566
Gareth Williams141d2382014-11-25 11:35:19 -0800567#ifdef ECM_INTERFACE_VLAN_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000568/*
Ben Menchaca84f36632014-02-28 20:57:38 +0000569 * ecm_interface_vlan_interface_establish()
570 * Returns a reference to a iface of the VLAN type, possibly creating one if necessary.
571 * Returns NULL on failure or a reference to interface.
572 */
573static struct ecm_db_iface_instance *ecm_interface_vlan_interface_establish(struct ecm_db_interface_info_vlan *type_info,
574 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
575{
576 struct ecm_db_iface_instance *nii;
577 struct ecm_db_iface_instance *ii;
578
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530579 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",
580 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 +0000581
582 /*
583 * Locate the iface
584 */
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530585 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 +0000586 if (ii) {
587 DEBUG_TRACE("%p: iface established\n", ii);
588 return ii;
589 }
590
591 /*
592 * No iface - create one
593 */
594 nii = ecm_db_iface_alloc();
595 if (!nii) {
596 DEBUG_WARN("Failed to establish iface\n");
597 return NULL;
598 }
599
600 /*
601 * Add iface into the database, atomically to avoid races creating the same thing
602 */
603 spin_lock_bh(&ecm_interface_lock);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530604 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 +0000605 if (ii) {
606 spin_unlock_bh(&ecm_interface_lock);
607 ecm_db_iface_deref(nii);
608 return ii;
609 }
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530610 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 -0500611 mtu, dev_interface_num, nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000612 spin_unlock_bh(&ecm_interface_lock);
613
614 DEBUG_TRACE("%p: vlan iface established\n", nii);
615 return nii;
616}
Gareth Williams141d2382014-11-25 11:35:19 -0800617#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000618
619/*
620 * ecm_interface_bridge_interface_establish()
621 * Returns a reference to a iface of the BRIDGE type, possibly creating one if necessary.
622 * Returns NULL on failure or a reference to interface.
623 */
624static struct ecm_db_iface_instance *ecm_interface_bridge_interface_establish(struct ecm_db_interface_info_bridge *type_info,
625 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
626{
627 struct ecm_db_iface_instance *nii;
628 struct ecm_db_iface_instance *ii;
629
630 DEBUG_INFO("Establish BRIDGE iface: %s with address: %pM, MTU: %d, if num: %d, nss if id: %d\n",
631 dev_name, type_info->address, mtu, dev_interface_num, nss_interface_num);
632
633 /*
634 * Locate the iface
635 */
636 ii = ecm_db_iface_find_and_ref_bridge(type_info->address);
637 if (ii) {
638 DEBUG_TRACE("%p: iface established\n", ii);
639 return ii;
640 }
641
642 /*
643 * No iface - create one
644 */
645 nii = ecm_db_iface_alloc();
646 if (!nii) {
647 DEBUG_WARN("Failed to establish iface\n");
648 return NULL;
649 }
650
651 /*
652 * Add iface into the database, atomically to avoid races creating the same thing
653 */
654 spin_lock_bh(&ecm_interface_lock);
655 ii = ecm_db_iface_find_and_ref_bridge(type_info->address);
656 if (ii) {
657 spin_unlock_bh(&ecm_interface_lock);
658 ecm_db_iface_deref(nii);
659 return ii;
660 }
661 ecm_db_iface_add_bridge(nii, type_info->address, dev_name,
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500662 mtu, dev_interface_num, nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000663 spin_unlock_bh(&ecm_interface_lock);
664
665 DEBUG_TRACE("%p: bridge iface established\n", nii);
666 return nii;
667}
668
669/*
670 * ecm_interface_lag_interface_establish()
671 * Returns a reference to a iface of the LAG type, possibly creating one if necessary.
672 * Returns NULL on failure or a reference to interface.
673 */
674static struct ecm_db_iface_instance *ecm_interface_lag_interface_establish(struct ecm_db_interface_info_lag *type_info,
675 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
676{
677 struct ecm_db_iface_instance *nii;
678 struct ecm_db_iface_instance *ii;
679
680 DEBUG_INFO("Establish LAG iface: %s with address: %pM, MTU: %d, if num: %d, nss if id: %d\n",
681 dev_name, type_info->address, mtu, dev_interface_num, nss_interface_num);
682
683 /*
684 * Locate the iface
685 */
686 ii = ecm_db_iface_find_and_ref_lag(type_info->address);
687 if (ii) {
688 DEBUG_TRACE("%p: iface established\n", ii);
689 return ii;
690 }
691
692 /*
693 * No iface - create one
694 */
695 nii = ecm_db_iface_alloc();
696 if (!nii) {
697 DEBUG_WARN("Failed to establish iface\n");
698 return NULL;
699 }
700
701 /*
702 * Add iface into the database, atomically to avoid races creating the same thing
703 */
704 spin_lock_bh(&ecm_interface_lock);
705 ii = ecm_db_iface_find_and_ref_lag(type_info->address);
706 if (ii) {
707 spin_unlock_bh(&ecm_interface_lock);
708 ecm_db_iface_deref(nii);
709 return ii;
710 }
711 ecm_db_iface_add_lag(nii, type_info->address, dev_name,
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500712 mtu, dev_interface_num, nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000713 spin_unlock_bh(&ecm_interface_lock);
714
715 DEBUG_TRACE("%p: lag iface established\n", nii);
716 return nii;
717}
718
719/*
720 * ecm_interface_ethernet_interface_establish()
721 * Returns a reference to a iface of the ETHERNET type, possibly creating one if necessary.
722 * Returns NULL on failure or a reference to interface.
723 */
724static struct ecm_db_iface_instance *ecm_interface_ethernet_interface_establish(struct ecm_db_interface_info_ethernet *type_info,
725 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
726{
727 struct ecm_db_iface_instance *nii;
728 struct ecm_db_iface_instance *ii;
729
730 DEBUG_INFO("Establish ETHERNET iface: %s with address: %pM, MTU: %d, if num: %d, nss if id: %d\n",
731 dev_name, type_info->address, mtu, dev_interface_num, nss_interface_num);
732
733 /*
734 * Locate the iface
735 */
Tushar Mathur4ab0bf92014-06-10 20:37:07 +0530736 ii = ecm_db_iface_ifidx_find_and_ref_ethernet(type_info->address, dev_interface_num);
737
Ben Menchaca84f36632014-02-28 20:57:38 +0000738 if (ii) {
739 DEBUG_TRACE("%p: iface established\n", ii);
740 return ii;
741 }
742
743 /*
744 * No iface - create one
745 */
746 nii = ecm_db_iface_alloc();
747 if (!nii) {
748 DEBUG_WARN("Failed to establish iface\n");
749 return NULL;
750 }
751
752 /*
753 * Add iface into the database, atomically to avoid races creating the same thing
754 */
755 spin_lock_bh(&ecm_interface_lock);
Tushar Mathur4ab0bf92014-06-10 20:37:07 +0530756 ii = ecm_db_iface_ifidx_find_and_ref_ethernet(type_info->address, dev_interface_num);
Ben Menchaca84f36632014-02-28 20:57:38 +0000757 if (ii) {
758 spin_unlock_bh(&ecm_interface_lock);
759 ecm_db_iface_deref(nii);
760 return ii;
761 }
762 ecm_db_iface_add_ethernet(nii, type_info->address, dev_name,
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500763 mtu, dev_interface_num, nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000764 spin_unlock_bh(&ecm_interface_lock);
765
766 DEBUG_TRACE("%p: ethernet iface established\n", nii);
767 return nii;
768}
769
Gareth Williamsdbb2bfd2014-11-20 16:42:09 -0800770#ifdef ECM_INTERFACE_PPP_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000771/*
772 * ecm_interface_pppoe_interface_establish()
773 * Returns a reference to a iface of the PPPoE type, possibly creating one if necessary.
774 * Returns NULL on failure or a reference to interface.
775 */
776static struct ecm_db_iface_instance *ecm_interface_pppoe_interface_establish(struct ecm_db_interface_info_pppoe *type_info,
777 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
778{
779 struct ecm_db_iface_instance *nii;
780 struct ecm_db_iface_instance *ii;
781
782 DEBUG_INFO("Establish PPPoE iface: %s with session id: %u, remote mac: %pM, MTU: %d, if num: %d, nss if id: %d\n",
783 dev_name, type_info->pppoe_session_id, type_info->remote_mac, mtu, dev_interface_num, nss_interface_num);
784
785 /*
786 * Locate the iface
787 */
788 ii = ecm_db_iface_find_and_ref_pppoe(type_info->pppoe_session_id, type_info->remote_mac);
789 if (ii) {
790 DEBUG_TRACE("%p: iface established\n", ii);
791 return ii;
792 }
793
794 /*
795 * No iface - create one
796 */
797 nii = ecm_db_iface_alloc();
798 if (!nii) {
799 DEBUG_WARN("Failed to establish iface\n");
800 return NULL;
801 }
802
803 /*
804 * Add iface into the database, atomically to avoid races creating the same thing
805 */
806 spin_lock_bh(&ecm_interface_lock);
807 ii = ecm_db_iface_find_and_ref_pppoe(type_info->pppoe_session_id, type_info->remote_mac);
808 if (ii) {
809 spin_unlock_bh(&ecm_interface_lock);
810 ecm_db_iface_deref(nii);
811 return ii;
812 }
813 ecm_db_iface_add_pppoe(nii, type_info->pppoe_session_id, type_info->remote_mac, dev_name,
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500814 mtu, dev_interface_num, nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000815 spin_unlock_bh(&ecm_interface_lock);
816
817 DEBUG_TRACE("%p: pppoe iface established\n", nii);
818 return nii;
819}
Gareth Williamsc5b9d712014-05-09 20:40:07 +0100820#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000821
822/*
823 * ecm_interface_unknown_interface_establish()
824 * Returns a reference to a iface of the UNKNOWN type, possibly creating one if necessary.
825 * Returns NULL on failure or a reference to interface.
826 */
827static struct ecm_db_iface_instance *ecm_interface_unknown_interface_establish(struct ecm_db_interface_info_unknown *type_info,
828 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
829{
830 struct ecm_db_iface_instance *nii;
831 struct ecm_db_iface_instance *ii;
832
833 DEBUG_INFO("Establish UNKNOWN iface: %s with os_specific_ident: %u, MTU: %d, if num: %d, nss if id: %d\n",
834 dev_name, type_info->os_specific_ident, mtu, dev_interface_num, nss_interface_num);
835
836 /*
837 * Locate the iface
838 */
839 ii = ecm_db_iface_find_and_ref_unknown(type_info->os_specific_ident);
840 if (ii) {
841 DEBUG_TRACE("%p: iface established\n", ii);
842 return ii;
843 }
844
845 /*
846 * No iface - create one
847 */
848 nii = ecm_db_iface_alloc();
849 if (!nii) {
850 DEBUG_WARN("Failed to establish iface\n");
851 return NULL;
852 }
853
854 /*
855 * Add iface into the database, atomically to avoid races creating the same thing
856 */
857 spin_lock_bh(&ecm_interface_lock);
858 ii = ecm_db_iface_find_and_ref_unknown(type_info->os_specific_ident);
859 if (ii) {
860 spin_unlock_bh(&ecm_interface_lock);
861 ecm_db_iface_deref(nii);
862 return ii;
863 }
864 ecm_db_iface_add_unknown(nii, type_info->os_specific_ident, dev_name,
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500865 mtu, dev_interface_num, nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000866 spin_unlock_bh(&ecm_interface_lock);
867
868 DEBUG_TRACE("%p: unknown iface established\n", nii);
869 return nii;
870}
871
872/*
873 * ecm_interface_loopback_interface_establish()
874 * Returns a reference to a iface of the LOOPBACK type, possibly creating one if necessary.
875 * Returns NULL on failure or a reference to interface.
876 */
877static struct ecm_db_iface_instance *ecm_interface_loopback_interface_establish(struct ecm_db_interface_info_loopback *type_info,
878 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
879{
880 struct ecm_db_iface_instance *nii;
881 struct ecm_db_iface_instance *ii;
882
883 DEBUG_INFO("Establish LOOPBACK iface: %s with os_specific_ident: %u, MTU: %d, if num: %d, nss if id: %d\n",
884 dev_name, type_info->os_specific_ident, mtu, dev_interface_num, nss_interface_num);
885
886 /*
887 * Locate the iface
888 */
889 ii = ecm_db_iface_find_and_ref_loopback(type_info->os_specific_ident);
890 if (ii) {
891 DEBUG_TRACE("%p: iface established\n", ii);
892 return ii;
893 }
894
895 /*
896 * No iface - create one
897 */
898 nii = ecm_db_iface_alloc();
899 if (!nii) {
900 DEBUG_WARN("Failed to establish iface\n");
901 return NULL;
902 }
903
904 /*
905 * Add iface into the database, atomically to avoid races creating the same thing
906 */
907 spin_lock_bh(&ecm_interface_lock);
908 ii = ecm_db_iface_find_and_ref_loopback(type_info->os_specific_ident);
909 if (ii) {
910 spin_unlock_bh(&ecm_interface_lock);
911 ecm_db_iface_deref(nii);
912 return ii;
913 }
914 ecm_db_iface_add_loopback(nii, type_info->os_specific_ident, dev_name,
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500915 mtu, dev_interface_num, nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000916 spin_unlock_bh(&ecm_interface_lock);
917
918 DEBUG_TRACE("%p: loopback iface established\n", nii);
919 return nii;
920}
921
922/*
923 * ecm_interface_ipsec_tunnel_interface_establish()
924 * Returns a reference to a iface of the IPSEC_TUNNEL type, possibly creating one if necessary.
925 * Returns NULL on failure or a reference to interface.
926 *
927 * NOTE: GGG TODO THIS NEEDS TO TAKE A PROPER APPROACH TO IPSEC TUNNELS USING ENDPOINT ADDRESSING AS THE TYPE INFO KEYS
928 */
929static struct ecm_db_iface_instance *ecm_interface_ipsec_tunnel_interface_establish(struct ecm_db_interface_info_ipsec_tunnel *type_info,
930 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
931{
932 struct ecm_db_iface_instance *nii;
933 struct ecm_db_iface_instance *ii;
934
935 DEBUG_INFO("Establish IPSEC_TUNNEL iface: %s with os_specific_ident: %u, MTU: %d, if num: %d, nss if id: %d\n",
936 dev_name, type_info->os_specific_ident, mtu, dev_interface_num, nss_interface_num);
937
938 /*
939 * Locate the iface
940 */
941 ii = ecm_db_iface_find_and_ref_ipsec_tunnel(type_info->os_specific_ident);
942 if (ii) {
943 DEBUG_TRACE("%p: iface established\n", ii);
944 return ii;
945 }
946
947 /*
948 * No iface - create one
949 */
950 nii = ecm_db_iface_alloc();
951 if (!nii) {
952 DEBUG_WARN("Failed to establish iface\n");
953 return NULL;
954 }
955
956 /*
957 * Add iface into the database, atomically to avoid races creating the same thing
958 */
959 spin_lock_bh(&ecm_interface_lock);
960 ii = ecm_db_iface_find_and_ref_ipsec_tunnel(type_info->os_specific_ident);
961 if (ii) {
962 spin_unlock_bh(&ecm_interface_lock);
963 ecm_db_iface_deref(nii);
964 return ii;
965 }
966 ecm_db_iface_add_ipsec_tunnel(nii, type_info->os_specific_ident, dev_name,
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500967 mtu, dev_interface_num, nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000968 spin_unlock_bh(&ecm_interface_lock);
969
970 DEBUG_TRACE("%p: ipsec_tunnel iface established\n", nii);
971 return nii;
972}
973
Murat Sezgincc6eedf2014-05-09 23:59:19 -0700974#ifdef CONFIG_IPV6_SIT_6RD
Murat Sezginb3731e82014-11-26 12:20:59 -0800975#ifdef ECM_INTERFACE_SIT_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000976/*
977 * ecm_interface_sit_interface_establish()
978 * Returns a reference to a iface of the SIT type, possibly creating one if necessary.
979 * Returns NULL on failure or a reference to interface.
980 */
981static struct ecm_db_iface_instance *ecm_interface_sit_interface_establish(struct ecm_db_interface_info_sit *type_info,
982 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
983{
984 struct ecm_db_iface_instance *nii;
985 struct ecm_db_iface_instance *ii;
986
987 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",
988 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);
989
990 /*
991 * Locate the iface
992 */
993 ii = ecm_db_iface_find_and_ref_sit(type_info->saddr, type_info->daddr);
994 if (ii) {
995 DEBUG_TRACE("%p: iface established\n", ii);
996 return ii;
997 }
998
999 /*
1000 * No iface - create one
1001 */
1002 nii = ecm_db_iface_alloc();
1003 if (!nii) {
1004 DEBUG_WARN("Failed to establish iface\n");
1005 return NULL;
1006 }
1007
1008 /*
1009 * Add iface into the database, atomically to avoid races creating the same thing
1010 */
1011 spin_lock_bh(&ecm_interface_lock);
1012 ii = ecm_db_iface_find_and_ref_sit(type_info->saddr, type_info->daddr);
1013 if (ii) {
1014 spin_unlock_bh(&ecm_interface_lock);
1015 ecm_db_iface_deref(nii);
1016 return ii;
1017 }
1018 ecm_db_iface_add_sit(nii, type_info, dev_name, mtu, dev_interface_num,
Nicolas Costaf46c33b2014-05-15 10:02:00 -05001019 nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +00001020 spin_unlock_bh(&ecm_interface_lock);
1021
1022 DEBUG_TRACE("%p: sit iface established\n", nii);
1023 return nii;
1024}
Murat Sezgincc6eedf2014-05-09 23:59:19 -07001025#endif
Murat Sezginb3731e82014-11-26 12:20:59 -08001026#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001027
1028/*
1029 * ecm_interface_tunipip6_interface_establish()
1030 * Returns a reference to a iface of the TUNIPIP6 type, possibly creating one if necessary.
1031 * Returns NULL on failure or a reference to interface.
1032 */
1033static struct ecm_db_iface_instance *ecm_interface_tunipip6_interface_establish(struct ecm_db_interface_info_tunipip6 *type_info,
1034 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
1035{
1036 struct ecm_db_iface_instance *nii;
1037 struct ecm_db_iface_instance *ii;
1038
1039 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",
1040 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);
1041
1042 /*
1043 * Locate the iface
1044 */
1045 ii = ecm_db_iface_find_and_ref_tunipip6(type_info->saddr, type_info->daddr);
1046 if (ii) {
1047 DEBUG_TRACE("%p: iface established\n", ii);
1048 return ii;
1049 }
1050
1051 /*
1052 * No iface - create one
1053 */
1054 nii = ecm_db_iface_alloc();
1055 if (!nii) {
1056 DEBUG_WARN("Failed to establish iface\n");
1057 return NULL;
1058 }
1059
1060 /*
1061 * Add iface into the database, atomically to avoid races creating the same thing
1062 */
1063 spin_lock_bh(&ecm_interface_lock);
1064 ii = ecm_db_iface_find_and_ref_tunipip6(type_info->saddr, type_info->daddr);
1065 if (ii) {
1066 spin_unlock_bh(&ecm_interface_lock);
1067 ecm_db_iface_deref(nii);
1068 return ii;
1069 }
1070 ecm_db_iface_add_tunipip6(nii, type_info, dev_name, mtu, dev_interface_num,
Nicolas Costaf46c33b2014-05-15 10:02:00 -05001071 nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +00001072 spin_unlock_bh(&ecm_interface_lock);
1073
1074 DEBUG_TRACE("%p: tunipip6 iface established\n", nii);
1075 return nii;
1076}
1077
1078/*
1079 * ecm_interface_establish_and_ref()
1080 * Establish an interface instance for the given interface detail.
1081 */
1082struct ecm_db_iface_instance *ecm_interface_establish_and_ref(struct net_device *dev)
1083{
1084 int32_t dev_interface_num;
1085 char *dev_name;
1086 int32_t dev_type;
1087 int32_t dev_mtu;
1088 int32_t nss_interface_num;
1089 struct ecm_db_iface_instance *ii;
1090 union {
1091 struct ecm_db_interface_info_ethernet ethernet; /* type == ECM_DB_IFACE_TYPE_ETHERNET */
Gareth Williams141d2382014-11-25 11:35:19 -08001092#ifdef ECM_INTERFACE_VLAN_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001093 struct ecm_db_interface_info_vlan vlan; /* type == ECM_DB_IFACE_TYPE_VLAN */
Gareth Williams141d2382014-11-25 11:35:19 -08001094#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001095 struct ecm_db_interface_info_lag lag; /* type == ECM_DB_IFACE_TYPE_LAG */
1096 struct ecm_db_interface_info_bridge bridge; /* type == ECM_DB_IFACE_TYPE_BRIDGE */
1097 struct ecm_db_interface_info_pppoe pppoe; /* type == ECM_DB_IFACE_TYPE_PPPOE */
1098 struct ecm_db_interface_info_unknown unknown; /* type == ECM_DB_IFACE_TYPE_UNKNOWN */
1099 struct ecm_db_interface_info_loopback loopback; /* type == ECM_DB_IFACE_TYPE_LOOPBACK */
1100 struct ecm_db_interface_info_ipsec_tunnel ipsec_tunnel; /* type == ECM_DB_IFACE_TYPE_IPSEC_TUNNEL */
1101 struct ecm_db_interface_info_sit sit; /* type == ECM_DB_IFACE_TYPE_SIT */
1102 struct ecm_db_interface_info_tunipip6 tunipip6; /* type == ECM_DB_IFACE_TYPE_TUNIPIP6 */
1103 } type_info;
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001104
Gareth Williamsdbb2bfd2014-11-20 16:42:09 -08001105#ifdef ECM_INTERFACE_PPP_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001106 int channel_count;
1107 struct ppp_channel *ppp_chan[1];
Ben Menchaca84f36632014-02-28 20:57:38 +00001108 int channel_protocol;
Ben Menchaca84f36632014-02-28 20:57:38 +00001109 struct pppoe_opt addressing;
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001110#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001111
1112 /*
1113 * Get basic information about the given device
1114 */
1115 dev_interface_num = dev->ifindex;
1116 dev_name = dev->name;
1117 dev_type = dev->type;
1118 dev_mtu = dev->mtu;
1119
1120 /*
1121 * Does the NSS recognise this interface?
1122 */
1123 nss_interface_num = nss_cmn_get_interface_number_by_dev(dev);
1124
1125 DEBUG_TRACE("Establish interface instance for device: %p is type: %d, name: %s, ifindex: %d, nss_if: %d, mtu: %d\n",
1126 dev, dev_type, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1127
1128 /*
1129 * Extract from the device more type-specific information
1130 */
1131 if (dev_type == ARPHRD_ETHER) {
1132 /*
1133 * Ethernet - but what sub type?
1134 */
1135
Gareth Williams141d2382014-11-25 11:35:19 -08001136#ifdef ECM_INTERFACE_VLAN_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001137 /*
1138 * VLAN?
1139 */
1140 if (is_vlan_dev(dev)) {
1141 /*
1142 * VLAN master
1143 * GGG No locking needed here, ASSUMPTION is that real_dev is held for as long as we have dev.
1144 */
1145 memcpy(type_info.vlan.address, dev->dev_addr, 6);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301146 type_info.vlan.vlan_tag = vlan_dev_vlan_id(dev);
1147 type_info.vlan.vlan_tpid = VLAN_CTAG_TPID;
1148 DEBUG_TRACE("Net device: %p is VLAN, mac: %pM, vlan_id: %x vlan_tpid: %x\n",
1149 dev, type_info.vlan.address, type_info.vlan.vlan_tag, type_info.vlan.vlan_tpid);
Ben Menchaca84f36632014-02-28 20:57:38 +00001150
1151 /*
1152 * Establish this type of interface
1153 */
1154 ii = ecm_interface_vlan_interface_establish(&type_info.vlan, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1155 return ii;
1156 }
Gareth Williams141d2382014-11-25 11:35:19 -08001157#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001158
1159 /*
1160 * BRIDGE?
1161 */
1162 if (ecm_front_end_is_bridge_device(dev)) {
1163 /*
1164 * Bridge
1165 */
1166 memcpy(type_info.bridge.address, dev->dev_addr, 6);
1167
1168 DEBUG_TRACE("Net device: %p is BRIDGE, mac: %pM\n",
1169 dev, type_info.bridge.address);
1170
1171 /*
1172 * Establish this type of interface
1173 */
1174 ii = ecm_interface_bridge_interface_establish(&type_info.bridge, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1175 return ii;
1176 }
1177
1178 /*
1179 * LAG?
1180 */
1181 if (ecm_front_end_is_lag_master(dev)) {
1182 /*
1183 * Link aggregation
1184 */
1185 memcpy(type_info.lag.address, dev->dev_addr, 6);
1186
1187 DEBUG_TRACE("Net device: %p is LAG, mac: %pM\n",
1188 dev, type_info.lag.address);
1189
1190 /*
1191 * Establish this type of interface
1192 */
1193 ii = ecm_interface_lag_interface_establish(&type_info.lag, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1194 return ii;
1195 }
1196
1197 /*
1198 * ETHERNET!
1199 * Just plain ethernet it seems
1200 */
1201 memcpy(type_info.ethernet.address, dev->dev_addr, 6);
1202 DEBUG_TRACE("Net device: %p is ETHERNET, mac: %pM\n",
1203 dev, type_info.ethernet.address);
1204
1205 /*
1206 * Establish this type of interface
1207 */
1208 ii = ecm_interface_ethernet_interface_establish(&type_info.ethernet, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1209 return ii;
1210 }
1211
1212 /*
1213 * LOOPBACK?
1214 */
1215 if (dev_type == ARPHRD_LOOPBACK) {
1216 DEBUG_TRACE("Net device: %p is LOOPBACK type: %d\n", dev, dev_type);
1217 type_info.loopback.os_specific_ident = dev_interface_num;
1218 ii = ecm_interface_loopback_interface_establish(&type_info.loopback, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1219 return ii;
1220 }
1221
1222 /*
1223 * IPSEC?
1224 */
1225 if (dev_type == ECM_ARPHRD_IPSEC_TUNNEL_TYPE) {
1226 DEBUG_TRACE("Net device: %p is IPSec tunnel type: %d\n", dev, dev_type);
1227 type_info.ipsec_tunnel.os_specific_ident = dev_interface_num;
Ankit Dhanuka6d5014a2014-06-22 17:21:44 +05301228
1229 /*
1230 * nss_interface_num for all IPsec tunnels will always be NSS_C2C_TX_INTERFACE
1231 */
1232 nss_interface_num = NSS_C2C_TX_INTERFACE;
1233
Ben Menchaca84f36632014-02-28 20:57:38 +00001234 // GGG TODO Flesh this out with tunnel endpoint addressing detail
1235 ii = ecm_interface_ipsec_tunnel_interface_establish(&type_info.ipsec_tunnel, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1236 return ii;
1237 }
1238
Murat Sezgincc6eedf2014-05-09 23:59:19 -07001239#ifdef CONFIG_IPV6_SIT_6RD
Murat Sezginb3731e82014-11-26 12:20:59 -08001240#ifdef ECM_INTERFACE_SIT_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001241 /*
1242 * SIT (6-in-4)?
1243 */
1244 if (dev_type == ARPHRD_SIT) {
1245 struct ip_tunnel *tunnel;
1246 struct ip_tunnel_6rd_parm *ip6rd;
1247 const struct iphdr *tiph;
1248
1249 DEBUG_TRACE("Net device: %p is SIT (6-in-4) type: %d\n", dev, dev_type);
1250
1251 tunnel = (struct ip_tunnel*)netdev_priv(dev);
1252 ip6rd = &tunnel->ip6rd;
1253
1254 /*
1255 * Get the Tunnel device IP header info
1256 */
1257 tiph = &tunnel->parms.iph ;
1258
1259 type_info.sit.prefixlen = ip6rd->prefixlen;
1260 type_info.sit.relay_prefix = ip6rd->relay_prefix;
1261 type_info.sit.relay_prefixlen = ip6rd->relay_prefixlen;
1262 ECM_NIN4_ADDR_TO_IP_ADDR(type_info.sit.saddr, tiph->saddr);
1263 ECM_NIN4_ADDR_TO_IP_ADDR(type_info.sit.daddr, tiph->daddr);
1264 type_info.sit.prefix[0] = ntohl(ip6rd->prefix.s6_addr32[0]);
1265 type_info.sit.prefix[1] = ntohl(ip6rd->prefix.s6_addr32[1]);
1266 type_info.sit.prefix[2] = ntohl(ip6rd->prefix.s6_addr32[2]);
1267 type_info.sit.prefix[3] = ntohl(ip6rd->prefix.s6_addr32[3]);
1268 type_info.sit.ttl = tiph->ttl;
1269 type_info.sit.tos = tiph->tos;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301270
Ben Menchaca84f36632014-02-28 20:57:38 +00001271 ii = ecm_interface_sit_interface_establish(&type_info.sit, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1272 return ii;
1273 }
Murat Sezgincc6eedf2014-05-09 23:59:19 -07001274#endif
Murat Sezginb3731e82014-11-26 12:20:59 -08001275#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001276
1277 /*
1278 * IPIP6 Tunnel?
1279 */
1280 if (dev_type == ARPHRD_TUNNEL6) {
1281 struct ip6_tnl *tunnel;
1282 struct flowi6 *fl6;
1283
1284 DEBUG_TRACE("Net device: %p is TUNIPIP6 type: %d\n", dev, dev_type);
1285
1286 /*
1287 * Get the tunnel device flow information (discover the output path of the tunnel)
1288 */
1289 tunnel = (struct ip6_tnl *)netdev_priv(dev);
1290 fl6 = &tunnel->fl.u.ip6;
1291
1292 ECM_NIN6_ADDR_TO_IP_ADDR(type_info.tunipip6.saddr, fl6->saddr);
1293 ECM_NIN6_ADDR_TO_IP_ADDR(type_info.tunipip6.daddr, fl6->daddr);
1294 type_info.tunipip6.hop_limit = tunnel->parms.hop_limit;
1295 type_info.tunipip6.flags = ntohl(tunnel->parms.flags);
1296 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 +05301297
Ben Menchaca84f36632014-02-28 20:57:38 +00001298 ii = ecm_interface_tunipip6_interface_establish(&type_info.tunipip6, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1299 return ii;
1300 }
1301
1302 /*
1303 * If this is NOT PPP then it is unknown to the ecm
1304 */
1305 if (dev_type != ARPHRD_PPP) {
1306 DEBUG_TRACE("Net device: %p is UNKNOWN type: %d\n", dev, dev_type);
1307 type_info.unknown.os_specific_ident = dev_interface_num;
1308
1309 /*
1310 * Establish this type of interface
1311 */
1312 ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1313 return ii;
1314 }
1315
Gareth Williamsdbb2bfd2014-11-20 16:42:09 -08001316#ifndef ECM_INTERFACE_PPP_ENABLE
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001317 /*
1318 * PPP support is NOT provided for.
1319 * Interface is therefore unknown
1320 */
1321 DEBUG_TRACE("Net device: %p is UNKNOWN (PPP Unsupported) type: %d\n", dev, dev_type);
1322 type_info.unknown.os_specific_ident = dev_interface_num;
1323
1324 /*
1325 * Establish this type of interface
1326 */
1327 ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1328 return ii;
1329#else
Ben Menchaca84f36632014-02-28 20:57:38 +00001330 /*
1331 * PPP - but what is the channel type?
1332 * First: If this is multi-link then we do not support it
1333 */
1334 if (ppp_is_multilink(dev) > 0) {
1335 DEBUG_TRACE("Net device: %p is MULTILINK PPP - Unknown to the ECM\n", dev);
1336 type_info.unknown.os_specific_ident = dev_interface_num;
1337
1338 /*
1339 * Establish this type of interface
1340 */
1341 ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1342 return ii;
1343 }
1344
1345 DEBUG_TRACE("Net device: %p is PPP\n", dev);
1346
1347 /*
1348 * Get the PPP channel and then enquire what kind of channel it is
1349 * NOTE: Not multilink so only one channel to get.
1350 */
1351 channel_count = ppp_hold_channels(dev, ppp_chan, 1);
1352 if (channel_count != 1) {
Gareth Williams6f96a4b2014-05-29 19:41:21 +01001353 DEBUG_TRACE("Net device: %p PPP has %d channels - ECM cannot handle this (interface becomes Unknown type)\n",
1354 dev, channel_count);
Ben Menchaca84f36632014-02-28 20:57:38 +00001355 type_info.unknown.os_specific_ident = dev_interface_num;
1356
1357 /*
1358 * Establish this type of interface
1359 */
1360 ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1361 return ii;
1362 }
1363
1364 /*
1365 * Get channel protocol type
Gareth Williams6f96a4b2014-05-29 19:41:21 +01001366 * NOTE: Not all PPP channels support channel specific methods.
Ben Menchaca84f36632014-02-28 20:57:38 +00001367 */
Gareth Williams6f96a4b2014-05-29 19:41:21 +01001368 channel_protocol = ppp_channel_get_protocol(ppp_chan[0]);
Ben Menchaca84f36632014-02-28 20:57:38 +00001369 if (channel_protocol != PX_PROTO_OE) {
1370 DEBUG_TRACE("Net device: %p PPP channel protocol: %d - Unknown to the ECM\n", dev, channel_protocol);
1371 type_info.unknown.os_specific_ident = dev_interface_num;
1372
1373 /*
1374 * Release the channel
1375 */
1376 ppp_release_channels(ppp_chan, 1);
1377
1378 /*
1379 * Establish this type of interface
1380 */
1381 ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1382 return ii;
1383 }
1384
1385 /*
1386 * PPPoE channel
1387 */
1388 DEBUG_TRACE("Net device: %p PPP channel is PPPoE\n", dev);
1389
1390 /*
1391 * Get PPPoE session information and the underlying device it is using.
Ben Menchaca84f36632014-02-28 20:57:38 +00001392 */
Gareth Williams6f96a4b2014-05-29 19:41:21 +01001393 pppoe_channel_addressing_get(ppp_chan[0], &addressing);
1394 type_info.pppoe.pppoe_session_id = (uint16_t)ntohs((uint16_t)addressing.pa.sid);
Ben Menchaca84f36632014-02-28 20:57:38 +00001395 memcpy(type_info.pppoe.remote_mac, addressing.pa.remote, ETH_ALEN);
Gareth Williams6f96a4b2014-05-29 19:41:21 +01001396 dev_put(addressing.dev);
Ben Menchaca84f36632014-02-28 20:57:38 +00001397
1398 /*
1399 * Release the channel. Note that next_dev is still (correctly) held.
1400 */
1401 ppp_release_channels(ppp_chan, 1);
1402
1403 DEBUG_TRACE("Net device: %p PPPoE session: %x, remote mac: %pM\n",
1404 dev, type_info.pppoe.pppoe_session_id, type_info.pppoe.remote_mac);
1405
1406 /*
1407 * Establish this type of interface
1408 */
1409 ii = ecm_interface_pppoe_interface_establish(&type_info.pppoe, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1410 return ii;
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001411#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001412}
1413EXPORT_SYMBOL(ecm_interface_establish_and_ref);
1414
1415/*
1416 * ecm_interface_heirarchy_construct()
1417 * Construct an interface heirarchy.
1418 *
1419 * Using the given addressing, locate the interface heirarchy used to emit packets to that destination.
1420 * This is the heirarchy of interfaces a packet would transit to emit from the device.
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001421 *
1422 * We will use the given src/dest devices when is_routed is false.
1423 * When is_routed is true we will try routing tables first, failing back to any given.
1424 *
Ben Menchaca84f36632014-02-28 20:57:38 +00001425 * For example, with this network arrangement:
1426 *
1427 * PPPoE--VLAN--BRIDGE--BRIDGE_PORT(LAG_MASTER)--LAG_SLAVE_0--10.22.33.11
1428 *
Gareth Williams43fc0852014-05-26 19:10:00 +01001429 * 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 +00001430 * LAG_SLAVE_0 @ [ECM_DB_IFACE_HEIRARCHY_MAX - 5]
1431 * LAG_MASTER @ [ECM_DB_IFACE_HEIRARCHY_MAX - 4]
1432 * BRIDGE @ [ECM_DB_IFACE_HEIRARCHY_MAX - 3]
1433 * VLAN @ [ECM_DB_IFACE_HEIRARCHY_MAX - 2]
1434 * PPPOE @ [ECM_DB_IFACE_HEIRARCHY_MAX - 1]
1435 * The value returned is (ECM_DB_IFACE_HEIRARCHY_MAX - 5)
1436 *
1437 * IMPORTANT: This function will return any known interfaces in the database, when interfaces do not exist in the database
1438 * they will be created and added automatically to the database.
1439 *
1440 * GGG TODO Make this function work for IPv6!!!!!!!!!!!!!!
1441 */
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001442int32_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 +05301443 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 +00001444{
Ben Menchaca84f36632014-02-28 20:57:38 +00001445 int protocol;
1446 ip_addr_t src_addr;
1447 ip_addr_t dest_addr;
Ben Menchaca84f36632014-02-28 20:57:38 +00001448 struct net_device *dest_dev;
Ben Menchaca84f36632014-02-28 20:57:38 +00001449 char *dest_dev_name;
Ben Menchaca84f36632014-02-28 20:57:38 +00001450 int32_t dest_dev_type;
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001451 struct net_device *src_dev;
1452 char *src_dev_name;
1453 int32_t src_dev_type;
Ben Menchaca84f36632014-02-28 20:57:38 +00001454 int32_t current_interface_index;
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001455 bool from_local_addr;
Ben Menchaca84f36632014-02-28 20:57:38 +00001456
1457 /*
1458 * Get a big endian of the IPv4 address we have been given as our starting point.
1459 */
1460 protocol = packet_protocol;
1461 ECM_IP_ADDR_COPY(src_addr, packet_src_addr);
1462 ECM_IP_ADDR_COPY(dest_addr, packet_dest_addr);
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001463 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",
1464 ECM_IP_ADDR_TO_DOT(src_addr), ECM_IP_ADDR_TO_DOT(dest_addr), protocol);
Ben Menchaca84f36632014-02-28 20:57:38 +00001465
1466 /*
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001467 * Get device to reach the given destination address.
1468 * If the heirarchy is for a routed connection we must try route lookup first, falling back to any given_dest_dev.
1469 * 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 +00001470 */
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001471 from_local_addr = false;
1472 if (is_routed) {
1473 dest_dev = ecm_interface_dev_find_by_addr(dest_addr, &from_local_addr);
1474 if (!dest_dev && given_dest_dev) {
1475 /*
1476 * Fall back to any given
1477 */
1478 dest_dev = given_dest_dev;
1479 dev_hold(dest_dev);
Gareth Williams43fc0852014-05-26 19:10:00 +01001480 }
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001481 } else if (given_dest_dev) {
1482 dest_dev = given_dest_dev;
1483 dev_hold(dest_dev);
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05301484 } else {
1485 /*
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001486 * Fall back to routed look up
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05301487 */
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001488 dest_dev = ecm_interface_dev_find_by_addr(dest_addr, &from_local_addr);
Gareth Williams43fc0852014-05-26 19:10:00 +01001489 }
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05301490
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001491 /*
1492 * GGG ALERT: If the address is a local address and protocol is an IP tunnel
1493 * then this connection is a tunnel endpoint made to this device.
1494 * In which case we circumvent all proper procedure and just hack the devices to make stuff work.
1495 * GGG TODO THIS MUST BE FIXED - WE MUST USE THE INTERFACE HIERARCHY FOR ITS INTENDED PURPOSE TO
1496 * PARSE THE DEVICES AND WORK OUT THE PROPER INTERFACES INVOLVED.
1497 * E.G. IF WE TRIED TO RUN A TUNNEL OVER A VLAN OR QINQ THIS WILL BREAK AS WE DON'T DISCOVER THAT HIERARCHY
1498 */
1499 if (dest_dev && from_local_addr && (protocol == IPPROTO_IPV6)) {
1500 dev_put(dest_dev);
1501 dest_dev = given_dest_dev;
1502 if (dest_dev) {
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05301503 dev_hold(dest_dev);
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001504 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 +05301505 }
Gareth Williams43fc0852014-05-26 19:10:00 +01001506 }
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001507 if (!dest_dev) {
1508 DEBUG_WARN("dest_addr: " ECM_IP_ADDR_OCTAL_FMT " - cannot locate device\n", ECM_IP_ADDR_TO_OCTAL(dest_addr));
1509 return ECM_DB_IFACE_HEIRARCHY_MAX;
1510 }
Ben Menchaca84f36632014-02-28 20:57:38 +00001511 dest_dev_name = dest_dev->name;
1512 dest_dev_type = dest_dev->type;
1513
1514 /*
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001515 * Get device to reach the given source address.
1516 * If the heirarchy is for a routed connection we must try route lookup first, falling back to any given_src_dev.
1517 * If the heirarchy is NOT for a routed connection we try the given_src_dev first, followed by routed lookup.
1518 */
1519 from_local_addr = false;
1520 if (is_routed) {
1521 src_dev = ecm_interface_dev_find_by_addr(src_addr, &from_local_addr);
1522 if (!src_dev && given_src_dev) {
1523 /*
1524 * Fall back to any given
1525 */
1526 src_dev = given_src_dev;
1527 dev_hold(src_dev);
1528 }
1529 } else if (given_src_dev) {
1530 src_dev = given_src_dev;
1531 dev_hold(src_dev);
1532 } else {
1533 /*
1534 * Fall back to routed look up
1535 */
1536 src_dev = ecm_interface_dev_find_by_addr(src_addr, &from_local_addr);
1537 }
1538
1539 /*
1540 * GGG ALERT: If the address is a local address and protocol is an IP tunnel
1541 * then this connection is a tunnel endpoint made to this device.
1542 * In which case we circumvent all proper procedure and just hack the devices to make stuff work.
1543 * GGG TODO THIS MUST BE FIXED - WE MUST USE THE INTERFACE HIERARCHY FOR ITS INTENDED PURPOSE TO
1544 * PARSE THE DEVICES AND WORK OUT THE PROPER INTERFACES INVOLVED.
1545 * E.G. IF WE TRIED TO RUN A TUNNEL OVER A VLAN OR QINQ THIS WILL BREAK AS WE DON'T DISCOVER THAT HIERARCHY
1546 */
1547 if (src_dev && from_local_addr && (protocol == IPPROTO_IPV6)) {
1548 dev_put(src_dev);
1549 src_dev = given_src_dev;
1550 if (src_dev) {
1551 dev_hold(src_dev);
1552 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);
1553 }
1554 }
1555 if (!src_dev) {
1556 DEBUG_WARN("src_addr: " ECM_IP_ADDR_OCTAL_FMT " - cannot locate device\n", ECM_IP_ADDR_TO_OCTAL(src_addr));
1557 dev_put(dest_dev);
1558 return ECM_DB_IFACE_HEIRARCHY_MAX;
1559 }
1560 src_dev_name = src_dev->name;
1561 src_dev_type = src_dev->type;
1562
1563 /*
1564 * Check if source and dest dev are same.
1565 * For the forwarded flows which involve tunnels this will happen when called from input hook.
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05301566 */
1567 if (src_dev == dest_dev) {
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001568 DEBUG_TRACE("Protocol is :%d source dev and dest dev are same\n", protocol);
Ankit Dhanuka60683c52014-06-09 17:43:38 +05301569 if ((protocol == IPPROTO_IPV6) || (protocol == IPPROTO_ESP)) {
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05301570 /*
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001571 * This happens from the input hook
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05301572 * We do not want to create a connection entry for this
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001573 * GGG TODO YES WE DO.
1574 * GGG TODO THIS CONCERNS ME AS THIS SHOULD BE CAUGHT MUCH
1575 * EARLIER IN THE FRONT END IF POSSIBLE TO AVOID PERFORMANCE PENALTIES.
1576 * WE HAVE DONE A TREMENDOUS AMOUT OF WORK TO GET TO THIS POINT.
1577 * WE WILL ABORT HERE AND THIS WILL BE REPEATED FOR EVERY PACKET.
1578 * IN KEEPING WITH THE ECM DESIGN IT IS BETTER TO CREATE A CONNECTION AND RECORD IN THE HIERARCHY
1579 * ENOUGH INFORMATION TO ENSURE THAT ACCELERATION IS NOT BROKEN / DOES NOT OCCUR AT ALL.
1580 * THAT WAY WE DO A HEAVYWEIGHT ESTABLISHING OF A CONNECTION ONCE AND NEVER AGAIN...
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05301581 */
1582 dev_put(src_dev);
1583 dev_put(dest_dev);
1584 return ECM_DB_IFACE_HEIRARCHY_MAX;
1585 }
1586 }
1587
1588 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00001589 * Iterate until we are done or get to the max number of interfaces we can record.
1590 * NOTE: current_interface_index tracks the position of the first interface position in interfaces[]
1591 * because we add from the end first_interface grows downwards.
1592 */
1593 current_interface_index = ECM_DB_IFACE_HEIRARCHY_MAX;
1594 while (current_interface_index > 0) {
1595 struct ecm_db_iface_instance *ii;
1596 struct net_device *next_dev;
1597
1598 /*
1599 * Get the ecm db interface instance for the device at hand
1600 */
1601 ii = ecm_interface_establish_and_ref(dest_dev);
1602
1603 /*
1604 * If the interface could not be established then we abort
1605 */
1606 if (!ii) {
1607 DEBUG_WARN("Failed to establish interface: %p, name: %s\n", dest_dev, dest_dev_name);
1608 dev_put(src_dev);
1609 dev_put(dest_dev);
1610
1611 /*
1612 * Release the interfaces heirarchy we constructed to this point.
1613 */
1614 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1615 return ECM_DB_IFACE_HEIRARCHY_MAX;
1616 }
1617
1618 /*
1619 * Record the interface instance into the interfaces[]
1620 */
1621 current_interface_index--;
1622 interfaces[current_interface_index] = ii;
1623
1624 /*
1625 * Now we have to figure out what the next device will be (in the transmission path) the skb
1626 * will use to emit to the destination address.
1627 */
1628 do {
Gareth Williamsdbb2bfd2014-11-20 16:42:09 -08001629#ifdef ECM_INTERFACE_PPP_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001630 int channel_count;
1631 struct ppp_channel *ppp_chan[1];
Ben Menchaca84f36632014-02-28 20:57:38 +00001632 int channel_protocol;
Ben Menchaca84f36632014-02-28 20:57:38 +00001633 struct pppoe_opt addressing;
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001634#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001635
1636 DEBUG_TRACE("Net device: %p is type: %d, name: %s\n", dest_dev, dest_dev_type, dest_dev_name);
1637 next_dev = NULL;
1638
1639 if (dest_dev_type == ARPHRD_ETHER) {
1640 /*
1641 * Ethernet - but what sub type?
1642 */
1643
Gareth Williams141d2382014-11-25 11:35:19 -08001644#ifdef ECM_INTERFACE_VLAN_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001645 /*
1646 * VLAN?
1647 */
1648 if (is_vlan_dev(dest_dev)) {
1649 /*
1650 * VLAN master
1651 * No locking needed here, ASSUMPTION is that real_dev is held for as long as we have dev.
1652 */
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301653 next_dev = vlan_dev_real_dev(dest_dev);
Ben Menchaca84f36632014-02-28 20:57:38 +00001654 dev_hold(next_dev);
1655 DEBUG_TRACE("Net device: %p is VLAN, slave dev: %p (%s)\n",
1656 dest_dev, next_dev, next_dev->name);
1657 break;
1658 }
Gareth Williams141d2382014-11-25 11:35:19 -08001659#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001660
1661 /*
1662 * BRIDGE?
1663 */
1664 if (ecm_front_end_is_bridge_device(dest_dev)) {
1665 /*
1666 * Bridge
1667 * Figure out which port device the skb will go to using the dest_addr.
1668 */
1669 bool on_link;
Murat Sezginebf8a642014-06-06 12:51:43 -07001670 ip_addr_t gw_addr = ECM_IP_ADDR_NULL;
Ben Menchaca84f36632014-02-28 20:57:38 +00001671 uint8_t mac_addr[ETH_ALEN];
1672 if (!ecm_interface_mac_addr_get(dest_addr, mac_addr, &on_link, gw_addr)) {
1673 /*
1674 * Possible ARP does not know the address yet
1675 */
Gareth Williams9e1d17a2014-05-26 19:40:10 +01001676 DEBUG_INFO("Unable to obtain MAC address for " ECM_IP_ADDR_DOT_FMT "\n", ECM_IP_ADDR_TO_DOT(dest_addr));
1677 if (ECM_IP_ADDR_IS_V4(dest_addr)) {
1678 __be32 ipv4_addr;
1679 __be32 src_ip;
1680
1681 /*
1682 * Issue an ARP request for it, select the src_ip from which to issue the request.
1683 */
1684 ECM_IP_ADDR_TO_NIN4_ADDR(ipv4_addr, dest_addr);
1685 src_ip = inet_select_addr(dest_dev, ipv4_addr, RT_SCOPE_LINK);
1686 if (!src_ip) {
1687 DEBUG_TRACE("failed to lookup IP for %pI4\n", &ipv4_addr);
1688
1689 dev_put(src_dev);
1690 dev_put(dest_dev);
1691
1692 /*
1693 * Release the interfaces heirarchy we constructed to this point.
1694 */
1695 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1696 return ECM_DB_IFACE_HEIRARCHY_MAX;
1697 }
1698
1699 /*
1700 * If we have a GW for this address, then we have to send ARP request to the GW
1701 */
Murat Sezginebf8a642014-06-06 12:51:43 -07001702 if (!on_link && !ECM_IP_ADDR_IS_NULL(gw_addr)) {
Sol Kavyd3fd5d82014-06-05 19:27:04 -07001703 ECM_IP_ADDR_TO_NIN4_ADDR(ipv4_addr, gw_addr);
Gareth Williams9e1d17a2014-05-26 19:40:10 +01001704 }
1705
1706 DEBUG_TRACE("Send ARP for %pI4 using src_ip as %pI4\n", &ipv4_addr, &src_ip);
1707 arp_send(ARPOP_REQUEST, ETH_P_ARP, ipv4_addr, dest_dev, src_ip, NULL, NULL, NULL);
1708 }
1709
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001710 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 +00001711 dev_put(src_dev);
1712 dev_put(dest_dev);
1713
1714 /*
1715 * Release the interfaces heirarchy we constructed to this point.
1716 */
1717 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1718 return ECM_DB_IFACE_HEIRARCHY_MAX;
1719 }
1720 next_dev = br_port_dev_get(dest_dev, mac_addr);
1721 if (!next_dev) {
1722 DEBUG_WARN("Unable to obtain output port for: %pM\n", mac_addr);
1723 dev_put(src_dev);
1724 dev_put(dest_dev);
1725
1726 /*
1727 * Release the interfaces heirarchy we constructed to this point.
1728 */
1729 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1730 return ECM_DB_IFACE_HEIRARCHY_MAX;
1731 }
1732 DEBUG_TRACE("Net device: %p is BRIDGE, next_dev: %p (%s)\n", dest_dev, next_dev, next_dev->name);
1733 break;
1734 }
Murat Sezginb3731e82014-11-26 12:20:59 -08001735#ifdef ECM_INTERFACE_BOND_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001736 /*
1737 * LAG?
1738 */
1739 if (ecm_front_end_is_lag_master(dest_dev)) {
1740 /*
1741 * Link aggregation
Murat Sezginb3731e82014-11-26 12:20:59 -08001742 * Figure out whiich slave device of the link aggregation will be used to reach the destination.
Ben Menchaca84f36632014-02-28 20:57:38 +00001743 */
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05301744 bool dest_on_link = false;
1745 ip_addr_t dest_gw_addr = ECM_IP_ADDR_NULL;
1746 uint32_t src_addr_32 = 0;
1747 uint32_t dest_addr_32 = 0;
Ben Menchaca84f36632014-02-28 20:57:38 +00001748 uint8_t src_mac_addr[ETH_ALEN];
1749 uint8_t dest_mac_addr[ETH_ALEN];
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05301750 struct net_device *master_dev = NULL;
Ben Menchaca84f36632014-02-28 20:57:38 +00001751
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05301752 memset(src_mac_addr, 0, ETH_ALEN);
1753 memset(dest_mac_addr, 0, ETH_ALEN);
Ben Menchaca84f36632014-02-28 20:57:38 +00001754
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05301755 ECM_IP_ADDR_TO_NIN4_ADDR(src_addr_32, src_addr);
1756 ECM_IP_ADDR_TO_NIN4_ADDR(dest_addr_32, dest_addr);
1757
1758 if (!is_routed) {
1759 memcpy(src_mac_addr, src_node_addr, ETH_ALEN);
1760 memcpy(dest_mac_addr, dest_node_addr, ETH_ALEN);
1761 } else {
Murat Sezginb3731e82014-11-26 12:20:59 -08001762 struct net_device *dest_dev_master;
1763
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05301764 /*
1765 * Use appropriate source MAC address for routed packets
1766 */
Murat Sezginb3731e82014-11-26 12:20:59 -08001767 dest_dev_master = ecm_interface_get_and_hold_dev_master(dest_dev);
1768 if (dest_dev_master) {
1769 memcpy(src_mac_addr, dest_dev_master->dev_addr, ETH_ALEN);
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05301770 } else {
1771 memcpy(src_mac_addr, dest_dev->dev_addr, ETH_ALEN);
1772 }
1773
1774 /*
1775 * Determine destination MAC address for this routed packet
1776 */
1777 if (!ecm_interface_mac_addr_get(dest_addr, dest_mac_addr,
1778 &dest_on_link, dest_gw_addr)) {
1779 __be32 ipv4_addr = 0;
1780 __be32 src_ip = 0;
1781 DEBUG_WARN("Unable to obtain MAC address for "
1782 ECM_IP_ADDR_DOT_FMT "\n", ECM_IP_ADDR_TO_DOT(dest_addr));
1783
1784
1785 /*
1786 * Issue an ARP request, select the src_ip from which to issue the request.
1787 */
1788
1789 /*
1790 * find proper interfce from which to issue ARP
1791 */
Murat Sezginb3731e82014-11-26 12:20:59 -08001792 if (dest_dev_master) {
1793 master_dev = dest_dev_master;
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05301794 } else {
1795 master_dev = dest_dev;
1796 }
1797
1798 dev_hold(master_dev);
1799
Murat Sezginb3731e82014-11-26 12:20:59 -08001800 if (dest_dev_master) {
1801 dev_put(dest_dev_master);
1802 }
1803
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05301804 ECM_IP_ADDR_TO_NIN4_ADDR(ipv4_addr, dest_addr);
1805 src_ip = inet_select_addr(master_dev, ipv4_addr, RT_SCOPE_LINK);
1806 if (!src_ip) {
1807 DEBUG_TRACE("failed to lookup IP for %pI4\n", &ipv4_addr);
1808
1809 dev_put(src_dev);
1810 dev_put(dest_dev);
1811 dev_put(master_dev);
1812
1813 /*
1814 * Release the interfaces heirarchy we constructed to this point.
1815 */
1816 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1817 return ECM_DB_IFACE_HEIRARCHY_MAX;
1818 }
1819
1820 /*
1821 * If we have a GW for this address, then we have to send ARP request to the GW
1822 */
1823 if (!dest_on_link && !ECM_IP_ADDR_IS_NULL(dest_gw_addr)) {
1824 ECM_IP_ADDR_TO_NIN4_ADDR(ipv4_addr, dest_gw_addr);
1825 }
1826
1827 DEBUG_TRACE("Send ARP for %pI4 using src_ip as %pI4\n", &ipv4_addr, &src_ip);
1828 arp_send(ARPOP_REQUEST, ETH_P_ARP, ipv4_addr, master_dev, src_ip, NULL, NULL, NULL);
1829
1830
1831 dev_put(src_dev);
1832 dev_put(dest_dev);
1833 dev_put(master_dev);
1834 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1835 return ECM_DB_IFACE_HEIRARCHY_MAX;
1836 }
Murat Sezginb3731e82014-11-26 12:20:59 -08001837
1838 if (dest_dev_master) {
1839 dev_put(dest_dev_master);
1840 }
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05301841 }
1842
1843 next_dev = bond_get_tx_dev(NULL, src_mac_addr, dest_mac_addr,
1844 &src_addr_32, &dest_addr_32,
1845 htons((uint16_t)ETH_P_IP), dest_dev);
Tushar Mathur933907c2014-06-24 17:06:14 +05301846 if (next_dev && netif_carrier_ok(next_dev)) {
Ben Menchaca84f36632014-02-28 20:57:38 +00001847 dev_hold(next_dev);
1848 } else {
1849 DEBUG_WARN("Unable to obtain LAG output slave device\n");
1850 dev_put(src_dev);
1851 dev_put(dest_dev);
1852
1853 /*
1854 * Release the interfaces heirarchy we constructed to this point.
1855 */
1856 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1857 return ECM_DB_IFACE_HEIRARCHY_MAX;
1858 }
1859
1860 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 +00001861 break;
1862 }
Murat Sezginb3731e82014-11-26 12:20:59 -08001863#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001864
1865 /*
1866 * ETHERNET!
1867 * Just plain ethernet it seems.
1868 */
1869 DEBUG_TRACE("Net device: %p is ETHERNET\n", dest_dev);
1870 break;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301871 }
Ben Menchaca84f36632014-02-28 20:57:38 +00001872
1873 /*
1874 * LOOPBACK?
1875 */
1876 if (dest_dev_type == ARPHRD_LOOPBACK) {
1877 DEBUG_TRACE("Net device: %p is LOOPBACK type: %d\n", dest_dev, dest_dev_type);
1878 break;
1879 }
1880
1881 /*
1882 * IPSEC?
1883 */
1884 if (dest_dev_type == ECM_ARPHRD_IPSEC_TUNNEL_TYPE) {
1885 DEBUG_TRACE("Net device: %p is IPSec tunnel type: %d\n", dest_dev, dest_dev_type);
1886 // GGG TODO Figure out the next device the tunnel is using...
1887 break;
1888 }
1889
1890 /*
1891 * SIT (6-in-4)?
1892 */
1893 if (dest_dev_type == ARPHRD_SIT) {
1894 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 +01001895 // GGG TODO Figure out the next device the tunnel is using...
Ben Menchaca84f36632014-02-28 20:57:38 +00001896 break;
1897 }
1898
1899 /*
1900 * IPIP6 Tunnel?
1901 */
1902 if (dest_dev_type == ARPHRD_TUNNEL6) {
1903 DEBUG_TRACE("Net device: %p is TUNIPIP6 type: %d\n", dest_dev, dest_dev_type);
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001904 // GGG TODO Figure out the next device the tunnel is using...
Ben Menchaca84f36632014-02-28 20:57:38 +00001905 break;
1906 }
1907
1908 /*
1909 * If this is NOT PPP then it is unknown to the ecm and we cannot figure out it's next device.
1910 */
1911 if (dest_dev_type != ARPHRD_PPP) {
1912 DEBUG_TRACE("Net device: %p is UNKNOWN type: %d\n", dest_dev, dest_dev_type);
1913 break;
1914 }
1915
Gareth Williamsdbb2bfd2014-11-20 16:42:09 -08001916#ifndef ECM_INTERFACE_PPP_ENABLE
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001917 DEBUG_TRACE("Net device: %p is UNKNOWN (PPP Unsupported) type: %d\n", dest_dev, dest_dev_type);
1918#else
Ben Menchaca84f36632014-02-28 20:57:38 +00001919 /*
1920 * PPP - but what is the channel type?
1921 * First: If this is multi-link then we do not support it
1922 */
1923 if (ppp_is_multilink(dest_dev) > 0) {
1924 DEBUG_TRACE("Net device: %p is MULTILINK PPP - Unknown to the ECM\n", dest_dev);
1925 break;
1926 }
1927
1928 DEBUG_TRACE("Net device: %p is PPP\n", dest_dev);
1929
1930 /*
1931 * Get the PPP channel and then enquire what kind of channel it is
1932 * NOTE: Not multilink so only one channel to get.
1933 */
1934 channel_count = ppp_hold_channels(dest_dev, ppp_chan, 1);
1935 if (channel_count != 1) {
1936 DEBUG_TRACE("Net device: %p PPP has %d channels - Unknown to the ECM\n",
1937 dest_dev, channel_count);
1938 break;
1939 }
1940
1941 /*
1942 * Get channel protocol type
Gareth Williams6f96a4b2014-05-29 19:41:21 +01001943 * NOTE: Not all PPP channels support channel specific methods.
Ben Menchaca84f36632014-02-28 20:57:38 +00001944 */
Gareth Williams6f96a4b2014-05-29 19:41:21 +01001945 channel_protocol = ppp_channel_get_protocol(ppp_chan[0]);
Ben Menchaca84f36632014-02-28 20:57:38 +00001946 if (channel_protocol != PX_PROTO_OE) {
1947 DEBUG_TRACE("Net device: %p PPP channel protocol: %d - Unknown to the ECM\n",
1948 dest_dev, channel_protocol);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301949
Ben Menchaca84f36632014-02-28 20:57:38 +00001950 /*
1951 * Release the channel
1952 */
1953 ppp_release_channels(ppp_chan, 1);
1954
1955 break;
1956 }
1957
1958 /*
1959 * PPPoE channel
1960 */
1961 DEBUG_TRACE("Net device: %p PPP channel is PPPoE\n", dest_dev);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301962
Ben Menchaca84f36632014-02-28 20:57:38 +00001963 /*
1964 * Get PPPoE session information and the underlying device it is using.
Ben Menchaca84f36632014-02-28 20:57:38 +00001965 */
Gareth Williams6f96a4b2014-05-29 19:41:21 +01001966 pppoe_channel_addressing_get(ppp_chan[0], &addressing);
Ben Menchaca84f36632014-02-28 20:57:38 +00001967
1968 /*
1969 * Copy the dev hold into this, we will release the hold later
1970 */
1971 next_dev = addressing.dev;
1972
1973 DEBUG_TRACE("Net device: %p, next device: %p (%s)\n", dest_dev, next_dev, next_dev->name);
1974
1975 /*
1976 * Release the channel. Note that next_dev is still (correctly) held.
1977 */
1978 ppp_release_channels(ppp_chan, 1);
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001979#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001980 } while (false);
1981
1982 /*
Gareth Williamsa11d4352014-05-14 18:25:49 +01001983 * No longer need dest_dev as it may become next_dev
Ben Menchaca84f36632014-02-28 20:57:38 +00001984 */
Ben Menchaca84f36632014-02-28 20:57:38 +00001985 dev_put(dest_dev);
1986
1987 /*
1988 * Check out the next_dev, if any
1989 */
1990 if (!next_dev) {
1991 int32_t i __attribute__((unused));
1992 DEBUG_INFO("Completed interface heirarchy construct with first interface @: %d\n", current_interface_index);
1993#if DEBUG_LEVEL > 1
1994 for (i = current_interface_index; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
1995 DEBUG_TRACE("\tInterface @ %d: %p, type: %d, name: %s\n",
1996 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 +05301997
Ben Menchaca84f36632014-02-28 20:57:38 +00001998 }
1999#endif
Gareth Williamsa11d4352014-05-14 18:25:49 +01002000
2001 /*
2002 * Release src_dev now
2003 */
2004 dev_put(src_dev);
Ben Menchaca84f36632014-02-28 20:57:38 +00002005 return current_interface_index;
2006 }
2007
Gareth Williamsa11d4352014-05-14 18:25:49 +01002008 /*
2009 * dest_dev becomes next_dev
2010 */
Ben Menchaca84f36632014-02-28 20:57:38 +00002011 dest_dev = next_dev;
2012 dest_dev_name = dest_dev->name;
2013 dest_dev_type = dest_dev->type;
2014 }
2015
2016 DEBUG_WARN("Too many interfaces: %d\n", current_interface_index);
2017 DEBUG_ASSERT(current_interface_index == 0, "Bad logic handling current_interface_index: %d\n", current_interface_index);
2018 dev_put(src_dev);
2019 dev_put(dest_dev);
2020
2021 /*
2022 * Release the interfaces heirarchy we constructed to this point.
2023 */
2024 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
2025 return ECM_DB_IFACE_HEIRARCHY_MAX;
2026}
2027EXPORT_SYMBOL(ecm_interface_heirarchy_construct);
2028
2029/*
Gareth Williamsadf425f2014-05-26 19:29:02 +01002030 * ecm_interface_list_stats_update()
2031 * Given an interface list, walk the interfaces and update the stats for certain types.
2032 */
2033static void ecm_interface_list_stats_update(int iface_list_first, struct ecm_db_iface_instance *iface_list[], uint8_t *mac_addr,
2034 uint32_t tx_packets, uint32_t tx_bytes, uint32_t rx_packets, uint32_t rx_bytes)
2035{
2036 int list_index;
2037
2038 for (list_index = iface_list_first; (list_index < ECM_DB_IFACE_HEIRARCHY_MAX); list_index++) {
2039 struct ecm_db_iface_instance *ii;
2040 ecm_db_iface_type_t ii_type;
2041 char *ii_name;
2042 struct net_device *dev;
2043
2044 ii = iface_list[list_index];
2045 ii_type = ecm_db_connection_iface_type_get(ii);
2046 ii_name = ecm_db_interface_type_to_string(ii_type);
2047 DEBUG_TRACE("list_index: %d, ii: %p, type: %d (%s)\n", list_index, ii, ii_type, ii_name);
2048
2049 /*
2050 * Locate real device in system
2051 */
2052 dev = dev_get_by_index(&init_net, ecm_db_iface_interface_identifier_get(ii));
2053 if (!dev) {
2054 DEBUG_WARN("Could not locate interface\n");
2055 continue;
2056 }
2057 DEBUG_TRACE("found dev: %p (%s)\n", dev, dev->name);
2058
Selin Dag1af781a2014-06-10 10:37:54 -07002059 /*
2060 * Refresh the bridge forward table entry if the port is a bridge port
2061 * Note: A bridge port can be of different interface type, e.g VLAN, ethernet.
2062 * This check, therefore, should be performed for all interface types.
2063 */
2064 if (is_valid_ether_addr(mac_addr) && ecm_front_end_is_bridge_port(dev)) {
2065 DEBUG_TRACE("Update bridge fdb entry for mac: %pM\n", mac_addr);
2066 br_refresh_fdb_entry(dev, mac_addr);
2067 }
2068
Gareth Williamsadf425f2014-05-26 19:29:02 +01002069 switch (ii_type) {
2070 struct rtnl_link_stats64 stats;
2071
Gareth Williams141d2382014-11-25 11:35:19 -08002072#ifdef ECM_INTERFACE_VLAN_ENABLE
Gareth Williamsadf425f2014-05-26 19:29:02 +01002073 case ECM_DB_IFACE_TYPE_VLAN:
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05302074 DEBUG_INFO("VLAN\n");
Gareth Williamsadf425f2014-05-26 19:29:02 +01002075 stats.rx_packets = rx_packets;
2076 stats.rx_bytes = rx_bytes;
2077 stats.tx_packets = tx_packets;
2078 stats.tx_bytes = tx_bytes;
2079 __vlan_dev_update_accel_stats(dev, &stats);
2080 break;
Gareth Williams141d2382014-11-25 11:35:19 -08002081#endif
Gareth Williamsadf425f2014-05-26 19:29:02 +01002082 case ECM_DB_IFACE_TYPE_BRIDGE:
2083 DEBUG_INFO("BRIDGE\n");
2084 stats.rx_packets = rx_packets;
2085 stats.rx_bytes = rx_bytes;
2086 stats.tx_packets = tx_packets;
2087 stats.tx_bytes = tx_bytes;
2088 br_dev_update_stats(dev, &stats);
Gareth Williamsadf425f2014-05-26 19:29:02 +01002089 break;
Gareth Williamsadf425f2014-05-26 19:29:02 +01002090 default:
2091 /*
2092 * TODO: Extend it accordingly
2093 */
2094 break;
2095 }
2096
2097 dev_put(dev);
2098 }
2099}
2100
2101/*
2102 * ecm_interface_stats_update()
2103 * Using the interface lists for the given connection, update the interface statistics for each.
2104 *
2105 * 'from' here is wrt the connection 'from' side. Likewise with 'to'.
2106 * TX is wrt what the interface has transmitted. RX is what the interface has received.
2107 */
2108void ecm_interface_stats_update(struct ecm_db_connection_instance *ci,
2109 uint32_t from_tx_packets, uint32_t from_tx_bytes, uint32_t from_rx_packets, uint32_t from_rx_bytes,
2110 uint32_t to_tx_packets, uint32_t to_tx_bytes, uint32_t to_rx_packets, uint32_t to_rx_bytes)
2111{
2112 struct ecm_db_iface_instance *from_ifaces[ECM_DB_IFACE_HEIRARCHY_MAX];
2113 struct ecm_db_iface_instance *to_ifaces[ECM_DB_IFACE_HEIRARCHY_MAX];
2114 int from_ifaces_first;
2115 int to_ifaces_first;
2116 uint8_t mac_addr[ETH_ALEN];
2117
2118 /*
2119 * Iterate the 'from' side interfaces and update statistics and state for the real HLOS interfaces
2120 * from_tx_packets / bytes: the amount transmitted by the 'from' interface
2121 * from_rx_packets / bytes: the amount received by the 'from' interface
2122 */
2123 DEBUG_INFO("%p: Update from interface stats\n", ci);
2124 from_ifaces_first = ecm_db_connection_from_interfaces_get_and_ref(ci, from_ifaces);
2125 ecm_db_connection_from_node_address_get(ci, mac_addr);
2126 ecm_interface_list_stats_update(from_ifaces_first, from_ifaces, mac_addr, from_tx_packets, from_tx_bytes, from_rx_packets, from_rx_bytes);
2127 ecm_db_connection_interfaces_deref(from_ifaces, from_ifaces_first);
2128
2129 /*
2130 * Iterate the 'to' side interfaces and update statistics and state for the real HLOS interfaces
2131 * to_tx_packets / bytes: the amount transmitted by the 'to' interface
2132 * to_rx_packets / bytes: the amount received by the 'to' interface
2133 */
2134 DEBUG_INFO("%p: Update to interface stats\n", ci);
2135 to_ifaces_first = ecm_db_connection_to_interfaces_get_and_ref(ci, to_ifaces);
2136 ecm_db_connection_to_node_address_get(ci, mac_addr);
2137 ecm_interface_list_stats_update(to_ifaces_first, to_ifaces, mac_addr, to_tx_packets, to_tx_bytes, to_rx_packets, to_rx_bytes);
2138 ecm_db_connection_interfaces_deref(to_ifaces, to_ifaces_first);
2139}
2140EXPORT_SYMBOL(ecm_interface_stats_update);
2141
2142/*
Gareth Williams3cb1ffc2014-09-19 16:04:35 +01002143 * ecm_interface_regenerate_connection()
2144 * Re-generate a specific connection
2145 */
2146void ecm_interface_regenerate_connection(struct ecm_db_connection_instance *ci)
2147{
2148 struct ecm_front_end_connection_instance *feci;
2149
2150 DEBUG_TRACE("Regenerate connection: %p\n", ci);
2151
2152 /*
2153 * Flag the connection as needing re-generation.
2154 * Re-generation occurs when we next see traffic OR an acceleration engine sync for this connection.
2155 * Refer to front end protocol specific process() functions.
2156 */
2157 ecm_db_connection_classifier_generation_change(ci);
2158
2159 /*
2160 * If the connection is accelerated then force deceleration.
2161 * Under normal circumstances deceleration would occur on the next sync received,
2162 * however, there is a situation where a sync may not occur if, say, a cable has been pulled.
2163 * The acceleration engine would see no further traffic to trigger sending a sync and so
2164 * re-generation would not occur.
2165 * The connection would stall and no-regeneration would happen leaving the connection in bad state.
2166 * NOTE: We can just call decelerate() upon the front end - if its not accelerated this will have no effect.
2167 */
2168 feci = ecm_db_connection_front_end_get_and_ref(ci);
2169 feci->decelerate(feci);
2170 feci->deref(feci);
2171}
2172
2173/*
Ben Menchaca84f36632014-02-28 20:57:38 +00002174 * ecm_interface_regenerate_connections()
2175 * Cause regeneration of all connections that are using the specified interface.
2176 */
2177static void ecm_interface_regenerate_connections(struct ecm_db_iface_instance *ii)
2178{
2179 struct ecm_db_connection_instance *ci;
2180
2181 DEBUG_TRACE("Regenerate connections using interface: %p\n", ii);
2182
2183 /*
2184 * Iterate the connections of this interface and cause each one to be re-generated.
2185 * GGG TODO NOTE: If this proves slow (need metrics here) we could just regenerate the "lot" with one very simple call.
2186 * 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
2187 * but at the cost of performance.
2188 */
2189 DEBUG_TRACE("%p: Regenerate 'from' connections\n", ii);
2190 ci = ecm_db_iface_connections_from_get_and_ref_first(ii);
2191 while (ci) {
2192 struct ecm_db_connection_instance *cin;
2193 cin = ecm_db_connection_iface_from_get_and_ref_next(ci);
2194
2195 DEBUG_TRACE("%p: Regenerate: %p", ii, ci);
Gareth Williams3cb1ffc2014-09-19 16:04:35 +01002196 ecm_interface_regenerate_connection(ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00002197 ecm_db_connection_deref(ci);
2198 ci = cin;
2199 }
2200
2201 DEBUG_TRACE("%p: Regenerate 'to' connections\n", ii);
2202 ci = ecm_db_iface_connections_to_get_and_ref_first(ii);
2203 while (ci) {
2204 struct ecm_db_connection_instance *cin;
2205 cin = ecm_db_connection_iface_to_get_and_ref_next(ci);
2206
2207 DEBUG_TRACE("%p: Regenerate: %p", ii, ci);
Gareth Williams3cb1ffc2014-09-19 16:04:35 +01002208 ecm_interface_regenerate_connection(ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00002209 ecm_db_connection_deref(ci);
2210 ci = cin;
2211 }
2212
2213 DEBUG_TRACE("%p: Regenerate 'from_nat' connections\n", ii);
2214 ci = ecm_db_iface_connections_nat_from_get_and_ref_first(ii);
2215 while (ci) {
2216 struct ecm_db_connection_instance *cin;
2217 cin = ecm_db_connection_iface_nat_from_get_and_ref_next(ci);
2218
2219 DEBUG_TRACE("%p: Regenerate: %p", ii, ci);
Gareth Williams3cb1ffc2014-09-19 16:04:35 +01002220 ecm_interface_regenerate_connection(ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00002221 ecm_db_connection_deref(ci);
2222 ci = cin;
2223 }
2224
2225 DEBUG_TRACE("%p: Regenerate 'to_nat' connections\n", ii);
2226 ci = ecm_db_iface_connections_nat_to_get_and_ref_first(ii);
2227 while (ci) {
2228 struct ecm_db_connection_instance *cin;
2229 cin = ecm_db_connection_iface_nat_to_get_and_ref_next(ci);
2230
2231 DEBUG_TRACE("%p: Regenerate: %p", ii, ci);
Gareth Williams3cb1ffc2014-09-19 16:04:35 +01002232 ecm_interface_regenerate_connection(ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00002233 ecm_db_connection_deref(ci);
2234 ci = cin;
2235 }
2236
2237 DEBUG_TRACE("%p: Regenerate COMPLETE\n", ii);
2238}
2239
2240/*
2241 * ecm_interface_dev_regenerate_connections()
2242 * Cause regeneration of all connections that are using the specified interface.
2243 */
2244static void ecm_interface_dev_regenerate_connections(struct net_device *dev)
2245{
2246 struct ecm_db_iface_instance *ii;
2247
2248 DEBUG_INFO("Regenerate connections for: %p (%s)\n", dev, dev->name);
2249
2250 /*
2251 * Establish the interface for the given device.
2252 * NOTE: The cute thing here is even if dev is previously unknown to us this will create an interface instance
2253 * 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.
2254 * However if the interface is known to us then we will get it returned by this function and process it accordingly.
2255 */
2256 ii = ecm_interface_establish_and_ref(dev);
2257 if (!ii) {
2258 DEBUG_WARN("%p: No interface instance could be established for this dev\n", dev);
2259 return;
2260 }
2261 ecm_interface_regenerate_connections(ii);
2262 DEBUG_TRACE("%p: Regenerate for %p: COMPLETE\n", dev, ii);
2263 ecm_db_iface_deref(ii);
2264}
2265
2266/*
2267 * ecm_interface_mtu_change()
2268 * MTU of interface has changed
2269 */
2270static void ecm_interface_mtu_change(struct net_device *dev)
2271{
2272 int mtu;
2273 struct ecm_db_iface_instance *ii;
2274
2275 mtu = dev->mtu;
2276 DEBUG_INFO("%p (%s): MTU Change to: %d\n", dev, dev->name, mtu);
2277
2278 /*
2279 * Establish the interface for the given device.
2280 */
2281 ii = ecm_interface_establish_and_ref(dev);
2282 if (!ii) {
2283 DEBUG_WARN("%p: No interface instance could be established for this dev\n", dev);
2284 return;
2285 }
2286
2287 /*
2288 * Change the mtu
2289 */
2290 ecm_db_iface_mtu_reset(ii, mtu);
2291 DEBUG_TRACE("%p (%s): MTU Changed to: %d\n", dev, dev->name, mtu);
2292 ecm_interface_regenerate_connections(ii);
2293 DEBUG_TRACE("%p: Regenerate for %p: COMPLETE\n", dev, ii);
2294 ecm_db_iface_deref(ii);
2295}
2296
2297/*
2298 * ecm_interface_netdev_notifier_callback()
2299 * Netdevice notifier callback to inform us of change of state of a netdevice
2300 */
2301static int ecm_interface_netdev_notifier_callback(struct notifier_block *this, unsigned long event, void *ptr)
2302{
2303 struct net_device *dev __attribute__ ((unused)) = (struct net_device *)ptr;
2304
2305 DEBUG_INFO("Net device notifier for: %p, name: %s, event: %lx\n", dev, dev->name, event);
2306
2307 switch (event) {
2308 case NETDEV_DOWN:
2309 DEBUG_INFO("Net device: %p, DOWN\n", dev);
2310 ecm_interface_dev_regenerate_connections(dev);
2311 break;
2312
2313 case NETDEV_CHANGE:
2314 DEBUG_INFO("Net device: %p, CHANGE\n", dev);
2315 if (!netif_carrier_ok(dev)) {
2316 DEBUG_INFO("Net device: %p, CARRIER BAD\n", dev);
Tushar Mathur933907c2014-06-24 17:06:14 +05302317 if (netif_is_bond_slave(dev)) {
Murat Sezginb3731e82014-11-26 12:20:59 -08002318 struct net_device *master;
2319 master = ecm_interface_get_and_hold_dev_master(dev);
2320 DEBUG_ASSERT(master, "Expected a master\n");
2321 ecm_interface_dev_regenerate_connections(master);
2322 dev_put(master);
Tushar Mathur933907c2014-06-24 17:06:14 +05302323 } else {
2324 ecm_interface_dev_regenerate_connections(dev);
2325 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002326 }
2327 break;
2328
2329 case NETDEV_CHANGEMTU:
2330 DEBUG_INFO("Net device: %p, MTU CHANGE\n", dev);
2331 ecm_interface_mtu_change(dev);
2332 break;
2333
2334 default:
2335 DEBUG_TRACE("Net device: %p, UNHANDLED: %lx\n", dev, event);
2336 break;
2337 }
2338
2339 return NOTIFY_DONE;
2340}
2341
2342/*
2343 * struct notifier_block ecm_interface_netdev_notifier
2344 * Registration for net device changes of state.
2345 */
2346static struct notifier_block ecm_interface_netdev_notifier __read_mostly = {
2347 .notifier_call = ecm_interface_netdev_notifier_callback,
2348};
2349
2350/*
Ben Menchaca84f36632014-02-28 20:57:38 +00002351 * ecm_interface_get_stop()
2352 */
Murat Sezgin1f381852014-11-20 09:51:07 -08002353static ssize_t ecm_interface_get_stop(struct device *dev,
2354 struct device_attribute *attr,
Ben Menchaca84f36632014-02-28 20:57:38 +00002355 char *buf)
2356{
2357 ssize_t count;
2358 int num;
2359
2360 /*
2361 * Operate under our locks
2362 */
2363 spin_lock_bh(&ecm_interface_lock);
2364 num = ecm_interface_stopped;
2365 spin_unlock_bh(&ecm_interface_lock);
2366
2367 count = snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", num);
2368 return count;
2369}
2370
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002371void ecm_interface_stop(int num)
2372{
2373 /*
2374 * Operate under our locks and stop further processing of packets
2375 */
2376 spin_lock_bh(&ecm_interface_lock);
2377 ecm_interface_stopped = num;
2378 spin_unlock_bh(&ecm_interface_lock);
2379
2380}
2381EXPORT_SYMBOL(ecm_interface_stop);
2382
2383
Ben Menchaca84f36632014-02-28 20:57:38 +00002384/*
2385 * ecm_interface_set_stop()
2386 */
Murat Sezgin1f381852014-11-20 09:51:07 -08002387static ssize_t ecm_interface_set_stop(struct device *dev,
2388 struct device_attribute *attr,
Ben Menchaca84f36632014-02-28 20:57:38 +00002389 const char *buf, size_t count)
2390{
2391 char num_buf[12];
2392 int num;
2393
2394 /*
2395 * Get the number from buf into a properly z-termed number buffer
2396 */
2397 if (count > 11) {
2398 return 0;
2399 }
2400 memcpy(num_buf, buf, count);
2401 num_buf[count] = '\0';
2402 sscanf(num_buf, "%d", &num);
2403 DEBUG_TRACE("ecm_interface_stop = %d\n", num);
2404
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002405 ecm_interface_stop(num);
Ben Menchaca84f36632014-02-28 20:57:38 +00002406
2407 return count;
2408}
2409
2410/*
Murat Sezgin1f381852014-11-20 09:51:07 -08002411 * System device attributes for the ECM interface.
Ben Menchaca84f36632014-02-28 20:57:38 +00002412 */
Murat Sezgin1f381852014-11-20 09:51:07 -08002413static DEVICE_ATTR(stop, 0644, ecm_interface_get_stop, ecm_interface_set_stop);
Ben Menchaca84f36632014-02-28 20:57:38 +00002414
2415/*
Murat Sezgin1f381852014-11-20 09:51:07 -08002416 * Sub system node.
2417 * Sys device control points can be found at /sys/devices/system/ecm_interface/ecm_interfaceX/
Ben Menchaca84f36632014-02-28 20:57:38 +00002418 */
Murat Sezgin1f381852014-11-20 09:51:07 -08002419static struct bus_type ecm_interface_subsys = {
Ben Menchaca84f36632014-02-28 20:57:38 +00002420 .name = "ecm_interface",
Murat Sezgin1f381852014-11-20 09:51:07 -08002421 .dev_name = "ecm_interface",
Ben Menchaca84f36632014-02-28 20:57:38 +00002422};
2423
2424/*
Murat Sezgin1f381852014-11-20 09:51:07 -08002425 * ecm_interface_dev_release()
2426 * This is a dummy release function for device.
2427 */
2428static void ecm_interface_dev_release(struct device *dev)
2429{
2430
2431}
2432
2433/*
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002434 * ecm_interface_init()
Ben Menchaca84f36632014-02-28 20:57:38 +00002435 */
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002436int ecm_interface_init(void)
Ben Menchaca84f36632014-02-28 20:57:38 +00002437{
2438 int result;
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002439 DEBUG_INFO("ECM Interface init\n");
Ben Menchaca84f36632014-02-28 20:57:38 +00002440
2441 /*
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002442 * Initialise our global lock
Ben Menchaca84f36632014-02-28 20:57:38 +00002443 */
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002444 spin_lock_init(&ecm_interface_lock);
Ben Menchaca84f36632014-02-28 20:57:38 +00002445
2446 /*
Murat Sezgin1f381852014-11-20 09:51:07 -08002447 * Register the sub system
Ben Menchaca84f36632014-02-28 20:57:38 +00002448 */
Murat Sezgin1f381852014-11-20 09:51:07 -08002449 result = subsys_system_register(&ecm_interface_subsys, NULL);
Ben Menchaca84f36632014-02-28 20:57:38 +00002450 if (result) {
Murat Sezgin1f381852014-11-20 09:51:07 -08002451 DEBUG_ERROR("Failed to register sub system %d\n", result);
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002452 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00002453 }
2454
2455 /*
Murat Sezgin1f381852014-11-20 09:51:07 -08002456 * Register system device control
Ben Menchaca84f36632014-02-28 20:57:38 +00002457 */
Murat Sezgin1f381852014-11-20 09:51:07 -08002458 memset(&ecm_interface_dev, 0, sizeof(ecm_interface_dev));
2459 ecm_interface_dev.id = 0;
2460 ecm_interface_dev.bus = &ecm_interface_subsys;
2461 ecm_interface_dev.release = &ecm_interface_dev_release;
2462 result = device_register(&ecm_interface_dev);
Ben Menchaca84f36632014-02-28 20:57:38 +00002463 if (result) {
Murat Sezgin1f381852014-11-20 09:51:07 -08002464 DEBUG_ERROR("Failed to register system device %d\n", result);
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002465 goto task_cleanup_1;
Ben Menchaca84f36632014-02-28 20:57:38 +00002466 }
2467
2468 /*
2469 * Create files, one for each parameter supported by this module
2470 */
Murat Sezgin1f381852014-11-20 09:51:07 -08002471 result = device_create_file(&ecm_interface_dev, &dev_attr_stop);
Ben Menchaca84f36632014-02-28 20:57:38 +00002472 if (result) {
2473 DEBUG_ERROR("Failed to register stop file %d\n", result);
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002474 goto task_cleanup_2;
Ben Menchaca84f36632014-02-28 20:57:38 +00002475 }
2476
2477 result = register_netdevice_notifier(&ecm_interface_netdev_notifier);
2478 if (result != 0) {
2479 DEBUG_ERROR("Failed to register netdevice notifier %d\n", result);
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002480 goto task_cleanup_2;
Ben Menchaca84f36632014-02-28 20:57:38 +00002481 }
2482
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002483 return 0;
Ben Menchaca84f36632014-02-28 20:57:38 +00002484
Ben Menchaca84f36632014-02-28 20:57:38 +00002485task_cleanup_2:
Murat Sezgin1f381852014-11-20 09:51:07 -08002486 device_unregister(&ecm_interface_dev);
Ben Menchaca84f36632014-02-28 20:57:38 +00002487task_cleanup_1:
Murat Sezgin1f381852014-11-20 09:51:07 -08002488 bus_unregister(&ecm_interface_subsys);
Ben Menchaca84f36632014-02-28 20:57:38 +00002489
Ben Menchaca84f36632014-02-28 20:57:38 +00002490 return result;
2491}
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002492EXPORT_SYMBOL(ecm_interface_init);
Ben Menchaca84f36632014-02-28 20:57:38 +00002493
2494/*
2495 * ecm_interface_exit()
2496 */
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002497void ecm_interface_exit(void)
Ben Menchaca84f36632014-02-28 20:57:38 +00002498{
2499 DEBUG_INFO("ECM Interface exit\n");
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002500
2501 spin_lock_bh(&ecm_interface_lock);
2502 ecm_interface_terminate_pending = true;
2503 spin_unlock_bh(&ecm_interface_lock);
2504
2505 unregister_netdevice_notifier(&ecm_interface_netdev_notifier);
Murat Sezgin1f381852014-11-20 09:51:07 -08002506
2507 device_remove_file(&ecm_interface_dev, &dev_attr_stop);
2508 device_unregister(&ecm_interface_dev);
2509 bus_unregister(&ecm_interface_subsys);
Ben Menchaca84f36632014-02-28 20:57:38 +00002510}
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002511EXPORT_SYMBOL(ecm_interface_exit);