blob: 88cf6da8b2c27a26671b665931b6d1c8c7fafa0a [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>
33#include <net/ip.h>
34#include <net/tcp.h>
35#include <asm/unaligned.h>
36#include <asm/uaccess.h> /* for put_user */
37#include <linux/inet.h>
38#include <linux/in6.h>
39#include <linux/in.h>
40#include <linux/udp.h>
41#include <linux/tcp.h>
42
43
44#include <linux/inetdevice.h>
45#include <net/ipip.h>
46#include <net/ip6_tunnel.h>
Gareth Williams43fc0852014-05-26 19:10:00 +010047#include <net/addrconf.h>
Ben Menchaca84f36632014-02-28 20:57:38 +000048#include <linux/if_arp.h>
49#include <linux/netfilter_ipv4.h>
50#include <linux/netfilter_bridge.h>
51#include <linux/if_bridge.h>
52#include <net/arp.h>
53#include <net/netfilter/nf_conntrack.h>
54#include <net/netfilter/nf_conntrack_acct.h>
55#include <net/netfilter/nf_conntrack_helper.h>
56#include <net/netfilter/nf_conntrack_l4proto.h>
57#include <net/netfilter/nf_conntrack_l3proto.h>
58#include <net/netfilter/nf_conntrack_zones.h>
59#include <net/netfilter/nf_conntrack_core.h>
60#include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
61#include <net/netfilter/ipv4/nf_defrag_ipv4.h>
62#include <linux/../../net/8021q/vlan.h>
63#include <linux/if_vlan.h>
64
65/*
66 * Debug output levels
67 * 0 = OFF
68 * 1 = ASSERTS / ERRORS
69 * 2 = 1 + WARN
70 * 3 = 2 + INFO
71 * 4 = 3 + TRACE
72 */
73#define DEBUG_LEVEL ECM_INTERFACE_DEBUG_LEVEL
74
75#include <nss_api_if.h>
76
77#include "ecm_types.h"
78#include "ecm_db_types.h"
79#include "ecm_tracker.h"
80#include "ecm_classifier.h"
81#include "ecm_front_end_types.h"
82#include "ecm_tracker_datagram.h"
83#include "ecm_tracker_udp.h"
84#include "ecm_tracker_tcp.h"
85#include "ecm_db.h"
86#include "ecm_interface.h"
87
88/*
Gareth Williamsadf425f2014-05-26 19:29:02 +010089 * TODO: Remove once the Linux image and headers get propogated.
90 */
91struct net_device *ipv6_dev_find(struct net *net, struct in6_addr *addr, int strict);
92
93/*
Ben Menchaca84f36632014-02-28 20:57:38 +000094 * Locking - concurrency control
95 */
96static spinlock_t ecm_interface_lock; /* Protect against SMP access between netfilter, events and private threaded function. */
97
98/*
99 * SysFS linkage
100 */
101static struct sys_device ecm_interface_sys_dev; /* SysFS linkage */
102
103/*
104 * General operational control
105 */
106static int ecm_interface_stopped = 0; /* When non-zero further traffic will not be processed */
107
108/*
109 * Management thread control
110 */
111static bool ecm_interface_terminate_pending = false; /* True when the user has signalled we should quit */
Ben Menchaca84f36632014-02-28 20:57:38 +0000112
113/*
Gareth Williamsadf425f2014-05-26 19:29:02 +0100114 * ecm_interface_dev_find_by_addr_ipv4()
115 * Return a hold to the device for the given IP address. Returns NULL on failure.
116 */
117static struct net_device *ecm_interface_dev_find_by_addr_ipv4(ip_addr_t addr)
118{
119 __be32 be_addr;
120 struct net_device *dev;
121
122 ECM_IP_ADDR_TO_NIN4_ADDR(be_addr, addr);
123 dev = ip_dev_find(&init_net, be_addr);
124 return dev;
125}
126
127/*
128 * ecm_interface_dev_find_by_addr_ipv6()
129 * Return a hold to the device for the given IP address. Returns NULL on failure.
130 */
131static struct net_device *ecm_interface_dev_find_by_addr_ipv6(ip_addr_t addr)
132{
133 struct in6_addr addr6;
134 struct net_device *dev;
135
136 ECM_IP_ADDR_TO_NIN6_ADDR(addr6, addr);
137 dev = (struct net_device *)ipv6_dev_find(&init_net, &addr6, 1);
138 return dev;
139}
140
141/*
142 * ecm_interface_dev_find_by_addr()
143 * Return the address locate the device on which it resides.
144 *
145 * Returns a hold to the device or NULL on failure.
146 */
147struct net_device *ecm_interface_dev_find_by_addr(ip_addr_t addr)
148{
149 char __attribute__((unused)) addr_str[40];
150
151 ecm_ip_addr_to_string(addr_str, addr);
152 DEBUG_TRACE("Locate dev for: %s\n", addr_str);
153
154 if (ECM_IP_ADDR_IS_V4(addr)) {
155 return ecm_interface_dev_find_by_addr_ipv4(addr);
156 }
157
158 return ecm_interface_dev_find_by_addr_ipv6(addr);
159}
160EXPORT_SYMBOL(ecm_interface_dev_find_by_addr);
161
162/*
Ben Menchaca84f36632014-02-28 20:57:38 +0000163 * ecm_interface_mac_addr_get_ipv6()
164 * Return mac for an IPv6 address
165 *
166 * GGG TODO Need to make sure this also works for local IP addresses too.
167 */
168static bool ecm_interface_mac_addr_get_ipv6(ip_addr_t addr, uint8_t *mac_addr, bool *on_link, ip_addr_t gw_addr)
169{
170 struct in6_addr daddr;
171 struct ecm_interface_route ecm_rt;
172 struct neighbour *neigh;
173 struct rt6_info *rt;
174 struct dst_entry *dst;
175
176 /*
177 * Get the MAC address that corresponds to IP address given.
178 * We look up the rt6_info entries and, from its neighbour structure, obtain the hardware address.
179 * This means we will also work if the neighbours are routers too.
180 */
181 ECM_IP_ADDR_TO_NIN6_ADDR(daddr, addr);
182 if (!ecm_interface_find_route_by_addr(addr, &ecm_rt)) {
183 return false;
184 }
185 DEBUG_ASSERT(!ecm_rt.v4_route, "Did not locate a v6 route!\n");
186
187 /*
188 * Is this destination on link or off-link via a gateway?
189 */
190 rt = ecm_rt.rt.rtv6;
191 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)) {
192 *on_link = false;
193 ECM_NIN6_ADDR_TO_IP_ADDR(gw_addr, rt->rt6i_gateway)
194 } else {
195 *on_link = true;
196 }
197
198 rcu_read_lock();
199 dst = ecm_rt.dst;
200 neigh = dst_get_neighbour_noref(dst);
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700201 if (neigh) {
202 neigh_hold(neigh);
203 } else {
204 neigh = neigh_lookup(&nd_tbl, &daddr, dst->dev);
205 }
Ben Menchaca84f36632014-02-28 20:57:38 +0000206 if (!neigh) {
207 rcu_read_unlock();
208 ecm_interface_route_release(&ecm_rt);
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700209 DEBUG_WARN("No neigh reference\n");
Ben Menchaca84f36632014-02-28 20:57:38 +0000210 return false;
211 }
212 if (!(neigh->nud_state & NUD_VALID)) {
213 rcu_read_unlock();
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700214 neigh_release(neigh);
Ben Menchaca84f36632014-02-28 20:57:38 +0000215 ecm_interface_route_release(&ecm_rt);
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700216 DEBUG_WARN("NUD invalid\n");
Ben Menchaca84f36632014-02-28 20:57:38 +0000217 return false;
218 }
219 if (!neigh->dev) {
220 rcu_read_unlock();
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700221 neigh_release(neigh);
Ben Menchaca84f36632014-02-28 20:57:38 +0000222 ecm_interface_route_release(&ecm_rt);
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700223 DEBUG_WARN("Neigh dev invalid\n");
Ben Menchaca84f36632014-02-28 20:57:38 +0000224 return false;
225 }
226
227 /*
228 * If neigh->dev is a loopback then addr is a local address in which case we take the MAC from given device
229 */
230 if (neigh->dev->flags & IFF_LOOPBACK) {
231 // GGG TODO Create an equivalent logic to that for ipv4, maybe need to create an ip6_dev_find()?
232 DEBUG_TRACE("local address " ECM_IP_ADDR_OCTAL_FMT " (found loopback)\n", ECM_IP_ADDR_TO_OCTAL(addr));
233 memset(mac_addr, 0, 6);
234 } else {
235 memcpy(mac_addr, neigh->ha, 6);
236 }
237 rcu_read_unlock();
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700238 neigh_release(neigh);
Ben Menchaca84f36632014-02-28 20:57:38 +0000239 ecm_interface_route_release(&ecm_rt);
240
241 DEBUG_TRACE(ECM_IP_ADDR_OCTAL_FMT " maps to %pM\n", ECM_IP_ADDR_TO_OCTAL(addr), mac_addr);
242 return true;
243}
244
245/*
246 * ecm_interface_mac_addr_get_ipv4()
247 * Return mac for an IPv4 address
248 */
249static bool ecm_interface_mac_addr_get_ipv4(ip_addr_t addr, uint8_t *mac_addr, bool *on_link, ip_addr_t gw_addr)
250{
251 struct neighbour *neigh;
252 struct ecm_interface_route ecm_rt;
253 struct rtable *rt;
254 struct dst_entry *dst;
255 __be32 ipv4_addr;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530256
Ben Menchaca84f36632014-02-28 20:57:38 +0000257 /*
258 * Get the MAC address that corresponds to IP address given.
259 * We look up the rtable entries and, from its neighbour structure, obtain the hardware address.
260 * This means we will also work if the neighbours are routers too.
261 * We also locate the MAC if the address is a local host address.
262 */
263 ECM_IP_ADDR_TO_NIN4_ADDR(ipv4_addr, addr);
264 if (!ecm_interface_find_route_by_addr(addr, &ecm_rt)) {
265 return false;
266 }
267 DEBUG_ASSERT(ecm_rt.v4_route, "Did not locate a v4 route!\n");
268
269 /*
270 * Is this destination on link or off-link via a gateway?
271 */
272 rt = ecm_rt.rt.rtv4;
273 if ((rt->rt_dst != rt->rt_gateway) || (rt->rt_flags & RTF_GATEWAY)) {
274 *on_link = false;
275 ECM_NIN4_ADDR_TO_IP_ADDR(gw_addr, rt->rt_gateway)
276 } else {
277 *on_link = true;
278 }
279
280 /*
281 * Get the neighbour entry for the address
282 */
283 rcu_read_lock();
284 dst = ecm_rt.dst;
285 neigh = dst_get_neighbour_noref(dst);
286 if (neigh) {
287 neigh_hold(neigh);
288 } else {
289 neigh = neigh_lookup(&arp_tbl, &ipv4_addr, dst->dev);
290 }
291 if (!neigh) {
292 rcu_read_unlock();
293 ecm_interface_route_release(&ecm_rt);
294 return false;
295 }
296 if (!(neigh->nud_state & NUD_VALID)) {
297 rcu_read_unlock();
298 neigh_release(neigh);
299 ecm_interface_route_release(&ecm_rt);
300 return false;
301 }
302 if (!neigh->dev) {
303 rcu_read_unlock();
304 neigh_release(neigh);
305 ecm_interface_route_release(&ecm_rt);
306 return false;
307 }
308
309 /*
310 * If the device is loopback this will be because the address is a local address
311 * In this case locate the device that has this local address and get its mac.
312 */
313 if (neigh->dev->type == ARPHRD_LOOPBACK) {
314 struct net_device *dev;
315
316 DEBUG_TRACE("%pI4 finds loopback device, dev: %p (%s)\n", &ipv4_addr, neigh->dev, neigh->dev->name);
317 rcu_read_unlock();
318 neigh_release(neigh);
319 ecm_interface_route_release(&ecm_rt);
320
321 /*
322 * Lookup the device that has this IP address assigned
323 */
324 dev = ip_dev_find(&init_net, ipv4_addr);
325 if (!dev) {
326 DEBUG_WARN("Unable to locate dev for: %pI4\n", &ipv4_addr);
327 return false;
328 }
329 memcpy(mac_addr, dev->dev_addr, (size_t)dev->addr_len);
330 DEBUG_TRACE("is local addr: %pI4, mac: %pM, dev ifindex: %d, dev: %p (%s), dev_type: %d\n",
331 &ipv4_addr, mac_addr, dev->ifindex, dev, dev->name, dev->type);
332 dev_put(dev);
333 return true;
334 }
335
336 if (!(neigh->dev->flags & IFF_NOARP)) {
337 memcpy(mac_addr, neigh->ha, (size_t)neigh->dev->addr_len);
338 } else {
339 DEBUG_TRACE("non-arp device: %p (%s, type: %d) to reach %pI4\n", neigh->dev, neigh->dev->name, neigh->dev->type, &ipv4_addr);
340 memset(mac_addr, 0, 6);
341 }
342 DEBUG_TRACE("addr: %pI4, mac: %pM, iif: %d, neigh dev ifindex: %d, dev: %p (%s), dev_type: %d\n",
343 &ipv4_addr, mac_addr, rt->rt_iif, neigh->dev->ifindex, neigh->dev, neigh->dev->name, neigh->dev->type);
344
345 rcu_read_unlock();
346 neigh_release(neigh);
347 ecm_interface_route_release(&ecm_rt);
348 return true;
349}
350
351/*
352 * ecm_interface_mac_addr_get()
353 * Return the mac address for the given IP address. Returns false on failure.
354 *
355 * 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.
356 *
357 * GGG TODO Make this function work for IPv6!!!!!!!!!!!!!!
358 */
359bool ecm_interface_mac_addr_get(ip_addr_t addr, uint8_t *mac_addr, bool *on_link, ip_addr_t gw_addr)
360{
361 if (ECM_IP_ADDR_IS_V4(addr)) {
362 return ecm_interface_mac_addr_get_ipv4(addr, mac_addr, on_link, gw_addr);
363 }
364
365 return ecm_interface_mac_addr_get_ipv6(addr, mac_addr, on_link, gw_addr);
366}
367EXPORT_SYMBOL(ecm_interface_mac_addr_get);
368
369/*
370 * ecm_interface_addr_find_route_by_addr_ipv4()
371 * Return the route for the given IP address. Returns NULL on failure.
372 */
373static bool ecm_interface_find_route_by_addr_ipv4(ip_addr_t addr, struct ecm_interface_route *ecm_rt)
374{
375 __be32 be_addr;
376
377 /*
378 * Get a route to the given IP address, this will allow us to also find the interface
379 * it is using to communicate with that IP address.
380 */
381 ECM_IP_ADDR_TO_NIN4_ADDR(be_addr, addr);
382 ecm_rt->rt.rtv4 = ip_route_output(&init_net, be_addr, 0, 0, 0);
383 if (IS_ERR(ecm_rt->rt.rtv4)) {
384 DEBUG_TRACE("No output route to: %pI4n\n", &be_addr);
385 return false;
386 }
387 DEBUG_TRACE("Output route to: %pI4n is: %p\n", &be_addr, ecm_rt->rt.rtv4);
388 ecm_rt->dst = (struct dst_entry *)ecm_rt->rt.rtv4;
389 ecm_rt->v4_route = true;
390 return true;
391}
392
393/*
394 * ecm_interface_addr_find_route_by_addr_ipv6()
395 * Return the route for the given IP address. Returns NULL on failure.
396 */
397static bool ecm_interface_find_route_by_addr_ipv6(ip_addr_t addr, struct ecm_interface_route *ecm_rt)
398{
399 struct in6_addr naddr;
400
401 ECM_IP_ADDR_TO_NIN6_ADDR(naddr, addr);
402
403 /*
404 * Get a route to the given IP address, this will allow us to also find the interface
405 * it is using to communicate with that IP address.
406 */
407 ecm_rt->rt.rtv6 = rt6_lookup(&init_net, &naddr, NULL, 0, 0);
408 if (!ecm_rt->rt.rtv6) {
409 DEBUG_TRACE("No output route to: " ECM_IP_ADDR_OCTAL_FMT "\n", ECM_IP_ADDR_TO_OCTAL(addr));
410 return NULL;
411 }
412 DEBUG_TRACE("Output route to: " ECM_IP_ADDR_OCTAL_FMT " is: %p\n", ECM_IP_ADDR_TO_OCTAL(addr), ecm_rt->rt.rtv6);
413 ecm_rt->dst = (struct dst_entry *)ecm_rt->rt.rtv6;
414 ecm_rt->v4_route = false;
415 return true;
416}
417
418/*
419 * ecm_interface_addr_find_route_by_addr()
420 * Return the route (in the given parameter) for the given IP address. Returns false on failure.
421 *
422 * Route is the device on which the addr is reachable, which may be loopback for local addresses.
423 *
424 * Returns true if the route was able to be located. The route must be released using ecm_interface_route_release().
425 */
426bool ecm_interface_find_route_by_addr(ip_addr_t addr, struct ecm_interface_route *ecm_rt)
427{
428 char __attribute__((unused)) addr_str[40];
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530429
Ben Menchaca84f36632014-02-28 20:57:38 +0000430 ecm_ip_addr_to_string(addr_str, addr);
431 DEBUG_TRACE("Locate route to: %s\n", addr_str);
432
433 if (ECM_IP_ADDR_IS_V4(addr)) {
434 return ecm_interface_find_route_by_addr_ipv4(addr, ecm_rt);
435 }
436
437 return ecm_interface_find_route_by_addr_ipv6(addr, ecm_rt);
438}
439EXPORT_SYMBOL(ecm_interface_find_route_by_addr);
440
441/*
442 * ecm_interface_route_release()
443 * Release an ecm route
444 */
445void ecm_interface_route_release(struct ecm_interface_route *rt)
446{
447 dst_release(rt->dst);
448}
449EXPORT_SYMBOL(ecm_interface_route_release);
450
451/*
Ben Menchaca84f36632014-02-28 20:57:38 +0000452 * ecm_interface_vlan_interface_establish()
453 * Returns a reference to a iface of the VLAN type, possibly creating one if necessary.
454 * Returns NULL on failure or a reference to interface.
455 */
456static struct ecm_db_iface_instance *ecm_interface_vlan_interface_establish(struct ecm_db_interface_info_vlan *type_info,
457 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
458{
459 struct ecm_db_iface_instance *nii;
460 struct ecm_db_iface_instance *ii;
461
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530462 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",
463 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 +0000464
465 /*
466 * Locate the iface
467 */
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530468 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 +0000469 if (ii) {
470 DEBUG_TRACE("%p: iface established\n", ii);
471 return ii;
472 }
473
474 /*
475 * No iface - create one
476 */
477 nii = ecm_db_iface_alloc();
478 if (!nii) {
479 DEBUG_WARN("Failed to establish iface\n");
480 return NULL;
481 }
482
483 /*
484 * Add iface into the database, atomically to avoid races creating the same thing
485 */
486 spin_lock_bh(&ecm_interface_lock);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530487 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 +0000488 if (ii) {
489 spin_unlock_bh(&ecm_interface_lock);
490 ecm_db_iface_deref(nii);
491 return ii;
492 }
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530493 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 -0500494 mtu, dev_interface_num, nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000495 spin_unlock_bh(&ecm_interface_lock);
496
497 DEBUG_TRACE("%p: vlan iface established\n", nii);
498 return nii;
499}
500
501/*
502 * ecm_interface_bridge_interface_establish()
503 * Returns a reference to a iface of the BRIDGE type, possibly creating one if necessary.
504 * Returns NULL on failure or a reference to interface.
505 */
506static struct ecm_db_iface_instance *ecm_interface_bridge_interface_establish(struct ecm_db_interface_info_bridge *type_info,
507 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
508{
509 struct ecm_db_iface_instance *nii;
510 struct ecm_db_iface_instance *ii;
511
512 DEBUG_INFO("Establish BRIDGE iface: %s with address: %pM, MTU: %d, if num: %d, nss if id: %d\n",
513 dev_name, type_info->address, mtu, dev_interface_num, nss_interface_num);
514
515 /*
516 * Locate the iface
517 */
518 ii = ecm_db_iface_find_and_ref_bridge(type_info->address);
519 if (ii) {
520 DEBUG_TRACE("%p: iface established\n", ii);
521 return ii;
522 }
523
524 /*
525 * No iface - create one
526 */
527 nii = ecm_db_iface_alloc();
528 if (!nii) {
529 DEBUG_WARN("Failed to establish iface\n");
530 return NULL;
531 }
532
533 /*
534 * Add iface into the database, atomically to avoid races creating the same thing
535 */
536 spin_lock_bh(&ecm_interface_lock);
537 ii = ecm_db_iface_find_and_ref_bridge(type_info->address);
538 if (ii) {
539 spin_unlock_bh(&ecm_interface_lock);
540 ecm_db_iface_deref(nii);
541 return ii;
542 }
543 ecm_db_iface_add_bridge(nii, type_info->address, dev_name,
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500544 mtu, dev_interface_num, nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000545 spin_unlock_bh(&ecm_interface_lock);
546
547 DEBUG_TRACE("%p: bridge iface established\n", nii);
548 return nii;
549}
550
551/*
552 * ecm_interface_lag_interface_establish()
553 * Returns a reference to a iface of the LAG type, possibly creating one if necessary.
554 * Returns NULL on failure or a reference to interface.
555 */
556static struct ecm_db_iface_instance *ecm_interface_lag_interface_establish(struct ecm_db_interface_info_lag *type_info,
557 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
558{
559 struct ecm_db_iface_instance *nii;
560 struct ecm_db_iface_instance *ii;
561
562 DEBUG_INFO("Establish LAG iface: %s with address: %pM, MTU: %d, if num: %d, nss if id: %d\n",
563 dev_name, type_info->address, mtu, dev_interface_num, nss_interface_num);
564
565 /*
566 * Locate the iface
567 */
568 ii = ecm_db_iface_find_and_ref_lag(type_info->address);
569 if (ii) {
570 DEBUG_TRACE("%p: iface established\n", ii);
571 return ii;
572 }
573
574 /*
575 * No iface - create one
576 */
577 nii = ecm_db_iface_alloc();
578 if (!nii) {
579 DEBUG_WARN("Failed to establish iface\n");
580 return NULL;
581 }
582
583 /*
584 * Add iface into the database, atomically to avoid races creating the same thing
585 */
586 spin_lock_bh(&ecm_interface_lock);
587 ii = ecm_db_iface_find_and_ref_lag(type_info->address);
588 if (ii) {
589 spin_unlock_bh(&ecm_interface_lock);
590 ecm_db_iface_deref(nii);
591 return ii;
592 }
593 ecm_db_iface_add_lag(nii, type_info->address, dev_name,
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500594 mtu, dev_interface_num, nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000595 spin_unlock_bh(&ecm_interface_lock);
596
597 DEBUG_TRACE("%p: lag iface established\n", nii);
598 return nii;
599}
600
601/*
602 * ecm_interface_ethernet_interface_establish()
603 * Returns a reference to a iface of the ETHERNET type, possibly creating one if necessary.
604 * Returns NULL on failure or a reference to interface.
605 */
606static struct ecm_db_iface_instance *ecm_interface_ethernet_interface_establish(struct ecm_db_interface_info_ethernet *type_info,
607 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
608{
609 struct ecm_db_iface_instance *nii;
610 struct ecm_db_iface_instance *ii;
611
612 DEBUG_INFO("Establish ETHERNET iface: %s with address: %pM, MTU: %d, if num: %d, nss if id: %d\n",
613 dev_name, type_info->address, mtu, dev_interface_num, nss_interface_num);
614
615 /*
616 * Locate the iface
617 */
618 ii = ecm_db_iface_find_and_ref_ethernet(type_info->address);
619 if (ii) {
620 DEBUG_TRACE("%p: iface established\n", ii);
621 return ii;
622 }
623
624 /*
625 * No iface - create one
626 */
627 nii = ecm_db_iface_alloc();
628 if (!nii) {
629 DEBUG_WARN("Failed to establish iface\n");
630 return NULL;
631 }
632
633 /*
634 * Add iface into the database, atomically to avoid races creating the same thing
635 */
636 spin_lock_bh(&ecm_interface_lock);
637 ii = ecm_db_iface_find_and_ref_ethernet(type_info->address);
638 if (ii) {
639 spin_unlock_bh(&ecm_interface_lock);
640 ecm_db_iface_deref(nii);
641 return ii;
642 }
643 ecm_db_iface_add_ethernet(nii, type_info->address, dev_name,
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500644 mtu, dev_interface_num, nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000645 spin_unlock_bh(&ecm_interface_lock);
646
647 DEBUG_TRACE("%p: ethernet iface established\n", nii);
648 return nii;
649}
650
Gareth Williamsc5b9d712014-05-09 20:40:07 +0100651#ifdef ECM_INTERFACE_PPP_SUPPORT
Ben Menchaca84f36632014-02-28 20:57:38 +0000652/*
653 * ecm_interface_pppoe_interface_establish()
654 * Returns a reference to a iface of the PPPoE 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_pppoe_interface_establish(struct ecm_db_interface_info_pppoe *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 PPPoE iface: %s with session id: %u, remote mac: %pM, MTU: %d, if num: %d, nss if id: %d\n",
664 dev_name, type_info->pppoe_session_id, type_info->remote_mac, mtu, dev_interface_num, nss_interface_num);
665
666 /*
667 * Locate the iface
668 */
669 ii = ecm_db_iface_find_and_ref_pppoe(type_info->pppoe_session_id, type_info->remote_mac);
670 if (ii) {
671 DEBUG_TRACE("%p: iface established\n", ii);
672 return ii;
673 }
674
675 /*
676 * No iface - create one
677 */
678 nii = ecm_db_iface_alloc();
679 if (!nii) {
680 DEBUG_WARN("Failed to establish iface\n");
681 return NULL;
682 }
683
684 /*
685 * Add iface into the database, atomically to avoid races creating the same thing
686 */
687 spin_lock_bh(&ecm_interface_lock);
688 ii = ecm_db_iface_find_and_ref_pppoe(type_info->pppoe_session_id, type_info->remote_mac);
689 if (ii) {
690 spin_unlock_bh(&ecm_interface_lock);
691 ecm_db_iface_deref(nii);
692 return ii;
693 }
694 ecm_db_iface_add_pppoe(nii, type_info->pppoe_session_id, type_info->remote_mac, dev_name,
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500695 mtu, dev_interface_num, nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000696 spin_unlock_bh(&ecm_interface_lock);
697
698 DEBUG_TRACE("%p: pppoe iface established\n", nii);
699 return nii;
700}
Gareth Williamsc5b9d712014-05-09 20:40:07 +0100701#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000702
703/*
704 * ecm_interface_unknown_interface_establish()
705 * Returns a reference to a iface of the UNKNOWN type, possibly creating one if necessary.
706 * Returns NULL on failure or a reference to interface.
707 */
708static struct ecm_db_iface_instance *ecm_interface_unknown_interface_establish(struct ecm_db_interface_info_unknown *type_info,
709 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
710{
711 struct ecm_db_iface_instance *nii;
712 struct ecm_db_iface_instance *ii;
713
714 DEBUG_INFO("Establish UNKNOWN iface: %s with os_specific_ident: %u, MTU: %d, if num: %d, nss if id: %d\n",
715 dev_name, type_info->os_specific_ident, mtu, dev_interface_num, nss_interface_num);
716
717 /*
718 * Locate the iface
719 */
720 ii = ecm_db_iface_find_and_ref_unknown(type_info->os_specific_ident);
721 if (ii) {
722 DEBUG_TRACE("%p: iface established\n", ii);
723 return ii;
724 }
725
726 /*
727 * No iface - create one
728 */
729 nii = ecm_db_iface_alloc();
730 if (!nii) {
731 DEBUG_WARN("Failed to establish iface\n");
732 return NULL;
733 }
734
735 /*
736 * Add iface into the database, atomically to avoid races creating the same thing
737 */
738 spin_lock_bh(&ecm_interface_lock);
739 ii = ecm_db_iface_find_and_ref_unknown(type_info->os_specific_ident);
740 if (ii) {
741 spin_unlock_bh(&ecm_interface_lock);
742 ecm_db_iface_deref(nii);
743 return ii;
744 }
745 ecm_db_iface_add_unknown(nii, type_info->os_specific_ident, dev_name,
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500746 mtu, dev_interface_num, nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000747 spin_unlock_bh(&ecm_interface_lock);
748
749 DEBUG_TRACE("%p: unknown iface established\n", nii);
750 return nii;
751}
752
753/*
754 * ecm_interface_loopback_interface_establish()
755 * Returns a reference to a iface of the LOOPBACK type, possibly creating one if necessary.
756 * Returns NULL on failure or a reference to interface.
757 */
758static struct ecm_db_iface_instance *ecm_interface_loopback_interface_establish(struct ecm_db_interface_info_loopback *type_info,
759 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
760{
761 struct ecm_db_iface_instance *nii;
762 struct ecm_db_iface_instance *ii;
763
764 DEBUG_INFO("Establish LOOPBACK iface: %s with os_specific_ident: %u, MTU: %d, if num: %d, nss if id: %d\n",
765 dev_name, type_info->os_specific_ident, mtu, dev_interface_num, nss_interface_num);
766
767 /*
768 * Locate the iface
769 */
770 ii = ecm_db_iface_find_and_ref_loopback(type_info->os_specific_ident);
771 if (ii) {
772 DEBUG_TRACE("%p: iface established\n", ii);
773 return ii;
774 }
775
776 /*
777 * No iface - create one
778 */
779 nii = ecm_db_iface_alloc();
780 if (!nii) {
781 DEBUG_WARN("Failed to establish iface\n");
782 return NULL;
783 }
784
785 /*
786 * Add iface into the database, atomically to avoid races creating the same thing
787 */
788 spin_lock_bh(&ecm_interface_lock);
789 ii = ecm_db_iface_find_and_ref_loopback(type_info->os_specific_ident);
790 if (ii) {
791 spin_unlock_bh(&ecm_interface_lock);
792 ecm_db_iface_deref(nii);
793 return ii;
794 }
795 ecm_db_iface_add_loopback(nii, type_info->os_specific_ident, dev_name,
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500796 mtu, dev_interface_num, nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000797 spin_unlock_bh(&ecm_interface_lock);
798
799 DEBUG_TRACE("%p: loopback iface established\n", nii);
800 return nii;
801}
802
803/*
804 * ecm_interface_ipsec_tunnel_interface_establish()
805 * Returns a reference to a iface of the IPSEC_TUNNEL type, possibly creating one if necessary.
806 * Returns NULL on failure or a reference to interface.
807 *
808 * NOTE: GGG TODO THIS NEEDS TO TAKE A PROPER APPROACH TO IPSEC TUNNELS USING ENDPOINT ADDRESSING AS THE TYPE INFO KEYS
809 */
810static struct ecm_db_iface_instance *ecm_interface_ipsec_tunnel_interface_establish(struct ecm_db_interface_info_ipsec_tunnel *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 IPSEC_TUNNEL 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_ipsec_tunnel(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_ipsec_tunnel(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_ipsec_tunnel(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: ipsec_tunnel iface established\n", nii);
852 return nii;
853}
854
Murat Sezgincc6eedf2014-05-09 23:59:19 -0700855#ifdef CONFIG_IPV6_SIT_6RD
Ben Menchaca84f36632014-02-28 20:57:38 +0000856/*
857 * ecm_interface_sit_interface_establish()
858 * Returns a reference to a iface of the SIT type, possibly creating one if necessary.
859 * Returns NULL on failure or a reference to interface.
860 */
861static struct ecm_db_iface_instance *ecm_interface_sit_interface_establish(struct ecm_db_interface_info_sit *type_info,
862 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
863{
864 struct ecm_db_iface_instance *nii;
865 struct ecm_db_iface_instance *ii;
866
867 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",
868 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);
869
870 /*
871 * Locate the iface
872 */
873 ii = ecm_db_iface_find_and_ref_sit(type_info->saddr, type_info->daddr);
874 if (ii) {
875 DEBUG_TRACE("%p: iface established\n", ii);
876 return ii;
877 }
878
879 /*
880 * No iface - create one
881 */
882 nii = ecm_db_iface_alloc();
883 if (!nii) {
884 DEBUG_WARN("Failed to establish iface\n");
885 return NULL;
886 }
887
888 /*
889 * Add iface into the database, atomically to avoid races creating the same thing
890 */
891 spin_lock_bh(&ecm_interface_lock);
892 ii = ecm_db_iface_find_and_ref_sit(type_info->saddr, type_info->daddr);
893 if (ii) {
894 spin_unlock_bh(&ecm_interface_lock);
895 ecm_db_iface_deref(nii);
896 return ii;
897 }
898 ecm_db_iface_add_sit(nii, type_info, dev_name, mtu, dev_interface_num,
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500899 nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000900 spin_unlock_bh(&ecm_interface_lock);
901
902 DEBUG_TRACE("%p: sit iface established\n", nii);
903 return nii;
904}
Murat Sezgincc6eedf2014-05-09 23:59:19 -0700905#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000906
907/*
908 * ecm_interface_tunipip6_interface_establish()
909 * Returns a reference to a iface of the TUNIPIP6 type, possibly creating one if necessary.
910 * Returns NULL on failure or a reference to interface.
911 */
912static struct ecm_db_iface_instance *ecm_interface_tunipip6_interface_establish(struct ecm_db_interface_info_tunipip6 *type_info,
913 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
914{
915 struct ecm_db_iface_instance *nii;
916 struct ecm_db_iface_instance *ii;
917
918 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",
919 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);
920
921 /*
922 * Locate the iface
923 */
924 ii = ecm_db_iface_find_and_ref_tunipip6(type_info->saddr, type_info->daddr);
925 if (ii) {
926 DEBUG_TRACE("%p: iface established\n", ii);
927 return ii;
928 }
929
930 /*
931 * No iface - create one
932 */
933 nii = ecm_db_iface_alloc();
934 if (!nii) {
935 DEBUG_WARN("Failed to establish iface\n");
936 return NULL;
937 }
938
939 /*
940 * Add iface into the database, atomically to avoid races creating the same thing
941 */
942 spin_lock_bh(&ecm_interface_lock);
943 ii = ecm_db_iface_find_and_ref_tunipip6(type_info->saddr, type_info->daddr);
944 if (ii) {
945 spin_unlock_bh(&ecm_interface_lock);
946 ecm_db_iface_deref(nii);
947 return ii;
948 }
949 ecm_db_iface_add_tunipip6(nii, type_info, dev_name, mtu, dev_interface_num,
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500950 nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000951 spin_unlock_bh(&ecm_interface_lock);
952
953 DEBUG_TRACE("%p: tunipip6 iface established\n", nii);
954 return nii;
955}
956
957/*
958 * ecm_interface_establish_and_ref()
959 * Establish an interface instance for the given interface detail.
960 */
961struct ecm_db_iface_instance *ecm_interface_establish_and_ref(struct net_device *dev)
962{
963 int32_t dev_interface_num;
964 char *dev_name;
965 int32_t dev_type;
966 int32_t dev_mtu;
967 int32_t nss_interface_num;
968 struct ecm_db_iface_instance *ii;
969 union {
970 struct ecm_db_interface_info_ethernet ethernet; /* type == ECM_DB_IFACE_TYPE_ETHERNET */
971 struct ecm_db_interface_info_vlan vlan; /* type == ECM_DB_IFACE_TYPE_VLAN */
972 struct ecm_db_interface_info_lag lag; /* type == ECM_DB_IFACE_TYPE_LAG */
973 struct ecm_db_interface_info_bridge bridge; /* type == ECM_DB_IFACE_TYPE_BRIDGE */
974 struct ecm_db_interface_info_pppoe pppoe; /* type == ECM_DB_IFACE_TYPE_PPPOE */
975 struct ecm_db_interface_info_unknown unknown; /* type == ECM_DB_IFACE_TYPE_UNKNOWN */
976 struct ecm_db_interface_info_loopback loopback; /* type == ECM_DB_IFACE_TYPE_LOOPBACK */
977 struct ecm_db_interface_info_ipsec_tunnel ipsec_tunnel; /* type == ECM_DB_IFACE_TYPE_IPSEC_TUNNEL */
978 struct ecm_db_interface_info_sit sit; /* type == ECM_DB_IFACE_TYPE_SIT */
979 struct ecm_db_interface_info_tunipip6 tunipip6; /* type == ECM_DB_IFACE_TYPE_TUNIPIP6 */
980 } type_info;
Gareth Williamsc5b9d712014-05-09 20:40:07 +0100981
982#ifdef ECM_INTERFACE_PPP_SUPPORT
Ben Menchaca84f36632014-02-28 20:57:38 +0000983 int channel_count;
984 struct ppp_channel *ppp_chan[1];
Ben Menchaca84f36632014-02-28 20:57:38 +0000985 int channel_protocol;
Ben Menchaca84f36632014-02-28 20:57:38 +0000986 struct pppoe_opt addressing;
Gareth Williamsc5b9d712014-05-09 20:40:07 +0100987#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000988
989 /*
990 * Get basic information about the given device
991 */
992 dev_interface_num = dev->ifindex;
993 dev_name = dev->name;
994 dev_type = dev->type;
995 dev_mtu = dev->mtu;
996
997 /*
998 * Does the NSS recognise this interface?
999 */
1000 nss_interface_num = nss_cmn_get_interface_number_by_dev(dev);
1001
1002 DEBUG_TRACE("Establish interface instance for device: %p is type: %d, name: %s, ifindex: %d, nss_if: %d, mtu: %d\n",
1003 dev, dev_type, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1004
1005 /*
1006 * Extract from the device more type-specific information
1007 */
1008 if (dev_type == ARPHRD_ETHER) {
1009 /*
1010 * Ethernet - but what sub type?
1011 */
1012
1013 /*
1014 * VLAN?
1015 */
1016 if (is_vlan_dev(dev)) {
1017 /*
1018 * VLAN master
1019 * GGG No locking needed here, ASSUMPTION is that real_dev is held for as long as we have dev.
1020 */
1021 memcpy(type_info.vlan.address, dev->dev_addr, 6);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301022 type_info.vlan.vlan_tag = vlan_dev_vlan_id(dev);
1023 type_info.vlan.vlan_tpid = VLAN_CTAG_TPID;
1024 DEBUG_TRACE("Net device: %p is VLAN, mac: %pM, vlan_id: %x vlan_tpid: %x\n",
1025 dev, type_info.vlan.address, type_info.vlan.vlan_tag, type_info.vlan.vlan_tpid);
Ben Menchaca84f36632014-02-28 20:57:38 +00001026
1027 /*
1028 * Establish this type of interface
1029 */
1030 ii = ecm_interface_vlan_interface_establish(&type_info.vlan, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1031 return ii;
1032 }
1033
1034 /*
1035 * BRIDGE?
1036 */
1037 if (ecm_front_end_is_bridge_device(dev)) {
1038 /*
1039 * Bridge
1040 */
1041 memcpy(type_info.bridge.address, dev->dev_addr, 6);
1042
1043 DEBUG_TRACE("Net device: %p is BRIDGE, mac: %pM\n",
1044 dev, type_info.bridge.address);
1045
1046 /*
1047 * Establish this type of interface
1048 */
1049 ii = ecm_interface_bridge_interface_establish(&type_info.bridge, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1050 return ii;
1051 }
1052
1053 /*
1054 * LAG?
1055 */
1056 if (ecm_front_end_is_lag_master(dev)) {
1057 /*
1058 * Link aggregation
1059 */
1060 memcpy(type_info.lag.address, dev->dev_addr, 6);
1061
1062 DEBUG_TRACE("Net device: %p is LAG, mac: %pM\n",
1063 dev, type_info.lag.address);
1064
1065 /*
1066 * Establish this type of interface
1067 */
1068 ii = ecm_interface_lag_interface_establish(&type_info.lag, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1069 return ii;
1070 }
1071
1072 /*
1073 * ETHERNET!
1074 * Just plain ethernet it seems
1075 */
1076 memcpy(type_info.ethernet.address, dev->dev_addr, 6);
1077 DEBUG_TRACE("Net device: %p is ETHERNET, mac: %pM\n",
1078 dev, type_info.ethernet.address);
1079
1080 /*
1081 * Establish this type of interface
1082 */
1083 ii = ecm_interface_ethernet_interface_establish(&type_info.ethernet, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1084 return ii;
1085 }
1086
1087 /*
1088 * LOOPBACK?
1089 */
1090 if (dev_type == ARPHRD_LOOPBACK) {
1091 DEBUG_TRACE("Net device: %p is LOOPBACK type: %d\n", dev, dev_type);
1092 type_info.loopback.os_specific_ident = dev_interface_num;
1093 ii = ecm_interface_loopback_interface_establish(&type_info.loopback, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1094 return ii;
1095 }
1096
1097 /*
1098 * IPSEC?
1099 */
1100 if (dev_type == ECM_ARPHRD_IPSEC_TUNNEL_TYPE) {
1101 DEBUG_TRACE("Net device: %p is IPSec tunnel type: %d\n", dev, dev_type);
1102 type_info.ipsec_tunnel.os_specific_ident = dev_interface_num;
1103 // GGG TODO Flesh this out with tunnel endpoint addressing detail
1104 ii = ecm_interface_ipsec_tunnel_interface_establish(&type_info.ipsec_tunnel, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1105 return ii;
1106 }
1107
Murat Sezgincc6eedf2014-05-09 23:59:19 -07001108#ifdef CONFIG_IPV6_SIT_6RD
Ben Menchaca84f36632014-02-28 20:57:38 +00001109 /*
1110 * SIT (6-in-4)?
1111 */
1112 if (dev_type == ARPHRD_SIT) {
1113 struct ip_tunnel *tunnel;
1114 struct ip_tunnel_6rd_parm *ip6rd;
1115 const struct iphdr *tiph;
1116
1117 DEBUG_TRACE("Net device: %p is SIT (6-in-4) type: %d\n", dev, dev_type);
1118
1119 tunnel = (struct ip_tunnel*)netdev_priv(dev);
1120 ip6rd = &tunnel->ip6rd;
1121
1122 /*
1123 * Get the Tunnel device IP header info
1124 */
1125 tiph = &tunnel->parms.iph ;
1126
1127 type_info.sit.prefixlen = ip6rd->prefixlen;
1128 type_info.sit.relay_prefix = ip6rd->relay_prefix;
1129 type_info.sit.relay_prefixlen = ip6rd->relay_prefixlen;
1130 ECM_NIN4_ADDR_TO_IP_ADDR(type_info.sit.saddr, tiph->saddr);
1131 ECM_NIN4_ADDR_TO_IP_ADDR(type_info.sit.daddr, tiph->daddr);
1132 type_info.sit.prefix[0] = ntohl(ip6rd->prefix.s6_addr32[0]);
1133 type_info.sit.prefix[1] = ntohl(ip6rd->prefix.s6_addr32[1]);
1134 type_info.sit.prefix[2] = ntohl(ip6rd->prefix.s6_addr32[2]);
1135 type_info.sit.prefix[3] = ntohl(ip6rd->prefix.s6_addr32[3]);
1136 type_info.sit.ttl = tiph->ttl;
1137 type_info.sit.tos = tiph->tos;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301138
Ben Menchaca84f36632014-02-28 20:57:38 +00001139 ii = ecm_interface_sit_interface_establish(&type_info.sit, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1140 return ii;
1141 }
Murat Sezgincc6eedf2014-05-09 23:59:19 -07001142#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001143
1144 /*
1145 * IPIP6 Tunnel?
1146 */
1147 if (dev_type == ARPHRD_TUNNEL6) {
1148 struct ip6_tnl *tunnel;
1149 struct flowi6 *fl6;
1150
1151 DEBUG_TRACE("Net device: %p is TUNIPIP6 type: %d\n", dev, dev_type);
1152
1153 /*
1154 * Get the tunnel device flow information (discover the output path of the tunnel)
1155 */
1156 tunnel = (struct ip6_tnl *)netdev_priv(dev);
1157 fl6 = &tunnel->fl.u.ip6;
1158
1159 ECM_NIN6_ADDR_TO_IP_ADDR(type_info.tunipip6.saddr, fl6->saddr);
1160 ECM_NIN6_ADDR_TO_IP_ADDR(type_info.tunipip6.daddr, fl6->daddr);
1161 type_info.tunipip6.hop_limit = tunnel->parms.hop_limit;
1162 type_info.tunipip6.flags = ntohl(tunnel->parms.flags);
1163 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 +05301164
Ben Menchaca84f36632014-02-28 20:57:38 +00001165 ii = ecm_interface_tunipip6_interface_establish(&type_info.tunipip6, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1166 return ii;
1167 }
1168
1169 /*
1170 * If this is NOT PPP then it is unknown to the ecm
1171 */
1172 if (dev_type != ARPHRD_PPP) {
1173 DEBUG_TRACE("Net device: %p is UNKNOWN type: %d\n", dev, dev_type);
1174 type_info.unknown.os_specific_ident = dev_interface_num;
1175
1176 /*
1177 * Establish this type of interface
1178 */
1179 ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1180 return ii;
1181 }
1182
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001183#ifndef ECM_INTERFACE_PPP_SUPPORT
1184 /*
1185 * PPP support is NOT provided for.
1186 * Interface is therefore unknown
1187 */
1188 DEBUG_TRACE("Net device: %p is UNKNOWN (PPP Unsupported) type: %d\n", dev, dev_type);
1189 type_info.unknown.os_specific_ident = dev_interface_num;
1190
1191 /*
1192 * Establish this type of interface
1193 */
1194 ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1195 return ii;
1196#else
Ben Menchaca84f36632014-02-28 20:57:38 +00001197 /*
1198 * PPP - but what is the channel type?
1199 * First: If this is multi-link then we do not support it
1200 */
1201 if (ppp_is_multilink(dev) > 0) {
1202 DEBUG_TRACE("Net device: %p is MULTILINK PPP - Unknown to the ECM\n", dev);
1203 type_info.unknown.os_specific_ident = dev_interface_num;
1204
1205 /*
1206 * Establish this type of interface
1207 */
1208 ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1209 return ii;
1210 }
1211
1212 DEBUG_TRACE("Net device: %p is PPP\n", dev);
1213
1214 /*
1215 * Get the PPP channel and then enquire what kind of channel it is
1216 * NOTE: Not multilink so only one channel to get.
1217 */
1218 channel_count = ppp_hold_channels(dev, ppp_chan, 1);
1219 if (channel_count != 1) {
Gareth Williams6f96a4b2014-05-29 19:41:21 +01001220 DEBUG_TRACE("Net device: %p PPP has %d channels - ECM cannot handle this (interface becomes Unknown type)\n",
1221 dev, channel_count);
Ben Menchaca84f36632014-02-28 20:57:38 +00001222 type_info.unknown.os_specific_ident = dev_interface_num;
1223
1224 /*
1225 * Establish this type of interface
1226 */
1227 ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1228 return ii;
1229 }
1230
1231 /*
1232 * Get channel protocol type
Gareth Williams6f96a4b2014-05-29 19:41:21 +01001233 * NOTE: Not all PPP channels support channel specific methods.
Ben Menchaca84f36632014-02-28 20:57:38 +00001234 */
Gareth Williams6f96a4b2014-05-29 19:41:21 +01001235 channel_protocol = ppp_channel_get_protocol(ppp_chan[0]);
Ben Menchaca84f36632014-02-28 20:57:38 +00001236 if (channel_protocol != PX_PROTO_OE) {
1237 DEBUG_TRACE("Net device: %p PPP channel protocol: %d - Unknown to the ECM\n", dev, channel_protocol);
1238 type_info.unknown.os_specific_ident = dev_interface_num;
1239
1240 /*
1241 * Release the channel
1242 */
1243 ppp_release_channels(ppp_chan, 1);
1244
1245 /*
1246 * Establish this type of interface
1247 */
1248 ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1249 return ii;
1250 }
1251
1252 /*
1253 * PPPoE channel
1254 */
1255 DEBUG_TRACE("Net device: %p PPP channel is PPPoE\n", dev);
1256
1257 /*
1258 * Get PPPoE session information and the underlying device it is using.
Ben Menchaca84f36632014-02-28 20:57:38 +00001259 */
Gareth Williams6f96a4b2014-05-29 19:41:21 +01001260 pppoe_channel_addressing_get(ppp_chan[0], &addressing);
1261 type_info.pppoe.pppoe_session_id = (uint16_t)ntohs((uint16_t)addressing.pa.sid);
Ben Menchaca84f36632014-02-28 20:57:38 +00001262 memcpy(type_info.pppoe.remote_mac, addressing.pa.remote, ETH_ALEN);
Gareth Williams6f96a4b2014-05-29 19:41:21 +01001263 dev_put(addressing.dev);
Ben Menchaca84f36632014-02-28 20:57:38 +00001264
1265 /*
1266 * Release the channel. Note that next_dev is still (correctly) held.
1267 */
1268 ppp_release_channels(ppp_chan, 1);
1269
1270 DEBUG_TRACE("Net device: %p PPPoE session: %x, remote mac: %pM\n",
1271 dev, type_info.pppoe.pppoe_session_id, type_info.pppoe.remote_mac);
1272
1273 /*
1274 * Establish this type of interface
1275 */
1276 ii = ecm_interface_pppoe_interface_establish(&type_info.pppoe, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1277 return ii;
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001278#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001279}
1280EXPORT_SYMBOL(ecm_interface_establish_and_ref);
1281
1282/*
1283 * ecm_interface_heirarchy_construct()
1284 * Construct an interface heirarchy.
1285 *
1286 * Using the given addressing, locate the interface heirarchy used to emit packets to that destination.
1287 * This is the heirarchy of interfaces a packet would transit to emit from the device.
1288 * For example, with this network arrangement:
1289 *
1290 * PPPoE--VLAN--BRIDGE--BRIDGE_PORT(LAG_MASTER)--LAG_SLAVE_0--10.22.33.11
1291 *
Gareth Williams43fc0852014-05-26 19:10:00 +01001292 * 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 +00001293 * LAG_SLAVE_0 @ [ECM_DB_IFACE_HEIRARCHY_MAX - 5]
1294 * LAG_MASTER @ [ECM_DB_IFACE_HEIRARCHY_MAX - 4]
1295 * BRIDGE @ [ECM_DB_IFACE_HEIRARCHY_MAX - 3]
1296 * VLAN @ [ECM_DB_IFACE_HEIRARCHY_MAX - 2]
1297 * PPPOE @ [ECM_DB_IFACE_HEIRARCHY_MAX - 1]
1298 * The value returned is (ECM_DB_IFACE_HEIRARCHY_MAX - 5)
1299 *
1300 * IMPORTANT: This function will return any known interfaces in the database, when interfaces do not exist in the database
1301 * they will be created and added automatically to the database.
1302 *
1303 * GGG TODO Make this function work for IPv6!!!!!!!!!!!!!!
1304 */
1305int32_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)
1306{
1307 char __attribute__((unused)) src_addr_str[40];
1308 char __attribute__((unused)) dest_addr_str[40];
1309 int protocol;
1310 ip_addr_t src_addr;
1311 ip_addr_t dest_addr;
Ben Menchaca84f36632014-02-28 20:57:38 +00001312 struct net_device *src_dev;
1313 struct net_device *dest_dev;
1314 char *src_dev_name;
1315 char *dest_dev_name;
1316 int32_t src_dev_type;
1317 int32_t dest_dev_type;
1318 int32_t current_interface_index;
1319
1320 /*
1321 * Get a big endian of the IPv4 address we have been given as our starting point.
1322 */
1323 protocol = packet_protocol;
1324 ECM_IP_ADDR_COPY(src_addr, packet_src_addr);
1325 ECM_IP_ADDR_COPY(dest_addr, packet_dest_addr);
1326 ecm_ip_addr_to_string(src_addr_str, src_addr);
1327 ecm_ip_addr_to_string(dest_addr_str, dest_addr);
1328 DEBUG_TRACE("Construct interface heirarchy for from src_addr: %s to dest_addr: %s, protocol: %d\n", src_addr_str, dest_addr_str, protocol);
1329
1330 /*
Gareth Williams43fc0852014-05-26 19:10:00 +01001331 * Get device from the given addresses
1332 * Is the address a local IP?
Ben Menchaca84f36632014-02-28 20:57:38 +00001333 */
Gareth Williams43fc0852014-05-26 19:10:00 +01001334 src_dev = ecm_interface_dev_find_by_addr(src_addr);
1335 if (!src_dev) {
1336 struct ecm_interface_route ecm_rt;
1337 struct dst_entry *dst;
Ben Menchaca84f36632014-02-28 20:57:38 +00001338
Gareth Williams43fc0852014-05-26 19:10:00 +01001339 DEBUG_TRACE("src_addr: %s is not local\n", src_addr_str);
Ben Menchaca84f36632014-02-28 20:57:38 +00001340
Gareth Williams43fc0852014-05-26 19:10:00 +01001341 /*
1342 * Not local.
1343 * Try a route to the address
1344 */
1345 if (!ecm_interface_find_route_by_addr(src_addr, &ecm_rt)) {
1346 DEBUG_WARN("src_addr: %s - no route\n", src_addr_str);
1347 return ECM_DB_IFACE_HEIRARCHY_MAX;
1348 }
1349 dst = ecm_rt.dst;
1350 src_dev = dst->dev;
1351 dev_hold(src_dev);
1352 ecm_interface_route_release(&ecm_rt);
1353 DEBUG_TRACE("src_addr: %s uses dev: %p(%s)\n", src_addr_str, src_dev, src_dev->name);
1354 }
Ben Menchaca84f36632014-02-28 20:57:38 +00001355 src_dev_name = src_dev->name;
1356 src_dev_type = src_dev->type;
1357
Gareth Williams43fc0852014-05-26 19:10:00 +01001358 dest_dev = ecm_interface_dev_find_by_addr(dest_addr);
1359 if (!dest_dev) {
1360 struct ecm_interface_route ecm_rt;
1361 struct dst_entry *dst;
1362
1363 DEBUG_TRACE("dest_addr: %s is not local\n", dest_addr_str);
1364
1365 /*
1366 * Try a route to the address
1367 */
1368 if (!ecm_interface_find_route_by_addr(dest_addr, &ecm_rt)) {
1369 DEBUG_WARN("dest_addr: %s - no route\n", dest_addr_str);
1370 dev_put(src_dev);
1371 return ECM_DB_IFACE_HEIRARCHY_MAX;
1372 }
1373 dst = ecm_rt.dst;
1374 dest_dev = dst->dev;
1375 dev_hold(dest_dev);
1376 ecm_interface_route_release(&ecm_rt);
1377 DEBUG_TRACE("dest_addr: %s uses dev: %p(%s)\n", dest_addr_str, dest_dev, dest_dev->name);
1378 }
Ben Menchaca84f36632014-02-28 20:57:38 +00001379 dest_dev_name = dest_dev->name;
1380 dest_dev_type = dest_dev->type;
1381
1382 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00001383 * Iterate until we are done or get to the max number of interfaces we can record.
1384 * NOTE: current_interface_index tracks the position of the first interface position in interfaces[]
1385 * because we add from the end first_interface grows downwards.
1386 */
1387 current_interface_index = ECM_DB_IFACE_HEIRARCHY_MAX;
1388 while (current_interface_index > 0) {
1389 struct ecm_db_iface_instance *ii;
1390 struct net_device *next_dev;
1391
1392 /*
1393 * Get the ecm db interface instance for the device at hand
1394 */
1395 ii = ecm_interface_establish_and_ref(dest_dev);
1396
1397 /*
1398 * If the interface could not be established then we abort
1399 */
1400 if (!ii) {
1401 DEBUG_WARN("Failed to establish interface: %p, name: %s\n", dest_dev, dest_dev_name);
1402 dev_put(src_dev);
1403 dev_put(dest_dev);
1404
1405 /*
1406 * Release the interfaces heirarchy we constructed to this point.
1407 */
1408 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1409 return ECM_DB_IFACE_HEIRARCHY_MAX;
1410 }
1411
1412 /*
1413 * Record the interface instance into the interfaces[]
1414 */
1415 current_interface_index--;
1416 interfaces[current_interface_index] = ii;
1417
1418 /*
1419 * Now we have to figure out what the next device will be (in the transmission path) the skb
1420 * will use to emit to the destination address.
1421 */
1422 do {
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001423#ifdef ECM_INTERFACE_PPP_SUPPORT
Ben Menchaca84f36632014-02-28 20:57:38 +00001424 int channel_count;
1425 struct ppp_channel *ppp_chan[1];
Ben Menchaca84f36632014-02-28 20:57:38 +00001426 int channel_protocol;
Ben Menchaca84f36632014-02-28 20:57:38 +00001427 struct pppoe_opt addressing;
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001428#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001429
1430 DEBUG_TRACE("Net device: %p is type: %d, name: %s\n", dest_dev, dest_dev_type, dest_dev_name);
1431 next_dev = NULL;
1432
1433 if (dest_dev_type == ARPHRD_ETHER) {
1434 /*
1435 * Ethernet - but what sub type?
1436 */
1437
1438 /*
1439 * VLAN?
1440 */
1441 if (is_vlan_dev(dest_dev)) {
1442 /*
1443 * VLAN master
1444 * No locking needed here, ASSUMPTION is that real_dev is held for as long as we have dev.
1445 */
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301446 next_dev = vlan_dev_real_dev(dest_dev);
Ben Menchaca84f36632014-02-28 20:57:38 +00001447 dev_hold(next_dev);
1448 DEBUG_TRACE("Net device: %p is VLAN, slave dev: %p (%s)\n",
1449 dest_dev, next_dev, next_dev->name);
1450 break;
1451 }
1452
1453 /*
1454 * BRIDGE?
1455 */
1456 if (ecm_front_end_is_bridge_device(dest_dev)) {
1457 /*
1458 * Bridge
1459 * Figure out which port device the skb will go to using the dest_addr.
1460 */
1461 bool on_link;
1462 ip_addr_t gw_addr;
1463 uint8_t mac_addr[ETH_ALEN];
1464 if (!ecm_interface_mac_addr_get(dest_addr, mac_addr, &on_link, gw_addr)) {
1465 /*
1466 * Possible ARP does not know the address yet
1467 */
Gareth Williams9e1d17a2014-05-26 19:40:10 +01001468 DEBUG_INFO("Unable to obtain MAC address for " ECM_IP_ADDR_DOT_FMT "\n", ECM_IP_ADDR_TO_DOT(dest_addr));
1469 if (ECM_IP_ADDR_IS_V4(dest_addr)) {
1470 __be32 ipv4_addr;
1471 __be32 src_ip;
1472
1473 /*
1474 * Issue an ARP request for it, select the src_ip from which to issue the request.
1475 */
1476 ECM_IP_ADDR_TO_NIN4_ADDR(ipv4_addr, dest_addr);
1477 src_ip = inet_select_addr(dest_dev, ipv4_addr, RT_SCOPE_LINK);
1478 if (!src_ip) {
1479 DEBUG_TRACE("failed to lookup IP for %pI4\n", &ipv4_addr);
1480
1481 dev_put(src_dev);
1482 dev_put(dest_dev);
1483
1484 /*
1485 * Release the interfaces heirarchy we constructed to this point.
1486 */
1487 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1488 return ECM_DB_IFACE_HEIRARCHY_MAX;
1489 }
1490
1491 /*
1492 * If we have a GW for this address, then we have to send ARP request to the GW
1493 */
1494 if (!ECM_IP_ADDR_IS_NULL(gw_addr)) {
1495 ECM_IP_ADDR_COPY(dest_addr, gw_addr);
1496 }
1497
1498 DEBUG_TRACE("Send ARP for %pI4 using src_ip as %pI4\n", &ipv4_addr, &src_ip);
1499 arp_send(ARPOP_REQUEST, ETH_P_ARP, ipv4_addr, dest_dev, src_ip, NULL, NULL, NULL);
1500 }
1501
Ben Menchaca84f36632014-02-28 20:57:38 +00001502 dev_put(src_dev);
1503 dev_put(dest_dev);
1504
1505 /*
1506 * Release the interfaces heirarchy we constructed to this point.
1507 */
1508 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1509 return ECM_DB_IFACE_HEIRARCHY_MAX;
1510 }
1511 next_dev = br_port_dev_get(dest_dev, mac_addr);
1512 if (!next_dev) {
1513 DEBUG_WARN("Unable to obtain output port for: %pM\n", mac_addr);
1514 dev_put(src_dev);
1515 dev_put(dest_dev);
1516
1517 /*
1518 * Release the interfaces heirarchy we constructed to this point.
1519 */
1520 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1521 return ECM_DB_IFACE_HEIRARCHY_MAX;
1522 }
1523 DEBUG_TRACE("Net device: %p is BRIDGE, next_dev: %p (%s)\n", dest_dev, next_dev, next_dev->name);
1524 break;
1525 }
1526
1527 /*
1528 * LAG?
1529 */
1530 if (ecm_front_end_is_lag_master(dest_dev)) {
1531 /*
1532 * Link aggregation
1533 * Figure out which slave device of the link aggregation will be used to reach the destination.
1534 */
1535 bool src_on_link;
1536 bool dest_on_link;
1537 ip_addr_t src_gw_addr;
1538 ip_addr_t dest_gw_addr;
1539 uint32_t src_addr_32;
1540 uint32_t dest_addr_32;
1541 uint8_t src_mac_addr[ETH_ALEN];
1542 uint8_t dest_mac_addr[ETH_ALEN];
1543
1544 if (!ecm_interface_mac_addr_get(src_addr, src_mac_addr, &src_on_link, src_gw_addr)) {
1545 /*
1546 * Possible ARP does not know the address yet
1547 */
1548 DEBUG_WARN("Unable to obtain MAC address for " ECM_IP_ADDR_DOT_FMT "\n", ECM_IP_ADDR_TO_DOT(src_addr));
1549 dev_put(src_dev);
1550 dev_put(dest_dev);
1551
1552 /*
1553 * Release the interfaces heirarchy we constructed to this point.
1554 */
1555 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1556 return ECM_DB_IFACE_HEIRARCHY_MAX;
1557 }
1558 if (!ecm_interface_mac_addr_get(dest_addr, dest_mac_addr, &dest_on_link, dest_gw_addr)) {
1559 /*
1560 * Possible ARP does not know the address yet
1561 */
1562 DEBUG_WARN("Unable to obtain MAC address for " ECM_IP_ADDR_DOT_FMT "\n", ECM_IP_ADDR_TO_DOT(dest_addr));
1563 dev_put(src_dev);
1564 dev_put(dest_dev);
1565
1566 /*
1567 * Release the interfaces heirarchy we constructed to this point.
1568 */
1569 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1570 return ECM_DB_IFACE_HEIRARCHY_MAX;
1571 }
1572
1573 ECM_IP_ADDR_TO_HIN4_ADDR(src_addr_32, src_addr);
1574 ECM_IP_ADDR_TO_HIN4_ADDR(dest_addr_32, dest_addr);
1575
1576 next_dev = bond_get_tx_dev(NULL, src_mac_addr, dest_mac_addr, &src_addr_32, &dest_addr_32, (uint16_t)protocol, dest_dev);
1577 if (next_dev) {
1578 dev_hold(next_dev);
1579 } else {
1580 DEBUG_WARN("Unable to obtain LAG output slave device\n");
1581 dev_put(src_dev);
1582 dev_put(dest_dev);
1583
1584 /*
1585 * Release the interfaces heirarchy we constructed to this point.
1586 */
1587 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1588 return ECM_DB_IFACE_HEIRARCHY_MAX;
1589 }
1590
1591 DEBUG_TRACE("Net device: %p is LAG, slave dev: %p (%s)\n", dest_dev, next_dev, next_dev->name);
1592
1593 break;
1594 }
1595
1596 /*
1597 * ETHERNET!
1598 * Just plain ethernet it seems.
1599 */
1600 DEBUG_TRACE("Net device: %p is ETHERNET\n", dest_dev);
1601 break;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301602 }
Ben Menchaca84f36632014-02-28 20:57:38 +00001603
1604 /*
1605 * LOOPBACK?
1606 */
1607 if (dest_dev_type == ARPHRD_LOOPBACK) {
1608 DEBUG_TRACE("Net device: %p is LOOPBACK type: %d\n", dest_dev, dest_dev_type);
1609 break;
1610 }
1611
1612 /*
1613 * IPSEC?
1614 */
1615 if (dest_dev_type == ECM_ARPHRD_IPSEC_TUNNEL_TYPE) {
1616 DEBUG_TRACE("Net device: %p is IPSec tunnel type: %d\n", dest_dev, dest_dev_type);
1617 // GGG TODO Figure out the next device the tunnel is using...
1618 break;
1619 }
1620
1621 /*
1622 * SIT (6-in-4)?
1623 */
1624 if (dest_dev_type == ARPHRD_SIT) {
1625 DEBUG_TRACE("Net device: %p is SIT (6-in-4) type: %d\n", dest_dev, dest_dev_type);
1626 break;
1627 }
1628
1629 /*
1630 * IPIP6 Tunnel?
1631 */
1632 if (dest_dev_type == ARPHRD_TUNNEL6) {
1633 DEBUG_TRACE("Net device: %p is TUNIPIP6 type: %d\n", dest_dev, dest_dev_type);
1634 break;
1635 }
1636
1637 /*
1638 * If this is NOT PPP then it is unknown to the ecm and we cannot figure out it's next device.
1639 */
1640 if (dest_dev_type != ARPHRD_PPP) {
1641 DEBUG_TRACE("Net device: %p is UNKNOWN type: %d\n", dest_dev, dest_dev_type);
1642 break;
1643 }
1644
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001645#ifndef ECM_INTERFACE_PPP_SUPPORT
1646 DEBUG_TRACE("Net device: %p is UNKNOWN (PPP Unsupported) type: %d\n", dest_dev, dest_dev_type);
1647#else
Ben Menchaca84f36632014-02-28 20:57:38 +00001648 /*
1649 * PPP - but what is the channel type?
1650 * First: If this is multi-link then we do not support it
1651 */
1652 if (ppp_is_multilink(dest_dev) > 0) {
1653 DEBUG_TRACE("Net device: %p is MULTILINK PPP - Unknown to the ECM\n", dest_dev);
1654 break;
1655 }
1656
1657 DEBUG_TRACE("Net device: %p is PPP\n", dest_dev);
1658
1659 /*
1660 * Get the PPP channel and then enquire what kind of channel it is
1661 * NOTE: Not multilink so only one channel to get.
1662 */
1663 channel_count = ppp_hold_channels(dest_dev, ppp_chan, 1);
1664 if (channel_count != 1) {
1665 DEBUG_TRACE("Net device: %p PPP has %d channels - Unknown to the ECM\n",
1666 dest_dev, channel_count);
1667 break;
1668 }
1669
1670 /*
1671 * Get channel protocol type
Gareth Williams6f96a4b2014-05-29 19:41:21 +01001672 * NOTE: Not all PPP channels support channel specific methods.
Ben Menchaca84f36632014-02-28 20:57:38 +00001673 */
Gareth Williams6f96a4b2014-05-29 19:41:21 +01001674 channel_protocol = ppp_channel_get_protocol(ppp_chan[0]);
Ben Menchaca84f36632014-02-28 20:57:38 +00001675 if (channel_protocol != PX_PROTO_OE) {
1676 DEBUG_TRACE("Net device: %p PPP channel protocol: %d - Unknown to the ECM\n",
1677 dest_dev, channel_protocol);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301678
Ben Menchaca84f36632014-02-28 20:57:38 +00001679 /*
1680 * Release the channel
1681 */
1682 ppp_release_channels(ppp_chan, 1);
1683
1684 break;
1685 }
1686
1687 /*
1688 * PPPoE channel
1689 */
1690 DEBUG_TRACE("Net device: %p PPP channel is PPPoE\n", dest_dev);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301691
Ben Menchaca84f36632014-02-28 20:57:38 +00001692 /*
1693 * Get PPPoE session information and the underlying device it is using.
Ben Menchaca84f36632014-02-28 20:57:38 +00001694 */
Gareth Williams6f96a4b2014-05-29 19:41:21 +01001695 pppoe_channel_addressing_get(ppp_chan[0], &addressing);
Ben Menchaca84f36632014-02-28 20:57:38 +00001696
1697 /*
1698 * Copy the dev hold into this, we will release the hold later
1699 */
1700 next_dev = addressing.dev;
1701
1702 DEBUG_TRACE("Net device: %p, next device: %p (%s)\n", dest_dev, next_dev, next_dev->name);
1703
1704 /*
1705 * Release the channel. Note that next_dev is still (correctly) held.
1706 */
1707 ppp_release_channels(ppp_chan, 1);
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001708#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001709 } while (false);
1710
1711 /*
Gareth Williamsa11d4352014-05-14 18:25:49 +01001712 * No longer need dest_dev as it may become next_dev
Ben Menchaca84f36632014-02-28 20:57:38 +00001713 */
Ben Menchaca84f36632014-02-28 20:57:38 +00001714 dev_put(dest_dev);
1715
1716 /*
1717 * Check out the next_dev, if any
1718 */
1719 if (!next_dev) {
1720 int32_t i __attribute__((unused));
1721 DEBUG_INFO("Completed interface heirarchy construct with first interface @: %d\n", current_interface_index);
1722#if DEBUG_LEVEL > 1
1723 for (i = current_interface_index; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
1724 DEBUG_TRACE("\tInterface @ %d: %p, type: %d, name: %s\n",
1725 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])));
1726 }
1727#endif
Gareth Williamsa11d4352014-05-14 18:25:49 +01001728
1729 /*
1730 * Release src_dev now
1731 */
1732 dev_put(src_dev);
1733
Ben Menchaca84f36632014-02-28 20:57:38 +00001734 return current_interface_index;
1735 }
1736
Gareth Williamsa11d4352014-05-14 18:25:49 +01001737 /*
1738 * dest_dev becomes next_dev
1739 */
Ben Menchaca84f36632014-02-28 20:57:38 +00001740 dest_dev = next_dev;
1741 dest_dev_name = dest_dev->name;
1742 dest_dev_type = dest_dev->type;
1743 }
1744
1745 DEBUG_WARN("Too many interfaces: %d\n", current_interface_index);
1746 DEBUG_ASSERT(current_interface_index == 0, "Bad logic handling current_interface_index: %d\n", current_interface_index);
1747 dev_put(src_dev);
1748 dev_put(dest_dev);
1749
1750 /*
1751 * Release the interfaces heirarchy we constructed to this point.
1752 */
1753 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1754 return ECM_DB_IFACE_HEIRARCHY_MAX;
1755}
1756EXPORT_SYMBOL(ecm_interface_heirarchy_construct);
1757
1758/*
Gareth Williamsadf425f2014-05-26 19:29:02 +01001759 * ecm_interface_list_stats_update()
1760 * Given an interface list, walk the interfaces and update the stats for certain types.
1761 */
1762static void ecm_interface_list_stats_update(int iface_list_first, struct ecm_db_iface_instance *iface_list[], uint8_t *mac_addr,
1763 uint32_t tx_packets, uint32_t tx_bytes, uint32_t rx_packets, uint32_t rx_bytes)
1764{
1765 int list_index;
1766
1767 for (list_index = iface_list_first; (list_index < ECM_DB_IFACE_HEIRARCHY_MAX); list_index++) {
1768 struct ecm_db_iface_instance *ii;
1769 ecm_db_iface_type_t ii_type;
1770 char *ii_name;
1771 struct net_device *dev;
1772
1773 ii = iface_list[list_index];
1774 ii_type = ecm_db_connection_iface_type_get(ii);
1775 ii_name = ecm_db_interface_type_to_string(ii_type);
1776 DEBUG_TRACE("list_index: %d, ii: %p, type: %d (%s)\n", list_index, ii, ii_type, ii_name);
1777
1778 /*
1779 * Locate real device in system
1780 */
1781 dev = dev_get_by_index(&init_net, ecm_db_iface_interface_identifier_get(ii));
1782 if (!dev) {
1783 DEBUG_WARN("Could not locate interface\n");
1784 continue;
1785 }
1786 DEBUG_TRACE("found dev: %p (%s)\n", dev, dev->name);
1787
1788 switch (ii_type) {
1789 struct rtnl_link_stats64 stats;
1790
1791 case ECM_DB_IFACE_TYPE_VLAN:
1792 DEBUG_INFO("%VLAN\n");
1793 stats.rx_packets = rx_packets;
1794 stats.rx_bytes = rx_bytes;
1795 stats.tx_packets = tx_packets;
1796 stats.tx_bytes = tx_bytes;
1797 __vlan_dev_update_accel_stats(dev, &stats);
1798 break;
1799 case ECM_DB_IFACE_TYPE_BRIDGE:
1800 DEBUG_INFO("BRIDGE\n");
1801 stats.rx_packets = rx_packets;
1802 stats.rx_bytes = rx_bytes;
1803 stats.tx_packets = tx_packets;
1804 stats.tx_bytes = tx_bytes;
1805 br_dev_update_stats(dev, &stats);
1806
1807 /*
1808 * Refresh the bridge forward table entry
1809 */
1810 DEBUG_TRACE("Update bridge fdb entry for mac: %pM\n", mac_addr);
1811 br_refresh_fdb_entry(dev, mac_addr);
1812 break;
1813
1814 default:
1815 /*
1816 * TODO: Extend it accordingly
1817 */
1818 break;
1819 }
1820
1821 dev_put(dev);
1822 }
1823}
1824
1825/*
1826 * ecm_interface_stats_update()
1827 * Using the interface lists for the given connection, update the interface statistics for each.
1828 *
1829 * 'from' here is wrt the connection 'from' side. Likewise with 'to'.
1830 * TX is wrt what the interface has transmitted. RX is what the interface has received.
1831 */
1832void ecm_interface_stats_update(struct ecm_db_connection_instance *ci,
1833 uint32_t from_tx_packets, uint32_t from_tx_bytes, uint32_t from_rx_packets, uint32_t from_rx_bytes,
1834 uint32_t to_tx_packets, uint32_t to_tx_bytes, uint32_t to_rx_packets, uint32_t to_rx_bytes)
1835{
1836 struct ecm_db_iface_instance *from_ifaces[ECM_DB_IFACE_HEIRARCHY_MAX];
1837 struct ecm_db_iface_instance *to_ifaces[ECM_DB_IFACE_HEIRARCHY_MAX];
1838 int from_ifaces_first;
1839 int to_ifaces_first;
1840 uint8_t mac_addr[ETH_ALEN];
1841
1842 /*
1843 * Iterate the 'from' side interfaces and update statistics and state for the real HLOS interfaces
1844 * from_tx_packets / bytes: the amount transmitted by the 'from' interface
1845 * from_rx_packets / bytes: the amount received by the 'from' interface
1846 */
1847 DEBUG_INFO("%p: Update from interface stats\n", ci);
1848 from_ifaces_first = ecm_db_connection_from_interfaces_get_and_ref(ci, from_ifaces);
1849 ecm_db_connection_from_node_address_get(ci, mac_addr);
1850 ecm_interface_list_stats_update(from_ifaces_first, from_ifaces, mac_addr, from_tx_packets, from_tx_bytes, from_rx_packets, from_rx_bytes);
1851 ecm_db_connection_interfaces_deref(from_ifaces, from_ifaces_first);
1852
1853 /*
1854 * Iterate the 'to' side interfaces and update statistics and state for the real HLOS interfaces
1855 * to_tx_packets / bytes: the amount transmitted by the 'to' interface
1856 * to_rx_packets / bytes: the amount received by the 'to' interface
1857 */
1858 DEBUG_INFO("%p: Update to interface stats\n", ci);
1859 to_ifaces_first = ecm_db_connection_to_interfaces_get_and_ref(ci, to_ifaces);
1860 ecm_db_connection_to_node_address_get(ci, mac_addr);
1861 ecm_interface_list_stats_update(to_ifaces_first, to_ifaces, mac_addr, to_tx_packets, to_tx_bytes, to_rx_packets, to_rx_bytes);
1862 ecm_db_connection_interfaces_deref(to_ifaces, to_ifaces_first);
1863}
1864EXPORT_SYMBOL(ecm_interface_stats_update);
1865
1866/*
Ben Menchaca84f36632014-02-28 20:57:38 +00001867 * ecm_interface_regenerate_connections()
1868 * Cause regeneration of all connections that are using the specified interface.
1869 */
1870static void ecm_interface_regenerate_connections(struct ecm_db_iface_instance *ii)
1871{
1872 struct ecm_db_connection_instance *ci;
1873
1874 DEBUG_TRACE("Regenerate connections using interface: %p\n", ii);
1875
1876 /*
1877 * Iterate the connections of this interface and cause each one to be re-generated.
1878 * GGG TODO NOTE: If this proves slow (need metrics here) we could just regenerate the "lot" with one very simple call.
1879 * 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
1880 * but at the cost of performance.
1881 */
1882 DEBUG_TRACE("%p: Regenerate 'from' connections\n", ii);
1883 ci = ecm_db_iface_connections_from_get_and_ref_first(ii);
1884 while (ci) {
1885 struct ecm_db_connection_instance *cin;
1886 cin = ecm_db_connection_iface_from_get_and_ref_next(ci);
1887
1888 DEBUG_TRACE("%p: Regenerate: %p", ii, ci);
1889 ecm_db_connection_classifier_generation_change(ci);
1890 ecm_db_connection_deref(ci);
1891 ci = cin;
1892 }
1893
1894 DEBUG_TRACE("%p: Regenerate 'to' connections\n", ii);
1895 ci = ecm_db_iface_connections_to_get_and_ref_first(ii);
1896 while (ci) {
1897 struct ecm_db_connection_instance *cin;
1898 cin = ecm_db_connection_iface_to_get_and_ref_next(ci);
1899
1900 DEBUG_TRACE("%p: Regenerate: %p", ii, ci);
1901 ecm_db_connection_classifier_generation_change(ci);
1902 ecm_db_connection_deref(ci);
1903 ci = cin;
1904 }
1905
1906 DEBUG_TRACE("%p: Regenerate 'from_nat' connections\n", ii);
1907 ci = ecm_db_iface_connections_nat_from_get_and_ref_first(ii);
1908 while (ci) {
1909 struct ecm_db_connection_instance *cin;
1910 cin = ecm_db_connection_iface_nat_from_get_and_ref_next(ci);
1911
1912 DEBUG_TRACE("%p: Regenerate: %p", ii, ci);
1913 ecm_db_connection_classifier_generation_change(ci);
1914 ecm_db_connection_deref(ci);
1915 ci = cin;
1916 }
1917
1918 DEBUG_TRACE("%p: Regenerate 'to_nat' connections\n", ii);
1919 ci = ecm_db_iface_connections_nat_to_get_and_ref_first(ii);
1920 while (ci) {
1921 struct ecm_db_connection_instance *cin;
1922 cin = ecm_db_connection_iface_nat_to_get_and_ref_next(ci);
1923
1924 DEBUG_TRACE("%p: Regenerate: %p", ii, ci);
1925 ecm_db_connection_classifier_generation_change(ci);
1926 ecm_db_connection_deref(ci);
1927 ci = cin;
1928 }
1929
1930 DEBUG_TRACE("%p: Regenerate COMPLETE\n", ii);
1931}
1932
1933/*
1934 * ecm_interface_dev_regenerate_connections()
1935 * Cause regeneration of all connections that are using the specified interface.
1936 */
1937static void ecm_interface_dev_regenerate_connections(struct net_device *dev)
1938{
1939 struct ecm_db_iface_instance *ii;
1940
1941 DEBUG_INFO("Regenerate connections for: %p (%s)\n", dev, dev->name);
1942
1943 /*
1944 * Establish the interface for the given device.
1945 * NOTE: The cute thing here is even if dev is previously unknown to us this will create an interface instance
1946 * 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.
1947 * However if the interface is known to us then we will get it returned by this function and process it accordingly.
1948 */
1949 ii = ecm_interface_establish_and_ref(dev);
1950 if (!ii) {
1951 DEBUG_WARN("%p: No interface instance could be established for this dev\n", dev);
1952 return;
1953 }
1954 ecm_interface_regenerate_connections(ii);
1955 DEBUG_TRACE("%p: Regenerate for %p: COMPLETE\n", dev, ii);
1956 ecm_db_iface_deref(ii);
1957}
1958
1959/*
1960 * ecm_interface_mtu_change()
1961 * MTU of interface has changed
1962 */
1963static void ecm_interface_mtu_change(struct net_device *dev)
1964{
1965 int mtu;
1966 struct ecm_db_iface_instance *ii;
1967
1968 mtu = dev->mtu;
1969 DEBUG_INFO("%p (%s): MTU Change to: %d\n", dev, dev->name, mtu);
1970
1971 /*
1972 * Establish the interface for the given device.
1973 */
1974 ii = ecm_interface_establish_and_ref(dev);
1975 if (!ii) {
1976 DEBUG_WARN("%p: No interface instance could be established for this dev\n", dev);
1977 return;
1978 }
1979
1980 /*
1981 * Change the mtu
1982 */
1983 ecm_db_iface_mtu_reset(ii, mtu);
1984 DEBUG_TRACE("%p (%s): MTU Changed to: %d\n", dev, dev->name, mtu);
1985 ecm_interface_regenerate_connections(ii);
1986 DEBUG_TRACE("%p: Regenerate for %p: COMPLETE\n", dev, ii);
1987 ecm_db_iface_deref(ii);
1988}
1989
1990/*
1991 * ecm_interface_netdev_notifier_callback()
1992 * Netdevice notifier callback to inform us of change of state of a netdevice
1993 */
1994static int ecm_interface_netdev_notifier_callback(struct notifier_block *this, unsigned long event, void *ptr)
1995{
1996 struct net_device *dev __attribute__ ((unused)) = (struct net_device *)ptr;
1997
1998 DEBUG_INFO("Net device notifier for: %p, name: %s, event: %lx\n", dev, dev->name, event);
1999
2000 switch (event) {
2001 case NETDEV_DOWN:
2002 DEBUG_INFO("Net device: %p, DOWN\n", dev);
2003 ecm_interface_dev_regenerate_connections(dev);
2004 break;
2005
2006 case NETDEV_CHANGE:
2007 DEBUG_INFO("Net device: %p, CHANGE\n", dev);
2008 if (!netif_carrier_ok(dev)) {
2009 DEBUG_INFO("Net device: %p, CARRIER BAD\n", dev);
2010 ecm_interface_dev_regenerate_connections(dev);
2011 }
2012 break;
2013
2014 case NETDEV_CHANGEMTU:
2015 DEBUG_INFO("Net device: %p, MTU CHANGE\n", dev);
2016 ecm_interface_mtu_change(dev);
2017 break;
2018
2019 default:
2020 DEBUG_TRACE("Net device: %p, UNHANDLED: %lx\n", dev, event);
2021 break;
2022 }
2023
2024 return NOTIFY_DONE;
2025}
2026
2027/*
2028 * struct notifier_block ecm_interface_netdev_notifier
2029 * Registration for net device changes of state.
2030 */
2031static struct notifier_block ecm_interface_netdev_notifier __read_mostly = {
2032 .notifier_call = ecm_interface_netdev_notifier_callback,
2033};
2034
2035/*
Ben Menchaca84f36632014-02-28 20:57:38 +00002036 * ecm_interface_get_stop()
2037 */
2038static ssize_t ecm_interface_get_stop(struct sys_device *dev,
2039 struct sysdev_attribute *attr,
2040 char *buf)
2041{
2042 ssize_t count;
2043 int num;
2044
2045 /*
2046 * Operate under our locks
2047 */
2048 spin_lock_bh(&ecm_interface_lock);
2049 num = ecm_interface_stopped;
2050 spin_unlock_bh(&ecm_interface_lock);
2051
2052 count = snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", num);
2053 return count;
2054}
2055
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002056void ecm_interface_stop(int num)
2057{
2058 /*
2059 * Operate under our locks and stop further processing of packets
2060 */
2061 spin_lock_bh(&ecm_interface_lock);
2062 ecm_interface_stopped = num;
2063 spin_unlock_bh(&ecm_interface_lock);
2064
2065}
2066EXPORT_SYMBOL(ecm_interface_stop);
2067
2068
Ben Menchaca84f36632014-02-28 20:57:38 +00002069/*
2070 * ecm_interface_set_stop()
2071 */
2072static ssize_t ecm_interface_set_stop(struct sys_device *dev,
2073 struct sysdev_attribute *attr,
2074 const char *buf, size_t count)
2075{
2076 char num_buf[12];
2077 int num;
2078
2079 /*
2080 * Get the number from buf into a properly z-termed number buffer
2081 */
2082 if (count > 11) {
2083 return 0;
2084 }
2085 memcpy(num_buf, buf, count);
2086 num_buf[count] = '\0';
2087 sscanf(num_buf, "%d", &num);
2088 DEBUG_TRACE("ecm_interface_stop = %d\n", num);
2089
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002090 ecm_interface_stop(num);
Ben Menchaca84f36632014-02-28 20:57:38 +00002091
2092 return count;
2093}
2094
2095/*
2096 * SysFS attributes for the default classifier itself.
2097 */
Ben Menchaca84f36632014-02-28 20:57:38 +00002098static SYSDEV_ATTR(stop, 0644, ecm_interface_get_stop, ecm_interface_set_stop);
2099
2100/*
2101 * SysFS class of the ubicom default classifier
2102 * SysFS control points can be found at /sys/devices/system/ecm_front_end/ecm_front_endX/
2103 */
2104static struct sysdev_class ecm_interface_sysclass = {
2105 .name = "ecm_interface",
2106};
2107
2108/*
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002109 * ecm_interface_init()
Ben Menchaca84f36632014-02-28 20:57:38 +00002110 */
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002111int ecm_interface_init(void)
Ben Menchaca84f36632014-02-28 20:57:38 +00002112{
2113 int result;
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002114 DEBUG_INFO("ECM Interface init\n");
Ben Menchaca84f36632014-02-28 20:57:38 +00002115
2116 /*
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002117 * Initialise our global lock
Ben Menchaca84f36632014-02-28 20:57:38 +00002118 */
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002119 spin_lock_init(&ecm_interface_lock);
Ben Menchaca84f36632014-02-28 20:57:38 +00002120
2121 /*
2122 * Register the sysfs class
2123 */
2124 result = sysdev_class_register(&ecm_interface_sysclass);
2125 if (result) {
2126 DEBUG_ERROR("Failed to register SysFS class %d\n", result);
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002127 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00002128 }
2129
2130 /*
2131 * Register SYSFS device control
2132 */
2133 memset(&ecm_interface_sys_dev, 0, sizeof(ecm_interface_sys_dev));
2134 ecm_interface_sys_dev.id = 0;
2135 ecm_interface_sys_dev.cls = &ecm_interface_sysclass;
2136 result = sysdev_register(&ecm_interface_sys_dev);
2137 if (result) {
2138 DEBUG_ERROR("Failed to register SysFS device %d\n", result);
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002139 goto task_cleanup_1;
Ben Menchaca84f36632014-02-28 20:57:38 +00002140 }
2141
2142 /*
2143 * Create files, one for each parameter supported by this module
2144 */
Ben Menchaca84f36632014-02-28 20:57:38 +00002145 result = sysdev_create_file(&ecm_interface_sys_dev, &attr_stop);
2146 if (result) {
2147 DEBUG_ERROR("Failed to register stop file %d\n", result);
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002148 goto task_cleanup_2;
Ben Menchaca84f36632014-02-28 20:57:38 +00002149 }
2150
2151 result = register_netdevice_notifier(&ecm_interface_netdev_notifier);
2152 if (result != 0) {
2153 DEBUG_ERROR("Failed to register netdevice notifier %d\n", result);
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002154 goto task_cleanup_2;
Ben Menchaca84f36632014-02-28 20:57:38 +00002155 }
2156
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002157 return 0;
Ben Menchaca84f36632014-02-28 20:57:38 +00002158
Ben Menchaca84f36632014-02-28 20:57:38 +00002159task_cleanup_2:
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002160 sysdev_unregister(&ecm_interface_sys_dev);
Ben Menchaca84f36632014-02-28 20:57:38 +00002161task_cleanup_1:
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002162 sysdev_class_unregister(&ecm_interface_sysclass);
Ben Menchaca84f36632014-02-28 20:57:38 +00002163
Ben Menchaca84f36632014-02-28 20:57:38 +00002164 return result;
2165}
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002166EXPORT_SYMBOL(ecm_interface_init);
Ben Menchaca84f36632014-02-28 20:57:38 +00002167
2168/*
2169 * ecm_interface_exit()
2170 */
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002171void ecm_interface_exit(void)
Ben Menchaca84f36632014-02-28 20:57:38 +00002172{
2173 DEBUG_INFO("ECM Interface exit\n");
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002174
2175 spin_lock_bh(&ecm_interface_lock);
2176 ecm_interface_terminate_pending = true;
2177 spin_unlock_bh(&ecm_interface_lock);
2178
2179 unregister_netdevice_notifier(&ecm_interface_netdev_notifier);
2180 sysdev_unregister(&ecm_interface_sys_dev);
2181 sysdev_class_unregister(&ecm_interface_sysclass);
Ben Menchaca84f36632014-02-28 20:57:38 +00002182}
Nicolas Costaf46c33b2014-05-15 10:02:00 -05002183EXPORT_SYMBOL(ecm_interface_exit);