blob: b0a010b34560261a734e5f84cc8adee7e49ca16a [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>
25#include <linux/sysdev.h>
26#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>
63#include <linux/../../net/8021q/vlan.h>
64#include <linux/if_vlan.h>
65
66/*
67 * Debug output levels
68 * 0 = OFF
69 * 1 = ASSERTS / ERRORS
70 * 2 = 1 + WARN
71 * 3 = 2 + INFO
72 * 4 = 3 + TRACE
73 */
74#define DEBUG_LEVEL ECM_INTERFACE_DEBUG_LEVEL
75
76#include <nss_api_if.h>
77
78#include "ecm_types.h"
79#include "ecm_db_types.h"
80#include "ecm_tracker.h"
81#include "ecm_classifier.h"
82#include "ecm_front_end_types.h"
83#include "ecm_tracker_datagram.h"
84#include "ecm_tracker_udp.h"
85#include "ecm_tracker_tcp.h"
86#include "ecm_db.h"
87#include "ecm_interface.h"
88
89/*
Gareth Williamsadf425f2014-05-26 19:29:02 +010090 * TODO: Remove once the Linux image and headers get propogated.
91 */
92struct net_device *ipv6_dev_find(struct net *net, struct in6_addr *addr, int strict);
93
94/*
Ben Menchaca84f36632014-02-28 20:57:38 +000095 * Locking - concurrency control
96 */
97static spinlock_t ecm_interface_lock; /* Protect against SMP access between netfilter, events and private threaded function. */
98
99/*
100 * SysFS linkage
101 */
102static struct sys_device ecm_interface_sys_dev; /* SysFS linkage */
103
104/*
105 * General operational control
106 */
107static int ecm_interface_stopped = 0; /* When non-zero further traffic will not be processed */
108
109/*
110 * Management thread control
111 */
112static bool ecm_interface_terminate_pending = false; /* True when the user has signalled we should quit */
Ben Menchaca84f36632014-02-28 20:57:38 +0000113
114/*
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100115 * ecm_interface_dev_find_by_local_addr_ipv4()
116 * Return a hold to the device for the given local IP address. Returns NULL on failure.
Gareth Williamsadf425f2014-05-26 19:29:02 +0100117 */
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100118static struct net_device *ecm_interface_dev_find_by_local_addr_ipv4(ip_addr_t addr)
Gareth Williamsadf425f2014-05-26 19:29:02 +0100119{
120 __be32 be_addr;
121 struct net_device *dev;
122
123 ECM_IP_ADDR_TO_NIN4_ADDR(be_addr, addr);
124 dev = ip_dev_find(&init_net, be_addr);
125 return dev;
126}
127
128/*
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100129 * ecm_interface_dev_find_by_local_addr_ipv6()
130 * Return a hold to the device for the given local IP address. Returns NULL on failure.
Gareth Williamsadf425f2014-05-26 19:29:02 +0100131 */
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100132static struct net_device *ecm_interface_dev_find_by_local_addr_ipv6(ip_addr_t addr)
Gareth Williamsadf425f2014-05-26 19:29:02 +0100133{
134 struct in6_addr addr6;
135 struct net_device *dev;
136
137 ECM_IP_ADDR_TO_NIN6_ADDR(addr6, addr);
138 dev = (struct net_device *)ipv6_dev_find(&init_net, &addr6, 1);
139 return dev;
140}
141
142/*
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100143 * ecm_interface_dev_find_by_local_addr()
144 * Return the device on which the local address resides.
Gareth Williamsadf425f2014-05-26 19:29:02 +0100145 *
146 * Returns a hold to the device or NULL on failure.
147 */
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100148struct net_device *ecm_interface_dev_find_by_local_addr(ip_addr_t addr)
Gareth Williamsadf425f2014-05-26 19:29:02 +0100149{
150 char __attribute__((unused)) addr_str[40];
151
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100152 DEBUG_ECM_IP_ADDR_TO_STRING(addr_str, addr);
Gareth Williamsadf425f2014-05-26 19:29:02 +0100153 DEBUG_TRACE("Locate dev for: %s\n", addr_str);
154
155 if (ECM_IP_ADDR_IS_V4(addr)) {
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100156 return ecm_interface_dev_find_by_local_addr_ipv4(addr);
Gareth Williamsadf425f2014-05-26 19:29:02 +0100157 }
158
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100159 return ecm_interface_dev_find_by_local_addr_ipv6(addr);
160}
161EXPORT_SYMBOL(ecm_interface_dev_find_by_local_addr);
162
163/*
164 * ecm_interface_dev_find_by_addr()
165 * Return the net device on which the given IP address resides. Returns NULL on faiure.
166 *
167 * NOTE: The device may be the device upon which has a default gateway to reach the address.
168 * from_local_addr is true when the device was found by a local address search.
169 */
170struct net_device *ecm_interface_dev_find_by_addr(ip_addr_t addr, bool *from_local_addr)
171{
172 char __attribute__((unused)) addr_str[40];
173 struct ecm_interface_route ecm_rt;
174 struct net_device *dev;
175 struct dst_entry *dst;
176
177 DEBUG_ECM_IP_ADDR_TO_STRING(addr_str, addr);
178
179 /*
180 * Is the address a local IP?
181 */
182 DEBUG_TRACE("find net device for address: %s\n", addr_str);
183 dev = ecm_interface_dev_find_by_local_addr(addr);
184 if (dev) {
185 *from_local_addr = true;
186 DEBUG_TRACE("addr: %s is local: %p (%s)\n", addr_str, dev, dev->name);
187 return dev;
188 }
189
190 DEBUG_TRACE("addr: %s is not local\n", addr_str);
191
192 /*
193 * Try a route to the address instead
194 * NOTE: This will locate a route entry in the route destination *cache*.
195 */
196 if (!ecm_interface_find_route_by_addr(addr, &ecm_rt)) {
197 DEBUG_WARN("addr: %s - no dev locatable\n", addr_str);
198 return NULL;
199 }
200
201 *from_local_addr = false;
202 dst = ecm_rt.dst;
203 dev = dst->dev;
204 dev_hold(dev);
205 ecm_interface_route_release(&ecm_rt);
206 DEBUG_TRACE("dest_addr: %s uses dev: %p(%s)\n", addr_str, dev, dev->name);
207 return dev;
Gareth Williamsadf425f2014-05-26 19:29:02 +0100208}
209EXPORT_SYMBOL(ecm_interface_dev_find_by_addr);
210
211/*
Ben Menchaca84f36632014-02-28 20:57:38 +0000212 * ecm_interface_mac_addr_get_ipv6()
213 * Return mac for an IPv6 address
214 *
215 * GGG TODO Need to make sure this also works for local IP addresses too.
216 */
217static bool ecm_interface_mac_addr_get_ipv6(ip_addr_t addr, uint8_t *mac_addr, bool *on_link, ip_addr_t gw_addr)
218{
219 struct in6_addr daddr;
220 struct ecm_interface_route ecm_rt;
221 struct neighbour *neigh;
222 struct rt6_info *rt;
223 struct dst_entry *dst;
224
225 /*
226 * Get the MAC address that corresponds to IP address given.
227 * We look up the rt6_info entries and, from its neighbour structure, obtain the hardware address.
228 * This means we will also work if the neighbours are routers too.
229 */
230 ECM_IP_ADDR_TO_NIN6_ADDR(daddr, addr);
231 if (!ecm_interface_find_route_by_addr(addr, &ecm_rt)) {
Kiran Kumar C. S. K7d178222014-06-27 18:47:29 +0530232 *on_link = false;
Ben Menchaca84f36632014-02-28 20:57:38 +0000233 return false;
234 }
235 DEBUG_ASSERT(!ecm_rt.v4_route, "Did not locate a v6 route!\n");
236
237 /*
238 * Is this destination on link or off-link via a gateway?
239 */
240 rt = ecm_rt.rt.rtv6;
241 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)) {
242 *on_link = false;
243 ECM_NIN6_ADDR_TO_IP_ADDR(gw_addr, rt->rt6i_gateway)
244 } else {
245 *on_link = true;
246 }
247
248 rcu_read_lock();
249 dst = ecm_rt.dst;
250 neigh = dst_get_neighbour_noref(dst);
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700251 if (neigh) {
252 neigh_hold(neigh);
253 } else {
254 neigh = neigh_lookup(&nd_tbl, &daddr, dst->dev);
255 }
Ben Menchaca84f36632014-02-28 20:57:38 +0000256 if (!neigh) {
257 rcu_read_unlock();
258 ecm_interface_route_release(&ecm_rt);
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700259 DEBUG_WARN("No neigh reference\n");
Ben Menchaca84f36632014-02-28 20:57:38 +0000260 return false;
261 }
262 if (!(neigh->nud_state & NUD_VALID)) {
263 rcu_read_unlock();
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700264 neigh_release(neigh);
Ben Menchaca84f36632014-02-28 20:57:38 +0000265 ecm_interface_route_release(&ecm_rt);
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700266 DEBUG_WARN("NUD invalid\n");
Ben Menchaca84f36632014-02-28 20:57:38 +0000267 return false;
268 }
269 if (!neigh->dev) {
270 rcu_read_unlock();
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700271 neigh_release(neigh);
Ben Menchaca84f36632014-02-28 20:57:38 +0000272 ecm_interface_route_release(&ecm_rt);
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700273 DEBUG_WARN("Neigh dev invalid\n");
Ben Menchaca84f36632014-02-28 20:57:38 +0000274 return false;
275 }
276
277 /*
278 * If neigh->dev is a loopback then addr is a local address in which case we take the MAC from given device
279 */
280 if (neigh->dev->flags & IFF_LOOPBACK) {
281 // GGG TODO Create an equivalent logic to that for ipv4, maybe need to create an ip6_dev_find()?
282 DEBUG_TRACE("local address " ECM_IP_ADDR_OCTAL_FMT " (found loopback)\n", ECM_IP_ADDR_TO_OCTAL(addr));
283 memset(mac_addr, 0, 6);
284 } else {
285 memcpy(mac_addr, neigh->ha, 6);
286 }
287 rcu_read_unlock();
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700288 neigh_release(neigh);
Ben Menchaca84f36632014-02-28 20:57:38 +0000289 ecm_interface_route_release(&ecm_rt);
290
291 DEBUG_TRACE(ECM_IP_ADDR_OCTAL_FMT " maps to %pM\n", ECM_IP_ADDR_TO_OCTAL(addr), mac_addr);
292 return true;
293}
294
295/*
296 * ecm_interface_mac_addr_get_ipv4()
297 * Return mac for an IPv4 address
298 */
299static bool ecm_interface_mac_addr_get_ipv4(ip_addr_t addr, uint8_t *mac_addr, bool *on_link, ip_addr_t gw_addr)
300{
301 struct neighbour *neigh;
302 struct ecm_interface_route ecm_rt;
303 struct rtable *rt;
304 struct dst_entry *dst;
305 __be32 ipv4_addr;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530306
Ben Menchaca84f36632014-02-28 20:57:38 +0000307 /*
308 * Get the MAC address that corresponds to IP address given.
309 * We look up the rtable entries and, from its neighbour structure, obtain the hardware address.
310 * This means we will also work if the neighbours are routers too.
311 * We also locate the MAC if the address is a local host address.
312 */
313 ECM_IP_ADDR_TO_NIN4_ADDR(ipv4_addr, addr);
314 if (!ecm_interface_find_route_by_addr(addr, &ecm_rt)) {
Kiran Kumar C. S. K7d178222014-06-27 18:47:29 +0530315 *on_link = false;
Ben Menchaca84f36632014-02-28 20:57:38 +0000316 return false;
317 }
318 DEBUG_ASSERT(ecm_rt.v4_route, "Did not locate a v4 route!\n");
319
320 /*
321 * Is this destination on link or off-link via a gateway?
322 */
323 rt = ecm_rt.rt.rtv4;
324 if ((rt->rt_dst != rt->rt_gateway) || (rt->rt_flags & RTF_GATEWAY)) {
325 *on_link = false;
326 ECM_NIN4_ADDR_TO_IP_ADDR(gw_addr, rt->rt_gateway)
327 } else {
328 *on_link = true;
329 }
330
331 /*
332 * Get the neighbour entry for the address
333 */
334 rcu_read_lock();
335 dst = ecm_rt.dst;
336 neigh = dst_get_neighbour_noref(dst);
337 if (neigh) {
338 neigh_hold(neigh);
339 } else {
340 neigh = neigh_lookup(&arp_tbl, &ipv4_addr, dst->dev);
341 }
342 if (!neigh) {
343 rcu_read_unlock();
344 ecm_interface_route_release(&ecm_rt);
345 return false;
346 }
347 if (!(neigh->nud_state & NUD_VALID)) {
348 rcu_read_unlock();
349 neigh_release(neigh);
350 ecm_interface_route_release(&ecm_rt);
351 return false;
352 }
353 if (!neigh->dev) {
354 rcu_read_unlock();
355 neigh_release(neigh);
356 ecm_interface_route_release(&ecm_rt);
357 return false;
358 }
359
360 /*
361 * If the device is loopback this will be because the address is a local address
362 * In this case locate the device that has this local address and get its mac.
363 */
364 if (neigh->dev->type == ARPHRD_LOOPBACK) {
365 struct net_device *dev;
366
367 DEBUG_TRACE("%pI4 finds loopback device, dev: %p (%s)\n", &ipv4_addr, neigh->dev, neigh->dev->name);
368 rcu_read_unlock();
369 neigh_release(neigh);
370 ecm_interface_route_release(&ecm_rt);
371
372 /*
373 * Lookup the device that has this IP address assigned
374 */
375 dev = ip_dev_find(&init_net, ipv4_addr);
376 if (!dev) {
377 DEBUG_WARN("Unable to locate dev for: %pI4\n", &ipv4_addr);
378 return false;
379 }
380 memcpy(mac_addr, dev->dev_addr, (size_t)dev->addr_len);
381 DEBUG_TRACE("is local addr: %pI4, mac: %pM, dev ifindex: %d, dev: %p (%s), dev_type: %d\n",
382 &ipv4_addr, mac_addr, dev->ifindex, dev, dev->name, dev->type);
383 dev_put(dev);
384 return true;
385 }
386
387 if (!(neigh->dev->flags & IFF_NOARP)) {
388 memcpy(mac_addr, neigh->ha, (size_t)neigh->dev->addr_len);
389 } else {
390 DEBUG_TRACE("non-arp device: %p (%s, type: %d) to reach %pI4\n", neigh->dev, neigh->dev->name, neigh->dev->type, &ipv4_addr);
391 memset(mac_addr, 0, 6);
392 }
393 DEBUG_TRACE("addr: %pI4, mac: %pM, iif: %d, neigh dev ifindex: %d, dev: %p (%s), dev_type: %d\n",
394 &ipv4_addr, mac_addr, rt->rt_iif, neigh->dev->ifindex, neigh->dev, neigh->dev->name, neigh->dev->type);
395
396 rcu_read_unlock();
397 neigh_release(neigh);
398 ecm_interface_route_release(&ecm_rt);
399 return true;
400}
401
402/*
403 * ecm_interface_mac_addr_get()
404 * Return the mac address for the given IP address. Returns false on failure.
405 *
406 * 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.
407 *
408 * GGG TODO Make this function work for IPv6!!!!!!!!!!!!!!
409 */
410bool ecm_interface_mac_addr_get(ip_addr_t addr, uint8_t *mac_addr, bool *on_link, ip_addr_t gw_addr)
411{
412 if (ECM_IP_ADDR_IS_V4(addr)) {
413 return ecm_interface_mac_addr_get_ipv4(addr, mac_addr, on_link, gw_addr);
414 }
415
416 return ecm_interface_mac_addr_get_ipv6(addr, mac_addr, on_link, gw_addr);
417}
418EXPORT_SYMBOL(ecm_interface_mac_addr_get);
419
420/*
421 * ecm_interface_addr_find_route_by_addr_ipv4()
422 * Return the route for the given IP address. Returns NULL on failure.
423 */
424static bool ecm_interface_find_route_by_addr_ipv4(ip_addr_t addr, struct ecm_interface_route *ecm_rt)
425{
426 __be32 be_addr;
427
428 /*
429 * Get a route to the given IP address, this will allow us to also find the interface
430 * it is using to communicate with that IP address.
431 */
432 ECM_IP_ADDR_TO_NIN4_ADDR(be_addr, addr);
433 ecm_rt->rt.rtv4 = ip_route_output(&init_net, be_addr, 0, 0, 0);
434 if (IS_ERR(ecm_rt->rt.rtv4)) {
435 DEBUG_TRACE("No output route to: %pI4n\n", &be_addr);
436 return false;
437 }
438 DEBUG_TRACE("Output route to: %pI4n is: %p\n", &be_addr, ecm_rt->rt.rtv4);
439 ecm_rt->dst = (struct dst_entry *)ecm_rt->rt.rtv4;
440 ecm_rt->v4_route = true;
441 return true;
442}
443
444/*
445 * ecm_interface_addr_find_route_by_addr_ipv6()
446 * Return the route for the given IP address. Returns NULL on failure.
447 */
448static bool ecm_interface_find_route_by_addr_ipv6(ip_addr_t addr, struct ecm_interface_route *ecm_rt)
449{
450 struct in6_addr naddr;
451
452 ECM_IP_ADDR_TO_NIN6_ADDR(naddr, addr);
453
454 /*
455 * Get a route to the given IP address, this will allow us to also find the interface
456 * it is using to communicate with that IP address.
457 */
458 ecm_rt->rt.rtv6 = rt6_lookup(&init_net, &naddr, NULL, 0, 0);
459 if (!ecm_rt->rt.rtv6) {
460 DEBUG_TRACE("No output route to: " ECM_IP_ADDR_OCTAL_FMT "\n", ECM_IP_ADDR_TO_OCTAL(addr));
461 return NULL;
462 }
463 DEBUG_TRACE("Output route to: " ECM_IP_ADDR_OCTAL_FMT " is: %p\n", ECM_IP_ADDR_TO_OCTAL(addr), ecm_rt->rt.rtv6);
464 ecm_rt->dst = (struct dst_entry *)ecm_rt->rt.rtv6;
465 ecm_rt->v4_route = false;
466 return true;
467}
468
469/*
470 * ecm_interface_addr_find_route_by_addr()
471 * Return the route (in the given parameter) for the given IP address. Returns false on failure.
472 *
473 * Route is the device on which the addr is reachable, which may be loopback for local addresses.
474 *
475 * Returns true if the route was able to be located. The route must be released using ecm_interface_route_release().
476 */
477bool ecm_interface_find_route_by_addr(ip_addr_t addr, struct ecm_interface_route *ecm_rt)
478{
479 char __attribute__((unused)) addr_str[40];
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530480
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100481 DEBUG_ECM_IP_ADDR_TO_STRING(addr_str, addr);
Ben Menchaca84f36632014-02-28 20:57:38 +0000482 DEBUG_TRACE("Locate route to: %s\n", addr_str);
483
484 if (ECM_IP_ADDR_IS_V4(addr)) {
485 return ecm_interface_find_route_by_addr_ipv4(addr, ecm_rt);
486 }
487
488 return ecm_interface_find_route_by_addr_ipv6(addr, ecm_rt);
489}
490EXPORT_SYMBOL(ecm_interface_find_route_by_addr);
491
492/*
493 * ecm_interface_route_release()
494 * Release an ecm route
495 */
496void ecm_interface_route_release(struct ecm_interface_route *rt)
497{
498 dst_release(rt->dst);
499}
500EXPORT_SYMBOL(ecm_interface_route_release);
501
502/*
Ben Menchaca84f36632014-02-28 20:57:38 +0000503 * ecm_interface_vlan_interface_establish()
504 * Returns a reference to a iface of the VLAN type, possibly creating one if necessary.
505 * Returns NULL on failure or a reference to interface.
506 */
507static struct ecm_db_iface_instance *ecm_interface_vlan_interface_establish(struct ecm_db_interface_info_vlan *type_info,
508 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
509{
510 struct ecm_db_iface_instance *nii;
511 struct ecm_db_iface_instance *ii;
512
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530513 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",
514 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 +0000515
516 /*
517 * Locate the iface
518 */
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530519 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 +0000520 if (ii) {
521 DEBUG_TRACE("%p: iface established\n", ii);
522 return ii;
523 }
524
525 /*
526 * No iface - create one
527 */
528 nii = ecm_db_iface_alloc();
529 if (!nii) {
530 DEBUG_WARN("Failed to establish iface\n");
531 return NULL;
532 }
533
534 /*
535 * Add iface into the database, atomically to avoid races creating the same thing
536 */
537 spin_lock_bh(&ecm_interface_lock);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530538 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 +0000539 if (ii) {
540 spin_unlock_bh(&ecm_interface_lock);
541 ecm_db_iface_deref(nii);
542 return ii;
543 }
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530544 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 -0500545 mtu, dev_interface_num, nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000546 spin_unlock_bh(&ecm_interface_lock);
547
548 DEBUG_TRACE("%p: vlan iface established\n", nii);
549 return nii;
550}
551
552/*
553 * ecm_interface_bridge_interface_establish()
554 * Returns a reference to a iface of the BRIDGE type, possibly creating one if necessary.
555 * Returns NULL on failure or a reference to interface.
556 */
557static struct ecm_db_iface_instance *ecm_interface_bridge_interface_establish(struct ecm_db_interface_info_bridge *type_info,
558 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
559{
560 struct ecm_db_iface_instance *nii;
561 struct ecm_db_iface_instance *ii;
562
563 DEBUG_INFO("Establish BRIDGE iface: %s with address: %pM, MTU: %d, if num: %d, nss if id: %d\n",
564 dev_name, type_info->address, mtu, dev_interface_num, nss_interface_num);
565
566 /*
567 * Locate the iface
568 */
569 ii = ecm_db_iface_find_and_ref_bridge(type_info->address);
570 if (ii) {
571 DEBUG_TRACE("%p: iface established\n", ii);
572 return ii;
573 }
574
575 /*
576 * No iface - create one
577 */
578 nii = ecm_db_iface_alloc();
579 if (!nii) {
580 DEBUG_WARN("Failed to establish iface\n");
581 return NULL;
582 }
583
584 /*
585 * Add iface into the database, atomically to avoid races creating the same thing
586 */
587 spin_lock_bh(&ecm_interface_lock);
588 ii = ecm_db_iface_find_and_ref_bridge(type_info->address);
589 if (ii) {
590 spin_unlock_bh(&ecm_interface_lock);
591 ecm_db_iface_deref(nii);
592 return ii;
593 }
594 ecm_db_iface_add_bridge(nii, type_info->address, dev_name,
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500595 mtu, dev_interface_num, nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000596 spin_unlock_bh(&ecm_interface_lock);
597
598 DEBUG_TRACE("%p: bridge iface established\n", nii);
599 return nii;
600}
601
602/*
603 * ecm_interface_lag_interface_establish()
604 * Returns a reference to a iface of the LAG type, possibly creating one if necessary.
605 * Returns NULL on failure or a reference to interface.
606 */
607static struct ecm_db_iface_instance *ecm_interface_lag_interface_establish(struct ecm_db_interface_info_lag *type_info,
608 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
609{
610 struct ecm_db_iface_instance *nii;
611 struct ecm_db_iface_instance *ii;
612
613 DEBUG_INFO("Establish LAG iface: %s with address: %pM, MTU: %d, if num: %d, nss if id: %d\n",
614 dev_name, type_info->address, mtu, dev_interface_num, nss_interface_num);
615
616 /*
617 * Locate the iface
618 */
619 ii = ecm_db_iface_find_and_ref_lag(type_info->address);
620 if (ii) {
621 DEBUG_TRACE("%p: iface established\n", ii);
622 return ii;
623 }
624
625 /*
626 * No iface - create one
627 */
628 nii = ecm_db_iface_alloc();
629 if (!nii) {
630 DEBUG_WARN("Failed to establish iface\n");
631 return NULL;
632 }
633
634 /*
635 * Add iface into the database, atomically to avoid races creating the same thing
636 */
637 spin_lock_bh(&ecm_interface_lock);
638 ii = ecm_db_iface_find_and_ref_lag(type_info->address);
639 if (ii) {
640 spin_unlock_bh(&ecm_interface_lock);
641 ecm_db_iface_deref(nii);
642 return ii;
643 }
644 ecm_db_iface_add_lag(nii, type_info->address, dev_name,
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500645 mtu, dev_interface_num, nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000646 spin_unlock_bh(&ecm_interface_lock);
647
648 DEBUG_TRACE("%p: lag iface established\n", nii);
649 return nii;
650}
651
652/*
653 * ecm_interface_ethernet_interface_establish()
654 * Returns a reference to a iface of the ETHERNET type, possibly creating one if necessary.
655 * Returns NULL on failure or a reference to interface.
656 */
657static struct ecm_db_iface_instance *ecm_interface_ethernet_interface_establish(struct ecm_db_interface_info_ethernet *type_info,
658 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
659{
660 struct ecm_db_iface_instance *nii;
661 struct ecm_db_iface_instance *ii;
662
663 DEBUG_INFO("Establish ETHERNET iface: %s with address: %pM, MTU: %d, if num: %d, nss if id: %d\n",
664 dev_name, type_info->address, mtu, dev_interface_num, nss_interface_num);
665
666 /*
667 * Locate the iface
668 */
Tushar Mathur4ab0bf92014-06-10 20:37:07 +0530669 ii = ecm_db_iface_ifidx_find_and_ref_ethernet(type_info->address, dev_interface_num);
670
Ben Menchaca84f36632014-02-28 20:57:38 +0000671 if (ii) {
672 DEBUG_TRACE("%p: iface established\n", ii);
673 return ii;
674 }
675
676 /*
677 * No iface - create one
678 */
679 nii = ecm_db_iface_alloc();
680 if (!nii) {
681 DEBUG_WARN("Failed to establish iface\n");
682 return NULL;
683 }
684
685 /*
686 * Add iface into the database, atomically to avoid races creating the same thing
687 */
688 spin_lock_bh(&ecm_interface_lock);
Tushar Mathur4ab0bf92014-06-10 20:37:07 +0530689 ii = ecm_db_iface_ifidx_find_and_ref_ethernet(type_info->address, dev_interface_num);
Ben Menchaca84f36632014-02-28 20:57:38 +0000690 if (ii) {
691 spin_unlock_bh(&ecm_interface_lock);
692 ecm_db_iface_deref(nii);
693 return ii;
694 }
695 ecm_db_iface_add_ethernet(nii, type_info->address, dev_name,
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500696 mtu, dev_interface_num, nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000697 spin_unlock_bh(&ecm_interface_lock);
698
699 DEBUG_TRACE("%p: ethernet iface established\n", nii);
700 return nii;
701}
702
Gareth Williamsc5b9d712014-05-09 20:40:07 +0100703#ifdef ECM_INTERFACE_PPP_SUPPORT
Ben Menchaca84f36632014-02-28 20:57:38 +0000704/*
705 * ecm_interface_pppoe_interface_establish()
706 * Returns a reference to a iface of the PPPoE type, possibly creating one if necessary.
707 * Returns NULL on failure or a reference to interface.
708 */
709static struct ecm_db_iface_instance *ecm_interface_pppoe_interface_establish(struct ecm_db_interface_info_pppoe *type_info,
710 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
711{
712 struct ecm_db_iface_instance *nii;
713 struct ecm_db_iface_instance *ii;
714
715 DEBUG_INFO("Establish PPPoE iface: %s with session id: %u, remote mac: %pM, MTU: %d, if num: %d, nss if id: %d\n",
716 dev_name, type_info->pppoe_session_id, type_info->remote_mac, mtu, dev_interface_num, nss_interface_num);
717
718 /*
719 * Locate the iface
720 */
721 ii = ecm_db_iface_find_and_ref_pppoe(type_info->pppoe_session_id, type_info->remote_mac);
722 if (ii) {
723 DEBUG_TRACE("%p: iface established\n", ii);
724 return ii;
725 }
726
727 /*
728 * No iface - create one
729 */
730 nii = ecm_db_iface_alloc();
731 if (!nii) {
732 DEBUG_WARN("Failed to establish iface\n");
733 return NULL;
734 }
735
736 /*
737 * Add iface into the database, atomically to avoid races creating the same thing
738 */
739 spin_lock_bh(&ecm_interface_lock);
740 ii = ecm_db_iface_find_and_ref_pppoe(type_info->pppoe_session_id, type_info->remote_mac);
741 if (ii) {
742 spin_unlock_bh(&ecm_interface_lock);
743 ecm_db_iface_deref(nii);
744 return ii;
745 }
746 ecm_db_iface_add_pppoe(nii, type_info->pppoe_session_id, type_info->remote_mac, dev_name,
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500747 mtu, dev_interface_num, nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000748 spin_unlock_bh(&ecm_interface_lock);
749
750 DEBUG_TRACE("%p: pppoe iface established\n", nii);
751 return nii;
752}
Gareth Williamsc5b9d712014-05-09 20:40:07 +0100753#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000754
755/*
756 * ecm_interface_unknown_interface_establish()
757 * Returns a reference to a iface of the UNKNOWN type, possibly creating one if necessary.
758 * Returns NULL on failure or a reference to interface.
759 */
760static struct ecm_db_iface_instance *ecm_interface_unknown_interface_establish(struct ecm_db_interface_info_unknown *type_info,
761 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
762{
763 struct ecm_db_iface_instance *nii;
764 struct ecm_db_iface_instance *ii;
765
766 DEBUG_INFO("Establish UNKNOWN iface: %s with os_specific_ident: %u, MTU: %d, if num: %d, nss if id: %d\n",
767 dev_name, type_info->os_specific_ident, mtu, dev_interface_num, nss_interface_num);
768
769 /*
770 * Locate the iface
771 */
772 ii = ecm_db_iface_find_and_ref_unknown(type_info->os_specific_ident);
773 if (ii) {
774 DEBUG_TRACE("%p: iface established\n", ii);
775 return ii;
776 }
777
778 /*
779 * No iface - create one
780 */
781 nii = ecm_db_iface_alloc();
782 if (!nii) {
783 DEBUG_WARN("Failed to establish iface\n");
784 return NULL;
785 }
786
787 /*
788 * Add iface into the database, atomically to avoid races creating the same thing
789 */
790 spin_lock_bh(&ecm_interface_lock);
791 ii = ecm_db_iface_find_and_ref_unknown(type_info->os_specific_ident);
792 if (ii) {
793 spin_unlock_bh(&ecm_interface_lock);
794 ecm_db_iface_deref(nii);
795 return ii;
796 }
797 ecm_db_iface_add_unknown(nii, type_info->os_specific_ident, dev_name,
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500798 mtu, dev_interface_num, nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000799 spin_unlock_bh(&ecm_interface_lock);
800
801 DEBUG_TRACE("%p: unknown iface established\n", nii);
802 return nii;
803}
804
805/*
806 * ecm_interface_loopback_interface_establish()
807 * Returns a reference to a iface of the LOOPBACK type, possibly creating one if necessary.
808 * Returns NULL on failure or a reference to interface.
809 */
810static struct ecm_db_iface_instance *ecm_interface_loopback_interface_establish(struct ecm_db_interface_info_loopback *type_info,
811 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
812{
813 struct ecm_db_iface_instance *nii;
814 struct ecm_db_iface_instance *ii;
815
816 DEBUG_INFO("Establish LOOPBACK iface: %s with os_specific_ident: %u, MTU: %d, if num: %d, nss if id: %d\n",
817 dev_name, type_info->os_specific_ident, mtu, dev_interface_num, nss_interface_num);
818
819 /*
820 * Locate the iface
821 */
822 ii = ecm_db_iface_find_and_ref_loopback(type_info->os_specific_ident);
823 if (ii) {
824 DEBUG_TRACE("%p: iface established\n", ii);
825 return ii;
826 }
827
828 /*
829 * No iface - create one
830 */
831 nii = ecm_db_iface_alloc();
832 if (!nii) {
833 DEBUG_WARN("Failed to establish iface\n");
834 return NULL;
835 }
836
837 /*
838 * Add iface into the database, atomically to avoid races creating the same thing
839 */
840 spin_lock_bh(&ecm_interface_lock);
841 ii = ecm_db_iface_find_and_ref_loopback(type_info->os_specific_ident);
842 if (ii) {
843 spin_unlock_bh(&ecm_interface_lock);
844 ecm_db_iface_deref(nii);
845 return ii;
846 }
847 ecm_db_iface_add_loopback(nii, type_info->os_specific_ident, dev_name,
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500848 mtu, dev_interface_num, nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000849 spin_unlock_bh(&ecm_interface_lock);
850
851 DEBUG_TRACE("%p: loopback iface established\n", nii);
852 return nii;
853}
854
855/*
856 * ecm_interface_ipsec_tunnel_interface_establish()
857 * Returns a reference to a iface of the IPSEC_TUNNEL type, possibly creating one if necessary.
858 * Returns NULL on failure or a reference to interface.
859 *
860 * NOTE: GGG TODO THIS NEEDS TO TAKE A PROPER APPROACH TO IPSEC TUNNELS USING ENDPOINT ADDRESSING AS THE TYPE INFO KEYS
861 */
862static struct ecm_db_iface_instance *ecm_interface_ipsec_tunnel_interface_establish(struct ecm_db_interface_info_ipsec_tunnel *type_info,
863 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
864{
865 struct ecm_db_iface_instance *nii;
866 struct ecm_db_iface_instance *ii;
867
868 DEBUG_INFO("Establish IPSEC_TUNNEL iface: %s with os_specific_ident: %u, MTU: %d, if num: %d, nss if id: %d\n",
869 dev_name, type_info->os_specific_ident, mtu, dev_interface_num, nss_interface_num);
870
871 /*
872 * Locate the iface
873 */
874 ii = ecm_db_iface_find_and_ref_ipsec_tunnel(type_info->os_specific_ident);
875 if (ii) {
876 DEBUG_TRACE("%p: iface established\n", ii);
877 return ii;
878 }
879
880 /*
881 * No iface - create one
882 */
883 nii = ecm_db_iface_alloc();
884 if (!nii) {
885 DEBUG_WARN("Failed to establish iface\n");
886 return NULL;
887 }
888
889 /*
890 * Add iface into the database, atomically to avoid races creating the same thing
891 */
892 spin_lock_bh(&ecm_interface_lock);
893 ii = ecm_db_iface_find_and_ref_ipsec_tunnel(type_info->os_specific_ident);
894 if (ii) {
895 spin_unlock_bh(&ecm_interface_lock);
896 ecm_db_iface_deref(nii);
897 return ii;
898 }
899 ecm_db_iface_add_ipsec_tunnel(nii, type_info->os_specific_ident, dev_name,
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500900 mtu, dev_interface_num, nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000901 spin_unlock_bh(&ecm_interface_lock);
902
903 DEBUG_TRACE("%p: ipsec_tunnel iface established\n", nii);
904 return nii;
905}
906
Murat Sezgincc6eedf2014-05-09 23:59:19 -0700907#ifdef CONFIG_IPV6_SIT_6RD
Ben Menchaca84f36632014-02-28 20:57:38 +0000908/*
909 * ecm_interface_sit_interface_establish()
910 * Returns a reference to a iface of the SIT type, possibly creating one if necessary.
911 * Returns NULL on failure or a reference to interface.
912 */
913static struct ecm_db_iface_instance *ecm_interface_sit_interface_establish(struct ecm_db_interface_info_sit *type_info,
914 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
915{
916 struct ecm_db_iface_instance *nii;
917 struct ecm_db_iface_instance *ii;
918
919 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",
920 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);
921
922 /*
923 * Locate the iface
924 */
925 ii = ecm_db_iface_find_and_ref_sit(type_info->saddr, type_info->daddr);
926 if (ii) {
927 DEBUG_TRACE("%p: iface established\n", ii);
928 return ii;
929 }
930
931 /*
932 * No iface - create one
933 */
934 nii = ecm_db_iface_alloc();
935 if (!nii) {
936 DEBUG_WARN("Failed to establish iface\n");
937 return NULL;
938 }
939
940 /*
941 * Add iface into the database, atomically to avoid races creating the same thing
942 */
943 spin_lock_bh(&ecm_interface_lock);
944 ii = ecm_db_iface_find_and_ref_sit(type_info->saddr, type_info->daddr);
945 if (ii) {
946 spin_unlock_bh(&ecm_interface_lock);
947 ecm_db_iface_deref(nii);
948 return ii;
949 }
950 ecm_db_iface_add_sit(nii, type_info, dev_name, mtu, dev_interface_num,
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500951 nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000952 spin_unlock_bh(&ecm_interface_lock);
953
954 DEBUG_TRACE("%p: sit iface established\n", nii);
955 return nii;
956}
Murat Sezgincc6eedf2014-05-09 23:59:19 -0700957#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000958
959/*
960 * ecm_interface_tunipip6_interface_establish()
961 * Returns a reference to a iface of the TUNIPIP6 type, possibly creating one if necessary.
962 * Returns NULL on failure or a reference to interface.
963 */
964static struct ecm_db_iface_instance *ecm_interface_tunipip6_interface_establish(struct ecm_db_interface_info_tunipip6 *type_info,
965 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
966{
967 struct ecm_db_iface_instance *nii;
968 struct ecm_db_iface_instance *ii;
969
970 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",
971 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);
972
973 /*
974 * Locate the iface
975 */
976 ii = ecm_db_iface_find_and_ref_tunipip6(type_info->saddr, type_info->daddr);
977 if (ii) {
978 DEBUG_TRACE("%p: iface established\n", ii);
979 return ii;
980 }
981
982 /*
983 * No iface - create one
984 */
985 nii = ecm_db_iface_alloc();
986 if (!nii) {
987 DEBUG_WARN("Failed to establish iface\n");
988 return NULL;
989 }
990
991 /*
992 * Add iface into the database, atomically to avoid races creating the same thing
993 */
994 spin_lock_bh(&ecm_interface_lock);
995 ii = ecm_db_iface_find_and_ref_tunipip6(type_info->saddr, type_info->daddr);
996 if (ii) {
997 spin_unlock_bh(&ecm_interface_lock);
998 ecm_db_iface_deref(nii);
999 return ii;
1000 }
1001 ecm_db_iface_add_tunipip6(nii, type_info, dev_name, mtu, dev_interface_num,
Nicolas Costaf46c33b2014-05-15 10:02:00 -05001002 nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +00001003 spin_unlock_bh(&ecm_interface_lock);
1004
1005 DEBUG_TRACE("%p: tunipip6 iface established\n", nii);
1006 return nii;
1007}
1008
1009/*
1010 * ecm_interface_establish_and_ref()
1011 * Establish an interface instance for the given interface detail.
1012 */
1013struct ecm_db_iface_instance *ecm_interface_establish_and_ref(struct net_device *dev)
1014{
1015 int32_t dev_interface_num;
1016 char *dev_name;
1017 int32_t dev_type;
1018 int32_t dev_mtu;
1019 int32_t nss_interface_num;
1020 struct ecm_db_iface_instance *ii;
1021 union {
1022 struct ecm_db_interface_info_ethernet ethernet; /* type == ECM_DB_IFACE_TYPE_ETHERNET */
1023 struct ecm_db_interface_info_vlan vlan; /* type == ECM_DB_IFACE_TYPE_VLAN */
1024 struct ecm_db_interface_info_lag lag; /* type == ECM_DB_IFACE_TYPE_LAG */
1025 struct ecm_db_interface_info_bridge bridge; /* type == ECM_DB_IFACE_TYPE_BRIDGE */
1026 struct ecm_db_interface_info_pppoe pppoe; /* type == ECM_DB_IFACE_TYPE_PPPOE */
1027 struct ecm_db_interface_info_unknown unknown; /* type == ECM_DB_IFACE_TYPE_UNKNOWN */
1028 struct ecm_db_interface_info_loopback loopback; /* type == ECM_DB_IFACE_TYPE_LOOPBACK */
1029 struct ecm_db_interface_info_ipsec_tunnel ipsec_tunnel; /* type == ECM_DB_IFACE_TYPE_IPSEC_TUNNEL */
1030 struct ecm_db_interface_info_sit sit; /* type == ECM_DB_IFACE_TYPE_SIT */
1031 struct ecm_db_interface_info_tunipip6 tunipip6; /* type == ECM_DB_IFACE_TYPE_TUNIPIP6 */
1032 } type_info;
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001033
1034#ifdef ECM_INTERFACE_PPP_SUPPORT
Ben Menchaca84f36632014-02-28 20:57:38 +00001035 int channel_count;
1036 struct ppp_channel *ppp_chan[1];
Ben Menchaca84f36632014-02-28 20:57:38 +00001037 int channel_protocol;
Ben Menchaca84f36632014-02-28 20:57:38 +00001038 struct pppoe_opt addressing;
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001039#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001040
1041 /*
1042 * Get basic information about the given device
1043 */
1044 dev_interface_num = dev->ifindex;
1045 dev_name = dev->name;
1046 dev_type = dev->type;
1047 dev_mtu = dev->mtu;
1048
1049 /*
1050 * Does the NSS recognise this interface?
1051 */
1052 nss_interface_num = nss_cmn_get_interface_number_by_dev(dev);
1053
1054 DEBUG_TRACE("Establish interface instance for device: %p is type: %d, name: %s, ifindex: %d, nss_if: %d, mtu: %d\n",
1055 dev, dev_type, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1056
1057 /*
1058 * Extract from the device more type-specific information
1059 */
1060 if (dev_type == ARPHRD_ETHER) {
1061 /*
1062 * Ethernet - but what sub type?
1063 */
1064
1065 /*
1066 * VLAN?
1067 */
1068 if (is_vlan_dev(dev)) {
1069 /*
1070 * VLAN master
1071 * GGG No locking needed here, ASSUMPTION is that real_dev is held for as long as we have dev.
1072 */
1073 memcpy(type_info.vlan.address, dev->dev_addr, 6);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301074 type_info.vlan.vlan_tag = vlan_dev_vlan_id(dev);
1075 type_info.vlan.vlan_tpid = VLAN_CTAG_TPID;
1076 DEBUG_TRACE("Net device: %p is VLAN, mac: %pM, vlan_id: %x vlan_tpid: %x\n",
1077 dev, type_info.vlan.address, type_info.vlan.vlan_tag, type_info.vlan.vlan_tpid);
Ben Menchaca84f36632014-02-28 20:57:38 +00001078
1079 /*
1080 * Establish this type of interface
1081 */
1082 ii = ecm_interface_vlan_interface_establish(&type_info.vlan, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1083 return ii;
1084 }
1085
1086 /*
1087 * BRIDGE?
1088 */
1089 if (ecm_front_end_is_bridge_device(dev)) {
1090 /*
1091 * Bridge
1092 */
1093 memcpy(type_info.bridge.address, dev->dev_addr, 6);
1094
1095 DEBUG_TRACE("Net device: %p is BRIDGE, mac: %pM\n",
1096 dev, type_info.bridge.address);
1097
1098 /*
1099 * Establish this type of interface
1100 */
1101 ii = ecm_interface_bridge_interface_establish(&type_info.bridge, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1102 return ii;
1103 }
1104
1105 /*
1106 * LAG?
1107 */
1108 if (ecm_front_end_is_lag_master(dev)) {
1109 /*
1110 * Link aggregation
1111 */
1112 memcpy(type_info.lag.address, dev->dev_addr, 6);
1113
1114 DEBUG_TRACE("Net device: %p is LAG, mac: %pM\n",
1115 dev, type_info.lag.address);
1116
1117 /*
1118 * Establish this type of interface
1119 */
1120 ii = ecm_interface_lag_interface_establish(&type_info.lag, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1121 return ii;
1122 }
1123
1124 /*
1125 * ETHERNET!
1126 * Just plain ethernet it seems
1127 */
1128 memcpy(type_info.ethernet.address, dev->dev_addr, 6);
1129 DEBUG_TRACE("Net device: %p is ETHERNET, mac: %pM\n",
1130 dev, type_info.ethernet.address);
1131
1132 /*
1133 * Establish this type of interface
1134 */
1135 ii = ecm_interface_ethernet_interface_establish(&type_info.ethernet, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1136 return ii;
1137 }
1138
1139 /*
1140 * LOOPBACK?
1141 */
1142 if (dev_type == ARPHRD_LOOPBACK) {
1143 DEBUG_TRACE("Net device: %p is LOOPBACK type: %d\n", dev, dev_type);
1144 type_info.loopback.os_specific_ident = dev_interface_num;
1145 ii = ecm_interface_loopback_interface_establish(&type_info.loopback, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1146 return ii;
1147 }
1148
1149 /*
1150 * IPSEC?
1151 */
1152 if (dev_type == ECM_ARPHRD_IPSEC_TUNNEL_TYPE) {
1153 DEBUG_TRACE("Net device: %p is IPSec tunnel type: %d\n", dev, dev_type);
1154 type_info.ipsec_tunnel.os_specific_ident = dev_interface_num;
Ankit Dhanuka6d5014a2014-06-22 17:21:44 +05301155
1156 /*
1157 * nss_interface_num for all IPsec tunnels will always be NSS_C2C_TX_INTERFACE
1158 */
1159 nss_interface_num = NSS_C2C_TX_INTERFACE;
1160
Ben Menchaca84f36632014-02-28 20:57:38 +00001161 // GGG TODO Flesh this out with tunnel endpoint addressing detail
1162 ii = ecm_interface_ipsec_tunnel_interface_establish(&type_info.ipsec_tunnel, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1163 return ii;
1164 }
1165
Murat Sezgincc6eedf2014-05-09 23:59:19 -07001166#ifdef CONFIG_IPV6_SIT_6RD
Ben Menchaca84f36632014-02-28 20:57:38 +00001167 /*
1168 * SIT (6-in-4)?
1169 */
1170 if (dev_type == ARPHRD_SIT) {
1171 struct ip_tunnel *tunnel;
1172 struct ip_tunnel_6rd_parm *ip6rd;
1173 const struct iphdr *tiph;
1174
1175 DEBUG_TRACE("Net device: %p is SIT (6-in-4) type: %d\n", dev, dev_type);
1176
1177 tunnel = (struct ip_tunnel*)netdev_priv(dev);
1178 ip6rd = &tunnel->ip6rd;
1179
1180 /*
1181 * Get the Tunnel device IP header info
1182 */
1183 tiph = &tunnel->parms.iph ;
1184
1185 type_info.sit.prefixlen = ip6rd->prefixlen;
1186 type_info.sit.relay_prefix = ip6rd->relay_prefix;
1187 type_info.sit.relay_prefixlen = ip6rd->relay_prefixlen;
1188 ECM_NIN4_ADDR_TO_IP_ADDR(type_info.sit.saddr, tiph->saddr);
1189 ECM_NIN4_ADDR_TO_IP_ADDR(type_info.sit.daddr, tiph->daddr);
1190 type_info.sit.prefix[0] = ntohl(ip6rd->prefix.s6_addr32[0]);
1191 type_info.sit.prefix[1] = ntohl(ip6rd->prefix.s6_addr32[1]);
1192 type_info.sit.prefix[2] = ntohl(ip6rd->prefix.s6_addr32[2]);
1193 type_info.sit.prefix[3] = ntohl(ip6rd->prefix.s6_addr32[3]);
1194 type_info.sit.ttl = tiph->ttl;
1195 type_info.sit.tos = tiph->tos;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301196
Ben Menchaca84f36632014-02-28 20:57:38 +00001197 ii = ecm_interface_sit_interface_establish(&type_info.sit, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1198 return ii;
1199 }
Murat Sezgincc6eedf2014-05-09 23:59:19 -07001200#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001201
1202 /*
1203 * IPIP6 Tunnel?
1204 */
1205 if (dev_type == ARPHRD_TUNNEL6) {
1206 struct ip6_tnl *tunnel;
1207 struct flowi6 *fl6;
1208
1209 DEBUG_TRACE("Net device: %p is TUNIPIP6 type: %d\n", dev, dev_type);
1210
1211 /*
1212 * Get the tunnel device flow information (discover the output path of the tunnel)
1213 */
1214 tunnel = (struct ip6_tnl *)netdev_priv(dev);
1215 fl6 = &tunnel->fl.u.ip6;
1216
1217 ECM_NIN6_ADDR_TO_IP_ADDR(type_info.tunipip6.saddr, fl6->saddr);
1218 ECM_NIN6_ADDR_TO_IP_ADDR(type_info.tunipip6.daddr, fl6->daddr);
1219 type_info.tunipip6.hop_limit = tunnel->parms.hop_limit;
1220 type_info.tunipip6.flags = ntohl(tunnel->parms.flags);
1221 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 +05301222
Ben Menchaca84f36632014-02-28 20:57:38 +00001223 ii = ecm_interface_tunipip6_interface_establish(&type_info.tunipip6, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1224 return ii;
1225 }
1226
1227 /*
1228 * If this is NOT PPP then it is unknown to the ecm
1229 */
1230 if (dev_type != ARPHRD_PPP) {
1231 DEBUG_TRACE("Net device: %p is UNKNOWN type: %d\n", dev, dev_type);
1232 type_info.unknown.os_specific_ident = dev_interface_num;
1233
1234 /*
1235 * Establish this type of interface
1236 */
1237 ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1238 return ii;
1239 }
1240
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001241#ifndef ECM_INTERFACE_PPP_SUPPORT
1242 /*
1243 * PPP support is NOT provided for.
1244 * Interface is therefore unknown
1245 */
1246 DEBUG_TRACE("Net device: %p is UNKNOWN (PPP Unsupported) type: %d\n", dev, dev_type);
1247 type_info.unknown.os_specific_ident = dev_interface_num;
1248
1249 /*
1250 * Establish this type of interface
1251 */
1252 ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1253 return ii;
1254#else
Ben Menchaca84f36632014-02-28 20:57:38 +00001255 /*
1256 * PPP - but what is the channel type?
1257 * First: If this is multi-link then we do not support it
1258 */
1259 if (ppp_is_multilink(dev) > 0) {
1260 DEBUG_TRACE("Net device: %p is MULTILINK PPP - Unknown to the ECM\n", dev);
1261 type_info.unknown.os_specific_ident = dev_interface_num;
1262
1263 /*
1264 * Establish this type of interface
1265 */
1266 ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1267 return ii;
1268 }
1269
1270 DEBUG_TRACE("Net device: %p is PPP\n", dev);
1271
1272 /*
1273 * Get the PPP channel and then enquire what kind of channel it is
1274 * NOTE: Not multilink so only one channel to get.
1275 */
1276 channel_count = ppp_hold_channels(dev, ppp_chan, 1);
1277 if (channel_count != 1) {
Gareth Williams6f96a4b2014-05-29 19:41:21 +01001278 DEBUG_TRACE("Net device: %p PPP has %d channels - ECM cannot handle this (interface becomes Unknown type)\n",
1279 dev, channel_count);
Ben Menchaca84f36632014-02-28 20:57:38 +00001280 type_info.unknown.os_specific_ident = dev_interface_num;
1281
1282 /*
1283 * Establish this type of interface
1284 */
1285 ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1286 return ii;
1287 }
1288
1289 /*
1290 * Get channel protocol type
Gareth Williams6f96a4b2014-05-29 19:41:21 +01001291 * NOTE: Not all PPP channels support channel specific methods.
Ben Menchaca84f36632014-02-28 20:57:38 +00001292 */
Gareth Williams6f96a4b2014-05-29 19:41:21 +01001293 channel_protocol = ppp_channel_get_protocol(ppp_chan[0]);
Ben Menchaca84f36632014-02-28 20:57:38 +00001294 if (channel_protocol != PX_PROTO_OE) {
1295 DEBUG_TRACE("Net device: %p PPP channel protocol: %d - Unknown to the ECM\n", dev, channel_protocol);
1296 type_info.unknown.os_specific_ident = dev_interface_num;
1297
1298 /*
1299 * Release the channel
1300 */
1301 ppp_release_channels(ppp_chan, 1);
1302
1303 /*
1304 * Establish this type of interface
1305 */
1306 ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1307 return ii;
1308 }
1309
1310 /*
1311 * PPPoE channel
1312 */
1313 DEBUG_TRACE("Net device: %p PPP channel is PPPoE\n", dev);
1314
1315 /*
1316 * Get PPPoE session information and the underlying device it is using.
Ben Menchaca84f36632014-02-28 20:57:38 +00001317 */
Gareth Williams6f96a4b2014-05-29 19:41:21 +01001318 pppoe_channel_addressing_get(ppp_chan[0], &addressing);
1319 type_info.pppoe.pppoe_session_id = (uint16_t)ntohs((uint16_t)addressing.pa.sid);
Ben Menchaca84f36632014-02-28 20:57:38 +00001320 memcpy(type_info.pppoe.remote_mac, addressing.pa.remote, ETH_ALEN);
Gareth Williams6f96a4b2014-05-29 19:41:21 +01001321 dev_put(addressing.dev);
Ben Menchaca84f36632014-02-28 20:57:38 +00001322
1323 /*
1324 * Release the channel. Note that next_dev is still (correctly) held.
1325 */
1326 ppp_release_channels(ppp_chan, 1);
1327
1328 DEBUG_TRACE("Net device: %p PPPoE session: %x, remote mac: %pM\n",
1329 dev, type_info.pppoe.pppoe_session_id, type_info.pppoe.remote_mac);
1330
1331 /*
1332 * Establish this type of interface
1333 */
1334 ii = ecm_interface_pppoe_interface_establish(&type_info.pppoe, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1335 return ii;
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001336#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001337}
1338EXPORT_SYMBOL(ecm_interface_establish_and_ref);
1339
1340/*
1341 * ecm_interface_heirarchy_construct()
1342 * Construct an interface heirarchy.
1343 *
1344 * Using the given addressing, locate the interface heirarchy used to emit packets to that destination.
1345 * This is the heirarchy of interfaces a packet would transit to emit from the device.
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001346 *
1347 * We will use the given src/dest devices when is_routed is false.
1348 * When is_routed is true we will try routing tables first, failing back to any given.
1349 *
Ben Menchaca84f36632014-02-28 20:57:38 +00001350 * For example, with this network arrangement:
1351 *
1352 * PPPoE--VLAN--BRIDGE--BRIDGE_PORT(LAG_MASTER)--LAG_SLAVE_0--10.22.33.11
1353 *
Gareth Williams43fc0852014-05-26 19:10:00 +01001354 * 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 +00001355 * LAG_SLAVE_0 @ [ECM_DB_IFACE_HEIRARCHY_MAX - 5]
1356 * LAG_MASTER @ [ECM_DB_IFACE_HEIRARCHY_MAX - 4]
1357 * BRIDGE @ [ECM_DB_IFACE_HEIRARCHY_MAX - 3]
1358 * VLAN @ [ECM_DB_IFACE_HEIRARCHY_MAX - 2]
1359 * PPPOE @ [ECM_DB_IFACE_HEIRARCHY_MAX - 1]
1360 * The value returned is (ECM_DB_IFACE_HEIRARCHY_MAX - 5)
1361 *
1362 * IMPORTANT: This function will return any known interfaces in the database, when interfaces do not exist in the database
1363 * they will be created and added automatically to the database.
1364 *
1365 * GGG TODO Make this function work for IPv6!!!!!!!!!!!!!!
1366 */
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001367int32_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 +05301368 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 +00001369{
Ben Menchaca84f36632014-02-28 20:57:38 +00001370 int protocol;
1371 ip_addr_t src_addr;
1372 ip_addr_t dest_addr;
Ben Menchaca84f36632014-02-28 20:57:38 +00001373 struct net_device *dest_dev;
Ben Menchaca84f36632014-02-28 20:57:38 +00001374 char *dest_dev_name;
Ben Menchaca84f36632014-02-28 20:57:38 +00001375 int32_t dest_dev_type;
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001376 struct net_device *src_dev;
1377 char *src_dev_name;
1378 int32_t src_dev_type;
Ben Menchaca84f36632014-02-28 20:57:38 +00001379 int32_t current_interface_index;
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001380 bool from_local_addr;
Ben Menchaca84f36632014-02-28 20:57:38 +00001381
1382 /*
1383 * Get a big endian of the IPv4 address we have been given as our starting point.
1384 */
1385 protocol = packet_protocol;
1386 ECM_IP_ADDR_COPY(src_addr, packet_src_addr);
1387 ECM_IP_ADDR_COPY(dest_addr, packet_dest_addr);
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001388 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",
1389 ECM_IP_ADDR_TO_DOT(src_addr), ECM_IP_ADDR_TO_DOT(dest_addr), protocol);
Ben Menchaca84f36632014-02-28 20:57:38 +00001390
1391 /*
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001392 * Get device to reach the given destination address.
1393 * If the heirarchy is for a routed connection we must try route lookup first, falling back to any given_dest_dev.
1394 * 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 +00001395 */
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001396 from_local_addr = false;
1397 if (is_routed) {
1398 dest_dev = ecm_interface_dev_find_by_addr(dest_addr, &from_local_addr);
1399 if (!dest_dev && given_dest_dev) {
1400 /*
1401 * Fall back to any given
1402 */
1403 dest_dev = given_dest_dev;
1404 dev_hold(dest_dev);
Gareth Williams43fc0852014-05-26 19:10:00 +01001405 }
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001406 } else if (given_dest_dev) {
1407 dest_dev = given_dest_dev;
1408 dev_hold(dest_dev);
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05301409 } else {
1410 /*
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001411 * Fall back to routed look up
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05301412 */
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001413 dest_dev = ecm_interface_dev_find_by_addr(dest_addr, &from_local_addr);
Gareth Williams43fc0852014-05-26 19:10:00 +01001414 }
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05301415
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001416 /*
1417 * GGG ALERT: If the address is a local address and protocol is an IP tunnel
1418 * then this connection is a tunnel endpoint made to this device.
1419 * In which case we circumvent all proper procedure and just hack the devices to make stuff work.
1420 * GGG TODO THIS MUST BE FIXED - WE MUST USE THE INTERFACE HIERARCHY FOR ITS INTENDED PURPOSE TO
1421 * PARSE THE DEVICES AND WORK OUT THE PROPER INTERFACES INVOLVED.
1422 * E.G. IF WE TRIED TO RUN A TUNNEL OVER A VLAN OR QINQ THIS WILL BREAK AS WE DON'T DISCOVER THAT HIERARCHY
1423 */
1424 if (dest_dev && from_local_addr && (protocol == IPPROTO_IPV6)) {
1425 dev_put(dest_dev);
1426 dest_dev = given_dest_dev;
1427 if (dest_dev) {
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05301428 dev_hold(dest_dev);
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001429 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 +05301430 }
Gareth Williams43fc0852014-05-26 19:10:00 +01001431 }
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001432 if (!dest_dev) {
1433 DEBUG_WARN("dest_addr: " ECM_IP_ADDR_OCTAL_FMT " - cannot locate device\n", ECM_IP_ADDR_TO_OCTAL(dest_addr));
1434 return ECM_DB_IFACE_HEIRARCHY_MAX;
1435 }
Ben Menchaca84f36632014-02-28 20:57:38 +00001436 dest_dev_name = dest_dev->name;
1437 dest_dev_type = dest_dev->type;
1438
1439 /*
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001440 * Get device to reach the given source address.
1441 * If the heirarchy is for a routed connection we must try route lookup first, falling back to any given_src_dev.
1442 * If the heirarchy is NOT for a routed connection we try the given_src_dev first, followed by routed lookup.
1443 */
1444 from_local_addr = false;
1445 if (is_routed) {
1446 src_dev = ecm_interface_dev_find_by_addr(src_addr, &from_local_addr);
1447 if (!src_dev && given_src_dev) {
1448 /*
1449 * Fall back to any given
1450 */
1451 src_dev = given_src_dev;
1452 dev_hold(src_dev);
1453 }
1454 } else if (given_src_dev) {
1455 src_dev = given_src_dev;
1456 dev_hold(src_dev);
1457 } else {
1458 /*
1459 * Fall back to routed look up
1460 */
1461 src_dev = ecm_interface_dev_find_by_addr(src_addr, &from_local_addr);
1462 }
1463
1464 /*
1465 * GGG ALERT: If the address is a local address and protocol is an IP tunnel
1466 * then this connection is a tunnel endpoint made to this device.
1467 * In which case we circumvent all proper procedure and just hack the devices to make stuff work.
1468 * GGG TODO THIS MUST BE FIXED - WE MUST USE THE INTERFACE HIERARCHY FOR ITS INTENDED PURPOSE TO
1469 * PARSE THE DEVICES AND WORK OUT THE PROPER INTERFACES INVOLVED.
1470 * E.G. IF WE TRIED TO RUN A TUNNEL OVER A VLAN OR QINQ THIS WILL BREAK AS WE DON'T DISCOVER THAT HIERARCHY
1471 */
1472 if (src_dev && from_local_addr && (protocol == IPPROTO_IPV6)) {
1473 dev_put(src_dev);
1474 src_dev = given_src_dev;
1475 if (src_dev) {
1476 dev_hold(src_dev);
1477 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);
1478 }
1479 }
1480 if (!src_dev) {
1481 DEBUG_WARN("src_addr: " ECM_IP_ADDR_OCTAL_FMT " - cannot locate device\n", ECM_IP_ADDR_TO_OCTAL(src_addr));
1482 dev_put(dest_dev);
1483 return ECM_DB_IFACE_HEIRARCHY_MAX;
1484 }
1485 src_dev_name = src_dev->name;
1486 src_dev_type = src_dev->type;
1487
1488 /*
1489 * Check if source and dest dev are same.
1490 * For the forwarded flows which involve tunnels this will happen when called from input hook.
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05301491 */
1492 if (src_dev == dest_dev) {
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001493 DEBUG_TRACE("Protocol is :%d source dev and dest dev are same\n", protocol);
Ankit Dhanuka60683c52014-06-09 17:43:38 +05301494 if ((protocol == IPPROTO_IPV6) || (protocol == IPPROTO_ESP)) {
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05301495 /*
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001496 * This happens from the input hook
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05301497 * We do not want to create a connection entry for this
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001498 * GGG TODO YES WE DO.
1499 * GGG TODO THIS CONCERNS ME AS THIS SHOULD BE CAUGHT MUCH
1500 * EARLIER IN THE FRONT END IF POSSIBLE TO AVOID PERFORMANCE PENALTIES.
1501 * WE HAVE DONE A TREMENDOUS AMOUT OF WORK TO GET TO THIS POINT.
1502 * WE WILL ABORT HERE AND THIS WILL BE REPEATED FOR EVERY PACKET.
1503 * IN KEEPING WITH THE ECM DESIGN IT IS BETTER TO CREATE A CONNECTION AND RECORD IN THE HIERARCHY
1504 * ENOUGH INFORMATION TO ENSURE THAT ACCELERATION IS NOT BROKEN / DOES NOT OCCUR AT ALL.
1505 * THAT WAY WE DO A HEAVYWEIGHT ESTABLISHING OF A CONNECTION ONCE AND NEVER AGAIN...
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05301506 */
1507 dev_put(src_dev);
1508 dev_put(dest_dev);
1509 return ECM_DB_IFACE_HEIRARCHY_MAX;
1510 }
1511 }
1512
1513 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00001514 * Iterate until we are done or get to the max number of interfaces we can record.
1515 * NOTE: current_interface_index tracks the position of the first interface position in interfaces[]
1516 * because we add from the end first_interface grows downwards.
1517 */
1518 current_interface_index = ECM_DB_IFACE_HEIRARCHY_MAX;
1519 while (current_interface_index > 0) {
1520 struct ecm_db_iface_instance *ii;
1521 struct net_device *next_dev;
1522
1523 /*
1524 * Get the ecm db interface instance for the device at hand
1525 */
1526 ii = ecm_interface_establish_and_ref(dest_dev);
1527
1528 /*
1529 * If the interface could not be established then we abort
1530 */
1531 if (!ii) {
1532 DEBUG_WARN("Failed to establish interface: %p, name: %s\n", dest_dev, dest_dev_name);
1533 dev_put(src_dev);
1534 dev_put(dest_dev);
1535
1536 /*
1537 * Release the interfaces heirarchy we constructed to this point.
1538 */
1539 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1540 return ECM_DB_IFACE_HEIRARCHY_MAX;
1541 }
1542
1543 /*
1544 * Record the interface instance into the interfaces[]
1545 */
1546 current_interface_index--;
1547 interfaces[current_interface_index] = ii;
1548
1549 /*
1550 * Now we have to figure out what the next device will be (in the transmission path) the skb
1551 * will use to emit to the destination address.
1552 */
1553 do {
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001554#ifdef ECM_INTERFACE_PPP_SUPPORT
Ben Menchaca84f36632014-02-28 20:57:38 +00001555 int channel_count;
1556 struct ppp_channel *ppp_chan[1];
Ben Menchaca84f36632014-02-28 20:57:38 +00001557 int channel_protocol;
Ben Menchaca84f36632014-02-28 20:57:38 +00001558 struct pppoe_opt addressing;
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001559#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001560
1561 DEBUG_TRACE("Net device: %p is type: %d, name: %s\n", dest_dev, dest_dev_type, dest_dev_name);
1562 next_dev = NULL;
1563
1564 if (dest_dev_type == ARPHRD_ETHER) {
1565 /*
1566 * Ethernet - but what sub type?
1567 */
1568
1569 /*
1570 * VLAN?
1571 */
1572 if (is_vlan_dev(dest_dev)) {
1573 /*
1574 * VLAN master
1575 * No locking needed here, ASSUMPTION is that real_dev is held for as long as we have dev.
1576 */
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301577 next_dev = vlan_dev_real_dev(dest_dev);
Ben Menchaca84f36632014-02-28 20:57:38 +00001578 dev_hold(next_dev);
1579 DEBUG_TRACE("Net device: %p is VLAN, slave dev: %p (%s)\n",
1580 dest_dev, next_dev, next_dev->name);
1581 break;
1582 }
1583
1584 /*
1585 * BRIDGE?
1586 */
1587 if (ecm_front_end_is_bridge_device(dest_dev)) {
1588 /*
1589 * Bridge
1590 * Figure out which port device the skb will go to using the dest_addr.
1591 */
1592 bool on_link;
Murat Sezginebf8a642014-06-06 12:51:43 -07001593 ip_addr_t gw_addr = ECM_IP_ADDR_NULL;
Ben Menchaca84f36632014-02-28 20:57:38 +00001594 uint8_t mac_addr[ETH_ALEN];
1595 if (!ecm_interface_mac_addr_get(dest_addr, mac_addr, &on_link, gw_addr)) {
1596 /*
1597 * Possible ARP does not know the address yet
1598 */
Gareth Williams9e1d17a2014-05-26 19:40:10 +01001599 DEBUG_INFO("Unable to obtain MAC address for " ECM_IP_ADDR_DOT_FMT "\n", ECM_IP_ADDR_TO_DOT(dest_addr));
1600 if (ECM_IP_ADDR_IS_V4(dest_addr)) {
1601 __be32 ipv4_addr;
1602 __be32 src_ip;
1603
1604 /*
1605 * Issue an ARP request for it, select the src_ip from which to issue the request.
1606 */
1607 ECM_IP_ADDR_TO_NIN4_ADDR(ipv4_addr, dest_addr);
1608 src_ip = inet_select_addr(dest_dev, ipv4_addr, RT_SCOPE_LINK);
1609 if (!src_ip) {
1610 DEBUG_TRACE("failed to lookup IP for %pI4\n", &ipv4_addr);
1611
1612 dev_put(src_dev);
1613 dev_put(dest_dev);
1614
1615 /*
1616 * Release the interfaces heirarchy we constructed to this point.
1617 */
1618 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1619 return ECM_DB_IFACE_HEIRARCHY_MAX;
1620 }
1621
1622 /*
1623 * If we have a GW for this address, then we have to send ARP request to the GW
1624 */
Murat Sezginebf8a642014-06-06 12:51:43 -07001625 if (!on_link && !ECM_IP_ADDR_IS_NULL(gw_addr)) {
Sol Kavyd3fd5d82014-06-05 19:27:04 -07001626 ECM_IP_ADDR_TO_NIN4_ADDR(ipv4_addr, gw_addr);
Gareth Williams9e1d17a2014-05-26 19:40:10 +01001627 }
1628
1629 DEBUG_TRACE("Send ARP for %pI4 using src_ip as %pI4\n", &ipv4_addr, &src_ip);
1630 arp_send(ARPOP_REQUEST, ETH_P_ARP, ipv4_addr, dest_dev, src_ip, NULL, NULL, NULL);
1631 }
1632
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001633 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 +00001634 dev_put(src_dev);
1635 dev_put(dest_dev);
1636
1637 /*
1638 * Release the interfaces heirarchy we constructed to this point.
1639 */
1640 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1641 return ECM_DB_IFACE_HEIRARCHY_MAX;
1642 }
1643 next_dev = br_port_dev_get(dest_dev, mac_addr);
1644 if (!next_dev) {
1645 DEBUG_WARN("Unable to obtain output port for: %pM\n", mac_addr);
1646 dev_put(src_dev);
1647 dev_put(dest_dev);
1648
1649 /*
1650 * Release the interfaces heirarchy we constructed to this point.
1651 */
1652 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1653 return ECM_DB_IFACE_HEIRARCHY_MAX;
1654 }
1655 DEBUG_TRACE("Net device: %p is BRIDGE, next_dev: %p (%s)\n", dest_dev, next_dev, next_dev->name);
1656 break;
1657 }
1658
1659 /*
1660 * LAG?
1661 */
1662 if (ecm_front_end_is_lag_master(dest_dev)) {
1663 /*
1664 * Link aggregation
1665 * Figure out which slave device of the link aggregation will be used to reach the destination.
1666 */
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05301667 bool dest_on_link = false;
1668 ip_addr_t dest_gw_addr = ECM_IP_ADDR_NULL;
1669 uint32_t src_addr_32 = 0;
1670 uint32_t dest_addr_32 = 0;
Ben Menchaca84f36632014-02-28 20:57:38 +00001671 uint8_t src_mac_addr[ETH_ALEN];
1672 uint8_t dest_mac_addr[ETH_ALEN];
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05301673 struct net_device *master_dev = NULL;
Ben Menchaca84f36632014-02-28 20:57:38 +00001674
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05301675 memset(src_mac_addr, 0, ETH_ALEN);
1676 memset(dest_mac_addr, 0, ETH_ALEN);
Ben Menchaca84f36632014-02-28 20:57:38 +00001677
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05301678 ECM_IP_ADDR_TO_NIN4_ADDR(src_addr_32, src_addr);
1679 ECM_IP_ADDR_TO_NIN4_ADDR(dest_addr_32, dest_addr);
1680
1681 if (!is_routed) {
1682 memcpy(src_mac_addr, src_node_addr, ETH_ALEN);
1683 memcpy(dest_mac_addr, dest_node_addr, ETH_ALEN);
1684 } else {
1685 /*
1686 * Use appropriate source MAC address for routed packets
1687 */
1688 if (dest_dev->master) {
1689 memcpy(src_mac_addr, dest_dev->master->dev_addr, ETH_ALEN);
1690 } else {
1691 memcpy(src_mac_addr, dest_dev->dev_addr, ETH_ALEN);
1692 }
1693
1694 /*
1695 * Determine destination MAC address for this routed packet
1696 */
1697 if (!ecm_interface_mac_addr_get(dest_addr, dest_mac_addr,
1698 &dest_on_link, dest_gw_addr)) {
1699 __be32 ipv4_addr = 0;
1700 __be32 src_ip = 0;
1701 DEBUG_WARN("Unable to obtain MAC address for "
1702 ECM_IP_ADDR_DOT_FMT "\n", ECM_IP_ADDR_TO_DOT(dest_addr));
1703
1704
1705 /*
1706 * Issue an ARP request, select the src_ip from which to issue the request.
1707 */
1708
1709 /*
1710 * find proper interfce from which to issue ARP
1711 */
1712 if (dest_dev->master) {
1713 master_dev = dest_dev->master;
1714 } else {
1715 master_dev = dest_dev;
1716 }
1717
1718 dev_hold(master_dev);
1719
1720 ECM_IP_ADDR_TO_NIN4_ADDR(ipv4_addr, dest_addr);
1721 src_ip = inet_select_addr(master_dev, ipv4_addr, RT_SCOPE_LINK);
1722 if (!src_ip) {
1723 DEBUG_TRACE("failed to lookup IP for %pI4\n", &ipv4_addr);
1724
1725 dev_put(src_dev);
1726 dev_put(dest_dev);
1727 dev_put(master_dev);
1728
1729 /*
1730 * Release the interfaces heirarchy we constructed to this point.
1731 */
1732 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1733 return ECM_DB_IFACE_HEIRARCHY_MAX;
1734 }
1735
1736 /*
1737 * If we have a GW for this address, then we have to send ARP request to the GW
1738 */
1739 if (!dest_on_link && !ECM_IP_ADDR_IS_NULL(dest_gw_addr)) {
1740 ECM_IP_ADDR_TO_NIN4_ADDR(ipv4_addr, dest_gw_addr);
1741 }
1742
1743 DEBUG_TRACE("Send ARP for %pI4 using src_ip as %pI4\n", &ipv4_addr, &src_ip);
1744 arp_send(ARPOP_REQUEST, ETH_P_ARP, ipv4_addr, master_dev, src_ip, NULL, NULL, NULL);
1745
1746
1747 dev_put(src_dev);
1748 dev_put(dest_dev);
1749 dev_put(master_dev);
1750 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1751 return ECM_DB_IFACE_HEIRARCHY_MAX;
1752 }
1753 }
1754
1755 next_dev = bond_get_tx_dev(NULL, src_mac_addr, dest_mac_addr,
1756 &src_addr_32, &dest_addr_32,
1757 htons((uint16_t)ETH_P_IP), dest_dev);
Tushar Mathur933907c2014-06-24 17:06:14 +05301758 if (next_dev && netif_carrier_ok(next_dev)) {
Ben Menchaca84f36632014-02-28 20:57:38 +00001759 dev_hold(next_dev);
1760 } else {
1761 DEBUG_WARN("Unable to obtain LAG output slave device\n");
1762 dev_put(src_dev);
1763 dev_put(dest_dev);
1764
1765 /*
1766 * Release the interfaces heirarchy we constructed to this point.
1767 */
1768 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1769 return ECM_DB_IFACE_HEIRARCHY_MAX;
1770 }
1771
1772 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 +00001773 break;
1774 }
1775
1776 /*
1777 * ETHERNET!
1778 * Just plain ethernet it seems.
1779 */
1780 DEBUG_TRACE("Net device: %p is ETHERNET\n", dest_dev);
1781 break;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301782 }
Ben Menchaca84f36632014-02-28 20:57:38 +00001783
1784 /*
1785 * LOOPBACK?
1786 */
1787 if (dest_dev_type == ARPHRD_LOOPBACK) {
1788 DEBUG_TRACE("Net device: %p is LOOPBACK type: %d\n", dest_dev, dest_dev_type);
1789 break;
1790 }
1791
1792 /*
1793 * IPSEC?
1794 */
1795 if (dest_dev_type == ECM_ARPHRD_IPSEC_TUNNEL_TYPE) {
1796 DEBUG_TRACE("Net device: %p is IPSec tunnel type: %d\n", dest_dev, dest_dev_type);
1797 // GGG TODO Figure out the next device the tunnel is using...
1798 break;
1799 }
1800
1801 /*
1802 * SIT (6-in-4)?
1803 */
1804 if (dest_dev_type == ARPHRD_SIT) {
1805 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 +01001806 // GGG TODO Figure out the next device the tunnel is using...
Ben Menchaca84f36632014-02-28 20:57:38 +00001807 break;
1808 }
1809
1810 /*
1811 * IPIP6 Tunnel?
1812 */
1813 if (dest_dev_type == ARPHRD_TUNNEL6) {
1814 DEBUG_TRACE("Net device: %p is TUNIPIP6 type: %d\n", dest_dev, dest_dev_type);
Gareth Williams46f4b5f2014-06-01 23:35:23 +01001815 // GGG TODO Figure out the next device the tunnel is using...
Ben Menchaca84f36632014-02-28 20:57:38 +00001816 break;
1817 }
1818
1819 /*
1820 * If this is NOT PPP then it is unknown to the ecm and we cannot figure out it's next device.
1821 */
1822 if (dest_dev_type != ARPHRD_PPP) {
1823 DEBUG_TRACE("Net device: %p is UNKNOWN type: %d\n", dest_dev, dest_dev_type);
1824 break;
1825 }
1826
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001827#ifndef ECM_INTERFACE_PPP_SUPPORT
1828 DEBUG_TRACE("Net device: %p is UNKNOWN (PPP Unsupported) type: %d\n", dest_dev, dest_dev_type);
1829#else
Ben Menchaca84f36632014-02-28 20:57:38 +00001830 /*
1831 * PPP - but what is the channel type?
1832 * First: If this is multi-link then we do not support it
1833 */
1834 if (ppp_is_multilink(dest_dev) > 0) {
1835 DEBUG_TRACE("Net device: %p is MULTILINK PPP - Unknown to the ECM\n", dest_dev);
1836 break;
1837 }
1838
1839 DEBUG_TRACE("Net device: %p is PPP\n", dest_dev);
1840
1841 /*
1842 * Get the PPP channel and then enquire what kind of channel it is
1843 * NOTE: Not multilink so only one channel to get.
1844 */
1845 channel_count = ppp_hold_channels(dest_dev, ppp_chan, 1);
1846 if (channel_count != 1) {
1847 DEBUG_TRACE("Net device: %p PPP has %d channels - Unknown to the ECM\n",
1848 dest_dev, channel_count);
1849 break;
1850 }
1851
1852 /*
1853 * Get channel protocol type
Gareth Williams6f96a4b2014-05-29 19:41:21 +01001854 * NOTE: Not all PPP channels support channel specific methods.
Ben Menchaca84f36632014-02-28 20:57:38 +00001855 */
Gareth Williams6f96a4b2014-05-29 19:41:21 +01001856 channel_protocol = ppp_channel_get_protocol(ppp_chan[0]);
Ben Menchaca84f36632014-02-28 20:57:38 +00001857 if (channel_protocol != PX_PROTO_OE) {
1858 DEBUG_TRACE("Net device: %p PPP channel protocol: %d - Unknown to the ECM\n",
1859 dest_dev, channel_protocol);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301860
Ben Menchaca84f36632014-02-28 20:57:38 +00001861 /*
1862 * Release the channel
1863 */
1864 ppp_release_channels(ppp_chan, 1);
1865
1866 break;
1867 }
1868
1869 /*
1870 * PPPoE channel
1871 */
1872 DEBUG_TRACE("Net device: %p PPP channel is PPPoE\n", dest_dev);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301873
Ben Menchaca84f36632014-02-28 20:57:38 +00001874 /*
1875 * Get PPPoE session information and the underlying device it is using.
Ben Menchaca84f36632014-02-28 20:57:38 +00001876 */
Gareth Williams6f96a4b2014-05-29 19:41:21 +01001877 pppoe_channel_addressing_get(ppp_chan[0], &addressing);
Ben Menchaca84f36632014-02-28 20:57:38 +00001878
1879 /*
1880 * Copy the dev hold into this, we will release the hold later
1881 */
1882 next_dev = addressing.dev;
1883
1884 DEBUG_TRACE("Net device: %p, next device: %p (%s)\n", dest_dev, next_dev, next_dev->name);
1885
1886 /*
1887 * Release the channel. Note that next_dev is still (correctly) held.
1888 */
1889 ppp_release_channels(ppp_chan, 1);
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001890#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001891 } while (false);
1892
1893 /*
Gareth Williamsa11d4352014-05-14 18:25:49 +01001894 * No longer need dest_dev as it may become next_dev
Ben Menchaca84f36632014-02-28 20:57:38 +00001895 */
Ben Menchaca84f36632014-02-28 20:57:38 +00001896 dev_put(dest_dev);
1897
1898 /*
1899 * Check out the next_dev, if any
1900 */
1901 if (!next_dev) {
1902 int32_t i __attribute__((unused));
1903 DEBUG_INFO("Completed interface heirarchy construct with first interface @: %d\n", current_interface_index);
1904#if DEBUG_LEVEL > 1
1905 for (i = current_interface_index; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
1906 DEBUG_TRACE("\tInterface @ %d: %p, type: %d, name: %s\n",
1907 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 +05301908
Ben Menchaca84f36632014-02-28 20:57:38 +00001909 }
1910#endif
Gareth Williamsa11d4352014-05-14 18:25:49 +01001911
1912 /*
1913 * Release src_dev now
1914 */
1915 dev_put(src_dev);
Ben Menchaca84f36632014-02-28 20:57:38 +00001916 return current_interface_index;
1917 }
1918
Gareth Williamsa11d4352014-05-14 18:25:49 +01001919 /*
1920 * dest_dev becomes next_dev
1921 */
Ben Menchaca84f36632014-02-28 20:57:38 +00001922 dest_dev = next_dev;
1923 dest_dev_name = dest_dev->name;
1924 dest_dev_type = dest_dev->type;
1925 }
1926
1927 DEBUG_WARN("Too many interfaces: %d\n", current_interface_index);
1928 DEBUG_ASSERT(current_interface_index == 0, "Bad logic handling current_interface_index: %d\n", current_interface_index);
1929 dev_put(src_dev);
1930 dev_put(dest_dev);
1931
1932 /*
1933 * Release the interfaces heirarchy we constructed to this point.
1934 */
1935 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1936 return ECM_DB_IFACE_HEIRARCHY_MAX;
1937}
1938EXPORT_SYMBOL(ecm_interface_heirarchy_construct);
1939
1940/*
Gareth Williamsadf425f2014-05-26 19:29:02 +01001941 * ecm_interface_list_stats_update()
1942 * Given an interface list, walk the interfaces and update the stats for certain types.
1943 */
1944static void ecm_interface_list_stats_update(int iface_list_first, struct ecm_db_iface_instance *iface_list[], uint8_t *mac_addr,
1945 uint32_t tx_packets, uint32_t tx_bytes, uint32_t rx_packets, uint32_t rx_bytes)
1946{
1947 int list_index;
1948
1949 for (list_index = iface_list_first; (list_index < ECM_DB_IFACE_HEIRARCHY_MAX); list_index++) {
1950 struct ecm_db_iface_instance *ii;
1951 ecm_db_iface_type_t ii_type;
1952 char *ii_name;
1953 struct net_device *dev;
1954
1955 ii = iface_list[list_index];
1956 ii_type = ecm_db_connection_iface_type_get(ii);
1957 ii_name = ecm_db_interface_type_to_string(ii_type);
1958 DEBUG_TRACE("list_index: %d, ii: %p, type: %d (%s)\n", list_index, ii, ii_type, ii_name);
1959
1960 /*
1961 * Locate real device in system
1962 */
1963 dev = dev_get_by_index(&init_net, ecm_db_iface_interface_identifier_get(ii));
1964 if (!dev) {
1965 DEBUG_WARN("Could not locate interface\n");
1966 continue;
1967 }
1968 DEBUG_TRACE("found dev: %p (%s)\n", dev, dev->name);
1969
Selin Dag1af781a2014-06-10 10:37:54 -07001970 /*
1971 * Refresh the bridge forward table entry if the port is a bridge port
1972 * Note: A bridge port can be of different interface type, e.g VLAN, ethernet.
1973 * This check, therefore, should be performed for all interface types.
1974 */
1975 if (is_valid_ether_addr(mac_addr) && ecm_front_end_is_bridge_port(dev)) {
1976 DEBUG_TRACE("Update bridge fdb entry for mac: %pM\n", mac_addr);
1977 br_refresh_fdb_entry(dev, mac_addr);
1978 }
1979
Gareth Williamsadf425f2014-05-26 19:29:02 +01001980 switch (ii_type) {
1981 struct rtnl_link_stats64 stats;
1982
1983 case ECM_DB_IFACE_TYPE_VLAN:
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05301984 DEBUG_INFO("VLAN\n");
Gareth Williamsadf425f2014-05-26 19:29:02 +01001985 stats.rx_packets = rx_packets;
1986 stats.rx_bytes = rx_bytes;
1987 stats.tx_packets = tx_packets;
1988 stats.tx_bytes = tx_bytes;
1989 __vlan_dev_update_accel_stats(dev, &stats);
1990 break;
1991 case ECM_DB_IFACE_TYPE_BRIDGE:
1992 DEBUG_INFO("BRIDGE\n");
1993 stats.rx_packets = rx_packets;
1994 stats.rx_bytes = rx_bytes;
1995 stats.tx_packets = tx_packets;
1996 stats.tx_bytes = tx_bytes;
1997 br_dev_update_stats(dev, &stats);
Gareth Williamsadf425f2014-05-26 19:29:02 +01001998 break;
Gareth Williamsadf425f2014-05-26 19:29:02 +01001999 default:
2000 /*
2001 * TODO: Extend it accordingly
2002 */
2003 break;
2004 }
2005
2006 dev_put(dev);
2007 }
2008}
2009
2010/*
2011 * ecm_interface_stats_update()
2012 * Using the interface lists for the given connection, update the interface statistics for each.
2013 *
2014 * 'from' here is wrt the connection 'from' side. Likewise with 'to'.
2015 * TX is wrt what the interface has transmitted. RX is what the interface has received.
2016 */
2017void ecm_interface_stats_update(struct ecm_db_connection_instance *ci,
2018 uint32_t from_tx_packets, uint32_t from_tx_bytes, uint32_t from_rx_packets, uint32_t from_rx_bytes,
2019 uint32_t to_tx_packets, uint32_t to_tx_bytes, uint32_t to_rx_packets, uint32_t to_rx_bytes)
2020{
2021 struct ecm_db_iface_instance *from_ifaces[ECM_DB_IFACE_HEIRARCHY_MAX];
2022 struct ecm_db_iface_instance *to_ifaces[ECM_DB_IFACE_HEIRARCHY_MAX];
2023 int from_ifaces_first;
2024 int to_ifaces_first;
2025 uint8_t mac_addr[ETH_ALEN];
2026
2027 /*
2028 * Iterate the 'from' side interfaces and update statistics and state for the real HLOS interfaces
2029 * from_tx_packets / bytes: the amount transmitted by the 'from' interface
2030 * from_rx_packets / bytes: the amount received by the 'from' interface
2031 */
2032 DEBUG_INFO("%p: Update from interface stats\n", ci);
2033 from_ifaces_first = ecm_db_connection_from_interfaces_get_and_ref(ci, from_ifaces);
2034 ecm_db_connection_from_node_address_get(ci, mac_addr);
2035 ecm_interface_list_stats_update(from_ifaces_first, from_ifaces, mac_addr, from_tx_packets, from_tx_bytes, from_rx_packets, from_rx_bytes);
2036 ecm_db_connection_interfaces_deref(from_ifaces, from_ifaces_first);
2037
2038 /*
2039 * Iterate the 'to' side interfaces and update statistics and state for the real HLOS interfaces
2040 * to_tx_packets / bytes: the amount transmitted by the 'to' interface
2041 * to_rx_packets / bytes: the amount received by the 'to' interface
2042 */
2043 DEBUG_INFO("%p: Update to interface stats\n", ci);
2044 to_ifaces_first = ecm_db_connection_to_interfaces_get_and_ref(ci, to_ifaces);
2045 ecm_db_connection_to_node_address_get(ci, mac_addr);
2046 ecm_interface_list_stats_update(to_ifaces_first, to_ifaces, mac_addr, to_tx_packets, to_tx_bytes, to_rx_packets, to_rx_bytes);
2047 ecm_db_connection_interfaces_deref(to_ifaces, to_ifaces_first);
2048}
2049EXPORT_SYMBOL(ecm_interface_stats_update);
2050
2051/*
Gareth Williams3cb1ffc2014-09-19 16:04:35 +01002052 * ecm_interface_regenerate_connection()
2053 * Re-generate a specific connection
2054 */
2055void ecm_interface_regenerate_connection(struct ecm_db_connection_instance *ci)
2056{
2057 struct ecm_front_end_connection_instance *feci;
2058
2059 DEBUG_TRACE("Regenerate connection: %p\n", ci);
2060
2061 /*
2062 * Flag the connection as needing re-generation.
2063 * Re-generation occurs when we next see traffic OR an acceleration engine sync for this connection.
2064 * Refer to front end protocol specific process() functions.
2065 */
2066 ecm_db_connection_classifier_generation_change(ci);
2067
2068 /*
2069 * If the connection is accelerated then force deceleration.
2070 * Under normal circumstances deceleration would occur on the next sync received,
2071 * however, there is a situation where a sync may not occur if, say, a cable has been pulled.
2072 * The acceleration engine would see no further traffic to trigger sending a sync and so
2073 * re-generation would not occur.
2074 * The connection would stall and no-regeneration would happen leaving the connection in bad state.
2075 * NOTE: We can just call decelerate() upon the front end - if its not accelerated this will have no effect.
2076 */
2077 feci = ecm_db_connection_front_end_get_and_ref(ci);
2078 feci->decelerate(feci);
2079 feci->deref(feci);
2080}
2081
2082/*
Ben Menchaca84f36632014-02-28 20:57:38 +00002083 * ecm_interface_regenerate_connections()
2084 * Cause regeneration of all connections that are using the specified interface.
2085 */
2086static void ecm_interface_regenerate_connections(struct ecm_db_iface_instance *ii)
2087{
2088 struct ecm_db_connection_instance *ci;
2089
2090 DEBUG_TRACE("Regenerate connections using interface: %p\n", ii);
2091
2092 /*
2093 * Iterate the connections of this interface and cause each one to be re-generated.
2094 * GGG TODO NOTE: If this proves slow (need metrics here) we could just regenerate the "lot" with one very simple call.
2095 * 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
2096 * but at the cost of performance.
2097 */
2098 DEBUG_TRACE("%p: Regenerate 'from' connections\n", ii);
2099 ci = ecm_db_iface_connections_from_get_and_ref_first(ii);
2100 while (ci) {
2101 struct ecm_db_connection_instance *cin;
2102 cin = ecm_db_connection_iface_from_get_and_ref_next(ci);
2103
2104 DEBUG_TRACE("%p: Regenerate: %p", ii, ci);
Gareth Williams3cb1ffc2014-09-19 16:04:35 +01002105 ecm_interface_regenerate_connection(ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00002106 ecm_db_connection_deref(ci);
2107 ci = cin;
2108 }
2109
2110 DEBUG_TRACE("%p: Regenerate 'to' connections\n", ii);
2111 ci = ecm_db_iface_connections_to_get_and_ref_first(ii);
2112 while (ci) {
2113 struct ecm_db_connection_instance *cin;
2114 cin = ecm_db_connection_iface_to_get_and_ref_next(ci);
2115
2116 DEBUG_TRACE("%p: Regenerate: %p", ii, ci);
Gareth Williams3cb1ffc2014-09-19 16:04:35 +01002117 ecm_interface_regenerate_connection(ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00002118 ecm_db_connection_deref(ci);
2119 ci = cin;
2120 }
2121
2122 DEBUG_TRACE("%p: Regenerate 'from_nat' connections\n", ii);
2123 ci = ecm_db_iface_connections_nat_from_get_and_ref_first(ii);
2124 while (ci) {
2125 struct ecm_db_connection_instance *cin;
2126 cin = ecm_db_connection_iface_nat_from_get_and_ref_next(ci);
2127
2128 DEBUG_TRACE("%p: Regenerate: %p", ii, ci);
Gareth Williams3cb1ffc2014-09-19 16:04:35 +01002129 ecm_interface_regenerate_connection(ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00002130 ecm_db_connection_deref(ci);
2131 ci = cin;
2132 }
2133
2134 DEBUG_TRACE("%p: Regenerate 'to_nat' connections\n", ii);
2135 ci = ecm_db_iface_connections_nat_to_get_and_ref_first(ii);
2136 while (ci) {
2137 struct ecm_db_connection_instance *cin;
2138 cin = ecm_db_connection_iface_nat_to_get_and_ref_next(ci);
2139
2140 DEBUG_TRACE("%p: Regenerate: %p", ii, ci);
Gareth Williams3cb1ffc2014-09-19 16:04:35 +01002141 ecm_interface_regenerate_connection(ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00002142 ecm_db_connection_deref(ci);
2143 ci = cin;
2144 }
2145
2146 DEBUG_TRACE("%p: Regenerate COMPLETE\n", ii);
2147}
2148
2149/*
2150 * ecm_interface_dev_regenerate_connections()
2151 * Cause regeneration of all connections that are using the specified interface.
2152 */
2153static void ecm_interface_dev_regenerate_connections(struct net_device *dev)
2154{
2155 struct ecm_db_iface_instance *ii;
2156
2157 DEBUG_INFO("Regenerate connections for: %p (%s)\n", dev, dev->name);
2158
2159 /*
2160 * Establish the interface for the given device.
2161 * NOTE: The cute thing here is even if dev is previously unknown to us this will create an interface instance
2162 * 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.
2163 * However if the interface is known to us then we will get it returned by this function and process it accordingly.
2164 */
2165 ii = ecm_interface_establish_and_ref(dev);
2166 if (!ii) {
2167 DEBUG_WARN("%p: No interface instance could be established for this dev\n", dev);
2168 return;
2169 }
2170 ecm_interface_regenerate_connections(ii);
2171 DEBUG_TRACE("%p: Regenerate for %p: COMPLETE\n", dev, ii);
2172 ecm_db_iface_deref(ii);
2173}
2174
2175/*
2176 * ecm_interface_mtu_change()
2177 * MTU of interface has changed
2178 */
2179static void ecm_interface_mtu_change(struct net_device *dev)
2180{
2181 int mtu;
2182 struct ecm_db_iface_instance *ii;
2183
2184 mtu = dev->mtu;
2185 DEBUG_INFO("%p (%s): MTU Change to: %d\n", dev, dev->name, mtu);
2186
2187 /*
2188 * Establish the interface for the given device.
2189 */
2190 ii = ecm_interface_establish_and_ref(dev);
2191 if (!ii) {
2192 DEBUG_WARN("%p: No interface instance could be established for this dev\n", dev);
2193 return;
2194 }
2195
2196 /*
2197 * Change the mtu
2198 */
2199 ecm_db_iface_mtu_reset(ii, mtu);
2200 DEBUG_TRACE("%p (%s): MTU Changed to: %d\n", dev, dev->name, mtu);
2201 ecm_interface_regenerate_connections(ii);
2202 DEBUG_TRACE("%p: Regenerate for %p: COMPLETE\n", dev, ii);
2203 ecm_db_iface_deref(ii);
2204}
2205
2206/*
2207 * ecm_interface_netdev_notifier_callback()
2208 * Netdevice notifier callback to inform us of change of state of a netdevice
2209 */
2210static int ecm_interface_netdev_notifier_callback(struct notifier_block *this, unsigned long event, void *ptr)
2211{
2212 struct net_device *dev __attribute__ ((unused)) = (struct net_device *)ptr;
2213
2214 DEBUG_INFO("Net device notifier for: %p, name: %s, event: %lx\n", dev, dev->name, event);
2215
2216 switch (event) {
2217 case NETDEV_DOWN:
2218 DEBUG_INFO("Net device: %p, DOWN\n", dev);
2219 ecm_interface_dev_regenerate_connections(dev);
2220 break;
2221
2222 case NETDEV_CHANGE:
2223 DEBUG_INFO("Net device: %p, CHANGE\n", dev);
2224 if (!netif_carrier_ok(dev)) {
2225 DEBUG_INFO("Net device: %p, CARRIER BAD\n", dev);
Tushar Mathur933907c2014-06-24 17:06:14 +05302226 if (netif_is_bond_slave(dev)) {
2227 ecm_interface_dev_regenerate_connections(dev->master);
2228 } else {
2229 ecm_interface_dev_regenerate_connections(dev);
2230 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002231 }
2232 break;
2233
2234 case NETDEV_CHANGEMTU:
2235 DEBUG_INFO("Net device: %p, MTU CHANGE\n", dev);
2236 ecm_interface_mtu_change(dev);
2237 break;
2238
2239 default:
2240 DEBUG_TRACE("Net device: %p, UNHANDLED: %lx\n", dev, event);
2241 break;
2242 }
2243
2244 return NOTIFY_DONE;
2245}
2246
2247/*
2248 * struct notifier_block ecm_interface_netdev_notifier
2249 * Registration for net device changes of state.
2250 */
2251static struct notifier_block ecm_interface_netdev_notifier __read_mostly = {
2252 .notifier_call = ecm_interface_netdev_notifier_callback,
2253};
2254
2255/*
Ben Menchaca84f36632014-02-28 20:57:38 +00002256 * ecm_interface_get_stop()
2257 */
2258static ssize_t ecm_interface_get_stop(struct sys_device *dev,
2259 struct sysdev_attribute *attr,
2260 char *buf)
2261{
2262 ssize_t count;
2263 int num;
2264
2265 /*
2266 * Operate under our locks
2267 */
2268 spin_lock_bh(&ecm_interface_lock);
2269 num = ecm_interface_stopped;
2270 spin_unlock_bh(&ecm_interface_lock);
2271
2272 count = snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", num);
2273 return count;
2274}
2275
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002276void ecm_interface_stop(int num)
2277{
2278 /*
2279 * Operate under our locks and stop further processing of packets
2280 */
2281 spin_lock_bh(&ecm_interface_lock);
2282 ecm_interface_stopped = num;
2283 spin_unlock_bh(&ecm_interface_lock);
2284
2285}
2286EXPORT_SYMBOL(ecm_interface_stop);
2287
2288
Ben Menchaca84f36632014-02-28 20:57:38 +00002289/*
2290 * ecm_interface_set_stop()
2291 */
2292static ssize_t ecm_interface_set_stop(struct sys_device *dev,
2293 struct sysdev_attribute *attr,
2294 const char *buf, size_t count)
2295{
2296 char num_buf[12];
2297 int num;
2298
2299 /*
2300 * Get the number from buf into a properly z-termed number buffer
2301 */
2302 if (count > 11) {
2303 return 0;
2304 }
2305 memcpy(num_buf, buf, count);
2306 num_buf[count] = '\0';
2307 sscanf(num_buf, "%d", &num);
2308 DEBUG_TRACE("ecm_interface_stop = %d\n", num);
2309
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002310 ecm_interface_stop(num);
Ben Menchaca84f36632014-02-28 20:57:38 +00002311
2312 return count;
2313}
2314
2315/*
2316 * SysFS attributes for the default classifier itself.
2317 */
Ben Menchaca84f36632014-02-28 20:57:38 +00002318static SYSDEV_ATTR(stop, 0644, ecm_interface_get_stop, ecm_interface_set_stop);
2319
2320/*
2321 * SysFS class of the ubicom default classifier
2322 * SysFS control points can be found at /sys/devices/system/ecm_front_end/ecm_front_endX/
2323 */
2324static struct sysdev_class ecm_interface_sysclass = {
2325 .name = "ecm_interface",
2326};
2327
2328/*
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002329 * ecm_interface_init()
Ben Menchaca84f36632014-02-28 20:57:38 +00002330 */
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002331int ecm_interface_init(void)
Ben Menchaca84f36632014-02-28 20:57:38 +00002332{
2333 int result;
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002334 DEBUG_INFO("ECM Interface init\n");
Ben Menchaca84f36632014-02-28 20:57:38 +00002335
2336 /*
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002337 * Initialise our global lock
Ben Menchaca84f36632014-02-28 20:57:38 +00002338 */
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002339 spin_lock_init(&ecm_interface_lock);
Ben Menchaca84f36632014-02-28 20:57:38 +00002340
2341 /*
2342 * Register the sysfs class
2343 */
2344 result = sysdev_class_register(&ecm_interface_sysclass);
2345 if (result) {
2346 DEBUG_ERROR("Failed to register SysFS class %d\n", result);
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002347 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00002348 }
2349
2350 /*
2351 * Register SYSFS device control
2352 */
2353 memset(&ecm_interface_sys_dev, 0, sizeof(ecm_interface_sys_dev));
2354 ecm_interface_sys_dev.id = 0;
2355 ecm_interface_sys_dev.cls = &ecm_interface_sysclass;
2356 result = sysdev_register(&ecm_interface_sys_dev);
2357 if (result) {
2358 DEBUG_ERROR("Failed to register SysFS device %d\n", result);
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002359 goto task_cleanup_1;
Ben Menchaca84f36632014-02-28 20:57:38 +00002360 }
2361
2362 /*
2363 * Create files, one for each parameter supported by this module
2364 */
Ben Menchaca84f36632014-02-28 20:57:38 +00002365 result = sysdev_create_file(&ecm_interface_sys_dev, &attr_stop);
2366 if (result) {
2367 DEBUG_ERROR("Failed to register stop file %d\n", result);
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002368 goto task_cleanup_2;
Ben Menchaca84f36632014-02-28 20:57:38 +00002369 }
2370
2371 result = register_netdevice_notifier(&ecm_interface_netdev_notifier);
2372 if (result != 0) {
2373 DEBUG_ERROR("Failed to register netdevice notifier %d\n", result);
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002374 goto task_cleanup_2;
Ben Menchaca84f36632014-02-28 20:57:38 +00002375 }
2376
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002377 return 0;
Ben Menchaca84f36632014-02-28 20:57:38 +00002378
Ben Menchaca84f36632014-02-28 20:57:38 +00002379task_cleanup_2:
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002380 sysdev_unregister(&ecm_interface_sys_dev);
Ben Menchaca84f36632014-02-28 20:57:38 +00002381task_cleanup_1:
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002382 sysdev_class_unregister(&ecm_interface_sysclass);
Ben Menchaca84f36632014-02-28 20:57:38 +00002383
Ben Menchaca84f36632014-02-28 20:57:38 +00002384 return result;
2385}
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002386EXPORT_SYMBOL(ecm_interface_init);
Ben Menchaca84f36632014-02-28 20:57:38 +00002387
2388/*
2389 * ecm_interface_exit()
2390 */
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002391void ecm_interface_exit(void)
Ben Menchaca84f36632014-02-28 20:57:38 +00002392{
2393 DEBUG_INFO("ECM Interface exit\n");
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002394
2395 spin_lock_bh(&ecm_interface_lock);
2396 ecm_interface_terminate_pending = true;
2397 spin_unlock_bh(&ecm_interface_lock);
2398
2399 unregister_netdevice_notifier(&ecm_interface_netdev_notifier);
2400 sysdev_unregister(&ecm_interface_sys_dev);
2401 sysdev_class_unregister(&ecm_interface_sysclass);
Ben Menchaca84f36632014-02-28 20:57:38 +00002402}
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002403EXPORT_SYMBOL(ecm_interface_exit);