blob: f85cffbe2527a9cc5f7771bc6a0d78d76b986ddf [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
17#include <linux/types.h>
18#include <linux/ip.h>
19#include <linux/tcp.h>
20#include <linux/module.h>
21#include <linux/skbuff.h>
22#include <linux/icmp.h>
23#include <linux/sysctl.h>
24#include <linux/kthread.h>
Murat Sezgin1f381852014-11-20 09:51:07 -080025#include <linux/device.h>
Ben Menchaca84f36632014-02-28 20:57:38 +000026#include <linux/fs.h>
27#include <linux/pkt_sched.h>
28#include <linux/string.h>
29#include <net/ip6_route.h>
30#include <net/ip6_fib.h>
31#include <net/ipv6.h>
32#include <net/route.h>
Gareth Williams46f4b5f2014-06-01 23:35:23 +010033#include <net/ip_fib.h>
Ben Menchaca84f36632014-02-28 20:57:38 +000034#include <net/ip.h>
35#include <net/tcp.h>
36#include <asm/unaligned.h>
37#include <asm/uaccess.h> /* for put_user */
38#include <linux/inet.h>
39#include <linux/in6.h>
40#include <linux/in.h>
41#include <linux/udp.h>
42#include <linux/tcp.h>
43
44
45#include <linux/inetdevice.h>
46#include <net/ipip.h>
47#include <net/ip6_tunnel.h>
Gareth Williams43fc0852014-05-26 19:10:00 +010048#include <net/addrconf.h>
Ben Menchaca84f36632014-02-28 20:57:38 +000049#include <linux/if_arp.h>
50#include <linux/netfilter_ipv4.h>
51#include <linux/netfilter_bridge.h>
52#include <linux/if_bridge.h>
53#include <net/arp.h>
54#include <net/netfilter/nf_conntrack.h>
55#include <net/netfilter/nf_conntrack_acct.h>
56#include <net/netfilter/nf_conntrack_helper.h>
57#include <net/netfilter/nf_conntrack_l4proto.h>
58#include <net/netfilter/nf_conntrack_l3proto.h>
59#include <net/netfilter/nf_conntrack_zones.h>
60#include <net/netfilter/nf_conntrack_core.h>
61#include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
62#include <net/netfilter/ipv4/nf_defrag_ipv4.h>
Gareth Williams141d2382014-11-25 11:35:19 -080063#ifdef ECM_INTERFACE_VLAN_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +000064#include <linux/../../net/8021q/vlan.h>
65#include <linux/if_vlan.h>
Gareth Williams141d2382014-11-25 11:35:19 -080066#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000067
68/*
69 * Debug output levels
70 * 0 = OFF
71 * 1 = ASSERTS / ERRORS
72 * 2 = 1 + WARN
73 * 3 = 2 + INFO
74 * 4 = 3 + TRACE
75 */
76#define DEBUG_LEVEL ECM_INTERFACE_DEBUG_LEVEL
77
78#include <nss_api_if.h>
79
80#include "ecm_types.h"
81#include "ecm_db_types.h"
82#include "ecm_tracker.h"
83#include "ecm_classifier.h"
84#include "ecm_front_end_types.h"
85#include "ecm_tracker_datagram.h"
86#include "ecm_tracker_udp.h"
87#include "ecm_tracker_tcp.h"
88#include "ecm_db.h"
89#include "ecm_interface.h"
90
Murat Sezgin49465a42014-11-24 15:37:48 -080091#ifdef ECM_FRONT_END_IPV6_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +000092/*
Gareth Williamsadf425f2014-05-26 19:29:02 +010093 * TODO: Remove once the Linux image and headers get propogated.
94 */
95struct net_device *ipv6_dev_find(struct net *net, struct in6_addr *addr, int strict);
Murat Sezgin49465a42014-11-24 15:37:48 -080096#endif
Gareth Williamsadf425f2014-05-26 19:29:02 +010097
98/*
Ben Menchaca84f36632014-02-28 20:57:38 +000099 * Locking - concurrency control
100 */
101static spinlock_t ecm_interface_lock; /* Protect against SMP access between netfilter, events and private threaded function. */
102
103/*
Murat Sezgin1f381852014-11-20 09:51:07 -0800104 * System device linkage
Ben Menchaca84f36632014-02-28 20:57:38 +0000105 */
Murat Sezgin1f381852014-11-20 09:51:07 -0800106static struct device ecm_interface_dev; /* System device linkage */
Ben Menchaca84f36632014-02-28 20:57:38 +0000107
108/*
109 * General operational control
110 */
111static int ecm_interface_stopped = 0; /* When non-zero further traffic will not be processed */
112
113/*
114 * Management thread control
115 */
116static bool ecm_interface_terminate_pending = false; /* True when the user has signalled we should quit */
Ben Menchaca84f36632014-02-28 20:57:38 +0000117
118/*
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100119 * ecm_interface_dev_find_by_local_addr_ipv4()
120 * Return a hold to the device for the given local IP address. Returns NULL on failure.
Gareth Williamsadf425f2014-05-26 19:29:02 +0100121 */
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100122static struct net_device *ecm_interface_dev_find_by_local_addr_ipv4(ip_addr_t addr)
Gareth Williamsadf425f2014-05-26 19:29:02 +0100123{
124 __be32 be_addr;
125 struct net_device *dev;
126
127 ECM_IP_ADDR_TO_NIN4_ADDR(be_addr, addr);
128 dev = ip_dev_find(&init_net, be_addr);
129 return dev;
130}
131
Murat Sezgin49465a42014-11-24 15:37:48 -0800132#ifdef ECM_FRONT_END_IPV6_ENABLE
Gareth Williamsadf425f2014-05-26 19:29:02 +0100133/*
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100134 * ecm_interface_dev_find_by_local_addr_ipv6()
135 * Return a hold to the device for the given local IP address. Returns NULL on failure.
Gareth Williamsadf425f2014-05-26 19:29:02 +0100136 */
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100137static struct net_device *ecm_interface_dev_find_by_local_addr_ipv6(ip_addr_t addr)
Gareth Williamsadf425f2014-05-26 19:29:02 +0100138{
139 struct in6_addr addr6;
140 struct net_device *dev;
141
142 ECM_IP_ADDR_TO_NIN6_ADDR(addr6, addr);
143 dev = (struct net_device *)ipv6_dev_find(&init_net, &addr6, 1);
144 return dev;
145}
Murat Sezgin49465a42014-11-24 15:37:48 -0800146#endif
Gareth Williamsadf425f2014-05-26 19:29:02 +0100147
148/*
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100149 * ecm_interface_dev_find_by_local_addr()
150 * Return the device on which the local address resides.
Gareth Williamsadf425f2014-05-26 19:29:02 +0100151 *
152 * Returns a hold to the device or NULL on failure.
153 */
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100154struct net_device *ecm_interface_dev_find_by_local_addr(ip_addr_t addr)
Gareth Williamsadf425f2014-05-26 19:29:02 +0100155{
156 char __attribute__((unused)) addr_str[40];
157
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100158 DEBUG_ECM_IP_ADDR_TO_STRING(addr_str, addr);
Gareth Williamsadf425f2014-05-26 19:29:02 +0100159 DEBUG_TRACE("Locate dev for: %s\n", addr_str);
160
161 if (ECM_IP_ADDR_IS_V4(addr)) {
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100162 return ecm_interface_dev_find_by_local_addr_ipv4(addr);
Gareth Williamsadf425f2014-05-26 19:29:02 +0100163 }
164
Murat Sezgin49465a42014-11-24 15:37:48 -0800165#ifdef ECM_FRONT_END_IPV6_ENABLE
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100166 return ecm_interface_dev_find_by_local_addr_ipv6(addr);
Murat Sezgin49465a42014-11-24 15:37:48 -0800167#else
168 return NULL;
169#endif
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100170}
171EXPORT_SYMBOL(ecm_interface_dev_find_by_local_addr);
172
173/*
174 * ecm_interface_dev_find_by_addr()
175 * Return the net device on which the given IP address resides. Returns NULL on faiure.
176 *
177 * NOTE: The device may be the device upon which has a default gateway to reach the address.
178 * from_local_addr is true when the device was found by a local address search.
179 */
180struct net_device *ecm_interface_dev_find_by_addr(ip_addr_t addr, bool *from_local_addr)
181{
182 char __attribute__((unused)) addr_str[40];
183 struct ecm_interface_route ecm_rt;
184 struct net_device *dev;
185 struct dst_entry *dst;
186
187 DEBUG_ECM_IP_ADDR_TO_STRING(addr_str, addr);
188
189 /*
190 * Is the address a local IP?
191 */
192 DEBUG_TRACE("find net device for address: %s\n", addr_str);
193 dev = ecm_interface_dev_find_by_local_addr(addr);
194 if (dev) {
195 *from_local_addr = true;
196 DEBUG_TRACE("addr: %s is local: %p (%s)\n", addr_str, dev, dev->name);
197 return dev;
198 }
199
200 DEBUG_TRACE("addr: %s is not local\n", addr_str);
201
202 /*
203 * Try a route to the address instead
204 * NOTE: This will locate a route entry in the route destination *cache*.
205 */
206 if (!ecm_interface_find_route_by_addr(addr, &ecm_rt)) {
207 DEBUG_WARN("addr: %s - no dev locatable\n", addr_str);
208 return NULL;
209 }
210
211 *from_local_addr = false;
212 dst = ecm_rt.dst;
213 dev = dst->dev;
214 dev_hold(dev);
215 ecm_interface_route_release(&ecm_rt);
216 DEBUG_TRACE("dest_addr: %s uses dev: %p(%s)\n", addr_str, dev, dev->name);
217 return dev;
Gareth Williamsadf425f2014-05-26 19:29:02 +0100218}
219EXPORT_SYMBOL(ecm_interface_dev_find_by_addr);
220
Murat Sezgin49465a42014-11-24 15:37:48 -0800221#ifdef ECM_FRONT_END_IPV6_ENABLE
Gareth Williamsadf425f2014-05-26 19:29:02 +0100222/*
Ben Menchaca84f36632014-02-28 20:57:38 +0000223 * ecm_interface_mac_addr_get_ipv6()
224 * Return mac for an IPv6 address
225 *
226 * GGG TODO Need to make sure this also works for local IP addresses too.
227 */
228static bool ecm_interface_mac_addr_get_ipv6(ip_addr_t addr, uint8_t *mac_addr, bool *on_link, ip_addr_t gw_addr)
229{
230 struct in6_addr daddr;
231 struct ecm_interface_route ecm_rt;
232 struct neighbour *neigh;
233 struct rt6_info *rt;
234 struct dst_entry *dst;
235
236 /*
237 * Get the MAC address that corresponds to IP address given.
238 * We look up the rt6_info entries and, from its neighbour structure, obtain the hardware address.
239 * This means we will also work if the neighbours are routers too.
240 */
241 ECM_IP_ADDR_TO_NIN6_ADDR(daddr, addr);
242 if (!ecm_interface_find_route_by_addr(addr, &ecm_rt)) {
Kiran Kumar C. S. K7d178222014-06-27 18:47:29 +0530243 *on_link = false;
Ben Menchaca84f36632014-02-28 20:57:38 +0000244 return false;
245 }
246 DEBUG_ASSERT(!ecm_rt.v4_route, "Did not locate a v6 route!\n");
247
248 /*
249 * Is this destination on link or off-link via a gateway?
250 */
251 rt = ecm_rt.rt.rtv6;
252 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)) {
253 *on_link = false;
254 ECM_NIN6_ADDR_TO_IP_ADDR(gw_addr, rt->rt6i_gateway)
255 } else {
256 *on_link = true;
257 }
258
259 rcu_read_lock();
260 dst = ecm_rt.dst;
261 neigh = dst_get_neighbour_noref(dst);
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700262 if (neigh) {
263 neigh_hold(neigh);
264 } else {
265 neigh = neigh_lookup(&nd_tbl, &daddr, dst->dev);
266 }
Ben Menchaca84f36632014-02-28 20:57:38 +0000267 if (!neigh) {
268 rcu_read_unlock();
269 ecm_interface_route_release(&ecm_rt);
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700270 DEBUG_WARN("No neigh reference\n");
Ben Menchaca84f36632014-02-28 20:57:38 +0000271 return false;
272 }
273 if (!(neigh->nud_state & NUD_VALID)) {
274 rcu_read_unlock();
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700275 neigh_release(neigh);
Ben Menchaca84f36632014-02-28 20:57:38 +0000276 ecm_interface_route_release(&ecm_rt);
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700277 DEBUG_WARN("NUD invalid\n");
Ben Menchaca84f36632014-02-28 20:57:38 +0000278 return false;
279 }
280 if (!neigh->dev) {
281 rcu_read_unlock();
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700282 neigh_release(neigh);
Ben Menchaca84f36632014-02-28 20:57:38 +0000283 ecm_interface_route_release(&ecm_rt);
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700284 DEBUG_WARN("Neigh dev invalid\n");
Ben Menchaca84f36632014-02-28 20:57:38 +0000285 return false;
286 }
287
288 /*
289 * If neigh->dev is a loopback then addr is a local address in which case we take the MAC from given device
290 */
291 if (neigh->dev->flags & IFF_LOOPBACK) {
292 // GGG TODO Create an equivalent logic to that for ipv4, maybe need to create an ip6_dev_find()?
293 DEBUG_TRACE("local address " ECM_IP_ADDR_OCTAL_FMT " (found loopback)\n", ECM_IP_ADDR_TO_OCTAL(addr));
294 memset(mac_addr, 0, 6);
295 } else {
296 memcpy(mac_addr, neigh->ha, 6);
297 }
298 rcu_read_unlock();
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700299 neigh_release(neigh);
Ben Menchaca84f36632014-02-28 20:57:38 +0000300 ecm_interface_route_release(&ecm_rt);
301
302 DEBUG_TRACE(ECM_IP_ADDR_OCTAL_FMT " maps to %pM\n", ECM_IP_ADDR_TO_OCTAL(addr), mac_addr);
303 return true;
304}
Murat Sezgin49465a42014-11-24 15:37:48 -0800305#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000306
307/*
308 * ecm_interface_mac_addr_get_ipv4()
309 * Return mac for an IPv4 address
310 */
311static bool ecm_interface_mac_addr_get_ipv4(ip_addr_t addr, uint8_t *mac_addr, bool *on_link, ip_addr_t gw_addr)
312{
313 struct neighbour *neigh;
314 struct ecm_interface_route ecm_rt;
315 struct rtable *rt;
316 struct dst_entry *dst;
317 __be32 ipv4_addr;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530318
Ben Menchaca84f36632014-02-28 20:57:38 +0000319 /*
320 * Get the MAC address that corresponds to IP address given.
321 * We look up the rtable entries and, from its neighbour structure, obtain the hardware address.
322 * This means we will also work if the neighbours are routers too.
323 * We also locate the MAC if the address is a local host address.
324 */
325 ECM_IP_ADDR_TO_NIN4_ADDR(ipv4_addr, addr);
326 if (!ecm_interface_find_route_by_addr(addr, &ecm_rt)) {
Kiran Kumar C. S. K7d178222014-06-27 18:47:29 +0530327 *on_link = false;
Ben Menchaca84f36632014-02-28 20:57:38 +0000328 return false;
329 }
330 DEBUG_ASSERT(ecm_rt.v4_route, "Did not locate a v4 route!\n");
331
332 /*
333 * Is this destination on link or off-link via a gateway?
334 */
335 rt = ecm_rt.rt.rtv4;
336 if ((rt->rt_dst != rt->rt_gateway) || (rt->rt_flags & RTF_GATEWAY)) {
337 *on_link = false;
338 ECM_NIN4_ADDR_TO_IP_ADDR(gw_addr, rt->rt_gateway)
339 } else {
340 *on_link = true;
341 }
342
343 /*
344 * Get the neighbour entry for the address
345 */
346 rcu_read_lock();
347 dst = ecm_rt.dst;
348 neigh = dst_get_neighbour_noref(dst);
349 if (neigh) {
350 neigh_hold(neigh);
351 } else {
352 neigh = neigh_lookup(&arp_tbl, &ipv4_addr, dst->dev);
353 }
354 if (!neigh) {
355 rcu_read_unlock();
356 ecm_interface_route_release(&ecm_rt);
357 return false;
358 }
359 if (!(neigh->nud_state & NUD_VALID)) {
360 rcu_read_unlock();
361 neigh_release(neigh);
362 ecm_interface_route_release(&ecm_rt);
363 return false;
364 }
365 if (!neigh->dev) {
366 rcu_read_unlock();
367 neigh_release(neigh);
368 ecm_interface_route_release(&ecm_rt);
369 return false;
370 }
371
372 /*
373 * If the device is loopback this will be because the address is a local address
374 * In this case locate the device that has this local address and get its mac.
375 */
376 if (neigh->dev->type == ARPHRD_LOOPBACK) {
377 struct net_device *dev;
378
379 DEBUG_TRACE("%pI4 finds loopback device, dev: %p (%s)\n", &ipv4_addr, neigh->dev, neigh->dev->name);
380 rcu_read_unlock();
381 neigh_release(neigh);
382 ecm_interface_route_release(&ecm_rt);
383
384 /*
385 * Lookup the device that has this IP address assigned
386 */
387 dev = ip_dev_find(&init_net, ipv4_addr);
388 if (!dev) {
389 DEBUG_WARN("Unable to locate dev for: %pI4\n", &ipv4_addr);
390 return false;
391 }
392 memcpy(mac_addr, dev->dev_addr, (size_t)dev->addr_len);
393 DEBUG_TRACE("is local addr: %pI4, mac: %pM, dev ifindex: %d, dev: %p (%s), dev_type: %d\n",
394 &ipv4_addr, mac_addr, dev->ifindex, dev, dev->name, dev->type);
395 dev_put(dev);
396 return true;
397 }
398
399 if (!(neigh->dev->flags & IFF_NOARP)) {
400 memcpy(mac_addr, neigh->ha, (size_t)neigh->dev->addr_len);
401 } else {
402 DEBUG_TRACE("non-arp device: %p (%s, type: %d) to reach %pI4\n", neigh->dev, neigh->dev->name, neigh->dev->type, &ipv4_addr);
403 memset(mac_addr, 0, 6);
404 }
405 DEBUG_TRACE("addr: %pI4, mac: %pM, iif: %d, neigh dev ifindex: %d, dev: %p (%s), dev_type: %d\n",
406 &ipv4_addr, mac_addr, rt->rt_iif, neigh->dev->ifindex, neigh->dev, neigh->dev->name, neigh->dev->type);
407
408 rcu_read_unlock();
409 neigh_release(neigh);
410 ecm_interface_route_release(&ecm_rt);
411 return true;
412}
413
414/*
415 * ecm_interface_mac_addr_get()
416 * Return the mac address for the given IP address. Returns false on failure.
417 *
418 * 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.
419 *
420 * GGG TODO Make this function work for IPv6!!!!!!!!!!!!!!
421 */
422bool ecm_interface_mac_addr_get(ip_addr_t addr, uint8_t *mac_addr, bool *on_link, ip_addr_t gw_addr)
423{
424 if (ECM_IP_ADDR_IS_V4(addr)) {
425 return ecm_interface_mac_addr_get_ipv4(addr, mac_addr, on_link, gw_addr);
426 }
427
Murat Sezgin49465a42014-11-24 15:37:48 -0800428#ifdef ECM_FRONT_END_IPV6_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000429 return ecm_interface_mac_addr_get_ipv6(addr, mac_addr, on_link, gw_addr);
Murat Sezgin49465a42014-11-24 15:37:48 -0800430#else
431 return false;
432#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000433}
434EXPORT_SYMBOL(ecm_interface_mac_addr_get);
435
436/*
437 * ecm_interface_addr_find_route_by_addr_ipv4()
438 * Return the route for the given IP address. Returns NULL on failure.
439 */
440static bool ecm_interface_find_route_by_addr_ipv4(ip_addr_t addr, struct ecm_interface_route *ecm_rt)
441{
442 __be32 be_addr;
443
444 /*
445 * Get a route to the given IP address, this will allow us to also find the interface
446 * it is using to communicate with that IP address.
447 */
448 ECM_IP_ADDR_TO_NIN4_ADDR(be_addr, addr);
449 ecm_rt->rt.rtv4 = ip_route_output(&init_net, be_addr, 0, 0, 0);
450 if (IS_ERR(ecm_rt->rt.rtv4)) {
451 DEBUG_TRACE("No output route to: %pI4n\n", &be_addr);
452 return false;
453 }
454 DEBUG_TRACE("Output route to: %pI4n is: %p\n", &be_addr, ecm_rt->rt.rtv4);
455 ecm_rt->dst = (struct dst_entry *)ecm_rt->rt.rtv4;
456 ecm_rt->v4_route = true;
457 return true;
458}
459
Murat Sezgin49465a42014-11-24 15:37:48 -0800460#ifdef ECM_FRONT_END_IPV6_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000461/*
462 * ecm_interface_addr_find_route_by_addr_ipv6()
463 * Return the route for the given IP address. Returns NULL on failure.
464 */
465static bool ecm_interface_find_route_by_addr_ipv6(ip_addr_t addr, struct ecm_interface_route *ecm_rt)
466{
467 struct in6_addr naddr;
468
469 ECM_IP_ADDR_TO_NIN6_ADDR(naddr, addr);
470
471 /*
472 * Get a route to the given IP address, this will allow us to also find the interface
473 * it is using to communicate with that IP address.
474 */
475 ecm_rt->rt.rtv6 = rt6_lookup(&init_net, &naddr, NULL, 0, 0);
476 if (!ecm_rt->rt.rtv6) {
477 DEBUG_TRACE("No output route to: " ECM_IP_ADDR_OCTAL_FMT "\n", ECM_IP_ADDR_TO_OCTAL(addr));
478 return NULL;
479 }
480 DEBUG_TRACE("Output route to: " ECM_IP_ADDR_OCTAL_FMT " is: %p\n", ECM_IP_ADDR_TO_OCTAL(addr), ecm_rt->rt.rtv6);
481 ecm_rt->dst = (struct dst_entry *)ecm_rt->rt.rtv6;
482 ecm_rt->v4_route = false;
483 return true;
484}
Murat Sezgin49465a42014-11-24 15:37:48 -0800485#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000486
487/*
488 * ecm_interface_addr_find_route_by_addr()
489 * Return the route (in the given parameter) for the given IP address. Returns false on failure.
490 *
491 * Route is the device on which the addr is reachable, which may be loopback for local addresses.
492 *
493 * Returns true if the route was able to be located. The route must be released using ecm_interface_route_release().
494 */
495bool ecm_interface_find_route_by_addr(ip_addr_t addr, struct ecm_interface_route *ecm_rt)
496{
497 char __attribute__((unused)) addr_str[40];
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530498
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100499 DEBUG_ECM_IP_ADDR_TO_STRING(addr_str, addr);
Ben Menchaca84f36632014-02-28 20:57:38 +0000500 DEBUG_TRACE("Locate route to: %s\n", addr_str);
501
502 if (ECM_IP_ADDR_IS_V4(addr)) {
503 return ecm_interface_find_route_by_addr_ipv4(addr, ecm_rt);
504 }
505
Murat Sezgin49465a42014-11-24 15:37:48 -0800506#ifdef ECM_FRONT_END_IPV6_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000507 return ecm_interface_find_route_by_addr_ipv6(addr, ecm_rt);
Murat Sezgin49465a42014-11-24 15:37:48 -0800508#else
509 return false;
510#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000511}
512EXPORT_SYMBOL(ecm_interface_find_route_by_addr);
513
514/*
515 * ecm_interface_route_release()
516 * Release an ecm route
517 */
518void ecm_interface_route_release(struct ecm_interface_route *rt)
519{
520 dst_release(rt->dst);
521}
522EXPORT_SYMBOL(ecm_interface_route_release);
523
Gareth Williams141d2382014-11-25 11:35:19 -0800524#ifdef ECM_INTERFACE_VLAN_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000525/*
Ben Menchaca84f36632014-02-28 20:57:38 +0000526 * ecm_interface_vlan_interface_establish()
527 * Returns a reference to a iface of the VLAN type, possibly creating one if necessary.
528 * Returns NULL on failure or a reference to interface.
529 */
530static struct ecm_db_iface_instance *ecm_interface_vlan_interface_establish(struct ecm_db_interface_info_vlan *type_info,
531 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
532{
533 struct ecm_db_iface_instance *nii;
534 struct ecm_db_iface_instance *ii;
535
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530536 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",
537 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 +0000538
539 /*
540 * Locate the iface
541 */
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530542 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 +0000543 if (ii) {
544 DEBUG_TRACE("%p: iface established\n", ii);
545 return ii;
546 }
547
548 /*
549 * No iface - create one
550 */
551 nii = ecm_db_iface_alloc();
552 if (!nii) {
553 DEBUG_WARN("Failed to establish iface\n");
554 return NULL;
555 }
556
557 /*
558 * Add iface into the database, atomically to avoid races creating the same thing
559 */
560 spin_lock_bh(&ecm_interface_lock);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530561 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 +0000562 if (ii) {
563 spin_unlock_bh(&ecm_interface_lock);
564 ecm_db_iface_deref(nii);
565 return ii;
566 }
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530567 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 -0500568 mtu, dev_interface_num, nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000569 spin_unlock_bh(&ecm_interface_lock);
570
571 DEBUG_TRACE("%p: vlan iface established\n", nii);
572 return nii;
573}
Gareth Williams141d2382014-11-25 11:35:19 -0800574#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000575
576/*
577 * ecm_interface_bridge_interface_establish()
578 * Returns a reference to a iface of the BRIDGE type, possibly creating one if necessary.
579 * Returns NULL on failure or a reference to interface.
580 */
581static struct ecm_db_iface_instance *ecm_interface_bridge_interface_establish(struct ecm_db_interface_info_bridge *type_info,
582 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
583{
584 struct ecm_db_iface_instance *nii;
585 struct ecm_db_iface_instance *ii;
586
587 DEBUG_INFO("Establish BRIDGE iface: %s with address: %pM, MTU: %d, if num: %d, nss if id: %d\n",
588 dev_name, type_info->address, mtu, dev_interface_num, nss_interface_num);
589
590 /*
591 * Locate the iface
592 */
593 ii = ecm_db_iface_find_and_ref_bridge(type_info->address);
594 if (ii) {
595 DEBUG_TRACE("%p: iface established\n", ii);
596 return ii;
597 }
598
599 /*
600 * No iface - create one
601 */
602 nii = ecm_db_iface_alloc();
603 if (!nii) {
604 DEBUG_WARN("Failed to establish iface\n");
605 return NULL;
606 }
607
608 /*
609 * Add iface into the database, atomically to avoid races creating the same thing
610 */
611 spin_lock_bh(&ecm_interface_lock);
612 ii = ecm_db_iface_find_and_ref_bridge(type_info->address);
613 if (ii) {
614 spin_unlock_bh(&ecm_interface_lock);
615 ecm_db_iface_deref(nii);
616 return ii;
617 }
618 ecm_db_iface_add_bridge(nii, type_info->address, dev_name,
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500619 mtu, dev_interface_num, nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000620 spin_unlock_bh(&ecm_interface_lock);
621
622 DEBUG_TRACE("%p: bridge iface established\n", nii);
623 return nii;
624}
625
626/*
627 * ecm_interface_lag_interface_establish()
628 * Returns a reference to a iface of the LAG type, possibly creating one if necessary.
629 * Returns NULL on failure or a reference to interface.
630 */
631static struct ecm_db_iface_instance *ecm_interface_lag_interface_establish(struct ecm_db_interface_info_lag *type_info,
632 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
633{
634 struct ecm_db_iface_instance *nii;
635 struct ecm_db_iface_instance *ii;
636
637 DEBUG_INFO("Establish LAG iface: %s with address: %pM, MTU: %d, if num: %d, nss if id: %d\n",
638 dev_name, type_info->address, mtu, dev_interface_num, nss_interface_num);
639
640 /*
641 * Locate the iface
642 */
643 ii = ecm_db_iface_find_and_ref_lag(type_info->address);
644 if (ii) {
645 DEBUG_TRACE("%p: iface established\n", ii);
646 return ii;
647 }
648
649 /*
650 * No iface - create one
651 */
652 nii = ecm_db_iface_alloc();
653 if (!nii) {
654 DEBUG_WARN("Failed to establish iface\n");
655 return NULL;
656 }
657
658 /*
659 * Add iface into the database, atomically to avoid races creating the same thing
660 */
661 spin_lock_bh(&ecm_interface_lock);
662 ii = ecm_db_iface_find_and_ref_lag(type_info->address);
663 if (ii) {
664 spin_unlock_bh(&ecm_interface_lock);
665 ecm_db_iface_deref(nii);
666 return ii;
667 }
668 ecm_db_iface_add_lag(nii, type_info->address, dev_name,
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500669 mtu, dev_interface_num, nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000670 spin_unlock_bh(&ecm_interface_lock);
671
672 DEBUG_TRACE("%p: lag iface established\n", nii);
673 return nii;
674}
675
676/*
677 * ecm_interface_ethernet_interface_establish()
678 * Returns a reference to a iface of the ETHERNET type, possibly creating one if necessary.
679 * Returns NULL on failure or a reference to interface.
680 */
681static struct ecm_db_iface_instance *ecm_interface_ethernet_interface_establish(struct ecm_db_interface_info_ethernet *type_info,
682 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
683{
684 struct ecm_db_iface_instance *nii;
685 struct ecm_db_iface_instance *ii;
686
687 DEBUG_INFO("Establish ETHERNET iface: %s with address: %pM, MTU: %d, if num: %d, nss if id: %d\n",
688 dev_name, type_info->address, mtu, dev_interface_num, nss_interface_num);
689
690 /*
691 * Locate the iface
692 */
Tushar Mathur4ab0bf92014-06-10 20:37:07 +0530693 ii = ecm_db_iface_ifidx_find_and_ref_ethernet(type_info->address, dev_interface_num);
694
Ben Menchaca84f36632014-02-28 20:57:38 +0000695 if (ii) {
696 DEBUG_TRACE("%p: iface established\n", ii);
697 return ii;
698 }
699
700 /*
701 * No iface - create one
702 */
703 nii = ecm_db_iface_alloc();
704 if (!nii) {
705 DEBUG_WARN("Failed to establish iface\n");
706 return NULL;
707 }
708
709 /*
710 * Add iface into the database, atomically to avoid races creating the same thing
711 */
712 spin_lock_bh(&ecm_interface_lock);
Tushar Mathur4ab0bf92014-06-10 20:37:07 +0530713 ii = ecm_db_iface_ifidx_find_and_ref_ethernet(type_info->address, dev_interface_num);
Ben Menchaca84f36632014-02-28 20:57:38 +0000714 if (ii) {
715 spin_unlock_bh(&ecm_interface_lock);
716 ecm_db_iface_deref(nii);
717 return ii;
718 }
719 ecm_db_iface_add_ethernet(nii, type_info->address, dev_name,
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500720 mtu, dev_interface_num, nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000721 spin_unlock_bh(&ecm_interface_lock);
722
723 DEBUG_TRACE("%p: ethernet iface established\n", nii);
724 return nii;
725}
726
Gareth Williamsdbb2bfd2014-11-20 16:42:09 -0800727#ifdef ECM_INTERFACE_PPP_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000728/*
729 * ecm_interface_pppoe_interface_establish()
730 * Returns a reference to a iface of the PPPoE type, possibly creating one if necessary.
731 * Returns NULL on failure or a reference to interface.
732 */
733static struct ecm_db_iface_instance *ecm_interface_pppoe_interface_establish(struct ecm_db_interface_info_pppoe *type_info,
734 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
735{
736 struct ecm_db_iface_instance *nii;
737 struct ecm_db_iface_instance *ii;
738
739 DEBUG_INFO("Establish PPPoE iface: %s with session id: %u, remote mac: %pM, MTU: %d, if num: %d, nss if id: %d\n",
740 dev_name, type_info->pppoe_session_id, type_info->remote_mac, mtu, dev_interface_num, nss_interface_num);
741
742 /*
743 * Locate the iface
744 */
745 ii = ecm_db_iface_find_and_ref_pppoe(type_info->pppoe_session_id, type_info->remote_mac);
746 if (ii) {
747 DEBUG_TRACE("%p: iface established\n", ii);
748 return ii;
749 }
750
751 /*
752 * No iface - create one
753 */
754 nii = ecm_db_iface_alloc();
755 if (!nii) {
756 DEBUG_WARN("Failed to establish iface\n");
757 return NULL;
758 }
759
760 /*
761 * Add iface into the database, atomically to avoid races creating the same thing
762 */
763 spin_lock_bh(&ecm_interface_lock);
764 ii = ecm_db_iface_find_and_ref_pppoe(type_info->pppoe_session_id, type_info->remote_mac);
765 if (ii) {
766 spin_unlock_bh(&ecm_interface_lock);
767 ecm_db_iface_deref(nii);
768 return ii;
769 }
770 ecm_db_iface_add_pppoe(nii, type_info->pppoe_session_id, type_info->remote_mac, dev_name,
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500771 mtu, dev_interface_num, nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000772 spin_unlock_bh(&ecm_interface_lock);
773
774 DEBUG_TRACE("%p: pppoe iface established\n", nii);
775 return nii;
776}
Gareth Williamsc5b9d712014-05-09 20:40:07 +0100777#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000778
779/*
780 * ecm_interface_unknown_interface_establish()
781 * Returns a reference to a iface of the UNKNOWN type, possibly creating one if necessary.
782 * Returns NULL on failure or a reference to interface.
783 */
784static struct ecm_db_iface_instance *ecm_interface_unknown_interface_establish(struct ecm_db_interface_info_unknown *type_info,
785 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
786{
787 struct ecm_db_iface_instance *nii;
788 struct ecm_db_iface_instance *ii;
789
790 DEBUG_INFO("Establish UNKNOWN iface: %s with os_specific_ident: %u, MTU: %d, if num: %d, nss if id: %d\n",
791 dev_name, type_info->os_specific_ident, mtu, dev_interface_num, nss_interface_num);
792
793 /*
794 * Locate the iface
795 */
796 ii = ecm_db_iface_find_and_ref_unknown(type_info->os_specific_ident);
797 if (ii) {
798 DEBUG_TRACE("%p: iface established\n", ii);
799 return ii;
800 }
801
802 /*
803 * No iface - create one
804 */
805 nii = ecm_db_iface_alloc();
806 if (!nii) {
807 DEBUG_WARN("Failed to establish iface\n");
808 return NULL;
809 }
810
811 /*
812 * Add iface into the database, atomically to avoid races creating the same thing
813 */
814 spin_lock_bh(&ecm_interface_lock);
815 ii = ecm_db_iface_find_and_ref_unknown(type_info->os_specific_ident);
816 if (ii) {
817 spin_unlock_bh(&ecm_interface_lock);
818 ecm_db_iface_deref(nii);
819 return ii;
820 }
821 ecm_db_iface_add_unknown(nii, type_info->os_specific_ident, dev_name,
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500822 mtu, dev_interface_num, nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000823 spin_unlock_bh(&ecm_interface_lock);
824
825 DEBUG_TRACE("%p: unknown iface established\n", nii);
826 return nii;
827}
828
829/*
830 * ecm_interface_loopback_interface_establish()
831 * Returns a reference to a iface of the LOOPBACK type, possibly creating one if necessary.
832 * Returns NULL on failure or a reference to interface.
833 */
834static struct ecm_db_iface_instance *ecm_interface_loopback_interface_establish(struct ecm_db_interface_info_loopback *type_info,
835 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
836{
837 struct ecm_db_iface_instance *nii;
838 struct ecm_db_iface_instance *ii;
839
840 DEBUG_INFO("Establish LOOPBACK iface: %s with os_specific_ident: %u, MTU: %d, if num: %d, nss if id: %d\n",
841 dev_name, type_info->os_specific_ident, mtu, dev_interface_num, nss_interface_num);
842
843 /*
844 * Locate the iface
845 */
846 ii = ecm_db_iface_find_and_ref_loopback(type_info->os_specific_ident);
847 if (ii) {
848 DEBUG_TRACE("%p: iface established\n", ii);
849 return ii;
850 }
851
852 /*
853 * No iface - create one
854 */
855 nii = ecm_db_iface_alloc();
856 if (!nii) {
857 DEBUG_WARN("Failed to establish iface\n");
858 return NULL;
859 }
860
861 /*
862 * Add iface into the database, atomically to avoid races creating the same thing
863 */
864 spin_lock_bh(&ecm_interface_lock);
865 ii = ecm_db_iface_find_and_ref_loopback(type_info->os_specific_ident);
866 if (ii) {
867 spin_unlock_bh(&ecm_interface_lock);
868 ecm_db_iface_deref(nii);
869 return ii;
870 }
871 ecm_db_iface_add_loopback(nii, type_info->os_specific_ident, dev_name,
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500872 mtu, dev_interface_num, nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000873 spin_unlock_bh(&ecm_interface_lock);
874
875 DEBUG_TRACE("%p: loopback iface established\n", nii);
876 return nii;
877}
878
879/*
880 * ecm_interface_ipsec_tunnel_interface_establish()
881 * Returns a reference to a iface of the IPSEC_TUNNEL type, possibly creating one if necessary.
882 * Returns NULL on failure or a reference to interface.
883 *
884 * NOTE: GGG TODO THIS NEEDS TO TAKE A PROPER APPROACH TO IPSEC TUNNELS USING ENDPOINT ADDRESSING AS THE TYPE INFO KEYS
885 */
886static struct ecm_db_iface_instance *ecm_interface_ipsec_tunnel_interface_establish(struct ecm_db_interface_info_ipsec_tunnel *type_info,
887 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
888{
889 struct ecm_db_iface_instance *nii;
890 struct ecm_db_iface_instance *ii;
891
892 DEBUG_INFO("Establish IPSEC_TUNNEL iface: %s with os_specific_ident: %u, MTU: %d, if num: %d, nss if id: %d\n",
893 dev_name, type_info->os_specific_ident, mtu, dev_interface_num, nss_interface_num);
894
895 /*
896 * Locate the iface
897 */
898 ii = ecm_db_iface_find_and_ref_ipsec_tunnel(type_info->os_specific_ident);
899 if (ii) {
900 DEBUG_TRACE("%p: iface established\n", ii);
901 return ii;
902 }
903
904 /*
905 * No iface - create one
906 */
907 nii = ecm_db_iface_alloc();
908 if (!nii) {
909 DEBUG_WARN("Failed to establish iface\n");
910 return NULL;
911 }
912
913 /*
914 * Add iface into the database, atomically to avoid races creating the same thing
915 */
916 spin_lock_bh(&ecm_interface_lock);
917 ii = ecm_db_iface_find_and_ref_ipsec_tunnel(type_info->os_specific_ident);
918 if (ii) {
919 spin_unlock_bh(&ecm_interface_lock);
920 ecm_db_iface_deref(nii);
921 return ii;
922 }
923 ecm_db_iface_add_ipsec_tunnel(nii, type_info->os_specific_ident, dev_name,
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500924 mtu, dev_interface_num, nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000925 spin_unlock_bh(&ecm_interface_lock);
926
927 DEBUG_TRACE("%p: ipsec_tunnel iface established\n", nii);
928 return nii;
929}
930
Murat Sezgincc6eedf2014-05-09 23:59:19 -0700931#ifdef CONFIG_IPV6_SIT_6RD
Ben Menchaca84f36632014-02-28 20:57:38 +0000932/*
933 * ecm_interface_sit_interface_establish()
934 * Returns a reference to a iface of the SIT type, possibly creating one if necessary.
935 * Returns NULL on failure or a reference to interface.
936 */
937static struct ecm_db_iface_instance *ecm_interface_sit_interface_establish(struct ecm_db_interface_info_sit *type_info,
938 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
939{
940 struct ecm_db_iface_instance *nii;
941 struct ecm_db_iface_instance *ii;
942
943 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",
944 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);
945
946 /*
947 * Locate the iface
948 */
949 ii = ecm_db_iface_find_and_ref_sit(type_info->saddr, type_info->daddr);
950 if (ii) {
951 DEBUG_TRACE("%p: iface established\n", ii);
952 return ii;
953 }
954
955 /*
956 * No iface - create one
957 */
958 nii = ecm_db_iface_alloc();
959 if (!nii) {
960 DEBUG_WARN("Failed to establish iface\n");
961 return NULL;
962 }
963
964 /*
965 * Add iface into the database, atomically to avoid races creating the same thing
966 */
967 spin_lock_bh(&ecm_interface_lock);
968 ii = ecm_db_iface_find_and_ref_sit(type_info->saddr, type_info->daddr);
969 if (ii) {
970 spin_unlock_bh(&ecm_interface_lock);
971 ecm_db_iface_deref(nii);
972 return ii;
973 }
974 ecm_db_iface_add_sit(nii, type_info, dev_name, mtu, dev_interface_num,
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500975 nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000976 spin_unlock_bh(&ecm_interface_lock);
977
978 DEBUG_TRACE("%p: sit iface established\n", nii);
979 return nii;
980}
Murat Sezgincc6eedf2014-05-09 23:59:19 -0700981#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000982
983/*
984 * ecm_interface_tunipip6_interface_establish()
985 * Returns a reference to a iface of the TUNIPIP6 type, possibly creating one if necessary.
986 * Returns NULL on failure or a reference to interface.
987 */
988static struct ecm_db_iface_instance *ecm_interface_tunipip6_interface_establish(struct ecm_db_interface_info_tunipip6 *type_info,
989 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
990{
991 struct ecm_db_iface_instance *nii;
992 struct ecm_db_iface_instance *ii;
993
994 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",
995 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);
996
997 /*
998 * Locate the iface
999 */
1000 ii = ecm_db_iface_find_and_ref_tunipip6(type_info->saddr, type_info->daddr);
1001 if (ii) {
1002 DEBUG_TRACE("%p: iface established\n", ii);
1003 return ii;
1004 }
1005
1006 /*
1007 * No iface - create one
1008 */
1009 nii = ecm_db_iface_alloc();
1010 if (!nii) {
1011 DEBUG_WARN("Failed to establish iface\n");
1012 return NULL;
1013 }
1014
1015 /*
1016 * Add iface into the database, atomically to avoid races creating the same thing
1017 */
1018 spin_lock_bh(&ecm_interface_lock);
1019 ii = ecm_db_iface_find_and_ref_tunipip6(type_info->saddr, type_info->daddr);
1020 if (ii) {
1021 spin_unlock_bh(&ecm_interface_lock);
1022 ecm_db_iface_deref(nii);
1023 return ii;
1024 }
1025 ecm_db_iface_add_tunipip6(nii, type_info, dev_name, mtu, dev_interface_num,
Nicolas Costaf46c33b2014-05-15 10:02:00 -05001026 nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +00001027 spin_unlock_bh(&ecm_interface_lock);
1028
1029 DEBUG_TRACE("%p: tunipip6 iface established\n", nii);
1030 return nii;
1031}
1032
1033/*
1034 * ecm_interface_establish_and_ref()
1035 * Establish an interface instance for the given interface detail.
1036 */
1037struct ecm_db_iface_instance *ecm_interface_establish_and_ref(struct net_device *dev)
1038{
1039 int32_t dev_interface_num;
1040 char *dev_name;
1041 int32_t dev_type;
1042 int32_t dev_mtu;
1043 int32_t nss_interface_num;
1044 struct ecm_db_iface_instance *ii;
1045 union {
1046 struct ecm_db_interface_info_ethernet ethernet; /* type == ECM_DB_IFACE_TYPE_ETHERNET */
Gareth Williams141d2382014-11-25 11:35:19 -08001047#ifdef ECM_INTERFACE_VLAN_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001048 struct ecm_db_interface_info_vlan vlan; /* type == ECM_DB_IFACE_TYPE_VLAN */
Gareth Williams141d2382014-11-25 11:35:19 -08001049#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001050 struct ecm_db_interface_info_lag lag; /* type == ECM_DB_IFACE_TYPE_LAG */
1051 struct ecm_db_interface_info_bridge bridge; /* type == ECM_DB_IFACE_TYPE_BRIDGE */
1052 struct ecm_db_interface_info_pppoe pppoe; /* type == ECM_DB_IFACE_TYPE_PPPOE */
1053 struct ecm_db_interface_info_unknown unknown; /* type == ECM_DB_IFACE_TYPE_UNKNOWN */
1054 struct ecm_db_interface_info_loopback loopback; /* type == ECM_DB_IFACE_TYPE_LOOPBACK */
1055 struct ecm_db_interface_info_ipsec_tunnel ipsec_tunnel; /* type == ECM_DB_IFACE_TYPE_IPSEC_TUNNEL */
1056 struct ecm_db_interface_info_sit sit; /* type == ECM_DB_IFACE_TYPE_SIT */
1057 struct ecm_db_interface_info_tunipip6 tunipip6; /* type == ECM_DB_IFACE_TYPE_TUNIPIP6 */
1058 } type_info;
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001059
Gareth Williamsdbb2bfd2014-11-20 16:42:09 -08001060#ifdef ECM_INTERFACE_PPP_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001061 int channel_count;
1062 struct ppp_channel *ppp_chan[1];
Ben Menchaca84f36632014-02-28 20:57:38 +00001063 int channel_protocol;
Ben Menchaca84f36632014-02-28 20:57:38 +00001064 struct pppoe_opt addressing;
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001065#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001066
1067 /*
1068 * Get basic information about the given device
1069 */
1070 dev_interface_num = dev->ifindex;
1071 dev_name = dev->name;
1072 dev_type = dev->type;
1073 dev_mtu = dev->mtu;
1074
1075 /*
1076 * Does the NSS recognise this interface?
1077 */
1078 nss_interface_num = nss_cmn_get_interface_number_by_dev(dev);
1079
1080 DEBUG_TRACE("Establish interface instance for device: %p is type: %d, name: %s, ifindex: %d, nss_if: %d, mtu: %d\n",
1081 dev, dev_type, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1082
1083 /*
1084 * Extract from the device more type-specific information
1085 */
1086 if (dev_type == ARPHRD_ETHER) {
1087 /*
1088 * Ethernet - but what sub type?
1089 */
1090
Gareth Williams141d2382014-11-25 11:35:19 -08001091#ifdef ECM_INTERFACE_VLAN_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001092 /*
1093 * VLAN?
1094 */
1095 if (is_vlan_dev(dev)) {
1096 /*
1097 * VLAN master
1098 * GGG No locking needed here, ASSUMPTION is that real_dev is held for as long as we have dev.
1099 */
1100 memcpy(type_info.vlan.address, dev->dev_addr, 6);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301101 type_info.vlan.vlan_tag = vlan_dev_vlan_id(dev);
1102 type_info.vlan.vlan_tpid = VLAN_CTAG_TPID;
1103 DEBUG_TRACE("Net device: %p is VLAN, mac: %pM, vlan_id: %x vlan_tpid: %x\n",
1104 dev, type_info.vlan.address, type_info.vlan.vlan_tag, type_info.vlan.vlan_tpid);
Ben Menchaca84f36632014-02-28 20:57:38 +00001105
1106 /*
1107 * Establish this type of interface
1108 */
1109 ii = ecm_interface_vlan_interface_establish(&type_info.vlan, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1110 return ii;
1111 }
Gareth Williams141d2382014-11-25 11:35:19 -08001112#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001113
1114 /*
1115 * BRIDGE?
1116 */
1117 if (ecm_front_end_is_bridge_device(dev)) {
1118 /*
1119 * Bridge
1120 */
1121 memcpy(type_info.bridge.address, dev->dev_addr, 6);
1122
1123 DEBUG_TRACE("Net device: %p is BRIDGE, mac: %pM\n",
1124 dev, type_info.bridge.address);
1125
1126 /*
1127 * Establish this type of interface
1128 */
1129 ii = ecm_interface_bridge_interface_establish(&type_info.bridge, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1130 return ii;
1131 }
1132
1133 /*
1134 * LAG?
1135 */
1136 if (ecm_front_end_is_lag_master(dev)) {
1137 /*
1138 * Link aggregation
1139 */
1140 memcpy(type_info.lag.address, dev->dev_addr, 6);
1141
1142 DEBUG_TRACE("Net device: %p is LAG, mac: %pM\n",
1143 dev, type_info.lag.address);
1144
1145 /*
1146 * Establish this type of interface
1147 */
1148 ii = ecm_interface_lag_interface_establish(&type_info.lag, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1149 return ii;
1150 }
1151
1152 /*
1153 * ETHERNET!
1154 * Just plain ethernet it seems
1155 */
1156 memcpy(type_info.ethernet.address, dev->dev_addr, 6);
1157 DEBUG_TRACE("Net device: %p is ETHERNET, mac: %pM\n",
1158 dev, type_info.ethernet.address);
1159
1160 /*
1161 * Establish this type of interface
1162 */
1163 ii = ecm_interface_ethernet_interface_establish(&type_info.ethernet, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1164 return ii;
1165 }
1166
1167 /*
1168 * LOOPBACK?
1169 */
1170 if (dev_type == ARPHRD_LOOPBACK) {
1171 DEBUG_TRACE("Net device: %p is LOOPBACK type: %d\n", dev, dev_type);
1172 type_info.loopback.os_specific_ident = dev_interface_num;
1173 ii = ecm_interface_loopback_interface_establish(&type_info.loopback, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1174 return ii;
1175 }
1176
1177 /*
1178 * IPSEC?
1179 */
1180 if (dev_type == ECM_ARPHRD_IPSEC_TUNNEL_TYPE) {
1181 DEBUG_TRACE("Net device: %p is IPSec tunnel type: %d\n", dev, dev_type);
1182 type_info.ipsec_tunnel.os_specific_ident = dev_interface_num;
Ankit Dhanuka6d5014a2014-06-22 17:21:44 +05301183
1184 /*
1185 * nss_interface_num for all IPsec tunnels will always be NSS_C2C_TX_INTERFACE
1186 */
1187 nss_interface_num = NSS_C2C_TX_INTERFACE;
1188
Ben Menchaca84f36632014-02-28 20:57:38 +00001189 // GGG TODO Flesh this out with tunnel endpoint addressing detail
1190 ii = ecm_interface_ipsec_tunnel_interface_establish(&type_info.ipsec_tunnel, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1191 return ii;
1192 }
1193
Murat Sezgincc6eedf2014-05-09 23:59:19 -07001194#ifdef CONFIG_IPV6_SIT_6RD
Ben Menchaca84f36632014-02-28 20:57:38 +00001195 /*
1196 * SIT (6-in-4)?
1197 */
1198 if (dev_type == ARPHRD_SIT) {
1199 struct ip_tunnel *tunnel;
1200 struct ip_tunnel_6rd_parm *ip6rd;
1201 const struct iphdr *tiph;
1202
1203 DEBUG_TRACE("Net device: %p is SIT (6-in-4) type: %d\n", dev, dev_type);
1204
1205 tunnel = (struct ip_tunnel*)netdev_priv(dev);
1206 ip6rd = &tunnel->ip6rd;
1207
1208 /*
1209 * Get the Tunnel device IP header info
1210 */
1211 tiph = &tunnel->parms.iph ;
1212
1213 type_info.sit.prefixlen = ip6rd->prefixlen;
1214 type_info.sit.relay_prefix = ip6rd->relay_prefix;
1215 type_info.sit.relay_prefixlen = ip6rd->relay_prefixlen;
1216 ECM_NIN4_ADDR_TO_IP_ADDR(type_info.sit.saddr, tiph->saddr);
1217 ECM_NIN4_ADDR_TO_IP_ADDR(type_info.sit.daddr, tiph->daddr);
1218 type_info.sit.prefix[0] = ntohl(ip6rd->prefix.s6_addr32[0]);
1219 type_info.sit.prefix[1] = ntohl(ip6rd->prefix.s6_addr32[1]);
1220 type_info.sit.prefix[2] = ntohl(ip6rd->prefix.s6_addr32[2]);
1221 type_info.sit.prefix[3] = ntohl(ip6rd->prefix.s6_addr32[3]);
1222 type_info.sit.ttl = tiph->ttl;
1223 type_info.sit.tos = tiph->tos;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301224
Ben Menchaca84f36632014-02-28 20:57:38 +00001225 ii = ecm_interface_sit_interface_establish(&type_info.sit, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1226 return ii;
1227 }
Murat Sezgincc6eedf2014-05-09 23:59:19 -07001228#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001229
1230 /*
1231 * IPIP6 Tunnel?
1232 */
1233 if (dev_type == ARPHRD_TUNNEL6) {
1234 struct ip6_tnl *tunnel;
1235 struct flowi6 *fl6;
1236
1237 DEBUG_TRACE("Net device: %p is TUNIPIP6 type: %d\n", dev, dev_type);
1238
1239 /*
1240 * Get the tunnel device flow information (discover the output path of the tunnel)
1241 */
1242 tunnel = (struct ip6_tnl *)netdev_priv(dev);
1243 fl6 = &tunnel->fl.u.ip6;
1244
1245 ECM_NIN6_ADDR_TO_IP_ADDR(type_info.tunipip6.saddr, fl6->saddr);
1246 ECM_NIN6_ADDR_TO_IP_ADDR(type_info.tunipip6.daddr, fl6->daddr);
1247 type_info.tunipip6.hop_limit = tunnel->parms.hop_limit;
1248 type_info.tunipip6.flags = ntohl(tunnel->parms.flags);
1249 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 +05301250
Ben Menchaca84f36632014-02-28 20:57:38 +00001251 ii = ecm_interface_tunipip6_interface_establish(&type_info.tunipip6, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1252 return ii;
1253 }
1254
1255 /*
1256 * If this is NOT PPP then it is unknown to the ecm
1257 */
1258 if (dev_type != ARPHRD_PPP) {
1259 DEBUG_TRACE("Net device: %p is UNKNOWN type: %d\n", dev, dev_type);
1260 type_info.unknown.os_specific_ident = dev_interface_num;
1261
1262 /*
1263 * Establish this type of interface
1264 */
1265 ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1266 return ii;
1267 }
1268
Gareth Williamsdbb2bfd2014-11-20 16:42:09 -08001269#ifndef ECM_INTERFACE_PPP_ENABLE
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001270 /*
1271 * PPP support is NOT provided for.
1272 * Interface is therefore unknown
1273 */
1274 DEBUG_TRACE("Net device: %p is UNKNOWN (PPP Unsupported) type: %d\n", dev, dev_type);
1275 type_info.unknown.os_specific_ident = dev_interface_num;
1276
1277 /*
1278 * Establish this type of interface
1279 */
1280 ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1281 return ii;
1282#else
Ben Menchaca84f36632014-02-28 20:57:38 +00001283 /*
1284 * PPP - but what is the channel type?
1285 * First: If this is multi-link then we do not support it
1286 */
1287 if (ppp_is_multilink(dev) > 0) {
1288 DEBUG_TRACE("Net device: %p is MULTILINK PPP - Unknown to the ECM\n", dev);
1289 type_info.unknown.os_specific_ident = dev_interface_num;
1290
1291 /*
1292 * Establish this type of interface
1293 */
1294 ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1295 return ii;
1296 }
1297
1298 DEBUG_TRACE("Net device: %p is PPP\n", dev);
1299
1300 /*
1301 * Get the PPP channel and then enquire what kind of channel it is
1302 * NOTE: Not multilink so only one channel to get.
1303 */
1304 channel_count = ppp_hold_channels(dev, ppp_chan, 1);
1305 if (channel_count != 1) {
Gareth Williams6f96a4b2014-05-29 19:41:21 +01001306 DEBUG_TRACE("Net device: %p PPP has %d channels - ECM cannot handle this (interface becomes Unknown type)\n",
1307 dev, channel_count);
Ben Menchaca84f36632014-02-28 20:57:38 +00001308 type_info.unknown.os_specific_ident = dev_interface_num;
1309
1310 /*
1311 * Establish this type of interface
1312 */
1313 ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1314 return ii;
1315 }
1316
1317 /*
1318 * Get channel protocol type
Gareth Williams6f96a4b2014-05-29 19:41:21 +01001319 * NOTE: Not all PPP channels support channel specific methods.
Ben Menchaca84f36632014-02-28 20:57:38 +00001320 */
Gareth Williams6f96a4b2014-05-29 19:41:21 +01001321 channel_protocol = ppp_channel_get_protocol(ppp_chan[0]);
Ben Menchaca84f36632014-02-28 20:57:38 +00001322 if (channel_protocol != PX_PROTO_OE) {
1323 DEBUG_TRACE("Net device: %p PPP channel protocol: %d - Unknown to the ECM\n", dev, channel_protocol);
1324 type_info.unknown.os_specific_ident = dev_interface_num;
1325
1326 /*
1327 * Release the channel
1328 */
1329 ppp_release_channels(ppp_chan, 1);
1330
1331 /*
1332 * Establish this type of interface
1333 */
1334 ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1335 return ii;
1336 }
1337
1338 /*
1339 * PPPoE channel
1340 */
1341 DEBUG_TRACE("Net device: %p PPP channel is PPPoE\n", dev);
1342
1343 /*
1344 * Get PPPoE session information and the underlying device it is using.
Ben Menchaca84f36632014-02-28 20:57:38 +00001345 */
Gareth Williams6f96a4b2014-05-29 19:41:21 +01001346 pppoe_channel_addressing_get(ppp_chan[0], &addressing);
1347 type_info.pppoe.pppoe_session_id = (uint16_t)ntohs((uint16_t)addressing.pa.sid);
Ben Menchaca84f36632014-02-28 20:57:38 +00001348 memcpy(type_info.pppoe.remote_mac, addressing.pa.remote, ETH_ALEN);
Gareth Williams6f96a4b2014-05-29 19:41:21 +01001349 dev_put(addressing.dev);
Ben Menchaca84f36632014-02-28 20:57:38 +00001350
1351 /*
1352 * Release the channel. Note that next_dev is still (correctly) held.
1353 */
1354 ppp_release_channels(ppp_chan, 1);
1355
1356 DEBUG_TRACE("Net device: %p PPPoE session: %x, remote mac: %pM\n",
1357 dev, type_info.pppoe.pppoe_session_id, type_info.pppoe.remote_mac);
1358
1359 /*
1360 * Establish this type of interface
1361 */
1362 ii = ecm_interface_pppoe_interface_establish(&type_info.pppoe, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1363 return ii;
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001364#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001365}
1366EXPORT_SYMBOL(ecm_interface_establish_and_ref);
1367
1368/*
1369 * ecm_interface_heirarchy_construct()
1370 * Construct an interface heirarchy.
1371 *
1372 * Using the given addressing, locate the interface heirarchy used to emit packets to that destination.
1373 * This is the heirarchy of interfaces a packet would transit to emit from the device.
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001374 *
1375 * We will use the given src/dest devices when is_routed is false.
1376 * When is_routed is true we will try routing tables first, failing back to any given.
1377 *
Ben Menchaca84f36632014-02-28 20:57:38 +00001378 * For example, with this network arrangement:
1379 *
1380 * PPPoE--VLAN--BRIDGE--BRIDGE_PORT(LAG_MASTER)--LAG_SLAVE_0--10.22.33.11
1381 *
Gareth Williams43fc0852014-05-26 19:10:00 +01001382 * 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 +00001383 * LAG_SLAVE_0 @ [ECM_DB_IFACE_HEIRARCHY_MAX - 5]
1384 * LAG_MASTER @ [ECM_DB_IFACE_HEIRARCHY_MAX - 4]
1385 * BRIDGE @ [ECM_DB_IFACE_HEIRARCHY_MAX - 3]
1386 * VLAN @ [ECM_DB_IFACE_HEIRARCHY_MAX - 2]
1387 * PPPOE @ [ECM_DB_IFACE_HEIRARCHY_MAX - 1]
1388 * The value returned is (ECM_DB_IFACE_HEIRARCHY_MAX - 5)
1389 *
1390 * IMPORTANT: This function will return any known interfaces in the database, when interfaces do not exist in the database
1391 * they will be created and added automatically to the database.
1392 *
1393 * GGG TODO Make this function work for IPv6!!!!!!!!!!!!!!
1394 */
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001395int32_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 +05301396 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 +00001397{
Ben Menchaca84f36632014-02-28 20:57:38 +00001398 int protocol;
1399 ip_addr_t src_addr;
1400 ip_addr_t dest_addr;
Ben Menchaca84f36632014-02-28 20:57:38 +00001401 struct net_device *dest_dev;
Ben Menchaca84f36632014-02-28 20:57:38 +00001402 char *dest_dev_name;
Ben Menchaca84f36632014-02-28 20:57:38 +00001403 int32_t dest_dev_type;
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001404 struct net_device *src_dev;
1405 char *src_dev_name;
1406 int32_t src_dev_type;
Ben Menchaca84f36632014-02-28 20:57:38 +00001407 int32_t current_interface_index;
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001408 bool from_local_addr;
Ben Menchaca84f36632014-02-28 20:57:38 +00001409
1410 /*
1411 * Get a big endian of the IPv4 address we have been given as our starting point.
1412 */
1413 protocol = packet_protocol;
1414 ECM_IP_ADDR_COPY(src_addr, packet_src_addr);
1415 ECM_IP_ADDR_COPY(dest_addr, packet_dest_addr);
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001416 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",
1417 ECM_IP_ADDR_TO_DOT(src_addr), ECM_IP_ADDR_TO_DOT(dest_addr), protocol);
Ben Menchaca84f36632014-02-28 20:57:38 +00001418
1419 /*
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001420 * Get device to reach the given destination address.
1421 * If the heirarchy is for a routed connection we must try route lookup first, falling back to any given_dest_dev.
1422 * 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 +00001423 */
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001424 from_local_addr = false;
1425 if (is_routed) {
1426 dest_dev = ecm_interface_dev_find_by_addr(dest_addr, &from_local_addr);
1427 if (!dest_dev && given_dest_dev) {
1428 /*
1429 * Fall back to any given
1430 */
1431 dest_dev = given_dest_dev;
1432 dev_hold(dest_dev);
Gareth Williams43fc0852014-05-26 19:10:00 +01001433 }
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001434 } else if (given_dest_dev) {
1435 dest_dev = given_dest_dev;
1436 dev_hold(dest_dev);
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05301437 } else {
1438 /*
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001439 * Fall back to routed look up
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05301440 */
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001441 dest_dev = ecm_interface_dev_find_by_addr(dest_addr, &from_local_addr);
Gareth Williams43fc0852014-05-26 19:10:00 +01001442 }
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05301443
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001444 /*
1445 * GGG ALERT: If the address is a local address and protocol is an IP tunnel
1446 * then this connection is a tunnel endpoint made to this device.
1447 * In which case we circumvent all proper procedure and just hack the devices to make stuff work.
1448 * GGG TODO THIS MUST BE FIXED - WE MUST USE THE INTERFACE HIERARCHY FOR ITS INTENDED PURPOSE TO
1449 * PARSE THE DEVICES AND WORK OUT THE PROPER INTERFACES INVOLVED.
1450 * E.G. IF WE TRIED TO RUN A TUNNEL OVER A VLAN OR QINQ THIS WILL BREAK AS WE DON'T DISCOVER THAT HIERARCHY
1451 */
1452 if (dest_dev && from_local_addr && (protocol == IPPROTO_IPV6)) {
1453 dev_put(dest_dev);
1454 dest_dev = given_dest_dev;
1455 if (dest_dev) {
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05301456 dev_hold(dest_dev);
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001457 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 +05301458 }
Gareth Williams43fc0852014-05-26 19:10:00 +01001459 }
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001460 if (!dest_dev) {
1461 DEBUG_WARN("dest_addr: " ECM_IP_ADDR_OCTAL_FMT " - cannot locate device\n", ECM_IP_ADDR_TO_OCTAL(dest_addr));
1462 return ECM_DB_IFACE_HEIRARCHY_MAX;
1463 }
Ben Menchaca84f36632014-02-28 20:57:38 +00001464 dest_dev_name = dest_dev->name;
1465 dest_dev_type = dest_dev->type;
1466
1467 /*
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001468 * Get device to reach the given source address.
1469 * If the heirarchy is for a routed connection we must try route lookup first, falling back to any given_src_dev.
1470 * If the heirarchy is NOT for a routed connection we try the given_src_dev first, followed by routed lookup.
1471 */
1472 from_local_addr = false;
1473 if (is_routed) {
1474 src_dev = ecm_interface_dev_find_by_addr(src_addr, &from_local_addr);
1475 if (!src_dev && given_src_dev) {
1476 /*
1477 * Fall back to any given
1478 */
1479 src_dev = given_src_dev;
1480 dev_hold(src_dev);
1481 }
1482 } else if (given_src_dev) {
1483 src_dev = given_src_dev;
1484 dev_hold(src_dev);
1485 } else {
1486 /*
1487 * Fall back to routed look up
1488 */
1489 src_dev = ecm_interface_dev_find_by_addr(src_addr, &from_local_addr);
1490 }
1491
1492 /*
1493 * GGG ALERT: If the address is a local address and protocol is an IP tunnel
1494 * then this connection is a tunnel endpoint made to this device.
1495 * In which case we circumvent all proper procedure and just hack the devices to make stuff work.
1496 * GGG TODO THIS MUST BE FIXED - WE MUST USE THE INTERFACE HIERARCHY FOR ITS INTENDED PURPOSE TO
1497 * PARSE THE DEVICES AND WORK OUT THE PROPER INTERFACES INVOLVED.
1498 * E.G. IF WE TRIED TO RUN A TUNNEL OVER A VLAN OR QINQ THIS WILL BREAK AS WE DON'T DISCOVER THAT HIERARCHY
1499 */
1500 if (src_dev && from_local_addr && (protocol == IPPROTO_IPV6)) {
1501 dev_put(src_dev);
1502 src_dev = given_src_dev;
1503 if (src_dev) {
1504 dev_hold(src_dev);
1505 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);
1506 }
1507 }
1508 if (!src_dev) {
1509 DEBUG_WARN("src_addr: " ECM_IP_ADDR_OCTAL_FMT " - cannot locate device\n", ECM_IP_ADDR_TO_OCTAL(src_addr));
1510 dev_put(dest_dev);
1511 return ECM_DB_IFACE_HEIRARCHY_MAX;
1512 }
1513 src_dev_name = src_dev->name;
1514 src_dev_type = src_dev->type;
1515
1516 /*
1517 * Check if source and dest dev are same.
1518 * For the forwarded flows which involve tunnels this will happen when called from input hook.
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05301519 */
1520 if (src_dev == dest_dev) {
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001521 DEBUG_TRACE("Protocol is :%d source dev and dest dev are same\n", protocol);
Ankit Dhanuka60683c52014-06-09 17:43:38 +05301522 if ((protocol == IPPROTO_IPV6) || (protocol == IPPROTO_ESP)) {
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05301523 /*
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001524 * This happens from the input hook
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05301525 * We do not want to create a connection entry for this
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001526 * GGG TODO YES WE DO.
1527 * GGG TODO THIS CONCERNS ME AS THIS SHOULD BE CAUGHT MUCH
1528 * EARLIER IN THE FRONT END IF POSSIBLE TO AVOID PERFORMANCE PENALTIES.
1529 * WE HAVE DONE A TREMENDOUS AMOUT OF WORK TO GET TO THIS POINT.
1530 * WE WILL ABORT HERE AND THIS WILL BE REPEATED FOR EVERY PACKET.
1531 * IN KEEPING WITH THE ECM DESIGN IT IS BETTER TO CREATE A CONNECTION AND RECORD IN THE HIERARCHY
1532 * ENOUGH INFORMATION TO ENSURE THAT ACCELERATION IS NOT BROKEN / DOES NOT OCCUR AT ALL.
1533 * THAT WAY WE DO A HEAVYWEIGHT ESTABLISHING OF A CONNECTION ONCE AND NEVER AGAIN...
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05301534 */
1535 dev_put(src_dev);
1536 dev_put(dest_dev);
1537 return ECM_DB_IFACE_HEIRARCHY_MAX;
1538 }
1539 }
1540
1541 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00001542 * Iterate until we are done or get to the max number of interfaces we can record.
1543 * NOTE: current_interface_index tracks the position of the first interface position in interfaces[]
1544 * because we add from the end first_interface grows downwards.
1545 */
1546 current_interface_index = ECM_DB_IFACE_HEIRARCHY_MAX;
1547 while (current_interface_index > 0) {
1548 struct ecm_db_iface_instance *ii;
1549 struct net_device *next_dev;
1550
1551 /*
1552 * Get the ecm db interface instance for the device at hand
1553 */
1554 ii = ecm_interface_establish_and_ref(dest_dev);
1555
1556 /*
1557 * If the interface could not be established then we abort
1558 */
1559 if (!ii) {
1560 DEBUG_WARN("Failed to establish interface: %p, name: %s\n", dest_dev, dest_dev_name);
1561 dev_put(src_dev);
1562 dev_put(dest_dev);
1563
1564 /*
1565 * Release the interfaces heirarchy we constructed to this point.
1566 */
1567 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1568 return ECM_DB_IFACE_HEIRARCHY_MAX;
1569 }
1570
1571 /*
1572 * Record the interface instance into the interfaces[]
1573 */
1574 current_interface_index--;
1575 interfaces[current_interface_index] = ii;
1576
1577 /*
1578 * Now we have to figure out what the next device will be (in the transmission path) the skb
1579 * will use to emit to the destination address.
1580 */
1581 do {
Gareth Williamsdbb2bfd2014-11-20 16:42:09 -08001582#ifdef ECM_INTERFACE_PPP_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001583 int channel_count;
1584 struct ppp_channel *ppp_chan[1];
Ben Menchaca84f36632014-02-28 20:57:38 +00001585 int channel_protocol;
Ben Menchaca84f36632014-02-28 20:57:38 +00001586 struct pppoe_opt addressing;
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001587#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001588
1589 DEBUG_TRACE("Net device: %p is type: %d, name: %s\n", dest_dev, dest_dev_type, dest_dev_name);
1590 next_dev = NULL;
1591
1592 if (dest_dev_type == ARPHRD_ETHER) {
1593 /*
1594 * Ethernet - but what sub type?
1595 */
1596
Gareth Williams141d2382014-11-25 11:35:19 -08001597#ifdef ECM_INTERFACE_VLAN_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001598 /*
1599 * VLAN?
1600 */
1601 if (is_vlan_dev(dest_dev)) {
1602 /*
1603 * VLAN master
1604 * No locking needed here, ASSUMPTION is that real_dev is held for as long as we have dev.
1605 */
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301606 next_dev = vlan_dev_real_dev(dest_dev);
Ben Menchaca84f36632014-02-28 20:57:38 +00001607 dev_hold(next_dev);
1608 DEBUG_TRACE("Net device: %p is VLAN, slave dev: %p (%s)\n",
1609 dest_dev, next_dev, next_dev->name);
1610 break;
1611 }
Gareth Williams141d2382014-11-25 11:35:19 -08001612#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001613
1614 /*
1615 * BRIDGE?
1616 */
1617 if (ecm_front_end_is_bridge_device(dest_dev)) {
1618 /*
1619 * Bridge
1620 * Figure out which port device the skb will go to using the dest_addr.
1621 */
1622 bool on_link;
Murat Sezginebf8a642014-06-06 12:51:43 -07001623 ip_addr_t gw_addr = ECM_IP_ADDR_NULL;
Ben Menchaca84f36632014-02-28 20:57:38 +00001624 uint8_t mac_addr[ETH_ALEN];
1625 if (!ecm_interface_mac_addr_get(dest_addr, mac_addr, &on_link, gw_addr)) {
1626 /*
1627 * Possible ARP does not know the address yet
1628 */
Gareth Williams9e1d17a2014-05-26 19:40:10 +01001629 DEBUG_INFO("Unable to obtain MAC address for " ECM_IP_ADDR_DOT_FMT "\n", ECM_IP_ADDR_TO_DOT(dest_addr));
1630 if (ECM_IP_ADDR_IS_V4(dest_addr)) {
1631 __be32 ipv4_addr;
1632 __be32 src_ip;
1633
1634 /*
1635 * Issue an ARP request for it, select the src_ip from which to issue the request.
1636 */
1637 ECM_IP_ADDR_TO_NIN4_ADDR(ipv4_addr, dest_addr);
1638 src_ip = inet_select_addr(dest_dev, ipv4_addr, RT_SCOPE_LINK);
1639 if (!src_ip) {
1640 DEBUG_TRACE("failed to lookup IP for %pI4\n", &ipv4_addr);
1641
1642 dev_put(src_dev);
1643 dev_put(dest_dev);
1644
1645 /*
1646 * Release the interfaces heirarchy we constructed to this point.
1647 */
1648 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1649 return ECM_DB_IFACE_HEIRARCHY_MAX;
1650 }
1651
1652 /*
1653 * If we have a GW for this address, then we have to send ARP request to the GW
1654 */
Murat Sezginebf8a642014-06-06 12:51:43 -07001655 if (!on_link && !ECM_IP_ADDR_IS_NULL(gw_addr)) {
Sol Kavyd3fd5d82014-06-05 19:27:04 -07001656 ECM_IP_ADDR_TO_NIN4_ADDR(ipv4_addr, gw_addr);
Gareth Williams9e1d17a2014-05-26 19:40:10 +01001657 }
1658
1659 DEBUG_TRACE("Send ARP for %pI4 using src_ip as %pI4\n", &ipv4_addr, &src_ip);
1660 arp_send(ARPOP_REQUEST, ETH_P_ARP, ipv4_addr, dest_dev, src_ip, NULL, NULL, NULL);
1661 }
1662
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001663 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 +00001664 dev_put(src_dev);
1665 dev_put(dest_dev);
1666
1667 /*
1668 * Release the interfaces heirarchy we constructed to this point.
1669 */
1670 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1671 return ECM_DB_IFACE_HEIRARCHY_MAX;
1672 }
1673 next_dev = br_port_dev_get(dest_dev, mac_addr);
1674 if (!next_dev) {
1675 DEBUG_WARN("Unable to obtain output port for: %pM\n", mac_addr);
1676 dev_put(src_dev);
1677 dev_put(dest_dev);
1678
1679 /*
1680 * Release the interfaces heirarchy we constructed to this point.
1681 */
1682 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1683 return ECM_DB_IFACE_HEIRARCHY_MAX;
1684 }
1685 DEBUG_TRACE("Net device: %p is BRIDGE, next_dev: %p (%s)\n", dest_dev, next_dev, next_dev->name);
1686 break;
1687 }
1688
1689 /*
1690 * LAG?
1691 */
1692 if (ecm_front_end_is_lag_master(dest_dev)) {
1693 /*
1694 * Link aggregation
1695 * Figure out which slave device of the link aggregation will be used to reach the destination.
1696 */
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05301697 bool dest_on_link = false;
1698 ip_addr_t dest_gw_addr = ECM_IP_ADDR_NULL;
1699 uint32_t src_addr_32 = 0;
1700 uint32_t dest_addr_32 = 0;
Ben Menchaca84f36632014-02-28 20:57:38 +00001701 uint8_t src_mac_addr[ETH_ALEN];
1702 uint8_t dest_mac_addr[ETH_ALEN];
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05301703 struct net_device *master_dev = NULL;
Ben Menchaca84f36632014-02-28 20:57:38 +00001704
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05301705 memset(src_mac_addr, 0, ETH_ALEN);
1706 memset(dest_mac_addr, 0, ETH_ALEN);
Ben Menchaca84f36632014-02-28 20:57:38 +00001707
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05301708 ECM_IP_ADDR_TO_NIN4_ADDR(src_addr_32, src_addr);
1709 ECM_IP_ADDR_TO_NIN4_ADDR(dest_addr_32, dest_addr);
1710
1711 if (!is_routed) {
1712 memcpy(src_mac_addr, src_node_addr, ETH_ALEN);
1713 memcpy(dest_mac_addr, dest_node_addr, ETH_ALEN);
1714 } else {
1715 /*
1716 * Use appropriate source MAC address for routed packets
1717 */
1718 if (dest_dev->master) {
1719 memcpy(src_mac_addr, dest_dev->master->dev_addr, ETH_ALEN);
1720 } else {
1721 memcpy(src_mac_addr, dest_dev->dev_addr, ETH_ALEN);
1722 }
1723
1724 /*
1725 * Determine destination MAC address for this routed packet
1726 */
1727 if (!ecm_interface_mac_addr_get(dest_addr, dest_mac_addr,
1728 &dest_on_link, dest_gw_addr)) {
1729 __be32 ipv4_addr = 0;
1730 __be32 src_ip = 0;
1731 DEBUG_WARN("Unable to obtain MAC address for "
1732 ECM_IP_ADDR_DOT_FMT "\n", ECM_IP_ADDR_TO_DOT(dest_addr));
1733
1734
1735 /*
1736 * Issue an ARP request, select the src_ip from which to issue the request.
1737 */
1738
1739 /*
1740 * find proper interfce from which to issue ARP
1741 */
1742 if (dest_dev->master) {
1743 master_dev = dest_dev->master;
1744 } else {
1745 master_dev = dest_dev;
1746 }
1747
1748 dev_hold(master_dev);
1749
1750 ECM_IP_ADDR_TO_NIN4_ADDR(ipv4_addr, dest_addr);
1751 src_ip = inet_select_addr(master_dev, ipv4_addr, RT_SCOPE_LINK);
1752 if (!src_ip) {
1753 DEBUG_TRACE("failed to lookup IP for %pI4\n", &ipv4_addr);
1754
1755 dev_put(src_dev);
1756 dev_put(dest_dev);
1757 dev_put(master_dev);
1758
1759 /*
1760 * Release the interfaces heirarchy we constructed to this point.
1761 */
1762 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1763 return ECM_DB_IFACE_HEIRARCHY_MAX;
1764 }
1765
1766 /*
1767 * If we have a GW for this address, then we have to send ARP request to the GW
1768 */
1769 if (!dest_on_link && !ECM_IP_ADDR_IS_NULL(dest_gw_addr)) {
1770 ECM_IP_ADDR_TO_NIN4_ADDR(ipv4_addr, dest_gw_addr);
1771 }
1772
1773 DEBUG_TRACE("Send ARP for %pI4 using src_ip as %pI4\n", &ipv4_addr, &src_ip);
1774 arp_send(ARPOP_REQUEST, ETH_P_ARP, ipv4_addr, master_dev, src_ip, NULL, NULL, NULL);
1775
1776
1777 dev_put(src_dev);
1778 dev_put(dest_dev);
1779 dev_put(master_dev);
1780 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1781 return ECM_DB_IFACE_HEIRARCHY_MAX;
1782 }
1783 }
1784
1785 next_dev = bond_get_tx_dev(NULL, src_mac_addr, dest_mac_addr,
1786 &src_addr_32, &dest_addr_32,
1787 htons((uint16_t)ETH_P_IP), dest_dev);
Tushar Mathur933907c2014-06-24 17:06:14 +05301788 if (next_dev && netif_carrier_ok(next_dev)) {
Ben Menchaca84f36632014-02-28 20:57:38 +00001789 dev_hold(next_dev);
1790 } else {
1791 DEBUG_WARN("Unable to obtain LAG output slave device\n");
1792 dev_put(src_dev);
1793 dev_put(dest_dev);
1794
1795 /*
1796 * Release the interfaces heirarchy we constructed to this point.
1797 */
1798 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1799 return ECM_DB_IFACE_HEIRARCHY_MAX;
1800 }
1801
1802 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 +00001803 break;
1804 }
1805
1806 /*
1807 * ETHERNET!
1808 * Just plain ethernet it seems.
1809 */
1810 DEBUG_TRACE("Net device: %p is ETHERNET\n", dest_dev);
1811 break;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301812 }
Ben Menchaca84f36632014-02-28 20:57:38 +00001813
1814 /*
1815 * LOOPBACK?
1816 */
1817 if (dest_dev_type == ARPHRD_LOOPBACK) {
1818 DEBUG_TRACE("Net device: %p is LOOPBACK type: %d\n", dest_dev, dest_dev_type);
1819 break;
1820 }
1821
1822 /*
1823 * IPSEC?
1824 */
1825 if (dest_dev_type == ECM_ARPHRD_IPSEC_TUNNEL_TYPE) {
1826 DEBUG_TRACE("Net device: %p is IPSec tunnel type: %d\n", dest_dev, dest_dev_type);
1827 // GGG TODO Figure out the next device the tunnel is using...
1828 break;
1829 }
1830
1831 /*
1832 * SIT (6-in-4)?
1833 */
1834 if (dest_dev_type == ARPHRD_SIT) {
1835 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 +01001836 // GGG TODO Figure out the next device the tunnel is using...
Ben Menchaca84f36632014-02-28 20:57:38 +00001837 break;
1838 }
1839
1840 /*
1841 * IPIP6 Tunnel?
1842 */
1843 if (dest_dev_type == ARPHRD_TUNNEL6) {
1844 DEBUG_TRACE("Net device: %p is TUNIPIP6 type: %d\n", dest_dev, dest_dev_type);
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001845 // GGG TODO Figure out the next device the tunnel is using...
Ben Menchaca84f36632014-02-28 20:57:38 +00001846 break;
1847 }
1848
1849 /*
1850 * If this is NOT PPP then it is unknown to the ecm and we cannot figure out it's next device.
1851 */
1852 if (dest_dev_type != ARPHRD_PPP) {
1853 DEBUG_TRACE("Net device: %p is UNKNOWN type: %d\n", dest_dev, dest_dev_type);
1854 break;
1855 }
1856
Gareth Williamsdbb2bfd2014-11-20 16:42:09 -08001857#ifndef ECM_INTERFACE_PPP_ENABLE
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001858 DEBUG_TRACE("Net device: %p is UNKNOWN (PPP Unsupported) type: %d\n", dest_dev, dest_dev_type);
1859#else
Ben Menchaca84f36632014-02-28 20:57:38 +00001860 /*
1861 * PPP - but what is the channel type?
1862 * First: If this is multi-link then we do not support it
1863 */
1864 if (ppp_is_multilink(dest_dev) > 0) {
1865 DEBUG_TRACE("Net device: %p is MULTILINK PPP - Unknown to the ECM\n", dest_dev);
1866 break;
1867 }
1868
1869 DEBUG_TRACE("Net device: %p is PPP\n", dest_dev);
1870
1871 /*
1872 * Get the PPP channel and then enquire what kind of channel it is
1873 * NOTE: Not multilink so only one channel to get.
1874 */
1875 channel_count = ppp_hold_channels(dest_dev, ppp_chan, 1);
1876 if (channel_count != 1) {
1877 DEBUG_TRACE("Net device: %p PPP has %d channels - Unknown to the ECM\n",
1878 dest_dev, channel_count);
1879 break;
1880 }
1881
1882 /*
1883 * Get channel protocol type
Gareth Williams6f96a4b2014-05-29 19:41:21 +01001884 * NOTE: Not all PPP channels support channel specific methods.
Ben Menchaca84f36632014-02-28 20:57:38 +00001885 */
Gareth Williams6f96a4b2014-05-29 19:41:21 +01001886 channel_protocol = ppp_channel_get_protocol(ppp_chan[0]);
Ben Menchaca84f36632014-02-28 20:57:38 +00001887 if (channel_protocol != PX_PROTO_OE) {
1888 DEBUG_TRACE("Net device: %p PPP channel protocol: %d - Unknown to the ECM\n",
1889 dest_dev, channel_protocol);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301890
Ben Menchaca84f36632014-02-28 20:57:38 +00001891 /*
1892 * Release the channel
1893 */
1894 ppp_release_channels(ppp_chan, 1);
1895
1896 break;
1897 }
1898
1899 /*
1900 * PPPoE channel
1901 */
1902 DEBUG_TRACE("Net device: %p PPP channel is PPPoE\n", dest_dev);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301903
Ben Menchaca84f36632014-02-28 20:57:38 +00001904 /*
1905 * Get PPPoE session information and the underlying device it is using.
Ben Menchaca84f36632014-02-28 20:57:38 +00001906 */
Gareth Williams6f96a4b2014-05-29 19:41:21 +01001907 pppoe_channel_addressing_get(ppp_chan[0], &addressing);
Ben Menchaca84f36632014-02-28 20:57:38 +00001908
1909 /*
1910 * Copy the dev hold into this, we will release the hold later
1911 */
1912 next_dev = addressing.dev;
1913
1914 DEBUG_TRACE("Net device: %p, next device: %p (%s)\n", dest_dev, next_dev, next_dev->name);
1915
1916 /*
1917 * Release the channel. Note that next_dev is still (correctly) held.
1918 */
1919 ppp_release_channels(ppp_chan, 1);
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001920#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001921 } while (false);
1922
1923 /*
Gareth Williamsa11d4352014-05-14 18:25:49 +01001924 * No longer need dest_dev as it may become next_dev
Ben Menchaca84f36632014-02-28 20:57:38 +00001925 */
Ben Menchaca84f36632014-02-28 20:57:38 +00001926 dev_put(dest_dev);
1927
1928 /*
1929 * Check out the next_dev, if any
1930 */
1931 if (!next_dev) {
1932 int32_t i __attribute__((unused));
1933 DEBUG_INFO("Completed interface heirarchy construct with first interface @: %d\n", current_interface_index);
1934#if DEBUG_LEVEL > 1
1935 for (i = current_interface_index; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
1936 DEBUG_TRACE("\tInterface @ %d: %p, type: %d, name: %s\n",
1937 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 +05301938
Ben Menchaca84f36632014-02-28 20:57:38 +00001939 }
1940#endif
Gareth Williamsa11d4352014-05-14 18:25:49 +01001941
1942 /*
1943 * Release src_dev now
1944 */
1945 dev_put(src_dev);
Ben Menchaca84f36632014-02-28 20:57:38 +00001946 return current_interface_index;
1947 }
1948
Gareth Williamsa11d4352014-05-14 18:25:49 +01001949 /*
1950 * dest_dev becomes next_dev
1951 */
Ben Menchaca84f36632014-02-28 20:57:38 +00001952 dest_dev = next_dev;
1953 dest_dev_name = dest_dev->name;
1954 dest_dev_type = dest_dev->type;
1955 }
1956
1957 DEBUG_WARN("Too many interfaces: %d\n", current_interface_index);
1958 DEBUG_ASSERT(current_interface_index == 0, "Bad logic handling current_interface_index: %d\n", current_interface_index);
1959 dev_put(src_dev);
1960 dev_put(dest_dev);
1961
1962 /*
1963 * Release the interfaces heirarchy we constructed to this point.
1964 */
1965 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1966 return ECM_DB_IFACE_HEIRARCHY_MAX;
1967}
1968EXPORT_SYMBOL(ecm_interface_heirarchy_construct);
1969
1970/*
Gareth Williamsadf425f2014-05-26 19:29:02 +01001971 * ecm_interface_list_stats_update()
1972 * Given an interface list, walk the interfaces and update the stats for certain types.
1973 */
1974static void ecm_interface_list_stats_update(int iface_list_first, struct ecm_db_iface_instance *iface_list[], uint8_t *mac_addr,
1975 uint32_t tx_packets, uint32_t tx_bytes, uint32_t rx_packets, uint32_t rx_bytes)
1976{
1977 int list_index;
1978
1979 for (list_index = iface_list_first; (list_index < ECM_DB_IFACE_HEIRARCHY_MAX); list_index++) {
1980 struct ecm_db_iface_instance *ii;
1981 ecm_db_iface_type_t ii_type;
1982 char *ii_name;
1983 struct net_device *dev;
1984
1985 ii = iface_list[list_index];
1986 ii_type = ecm_db_connection_iface_type_get(ii);
1987 ii_name = ecm_db_interface_type_to_string(ii_type);
1988 DEBUG_TRACE("list_index: %d, ii: %p, type: %d (%s)\n", list_index, ii, ii_type, ii_name);
1989
1990 /*
1991 * Locate real device in system
1992 */
1993 dev = dev_get_by_index(&init_net, ecm_db_iface_interface_identifier_get(ii));
1994 if (!dev) {
1995 DEBUG_WARN("Could not locate interface\n");
1996 continue;
1997 }
1998 DEBUG_TRACE("found dev: %p (%s)\n", dev, dev->name);
1999
Selin Dag1af781a2014-06-10 10:37:54 -07002000 /*
2001 * Refresh the bridge forward table entry if the port is a bridge port
2002 * Note: A bridge port can be of different interface type, e.g VLAN, ethernet.
2003 * This check, therefore, should be performed for all interface types.
2004 */
2005 if (is_valid_ether_addr(mac_addr) && ecm_front_end_is_bridge_port(dev)) {
2006 DEBUG_TRACE("Update bridge fdb entry for mac: %pM\n", mac_addr);
2007 br_refresh_fdb_entry(dev, mac_addr);
2008 }
2009
Gareth Williamsadf425f2014-05-26 19:29:02 +01002010 switch (ii_type) {
2011 struct rtnl_link_stats64 stats;
2012
Gareth Williams141d2382014-11-25 11:35:19 -08002013#ifdef ECM_INTERFACE_VLAN_ENABLE
Gareth Williamsadf425f2014-05-26 19:29:02 +01002014 case ECM_DB_IFACE_TYPE_VLAN:
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05302015 DEBUG_INFO("VLAN\n");
Gareth Williamsadf425f2014-05-26 19:29:02 +01002016 stats.rx_packets = rx_packets;
2017 stats.rx_bytes = rx_bytes;
2018 stats.tx_packets = tx_packets;
2019 stats.tx_bytes = tx_bytes;
2020 __vlan_dev_update_accel_stats(dev, &stats);
2021 break;
Gareth Williams141d2382014-11-25 11:35:19 -08002022#endif
Gareth Williamsadf425f2014-05-26 19:29:02 +01002023 case ECM_DB_IFACE_TYPE_BRIDGE:
2024 DEBUG_INFO("BRIDGE\n");
2025 stats.rx_packets = rx_packets;
2026 stats.rx_bytes = rx_bytes;
2027 stats.tx_packets = tx_packets;
2028 stats.tx_bytes = tx_bytes;
2029 br_dev_update_stats(dev, &stats);
Gareth Williamsadf425f2014-05-26 19:29:02 +01002030 break;
Gareth Williamsadf425f2014-05-26 19:29:02 +01002031 default:
2032 /*
2033 * TODO: Extend it accordingly
2034 */
2035 break;
2036 }
2037
2038 dev_put(dev);
2039 }
2040}
2041
2042/*
2043 * ecm_interface_stats_update()
2044 * Using the interface lists for the given connection, update the interface statistics for each.
2045 *
2046 * 'from' here is wrt the connection 'from' side. Likewise with 'to'.
2047 * TX is wrt what the interface has transmitted. RX is what the interface has received.
2048 */
2049void ecm_interface_stats_update(struct ecm_db_connection_instance *ci,
2050 uint32_t from_tx_packets, uint32_t from_tx_bytes, uint32_t from_rx_packets, uint32_t from_rx_bytes,
2051 uint32_t to_tx_packets, uint32_t to_tx_bytes, uint32_t to_rx_packets, uint32_t to_rx_bytes)
2052{
2053 struct ecm_db_iface_instance *from_ifaces[ECM_DB_IFACE_HEIRARCHY_MAX];
2054 struct ecm_db_iface_instance *to_ifaces[ECM_DB_IFACE_HEIRARCHY_MAX];
2055 int from_ifaces_first;
2056 int to_ifaces_first;
2057 uint8_t mac_addr[ETH_ALEN];
2058
2059 /*
2060 * Iterate the 'from' side interfaces and update statistics and state for the real HLOS interfaces
2061 * from_tx_packets / bytes: the amount transmitted by the 'from' interface
2062 * from_rx_packets / bytes: the amount received by the 'from' interface
2063 */
2064 DEBUG_INFO("%p: Update from interface stats\n", ci);
2065 from_ifaces_first = ecm_db_connection_from_interfaces_get_and_ref(ci, from_ifaces);
2066 ecm_db_connection_from_node_address_get(ci, mac_addr);
2067 ecm_interface_list_stats_update(from_ifaces_first, from_ifaces, mac_addr, from_tx_packets, from_tx_bytes, from_rx_packets, from_rx_bytes);
2068 ecm_db_connection_interfaces_deref(from_ifaces, from_ifaces_first);
2069
2070 /*
2071 * Iterate the 'to' side interfaces and update statistics and state for the real HLOS interfaces
2072 * to_tx_packets / bytes: the amount transmitted by the 'to' interface
2073 * to_rx_packets / bytes: the amount received by the 'to' interface
2074 */
2075 DEBUG_INFO("%p: Update to interface stats\n", ci);
2076 to_ifaces_first = ecm_db_connection_to_interfaces_get_and_ref(ci, to_ifaces);
2077 ecm_db_connection_to_node_address_get(ci, mac_addr);
2078 ecm_interface_list_stats_update(to_ifaces_first, to_ifaces, mac_addr, to_tx_packets, to_tx_bytes, to_rx_packets, to_rx_bytes);
2079 ecm_db_connection_interfaces_deref(to_ifaces, to_ifaces_first);
2080}
2081EXPORT_SYMBOL(ecm_interface_stats_update);
2082
2083/*
Gareth Williams3cb1ffc2014-09-19 16:04:35 +01002084 * ecm_interface_regenerate_connection()
2085 * Re-generate a specific connection
2086 */
2087void ecm_interface_regenerate_connection(struct ecm_db_connection_instance *ci)
2088{
2089 struct ecm_front_end_connection_instance *feci;
2090
2091 DEBUG_TRACE("Regenerate connection: %p\n", ci);
2092
2093 /*
2094 * Flag the connection as needing re-generation.
2095 * Re-generation occurs when we next see traffic OR an acceleration engine sync for this connection.
2096 * Refer to front end protocol specific process() functions.
2097 */
2098 ecm_db_connection_classifier_generation_change(ci);
2099
2100 /*
2101 * If the connection is accelerated then force deceleration.
2102 * Under normal circumstances deceleration would occur on the next sync received,
2103 * however, there is a situation where a sync may not occur if, say, a cable has been pulled.
2104 * The acceleration engine would see no further traffic to trigger sending a sync and so
2105 * re-generation would not occur.
2106 * The connection would stall and no-regeneration would happen leaving the connection in bad state.
2107 * NOTE: We can just call decelerate() upon the front end - if its not accelerated this will have no effect.
2108 */
2109 feci = ecm_db_connection_front_end_get_and_ref(ci);
2110 feci->decelerate(feci);
2111 feci->deref(feci);
2112}
2113
2114/*
Ben Menchaca84f36632014-02-28 20:57:38 +00002115 * ecm_interface_regenerate_connections()
2116 * Cause regeneration of all connections that are using the specified interface.
2117 */
2118static void ecm_interface_regenerate_connections(struct ecm_db_iface_instance *ii)
2119{
2120 struct ecm_db_connection_instance *ci;
2121
2122 DEBUG_TRACE("Regenerate connections using interface: %p\n", ii);
2123
2124 /*
2125 * Iterate the connections of this interface and cause each one to be re-generated.
2126 * GGG TODO NOTE: If this proves slow (need metrics here) we could just regenerate the "lot" with one very simple call.
2127 * 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
2128 * but at the cost of performance.
2129 */
2130 DEBUG_TRACE("%p: Regenerate 'from' connections\n", ii);
2131 ci = ecm_db_iface_connections_from_get_and_ref_first(ii);
2132 while (ci) {
2133 struct ecm_db_connection_instance *cin;
2134 cin = ecm_db_connection_iface_from_get_and_ref_next(ci);
2135
2136 DEBUG_TRACE("%p: Regenerate: %p", ii, ci);
Gareth Williams3cb1ffc2014-09-19 16:04:35 +01002137 ecm_interface_regenerate_connection(ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00002138 ecm_db_connection_deref(ci);
2139 ci = cin;
2140 }
2141
2142 DEBUG_TRACE("%p: Regenerate 'to' connections\n", ii);
2143 ci = ecm_db_iface_connections_to_get_and_ref_first(ii);
2144 while (ci) {
2145 struct ecm_db_connection_instance *cin;
2146 cin = ecm_db_connection_iface_to_get_and_ref_next(ci);
2147
2148 DEBUG_TRACE("%p: Regenerate: %p", ii, ci);
Gareth Williams3cb1ffc2014-09-19 16:04:35 +01002149 ecm_interface_regenerate_connection(ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00002150 ecm_db_connection_deref(ci);
2151 ci = cin;
2152 }
2153
2154 DEBUG_TRACE("%p: Regenerate 'from_nat' connections\n", ii);
2155 ci = ecm_db_iface_connections_nat_from_get_and_ref_first(ii);
2156 while (ci) {
2157 struct ecm_db_connection_instance *cin;
2158 cin = ecm_db_connection_iface_nat_from_get_and_ref_next(ci);
2159
2160 DEBUG_TRACE("%p: Regenerate: %p", ii, ci);
Gareth Williams3cb1ffc2014-09-19 16:04:35 +01002161 ecm_interface_regenerate_connection(ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00002162 ecm_db_connection_deref(ci);
2163 ci = cin;
2164 }
2165
2166 DEBUG_TRACE("%p: Regenerate 'to_nat' connections\n", ii);
2167 ci = ecm_db_iface_connections_nat_to_get_and_ref_first(ii);
2168 while (ci) {
2169 struct ecm_db_connection_instance *cin;
2170 cin = ecm_db_connection_iface_nat_to_get_and_ref_next(ci);
2171
2172 DEBUG_TRACE("%p: Regenerate: %p", ii, ci);
Gareth Williams3cb1ffc2014-09-19 16:04:35 +01002173 ecm_interface_regenerate_connection(ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00002174 ecm_db_connection_deref(ci);
2175 ci = cin;
2176 }
2177
2178 DEBUG_TRACE("%p: Regenerate COMPLETE\n", ii);
2179}
2180
2181/*
2182 * ecm_interface_dev_regenerate_connections()
2183 * Cause regeneration of all connections that are using the specified interface.
2184 */
2185static void ecm_interface_dev_regenerate_connections(struct net_device *dev)
2186{
2187 struct ecm_db_iface_instance *ii;
2188
2189 DEBUG_INFO("Regenerate connections for: %p (%s)\n", dev, dev->name);
2190
2191 /*
2192 * Establish the interface for the given device.
2193 * NOTE: The cute thing here is even if dev is previously unknown to us this will create an interface instance
2194 * 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.
2195 * However if the interface is known to us then we will get it returned by this function and process it accordingly.
2196 */
2197 ii = ecm_interface_establish_and_ref(dev);
2198 if (!ii) {
2199 DEBUG_WARN("%p: No interface instance could be established for this dev\n", dev);
2200 return;
2201 }
2202 ecm_interface_regenerate_connections(ii);
2203 DEBUG_TRACE("%p: Regenerate for %p: COMPLETE\n", dev, ii);
2204 ecm_db_iface_deref(ii);
2205}
2206
2207/*
2208 * ecm_interface_mtu_change()
2209 * MTU of interface has changed
2210 */
2211static void ecm_interface_mtu_change(struct net_device *dev)
2212{
2213 int mtu;
2214 struct ecm_db_iface_instance *ii;
2215
2216 mtu = dev->mtu;
2217 DEBUG_INFO("%p (%s): MTU Change to: %d\n", dev, dev->name, mtu);
2218
2219 /*
2220 * Establish the interface for the given device.
2221 */
2222 ii = ecm_interface_establish_and_ref(dev);
2223 if (!ii) {
2224 DEBUG_WARN("%p: No interface instance could be established for this dev\n", dev);
2225 return;
2226 }
2227
2228 /*
2229 * Change the mtu
2230 */
2231 ecm_db_iface_mtu_reset(ii, mtu);
2232 DEBUG_TRACE("%p (%s): MTU Changed to: %d\n", dev, dev->name, mtu);
2233 ecm_interface_regenerate_connections(ii);
2234 DEBUG_TRACE("%p: Regenerate for %p: COMPLETE\n", dev, ii);
2235 ecm_db_iface_deref(ii);
2236}
2237
2238/*
2239 * ecm_interface_netdev_notifier_callback()
2240 * Netdevice notifier callback to inform us of change of state of a netdevice
2241 */
2242static int ecm_interface_netdev_notifier_callback(struct notifier_block *this, unsigned long event, void *ptr)
2243{
2244 struct net_device *dev __attribute__ ((unused)) = (struct net_device *)ptr;
2245
2246 DEBUG_INFO("Net device notifier for: %p, name: %s, event: %lx\n", dev, dev->name, event);
2247
2248 switch (event) {
2249 case NETDEV_DOWN:
2250 DEBUG_INFO("Net device: %p, DOWN\n", dev);
2251 ecm_interface_dev_regenerate_connections(dev);
2252 break;
2253
2254 case NETDEV_CHANGE:
2255 DEBUG_INFO("Net device: %p, CHANGE\n", dev);
2256 if (!netif_carrier_ok(dev)) {
2257 DEBUG_INFO("Net device: %p, CARRIER BAD\n", dev);
Tushar Mathur933907c2014-06-24 17:06:14 +05302258 if (netif_is_bond_slave(dev)) {
2259 ecm_interface_dev_regenerate_connections(dev->master);
2260 } else {
2261 ecm_interface_dev_regenerate_connections(dev);
2262 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002263 }
2264 break;
2265
2266 case NETDEV_CHANGEMTU:
2267 DEBUG_INFO("Net device: %p, MTU CHANGE\n", dev);
2268 ecm_interface_mtu_change(dev);
2269 break;
2270
2271 default:
2272 DEBUG_TRACE("Net device: %p, UNHANDLED: %lx\n", dev, event);
2273 break;
2274 }
2275
2276 return NOTIFY_DONE;
2277}
2278
2279/*
2280 * struct notifier_block ecm_interface_netdev_notifier
2281 * Registration for net device changes of state.
2282 */
2283static struct notifier_block ecm_interface_netdev_notifier __read_mostly = {
2284 .notifier_call = ecm_interface_netdev_notifier_callback,
2285};
2286
2287/*
Ben Menchaca84f36632014-02-28 20:57:38 +00002288 * ecm_interface_get_stop()
2289 */
Murat Sezgin1f381852014-11-20 09:51:07 -08002290static ssize_t ecm_interface_get_stop(struct device *dev,
2291 struct device_attribute *attr,
Ben Menchaca84f36632014-02-28 20:57:38 +00002292 char *buf)
2293{
2294 ssize_t count;
2295 int num;
2296
2297 /*
2298 * Operate under our locks
2299 */
2300 spin_lock_bh(&ecm_interface_lock);
2301 num = ecm_interface_stopped;
2302 spin_unlock_bh(&ecm_interface_lock);
2303
2304 count = snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", num);
2305 return count;
2306}
2307
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002308void ecm_interface_stop(int num)
2309{
2310 /*
2311 * Operate under our locks and stop further processing of packets
2312 */
2313 spin_lock_bh(&ecm_interface_lock);
2314 ecm_interface_stopped = num;
2315 spin_unlock_bh(&ecm_interface_lock);
2316
2317}
2318EXPORT_SYMBOL(ecm_interface_stop);
2319
2320
Ben Menchaca84f36632014-02-28 20:57:38 +00002321/*
2322 * ecm_interface_set_stop()
2323 */
Murat Sezgin1f381852014-11-20 09:51:07 -08002324static ssize_t ecm_interface_set_stop(struct device *dev,
2325 struct device_attribute *attr,
Ben Menchaca84f36632014-02-28 20:57:38 +00002326 const char *buf, size_t count)
2327{
2328 char num_buf[12];
2329 int num;
2330
2331 /*
2332 * Get the number from buf into a properly z-termed number buffer
2333 */
2334 if (count > 11) {
2335 return 0;
2336 }
2337 memcpy(num_buf, buf, count);
2338 num_buf[count] = '\0';
2339 sscanf(num_buf, "%d", &num);
2340 DEBUG_TRACE("ecm_interface_stop = %d\n", num);
2341
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002342 ecm_interface_stop(num);
Ben Menchaca84f36632014-02-28 20:57:38 +00002343
2344 return count;
2345}
2346
2347/*
Murat Sezgin1f381852014-11-20 09:51:07 -08002348 * System device attributes for the ECM interface.
Ben Menchaca84f36632014-02-28 20:57:38 +00002349 */
Murat Sezgin1f381852014-11-20 09:51:07 -08002350static DEVICE_ATTR(stop, 0644, ecm_interface_get_stop, ecm_interface_set_stop);
Ben Menchaca84f36632014-02-28 20:57:38 +00002351
2352/*
Murat Sezgin1f381852014-11-20 09:51:07 -08002353 * Sub system node.
2354 * Sys device control points can be found at /sys/devices/system/ecm_interface/ecm_interfaceX/
Ben Menchaca84f36632014-02-28 20:57:38 +00002355 */
Murat Sezgin1f381852014-11-20 09:51:07 -08002356static struct bus_type ecm_interface_subsys = {
Ben Menchaca84f36632014-02-28 20:57:38 +00002357 .name = "ecm_interface",
Murat Sezgin1f381852014-11-20 09:51:07 -08002358 .dev_name = "ecm_interface",
Ben Menchaca84f36632014-02-28 20:57:38 +00002359};
2360
2361/*
Murat Sezgin1f381852014-11-20 09:51:07 -08002362 * ecm_interface_dev_release()
2363 * This is a dummy release function for device.
2364 */
2365static void ecm_interface_dev_release(struct device *dev)
2366{
2367
2368}
2369
2370/*
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002371 * ecm_interface_init()
Ben Menchaca84f36632014-02-28 20:57:38 +00002372 */
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002373int ecm_interface_init(void)
Ben Menchaca84f36632014-02-28 20:57:38 +00002374{
2375 int result;
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002376 DEBUG_INFO("ECM Interface init\n");
Ben Menchaca84f36632014-02-28 20:57:38 +00002377
2378 /*
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002379 * Initialise our global lock
Ben Menchaca84f36632014-02-28 20:57:38 +00002380 */
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002381 spin_lock_init(&ecm_interface_lock);
Ben Menchaca84f36632014-02-28 20:57:38 +00002382
2383 /*
Murat Sezgin1f381852014-11-20 09:51:07 -08002384 * Register the sub system
Ben Menchaca84f36632014-02-28 20:57:38 +00002385 */
Murat Sezgin1f381852014-11-20 09:51:07 -08002386 result = subsys_system_register(&ecm_interface_subsys, NULL);
Ben Menchaca84f36632014-02-28 20:57:38 +00002387 if (result) {
Murat Sezgin1f381852014-11-20 09:51:07 -08002388 DEBUG_ERROR("Failed to register sub system %d\n", result);
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002389 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00002390 }
2391
2392 /*
Murat Sezgin1f381852014-11-20 09:51:07 -08002393 * Register system device control
Ben Menchaca84f36632014-02-28 20:57:38 +00002394 */
Murat Sezgin1f381852014-11-20 09:51:07 -08002395 memset(&ecm_interface_dev, 0, sizeof(ecm_interface_dev));
2396 ecm_interface_dev.id = 0;
2397 ecm_interface_dev.bus = &ecm_interface_subsys;
2398 ecm_interface_dev.release = &ecm_interface_dev_release;
2399 result = device_register(&ecm_interface_dev);
Ben Menchaca84f36632014-02-28 20:57:38 +00002400 if (result) {
Murat Sezgin1f381852014-11-20 09:51:07 -08002401 DEBUG_ERROR("Failed to register system device %d\n", result);
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002402 goto task_cleanup_1;
Ben Menchaca84f36632014-02-28 20:57:38 +00002403 }
2404
2405 /*
2406 * Create files, one for each parameter supported by this module
2407 */
Murat Sezgin1f381852014-11-20 09:51:07 -08002408 result = device_create_file(&ecm_interface_dev, &dev_attr_stop);
Ben Menchaca84f36632014-02-28 20:57:38 +00002409 if (result) {
2410 DEBUG_ERROR("Failed to register stop file %d\n", result);
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002411 goto task_cleanup_2;
Ben Menchaca84f36632014-02-28 20:57:38 +00002412 }
2413
2414 result = register_netdevice_notifier(&ecm_interface_netdev_notifier);
2415 if (result != 0) {
2416 DEBUG_ERROR("Failed to register netdevice notifier %d\n", result);
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002417 goto task_cleanup_2;
Ben Menchaca84f36632014-02-28 20:57:38 +00002418 }
2419
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002420 return 0;
Ben Menchaca84f36632014-02-28 20:57:38 +00002421
Ben Menchaca84f36632014-02-28 20:57:38 +00002422task_cleanup_2:
Murat Sezgin1f381852014-11-20 09:51:07 -08002423 device_unregister(&ecm_interface_dev);
Ben Menchaca84f36632014-02-28 20:57:38 +00002424task_cleanup_1:
Murat Sezgin1f381852014-11-20 09:51:07 -08002425 bus_unregister(&ecm_interface_subsys);
Ben Menchaca84f36632014-02-28 20:57:38 +00002426
Ben Menchaca84f36632014-02-28 20:57:38 +00002427 return result;
2428}
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002429EXPORT_SYMBOL(ecm_interface_init);
Ben Menchaca84f36632014-02-28 20:57:38 +00002430
2431/*
2432 * ecm_interface_exit()
2433 */
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002434void ecm_interface_exit(void)
Ben Menchaca84f36632014-02-28 20:57:38 +00002435{
2436 DEBUG_INFO("ECM Interface exit\n");
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002437
2438 spin_lock_bh(&ecm_interface_lock);
2439 ecm_interface_terminate_pending = true;
2440 spin_unlock_bh(&ecm_interface_lock);
2441
2442 unregister_netdevice_notifier(&ecm_interface_netdev_notifier);
Murat Sezgin1f381852014-11-20 09:51:07 -08002443
2444 device_remove_file(&ecm_interface_dev, &dev_attr_stop);
2445 device_unregister(&ecm_interface_dev);
2446 bus_unregister(&ecm_interface_subsys);
Ben Menchaca84f36632014-02-28 20:57:38 +00002447}
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002448EXPORT_SYMBOL(ecm_interface_exit);