blob: 5230902aeed580695cbfc6333cb6da5156b08e9a [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>
47#include <linux/if_arp.h>
48#include <linux/netfilter_ipv4.h>
49#include <linux/netfilter_bridge.h>
50#include <linux/if_bridge.h>
51#include <net/arp.h>
52#include <net/netfilter/nf_conntrack.h>
53#include <net/netfilter/nf_conntrack_acct.h>
54#include <net/netfilter/nf_conntrack_helper.h>
55#include <net/netfilter/nf_conntrack_l4proto.h>
56#include <net/netfilter/nf_conntrack_l3proto.h>
57#include <net/netfilter/nf_conntrack_zones.h>
58#include <net/netfilter/nf_conntrack_core.h>
59#include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
60#include <net/netfilter/ipv4/nf_defrag_ipv4.h>
61#include <linux/../../net/8021q/vlan.h>
62#include <linux/if_vlan.h>
63
64/*
65 * Debug output levels
66 * 0 = OFF
67 * 1 = ASSERTS / ERRORS
68 * 2 = 1 + WARN
69 * 3 = 2 + INFO
70 * 4 = 3 + TRACE
71 */
72#define DEBUG_LEVEL ECM_INTERFACE_DEBUG_LEVEL
73
74#include <nss_api_if.h>
75
76#include "ecm_types.h"
77#include "ecm_db_types.h"
78#include "ecm_tracker.h"
79#include "ecm_classifier.h"
80#include "ecm_front_end_types.h"
81#include "ecm_tracker_datagram.h"
82#include "ecm_tracker_udp.h"
83#include "ecm_tracker_tcp.h"
84#include "ecm_db.h"
85#include "ecm_interface.h"
86
87/*
88 * Locking - concurrency control
89 */
90static spinlock_t ecm_interface_lock; /* Protect against SMP access between netfilter, events and private threaded function. */
91
92/*
93 * SysFS linkage
94 */
95static struct sys_device ecm_interface_sys_dev; /* SysFS linkage */
96
97/*
98 * General operational control
99 */
100static int ecm_interface_stopped = 0; /* When non-zero further traffic will not be processed */
101
102/*
103 * Management thread control
104 */
105static bool ecm_interface_terminate_pending = false; /* True when the user has signalled we should quit */
106static int ecm_interface_thread_refs = 0; /* >0 when the thread must stay active */
107static struct task_struct *ecm_interface_thread = NULL; /* Control thread */
108
109/*
110 * ecm_interface_mac_addr_get_ipv6()
111 * Return mac for an IPv6 address
112 *
113 * GGG TODO Need to make sure this also works for local IP addresses too.
114 */
115static bool ecm_interface_mac_addr_get_ipv6(ip_addr_t addr, uint8_t *mac_addr, bool *on_link, ip_addr_t gw_addr)
116{
117 struct in6_addr daddr;
118 struct ecm_interface_route ecm_rt;
119 struct neighbour *neigh;
120 struct rt6_info *rt;
121 struct dst_entry *dst;
122
123 /*
124 * Get the MAC address that corresponds to IP address given.
125 * We look up the rt6_info entries and, from its neighbour structure, obtain the hardware address.
126 * This means we will also work if the neighbours are routers too.
127 */
128 ECM_IP_ADDR_TO_NIN6_ADDR(daddr, addr);
129 if (!ecm_interface_find_route_by_addr(addr, &ecm_rt)) {
130 return false;
131 }
132 DEBUG_ASSERT(!ecm_rt.v4_route, "Did not locate a v6 route!\n");
133
134 /*
135 * Is this destination on link or off-link via a gateway?
136 */
137 rt = ecm_rt.rt.rtv6;
138 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)) {
139 *on_link = false;
140 ECM_NIN6_ADDR_TO_IP_ADDR(gw_addr, rt->rt6i_gateway)
141 } else {
142 *on_link = true;
143 }
144
145 rcu_read_lock();
146 dst = ecm_rt.dst;
147 neigh = dst_get_neighbour_noref(dst);
148 if (!neigh) {
149 rcu_read_unlock();
150 ecm_interface_route_release(&ecm_rt);
151 return false;
152 }
153 if (!(neigh->nud_state & NUD_VALID)) {
154 rcu_read_unlock();
155 ecm_interface_route_release(&ecm_rt);
156 return false;
157 }
158 if (!neigh->dev) {
159 rcu_read_unlock();
160 ecm_interface_route_release(&ecm_rt);
161 return false;
162 }
163
164 /*
165 * If neigh->dev is a loopback then addr is a local address in which case we take the MAC from given device
166 */
167 if (neigh->dev->flags & IFF_LOOPBACK) {
168 // GGG TODO Create an equivalent logic to that for ipv4, maybe need to create an ip6_dev_find()?
169 DEBUG_TRACE("local address " ECM_IP_ADDR_OCTAL_FMT " (found loopback)\n", ECM_IP_ADDR_TO_OCTAL(addr));
170 memset(mac_addr, 0, 6);
171 } else {
172 memcpy(mac_addr, neigh->ha, 6);
173 }
174 rcu_read_unlock();
175 ecm_interface_route_release(&ecm_rt);
176
177 DEBUG_TRACE(ECM_IP_ADDR_OCTAL_FMT " maps to %pM\n", ECM_IP_ADDR_TO_OCTAL(addr), mac_addr);
178 return true;
179}
180
181/*
182 * ecm_interface_mac_addr_get_ipv4()
183 * Return mac for an IPv4 address
184 */
185static bool ecm_interface_mac_addr_get_ipv4(ip_addr_t addr, uint8_t *mac_addr, bool *on_link, ip_addr_t gw_addr)
186{
187 struct neighbour *neigh;
188 struct ecm_interface_route ecm_rt;
189 struct rtable *rt;
190 struct dst_entry *dst;
191 __be32 ipv4_addr;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530192
Ben Menchaca84f36632014-02-28 20:57:38 +0000193 /*
194 * Get the MAC address that corresponds to IP address given.
195 * We look up the rtable entries and, from its neighbour structure, obtain the hardware address.
196 * This means we will also work if the neighbours are routers too.
197 * We also locate the MAC if the address is a local host address.
198 */
199 ECM_IP_ADDR_TO_NIN4_ADDR(ipv4_addr, addr);
200 if (!ecm_interface_find_route_by_addr(addr, &ecm_rt)) {
201 return false;
202 }
203 DEBUG_ASSERT(ecm_rt.v4_route, "Did not locate a v4 route!\n");
204
205 /*
206 * Is this destination on link or off-link via a gateway?
207 */
208 rt = ecm_rt.rt.rtv4;
209 if ((rt->rt_dst != rt->rt_gateway) || (rt->rt_flags & RTF_GATEWAY)) {
210 *on_link = false;
211 ECM_NIN4_ADDR_TO_IP_ADDR(gw_addr, rt->rt_gateway)
212 } else {
213 *on_link = true;
214 }
215
216 /*
217 * Get the neighbour entry for the address
218 */
219 rcu_read_lock();
220 dst = ecm_rt.dst;
221 neigh = dst_get_neighbour_noref(dst);
222 if (neigh) {
223 neigh_hold(neigh);
224 } else {
225 neigh = neigh_lookup(&arp_tbl, &ipv4_addr, dst->dev);
226 }
227 if (!neigh) {
228 rcu_read_unlock();
229 ecm_interface_route_release(&ecm_rt);
230 return false;
231 }
232 if (!(neigh->nud_state & NUD_VALID)) {
233 rcu_read_unlock();
234 neigh_release(neigh);
235 ecm_interface_route_release(&ecm_rt);
236 return false;
237 }
238 if (!neigh->dev) {
239 rcu_read_unlock();
240 neigh_release(neigh);
241 ecm_interface_route_release(&ecm_rt);
242 return false;
243 }
244
245 /*
246 * If the device is loopback this will be because the address is a local address
247 * In this case locate the device that has this local address and get its mac.
248 */
249 if (neigh->dev->type == ARPHRD_LOOPBACK) {
250 struct net_device *dev;
251
252 DEBUG_TRACE("%pI4 finds loopback device, dev: %p (%s)\n", &ipv4_addr, neigh->dev, neigh->dev->name);
253 rcu_read_unlock();
254 neigh_release(neigh);
255 ecm_interface_route_release(&ecm_rt);
256
257 /*
258 * Lookup the device that has this IP address assigned
259 */
260 dev = ip_dev_find(&init_net, ipv4_addr);
261 if (!dev) {
262 DEBUG_WARN("Unable to locate dev for: %pI4\n", &ipv4_addr);
263 return false;
264 }
265 memcpy(mac_addr, dev->dev_addr, (size_t)dev->addr_len);
266 DEBUG_TRACE("is local addr: %pI4, mac: %pM, dev ifindex: %d, dev: %p (%s), dev_type: %d\n",
267 &ipv4_addr, mac_addr, dev->ifindex, dev, dev->name, dev->type);
268 dev_put(dev);
269 return true;
270 }
271
272 if (!(neigh->dev->flags & IFF_NOARP)) {
273 memcpy(mac_addr, neigh->ha, (size_t)neigh->dev->addr_len);
274 } else {
275 DEBUG_TRACE("non-arp device: %p (%s, type: %d) to reach %pI4\n", neigh->dev, neigh->dev->name, neigh->dev->type, &ipv4_addr);
276 memset(mac_addr, 0, 6);
277 }
278 DEBUG_TRACE("addr: %pI4, mac: %pM, iif: %d, neigh dev ifindex: %d, dev: %p (%s), dev_type: %d\n",
279 &ipv4_addr, mac_addr, rt->rt_iif, neigh->dev->ifindex, neigh->dev, neigh->dev->name, neigh->dev->type);
280
281 rcu_read_unlock();
282 neigh_release(neigh);
283 ecm_interface_route_release(&ecm_rt);
284 return true;
285}
286
287/*
288 * ecm_interface_mac_addr_get()
289 * Return the mac address for the given IP address. Returns false on failure.
290 *
291 * 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.
292 *
293 * GGG TODO Make this function work for IPv6!!!!!!!!!!!!!!
294 */
295bool ecm_interface_mac_addr_get(ip_addr_t addr, uint8_t *mac_addr, bool *on_link, ip_addr_t gw_addr)
296{
297 if (ECM_IP_ADDR_IS_V4(addr)) {
298 return ecm_interface_mac_addr_get_ipv4(addr, mac_addr, on_link, gw_addr);
299 }
300
301 return ecm_interface_mac_addr_get_ipv6(addr, mac_addr, on_link, gw_addr);
302}
303EXPORT_SYMBOL(ecm_interface_mac_addr_get);
304
305/*
306 * ecm_interface_addr_find_route_by_addr_ipv4()
307 * Return the route for the given IP address. Returns NULL on failure.
308 */
309static bool ecm_interface_find_route_by_addr_ipv4(ip_addr_t addr, struct ecm_interface_route *ecm_rt)
310{
311 __be32 be_addr;
312
313 /*
314 * Get a route to the given IP address, this will allow us to also find the interface
315 * it is using to communicate with that IP address.
316 */
317 ECM_IP_ADDR_TO_NIN4_ADDR(be_addr, addr);
318 ecm_rt->rt.rtv4 = ip_route_output(&init_net, be_addr, 0, 0, 0);
319 if (IS_ERR(ecm_rt->rt.rtv4)) {
320 DEBUG_TRACE("No output route to: %pI4n\n", &be_addr);
321 return false;
322 }
323 DEBUG_TRACE("Output route to: %pI4n is: %p\n", &be_addr, ecm_rt->rt.rtv4);
324 ecm_rt->dst = (struct dst_entry *)ecm_rt->rt.rtv4;
325 ecm_rt->v4_route = true;
326 return true;
327}
328
329/*
330 * ecm_interface_addr_find_route_by_addr_ipv6()
331 * Return the route for the given IP address. Returns NULL on failure.
332 */
333static bool ecm_interface_find_route_by_addr_ipv6(ip_addr_t addr, struct ecm_interface_route *ecm_rt)
334{
335 struct in6_addr naddr;
336
337 ECM_IP_ADDR_TO_NIN6_ADDR(naddr, addr);
338
339 /*
340 * Get a route to the given IP address, this will allow us to also find the interface
341 * it is using to communicate with that IP address.
342 */
343 ecm_rt->rt.rtv6 = rt6_lookup(&init_net, &naddr, NULL, 0, 0);
344 if (!ecm_rt->rt.rtv6) {
345 DEBUG_TRACE("No output route to: " ECM_IP_ADDR_OCTAL_FMT "\n", ECM_IP_ADDR_TO_OCTAL(addr));
346 return NULL;
347 }
348 DEBUG_TRACE("Output route to: " ECM_IP_ADDR_OCTAL_FMT " is: %p\n", ECM_IP_ADDR_TO_OCTAL(addr), ecm_rt->rt.rtv6);
349 ecm_rt->dst = (struct dst_entry *)ecm_rt->rt.rtv6;
350 ecm_rt->v4_route = false;
351 return true;
352}
353
354/*
355 * ecm_interface_addr_find_route_by_addr()
356 * Return the route (in the given parameter) for the given IP address. Returns false on failure.
357 *
358 * Route is the device on which the addr is reachable, which may be loopback for local addresses.
359 *
360 * Returns true if the route was able to be located. The route must be released using ecm_interface_route_release().
361 */
362bool ecm_interface_find_route_by_addr(ip_addr_t addr, struct ecm_interface_route *ecm_rt)
363{
364 char __attribute__((unused)) addr_str[40];
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530365
Ben Menchaca84f36632014-02-28 20:57:38 +0000366 ecm_ip_addr_to_string(addr_str, addr);
367 DEBUG_TRACE("Locate route to: %s\n", addr_str);
368
369 if (ECM_IP_ADDR_IS_V4(addr)) {
370 return ecm_interface_find_route_by_addr_ipv4(addr, ecm_rt);
371 }
372
373 return ecm_interface_find_route_by_addr_ipv6(addr, ecm_rt);
374}
375EXPORT_SYMBOL(ecm_interface_find_route_by_addr);
376
377/*
378 * ecm_interface_route_release()
379 * Release an ecm route
380 */
381void ecm_interface_route_release(struct ecm_interface_route *rt)
382{
383 dst_release(rt->dst);
384}
385EXPORT_SYMBOL(ecm_interface_route_release);
386
387/*
388 * ecm_interface_bridge_iface_final()
389 * An interface object we created has been destroyed
390 */
391static void ecm_interface_bridge_iface_final(void *arg)
392{
393 DEBUG_INFO("Bridge interface final: %p\n", arg);
394
395 /*
396 * No longer need the ref to the thread
397 */
398 spin_lock_bh(&ecm_interface_lock);
399 ecm_interface_thread_refs--;
400 DEBUG_ASSERT(ecm_interface_thread_refs >= 0, "Thread refs wrap %d\n", ecm_interface_thread_refs);
401 spin_unlock_bh(&ecm_interface_lock);
402 wake_up_process(ecm_interface_thread);
403}
404
405/*
406 * ecm_interface_vlan_iface_final()
407 * An interface object we created has been destroyed
408 */
409static void ecm_interface_vlan_iface_final(void *arg)
410{
411 DEBUG_INFO("VLAN interface final: %p\n", arg);
412
413 /*
414 * No longer need the ref to the thread
415 */
416 spin_lock_bh(&ecm_interface_lock);
417 ecm_interface_thread_refs--;
418 DEBUG_ASSERT(ecm_interface_thread_refs >= 0, "Thread refs wrap %d\n", ecm_interface_thread_refs);
419 spin_unlock_bh(&ecm_interface_lock);
420 wake_up_process(ecm_interface_thread);
421}
422
423/*
424 * ecm_interface_lag_iface_final()
425 * An interface object we created has been destroyed
426 */
427static void ecm_interface_lag_iface_final(void *arg)
428{
429 DEBUG_INFO("LAG interface final: %p\n", arg);
430
431 /*
432 * No longer need the ref to the thread
433 */
434 spin_lock_bh(&ecm_interface_lock);
435 ecm_interface_thread_refs--;
436 DEBUG_ASSERT(ecm_interface_thread_refs >= 0, "Thread refs wrap %d\n", ecm_interface_thread_refs);
437 spin_unlock_bh(&ecm_interface_lock);
438 wake_up_process(ecm_interface_thread);
439}
440
441/*
442 * ecm_interface_ethernet_iface_final()
443 * An interface object we created has been destroyed
444 */
445static void ecm_interface_ethernet_iface_final(void *arg)
446{
447 DEBUG_INFO("ETHERNET interface final: %p\n", arg);
448
449 /*
450 * No longer need the ref to the thread
451 */
452 spin_lock_bh(&ecm_interface_lock);
453 ecm_interface_thread_refs--;
454 DEBUG_ASSERT(ecm_interface_thread_refs >= 0, "Thread refs wrap %d\n", ecm_interface_thread_refs);
455 spin_unlock_bh(&ecm_interface_lock);
456 wake_up_process(ecm_interface_thread);
457}
458
Gareth Williamsc5b9d712014-05-09 20:40:07 +0100459#ifdef ECM_INTERFACE_PPP_SUPPORT
Ben Menchaca84f36632014-02-28 20:57:38 +0000460/*
461 * ecm_interface_pppoe_iface_final()
462 * An interface object we created has been destroyed
463 */
464static void ecm_interface_pppoe_iface_final(void *arg)
465{
466 DEBUG_INFO("PPPoE interface final: %p\n", arg);
467
468 /*
469 * No longer need the ref to the thread
470 */
471 spin_lock_bh(&ecm_interface_lock);
472 ecm_interface_thread_refs--;
473 DEBUG_ASSERT(ecm_interface_thread_refs >= 0, "Thread refs wrap %d\n", ecm_interface_thread_refs);
474 spin_unlock_bh(&ecm_interface_lock);
475 wake_up_process(ecm_interface_thread);
476}
Gareth Williamsc5b9d712014-05-09 20:40:07 +0100477#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000478
479/*
480 * ecm_interface_unknown_iface_final()
481 * An interface object we created has been destroyed
482 */
483static void ecm_interface_unknown_iface_final(void *arg)
484{
485 DEBUG_INFO("UNKNOWN type interface final: %p\n", arg);
486
487 /*
488 * No longer need the ref to the thread
489 */
490 spin_lock_bh(&ecm_interface_lock);
491 ecm_interface_thread_refs--;
492 DEBUG_ASSERT(ecm_interface_thread_refs >= 0, "Thread refs wrap %d\n", ecm_interface_thread_refs);
493 spin_unlock_bh(&ecm_interface_lock);
494 wake_up_process(ecm_interface_thread);
495}
496
497/*
498 * ecm_interface_loopback_iface_final()
499 * An interface object we created has been destroyed
500 */
501static void ecm_interface_loopback_iface_final(void *arg)
502{
503 DEBUG_INFO("LOOPBACK type interface final: %p\n", arg);
504
505 /*
506 * No longer need the ref to the thread
507 */
508 spin_lock_bh(&ecm_interface_lock);
509 ecm_interface_thread_refs--;
510 DEBUG_ASSERT(ecm_interface_thread_refs >= 0, "Thread refs wrap %d\n", ecm_interface_thread_refs);
511 spin_unlock_bh(&ecm_interface_lock);
512 wake_up_process(ecm_interface_thread);
513}
514
515/*
516 * ecm_interface_ipsec_tunnel_iface_final()
517 * An interface object we created has been destroyed
518 */
519static void ecm_interface_ipsec_tunnel_iface_final(void *arg)
520{
521 DEBUG_INFO("IPSEC TUNNEL type interface final: %p\n", arg);
522
523 /*
524 * No longer need the ref to the thread
525 */
526 spin_lock_bh(&ecm_interface_lock);
527 ecm_interface_thread_refs--;
528 DEBUG_ASSERT(ecm_interface_thread_refs >= 0, "Thread refs wrap %d\n", ecm_interface_thread_refs);
529 spin_unlock_bh(&ecm_interface_lock);
530 wake_up_process(ecm_interface_thread);
531}
532
Murat Sezgincc6eedf2014-05-09 23:59:19 -0700533#ifdef CONFIG_IPV6_SIT_6RD
Ben Menchaca84f36632014-02-28 20:57:38 +0000534/*
535 * ecm_interface_sit_iface_final()
536 * An interface object we created has been destroyed
537 */
538static void ecm_interface_sit_iface_final(void *arg)
539{
540 DEBUG_INFO("SIT (6-in-4) type interface final: %p\n", arg);
541
542 /*
543 * No longer need the ref to the thread
544 */
545 spin_lock_bh(&ecm_interface_lock);
546 ecm_interface_thread_refs--;
547 DEBUG_ASSERT(ecm_interface_thread_refs >= 0, "Thread refs wrap %d\n", ecm_interface_thread_refs);
548 spin_unlock_bh(&ecm_interface_lock);
549 wake_up_process(ecm_interface_thread);
550}
Murat Sezgincc6eedf2014-05-09 23:59:19 -0700551#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000552
553/*
554 * ecm_interface_tunipip6_iface_final()
555 * An interface object we created has been destroyed
556 */
557static void ecm_interface_tunipip6_iface_final(void *arg)
558{
559 DEBUG_INFO("TUNIPIP6 type interface final: %p\n", arg);
560
561 /*
562 * No longer need the ref to the thread
563 */
564 spin_lock_bh(&ecm_interface_lock);
565 ecm_interface_thread_refs--;
566 DEBUG_ASSERT(ecm_interface_thread_refs >= 0, "Thread refs wrap %d\n", ecm_interface_thread_refs);
567 spin_unlock_bh(&ecm_interface_lock);
568 wake_up_process(ecm_interface_thread);
569}
570
571/*
572 * ecm_interface_vlan_interface_establish()
573 * Returns a reference to a iface of the VLAN type, possibly creating one if necessary.
574 * Returns NULL on failure or a reference to interface.
575 */
576static struct ecm_db_iface_instance *ecm_interface_vlan_interface_establish(struct ecm_db_interface_info_vlan *type_info,
577 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
578{
579 struct ecm_db_iface_instance *nii;
580 struct ecm_db_iface_instance *ii;
581
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530582 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",
583 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 +0000584
585 /*
586 * Locate the iface
587 */
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530588 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 +0000589 if (ii) {
590 DEBUG_TRACE("%p: iface established\n", ii);
591 return ii;
592 }
593
594 /*
595 * No iface - create one
596 */
597 nii = ecm_db_iface_alloc();
598 if (!nii) {
599 DEBUG_WARN("Failed to establish iface\n");
600 return NULL;
601 }
602
603 /*
604 * Add iface into the database, atomically to avoid races creating the same thing
605 */
606 spin_lock_bh(&ecm_interface_lock);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530607 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 +0000608 if (ii) {
609 spin_unlock_bh(&ecm_interface_lock);
610 ecm_db_iface_deref(nii);
611 return ii;
612 }
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530613 ecm_db_iface_add_vlan(nii, type_info->address, type_info->vlan_tag, type_info->vlan_tpid, dev_name,
Ben Menchaca84f36632014-02-28 20:57:38 +0000614 mtu, dev_interface_num, nss_interface_num, ecm_interface_vlan_iface_final, nii);
615
616 /*
617 * Ensure our thread persists (and hence this module) for as long as the interface is referenced as we could get
618 * callbacks from the database at any time.
619 */
620 ecm_interface_thread_refs++;
621 DEBUG_ASSERT(ecm_interface_thread_refs > 0, "Thread refs wrap %d\n", ecm_interface_thread_refs);
622 spin_unlock_bh(&ecm_interface_lock);
623
624 DEBUG_TRACE("%p: vlan iface established\n", nii);
625 return nii;
626}
627
628/*
629 * ecm_interface_bridge_interface_establish()
630 * Returns a reference to a iface of the BRIDGE type, possibly creating one if necessary.
631 * Returns NULL on failure or a reference to interface.
632 */
633static struct ecm_db_iface_instance *ecm_interface_bridge_interface_establish(struct ecm_db_interface_info_bridge *type_info,
634 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
635{
636 struct ecm_db_iface_instance *nii;
637 struct ecm_db_iface_instance *ii;
638
639 DEBUG_INFO("Establish BRIDGE iface: %s with address: %pM, MTU: %d, if num: %d, nss if id: %d\n",
640 dev_name, type_info->address, mtu, dev_interface_num, nss_interface_num);
641
642 /*
643 * Locate the iface
644 */
645 ii = ecm_db_iface_find_and_ref_bridge(type_info->address);
646 if (ii) {
647 DEBUG_TRACE("%p: iface established\n", ii);
648 return ii;
649 }
650
651 /*
652 * No iface - create one
653 */
654 nii = ecm_db_iface_alloc();
655 if (!nii) {
656 DEBUG_WARN("Failed to establish iface\n");
657 return NULL;
658 }
659
660 /*
661 * Add iface into the database, atomically to avoid races creating the same thing
662 */
663 spin_lock_bh(&ecm_interface_lock);
664 ii = ecm_db_iface_find_and_ref_bridge(type_info->address);
665 if (ii) {
666 spin_unlock_bh(&ecm_interface_lock);
667 ecm_db_iface_deref(nii);
668 return ii;
669 }
670 ecm_db_iface_add_bridge(nii, type_info->address, dev_name,
671 mtu, dev_interface_num, nss_interface_num, ecm_interface_bridge_iface_final, nii);
672
673 /*
674 * Ensure our thread persists (and hence this module) for as long as the interface is referenced as we could get
675 * callbacks from the database at any time.
676 */
677 ecm_interface_thread_refs++;
678 DEBUG_ASSERT(ecm_interface_thread_refs > 0, "Thread refs wrap %d\n", ecm_interface_thread_refs);
679 spin_unlock_bh(&ecm_interface_lock);
680
681 DEBUG_TRACE("%p: bridge iface established\n", nii);
682 return nii;
683}
684
685/*
686 * ecm_interface_lag_interface_establish()
687 * Returns a reference to a iface of the LAG type, possibly creating one if necessary.
688 * Returns NULL on failure or a reference to interface.
689 */
690static struct ecm_db_iface_instance *ecm_interface_lag_interface_establish(struct ecm_db_interface_info_lag *type_info,
691 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
692{
693 struct ecm_db_iface_instance *nii;
694 struct ecm_db_iface_instance *ii;
695
696 DEBUG_INFO("Establish LAG iface: %s with address: %pM, MTU: %d, if num: %d, nss if id: %d\n",
697 dev_name, type_info->address, mtu, dev_interface_num, nss_interface_num);
698
699 /*
700 * Locate the iface
701 */
702 ii = ecm_db_iface_find_and_ref_lag(type_info->address);
703 if (ii) {
704 DEBUG_TRACE("%p: iface established\n", ii);
705 return ii;
706 }
707
708 /*
709 * No iface - create one
710 */
711 nii = ecm_db_iface_alloc();
712 if (!nii) {
713 DEBUG_WARN("Failed to establish iface\n");
714 return NULL;
715 }
716
717 /*
718 * Add iface into the database, atomically to avoid races creating the same thing
719 */
720 spin_lock_bh(&ecm_interface_lock);
721 ii = ecm_db_iface_find_and_ref_lag(type_info->address);
722 if (ii) {
723 spin_unlock_bh(&ecm_interface_lock);
724 ecm_db_iface_deref(nii);
725 return ii;
726 }
727 ecm_db_iface_add_lag(nii, type_info->address, dev_name,
728 mtu, dev_interface_num, nss_interface_num, ecm_interface_lag_iface_final, nii);
729
730 /*
731 * Ensure our thread persists (and hence this module) for as long as the interface is referenced as we could get
732 * callbacks from the database at any time.
733 */
734 ecm_interface_thread_refs++;
735 DEBUG_ASSERT(ecm_interface_thread_refs > 0, "Thread refs wrap %d\n", ecm_interface_thread_refs);
736 spin_unlock_bh(&ecm_interface_lock);
737
738 DEBUG_TRACE("%p: lag iface established\n", nii);
739 return nii;
740}
741
742/*
743 * ecm_interface_ethernet_interface_establish()
744 * Returns a reference to a iface of the ETHERNET type, possibly creating one if necessary.
745 * Returns NULL on failure or a reference to interface.
746 */
747static struct ecm_db_iface_instance *ecm_interface_ethernet_interface_establish(struct ecm_db_interface_info_ethernet *type_info,
748 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
749{
750 struct ecm_db_iface_instance *nii;
751 struct ecm_db_iface_instance *ii;
752
753 DEBUG_INFO("Establish ETHERNET iface: %s with address: %pM, MTU: %d, if num: %d, nss if id: %d\n",
754 dev_name, type_info->address, mtu, dev_interface_num, nss_interface_num);
755
756 /*
757 * Locate the iface
758 */
759 ii = ecm_db_iface_find_and_ref_ethernet(type_info->address);
760 if (ii) {
761 DEBUG_TRACE("%p: iface established\n", ii);
762 return ii;
763 }
764
765 /*
766 * No iface - create one
767 */
768 nii = ecm_db_iface_alloc();
769 if (!nii) {
770 DEBUG_WARN("Failed to establish iface\n");
771 return NULL;
772 }
773
774 /*
775 * Add iface into the database, atomically to avoid races creating the same thing
776 */
777 spin_lock_bh(&ecm_interface_lock);
778 ii = ecm_db_iface_find_and_ref_ethernet(type_info->address);
779 if (ii) {
780 spin_unlock_bh(&ecm_interface_lock);
781 ecm_db_iface_deref(nii);
782 return ii;
783 }
784 ecm_db_iface_add_ethernet(nii, type_info->address, dev_name,
785 mtu, dev_interface_num, nss_interface_num, ecm_interface_ethernet_iface_final, nii);
786
787 /*
788 * Ensure our thread persists (and hence this module) for as long as the interface is referenced as we could get
789 * callbacks from the database at any time.
790 */
791 ecm_interface_thread_refs++;
792 DEBUG_ASSERT(ecm_interface_thread_refs > 0, "Thread refs wrap %d\n", ecm_interface_thread_refs);
793 spin_unlock_bh(&ecm_interface_lock);
794
795 DEBUG_TRACE("%p: ethernet iface established\n", nii);
796 return nii;
797}
798
Gareth Williamsc5b9d712014-05-09 20:40:07 +0100799#ifdef ECM_INTERFACE_PPP_SUPPORT
Ben Menchaca84f36632014-02-28 20:57:38 +0000800/*
801 * ecm_interface_pppoe_interface_establish()
802 * Returns a reference to a iface of the PPPoE type, possibly creating one if necessary.
803 * Returns NULL on failure or a reference to interface.
804 */
805static struct ecm_db_iface_instance *ecm_interface_pppoe_interface_establish(struct ecm_db_interface_info_pppoe *type_info,
806 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
807{
808 struct ecm_db_iface_instance *nii;
809 struct ecm_db_iface_instance *ii;
810
811 DEBUG_INFO("Establish PPPoE iface: %s with session id: %u, remote mac: %pM, MTU: %d, if num: %d, nss if id: %d\n",
812 dev_name, type_info->pppoe_session_id, type_info->remote_mac, mtu, dev_interface_num, nss_interface_num);
813
814 /*
815 * Locate the iface
816 */
817 ii = ecm_db_iface_find_and_ref_pppoe(type_info->pppoe_session_id, type_info->remote_mac);
818 if (ii) {
819 DEBUG_TRACE("%p: iface established\n", ii);
820 return ii;
821 }
822
823 /*
824 * No iface - create one
825 */
826 nii = ecm_db_iface_alloc();
827 if (!nii) {
828 DEBUG_WARN("Failed to establish iface\n");
829 return NULL;
830 }
831
832 /*
833 * Add iface into the database, atomically to avoid races creating the same thing
834 */
835 spin_lock_bh(&ecm_interface_lock);
836 ii = ecm_db_iface_find_and_ref_pppoe(type_info->pppoe_session_id, type_info->remote_mac);
837 if (ii) {
838 spin_unlock_bh(&ecm_interface_lock);
839 ecm_db_iface_deref(nii);
840 return ii;
841 }
842 ecm_db_iface_add_pppoe(nii, type_info->pppoe_session_id, type_info->remote_mac, dev_name,
843 mtu, dev_interface_num, nss_interface_num, ecm_interface_pppoe_iface_final, nii);
844
845 /*
846 * Ensure our thread persists (and hence this module) for as long as the interface is referenced as we could get
847 * callbacks from the database at any time.
848 */
849 ecm_interface_thread_refs++;
850 DEBUG_ASSERT(ecm_interface_thread_refs > 0, "Thread refs wrap %d\n", ecm_interface_thread_refs);
851 spin_unlock_bh(&ecm_interface_lock);
852
853 DEBUG_TRACE("%p: pppoe iface established\n", nii);
854 return nii;
855}
Gareth Williamsc5b9d712014-05-09 20:40:07 +0100856#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000857
858/*
859 * ecm_interface_unknown_interface_establish()
860 * Returns a reference to a iface of the UNKNOWN type, possibly creating one if necessary.
861 * Returns NULL on failure or a reference to interface.
862 */
863static struct ecm_db_iface_instance *ecm_interface_unknown_interface_establish(struct ecm_db_interface_info_unknown *type_info,
864 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
865{
866 struct ecm_db_iface_instance *nii;
867 struct ecm_db_iface_instance *ii;
868
869 DEBUG_INFO("Establish UNKNOWN iface: %s with os_specific_ident: %u, MTU: %d, if num: %d, nss if id: %d\n",
870 dev_name, type_info->os_specific_ident, mtu, dev_interface_num, nss_interface_num);
871
872 /*
873 * Locate the iface
874 */
875 ii = ecm_db_iface_find_and_ref_unknown(type_info->os_specific_ident);
876 if (ii) {
877 DEBUG_TRACE("%p: iface established\n", ii);
878 return ii;
879 }
880
881 /*
882 * No iface - create one
883 */
884 nii = ecm_db_iface_alloc();
885 if (!nii) {
886 DEBUG_WARN("Failed to establish iface\n");
887 return NULL;
888 }
889
890 /*
891 * Add iface into the database, atomically to avoid races creating the same thing
892 */
893 spin_lock_bh(&ecm_interface_lock);
894 ii = ecm_db_iface_find_and_ref_unknown(type_info->os_specific_ident);
895 if (ii) {
896 spin_unlock_bh(&ecm_interface_lock);
897 ecm_db_iface_deref(nii);
898 return ii;
899 }
900 ecm_db_iface_add_unknown(nii, type_info->os_specific_ident, dev_name,
901 mtu, dev_interface_num, nss_interface_num, ecm_interface_unknown_iface_final, nii);
902
903 /*
904 * Ensure our thread persists (and hence this module) for as long as the interface is referenced as we could get
905 * callbacks from the database at any time.
906 */
907 ecm_interface_thread_refs++;
908 DEBUG_ASSERT(ecm_interface_thread_refs > 0, "Thread refs wrap %d\n", ecm_interface_thread_refs);
909 spin_unlock_bh(&ecm_interface_lock);
910
911 DEBUG_TRACE("%p: unknown iface established\n", nii);
912 return nii;
913}
914
915/*
916 * ecm_interface_loopback_interface_establish()
917 * Returns a reference to a iface of the LOOPBACK type, possibly creating one if necessary.
918 * Returns NULL on failure or a reference to interface.
919 */
920static struct ecm_db_iface_instance *ecm_interface_loopback_interface_establish(struct ecm_db_interface_info_loopback *type_info,
921 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
922{
923 struct ecm_db_iface_instance *nii;
924 struct ecm_db_iface_instance *ii;
925
926 DEBUG_INFO("Establish LOOPBACK iface: %s with os_specific_ident: %u, MTU: %d, if num: %d, nss if id: %d\n",
927 dev_name, type_info->os_specific_ident, mtu, dev_interface_num, nss_interface_num);
928
929 /*
930 * Locate the iface
931 */
932 ii = ecm_db_iface_find_and_ref_loopback(type_info->os_specific_ident);
933 if (ii) {
934 DEBUG_TRACE("%p: iface established\n", ii);
935 return ii;
936 }
937
938 /*
939 * No iface - create one
940 */
941 nii = ecm_db_iface_alloc();
942 if (!nii) {
943 DEBUG_WARN("Failed to establish iface\n");
944 return NULL;
945 }
946
947 /*
948 * Add iface into the database, atomically to avoid races creating the same thing
949 */
950 spin_lock_bh(&ecm_interface_lock);
951 ii = ecm_db_iface_find_and_ref_loopback(type_info->os_specific_ident);
952 if (ii) {
953 spin_unlock_bh(&ecm_interface_lock);
954 ecm_db_iface_deref(nii);
955 return ii;
956 }
957 ecm_db_iface_add_loopback(nii, type_info->os_specific_ident, dev_name,
958 mtu, dev_interface_num, nss_interface_num, ecm_interface_loopback_iface_final, nii);
959
960 /*
961 * Ensure our thread persists (and hence this module) for as long as the interface is referenced as we could get
962 * callbacks from the database at any time.
963 */
964 ecm_interface_thread_refs++;
965 DEBUG_ASSERT(ecm_interface_thread_refs > 0, "Thread refs wrap %d\n", ecm_interface_thread_refs);
966 spin_unlock_bh(&ecm_interface_lock);
967
968 DEBUG_TRACE("%p: loopback iface established\n", nii);
969 return nii;
970}
971
972/*
973 * ecm_interface_ipsec_tunnel_interface_establish()
974 * Returns a reference to a iface of the IPSEC_TUNNEL type, possibly creating one if necessary.
975 * Returns NULL on failure or a reference to interface.
976 *
977 * NOTE: GGG TODO THIS NEEDS TO TAKE A PROPER APPROACH TO IPSEC TUNNELS USING ENDPOINT ADDRESSING AS THE TYPE INFO KEYS
978 */
979static struct ecm_db_iface_instance *ecm_interface_ipsec_tunnel_interface_establish(struct ecm_db_interface_info_ipsec_tunnel *type_info,
980 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
981{
982 struct ecm_db_iface_instance *nii;
983 struct ecm_db_iface_instance *ii;
984
985 DEBUG_INFO("Establish IPSEC_TUNNEL iface: %s with os_specific_ident: %u, MTU: %d, if num: %d, nss if id: %d\n",
986 dev_name, type_info->os_specific_ident, mtu, dev_interface_num, nss_interface_num);
987
988 /*
989 * Locate the iface
990 */
991 ii = ecm_db_iface_find_and_ref_ipsec_tunnel(type_info->os_specific_ident);
992 if (ii) {
993 DEBUG_TRACE("%p: iface established\n", ii);
994 return ii;
995 }
996
997 /*
998 * No iface - create one
999 */
1000 nii = ecm_db_iface_alloc();
1001 if (!nii) {
1002 DEBUG_WARN("Failed to establish iface\n");
1003 return NULL;
1004 }
1005
1006 /*
1007 * Add iface into the database, atomically to avoid races creating the same thing
1008 */
1009 spin_lock_bh(&ecm_interface_lock);
1010 ii = ecm_db_iface_find_and_ref_ipsec_tunnel(type_info->os_specific_ident);
1011 if (ii) {
1012 spin_unlock_bh(&ecm_interface_lock);
1013 ecm_db_iface_deref(nii);
1014 return ii;
1015 }
1016 ecm_db_iface_add_ipsec_tunnel(nii, type_info->os_specific_ident, dev_name,
1017 mtu, dev_interface_num, nss_interface_num, ecm_interface_ipsec_tunnel_iface_final, nii);
1018
1019 /*
1020 * Ensure our thread persists (and hence this module) for as long as the interface is referenced as we could get
1021 * callbacks from the database at any time.
1022 */
1023 ecm_interface_thread_refs++;
1024 DEBUG_ASSERT(ecm_interface_thread_refs > 0, "Thread refs wrap %d\n", ecm_interface_thread_refs);
1025 spin_unlock_bh(&ecm_interface_lock);
1026
1027 DEBUG_TRACE("%p: ipsec_tunnel iface established\n", nii);
1028 return nii;
1029}
1030
Murat Sezgincc6eedf2014-05-09 23:59:19 -07001031#ifdef CONFIG_IPV6_SIT_6RD
Ben Menchaca84f36632014-02-28 20:57:38 +00001032/*
1033 * ecm_interface_sit_interface_establish()
1034 * Returns a reference to a iface of the SIT type, possibly creating one if necessary.
1035 * Returns NULL on failure or a reference to interface.
1036 */
1037static struct ecm_db_iface_instance *ecm_interface_sit_interface_establish(struct ecm_db_interface_info_sit *type_info,
1038 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
1039{
1040 struct ecm_db_iface_instance *nii;
1041 struct ecm_db_iface_instance *ii;
1042
1043 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",
1044 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);
1045
1046 /*
1047 * Locate the iface
1048 */
1049 ii = ecm_db_iface_find_and_ref_sit(type_info->saddr, type_info->daddr);
1050 if (ii) {
1051 DEBUG_TRACE("%p: iface established\n", ii);
1052 return ii;
1053 }
1054
1055 /*
1056 * No iface - create one
1057 */
1058 nii = ecm_db_iface_alloc();
1059 if (!nii) {
1060 DEBUG_WARN("Failed to establish iface\n");
1061 return NULL;
1062 }
1063
1064 /*
1065 * Add iface into the database, atomically to avoid races creating the same thing
1066 */
1067 spin_lock_bh(&ecm_interface_lock);
1068 ii = ecm_db_iface_find_and_ref_sit(type_info->saddr, type_info->daddr);
1069 if (ii) {
1070 spin_unlock_bh(&ecm_interface_lock);
1071 ecm_db_iface_deref(nii);
1072 return ii;
1073 }
1074 ecm_db_iface_add_sit(nii, type_info, dev_name, mtu, dev_interface_num,
1075 nss_interface_num, ecm_interface_sit_iface_final, nii);
1076
1077 /*
1078 * Ensure our thread persists (and hence this module) for as long as the interface is referenced as we could get
1079 * callbacks from the database at any time.
1080 */
1081 ecm_interface_thread_refs++;
1082 DEBUG_ASSERT(ecm_interface_thread_refs > 0, "Thread refs wrap %d\n", ecm_interface_thread_refs);
1083 spin_unlock_bh(&ecm_interface_lock);
1084
1085 DEBUG_TRACE("%p: sit iface established\n", nii);
1086 return nii;
1087}
Murat Sezgincc6eedf2014-05-09 23:59:19 -07001088#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001089
1090/*
1091 * ecm_interface_tunipip6_interface_establish()
1092 * Returns a reference to a iface of the TUNIPIP6 type, possibly creating one if necessary.
1093 * Returns NULL on failure or a reference to interface.
1094 */
1095static struct ecm_db_iface_instance *ecm_interface_tunipip6_interface_establish(struct ecm_db_interface_info_tunipip6 *type_info,
1096 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
1097{
1098 struct ecm_db_iface_instance *nii;
1099 struct ecm_db_iface_instance *ii;
1100
1101 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",
1102 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);
1103
1104 /*
1105 * Locate the iface
1106 */
1107 ii = ecm_db_iface_find_and_ref_tunipip6(type_info->saddr, type_info->daddr);
1108 if (ii) {
1109 DEBUG_TRACE("%p: iface established\n", ii);
1110 return ii;
1111 }
1112
1113 /*
1114 * No iface - create one
1115 */
1116 nii = ecm_db_iface_alloc();
1117 if (!nii) {
1118 DEBUG_WARN("Failed to establish iface\n");
1119 return NULL;
1120 }
1121
1122 /*
1123 * Add iface into the database, atomically to avoid races creating the same thing
1124 */
1125 spin_lock_bh(&ecm_interface_lock);
1126 ii = ecm_db_iface_find_and_ref_tunipip6(type_info->saddr, type_info->daddr);
1127 if (ii) {
1128 spin_unlock_bh(&ecm_interface_lock);
1129 ecm_db_iface_deref(nii);
1130 return ii;
1131 }
1132 ecm_db_iface_add_tunipip6(nii, type_info, dev_name, mtu, dev_interface_num,
1133 nss_interface_num, ecm_interface_tunipip6_iface_final, nii);
1134
1135 /*
1136 * Ensure our thread persists (and hence this module) for as long as the interface is referenced as we could get
1137 * callbacks from the database at any time.
1138 */
1139 ecm_interface_thread_refs++;
1140 DEBUG_ASSERT(ecm_interface_thread_refs > 0, "Thread refs wrap %d\n", ecm_interface_thread_refs);
1141 spin_unlock_bh(&ecm_interface_lock);
1142
1143 DEBUG_TRACE("%p: tunipip6 iface established\n", nii);
1144 return nii;
1145}
1146
1147/*
1148 * ecm_interface_establish_and_ref()
1149 * Establish an interface instance for the given interface detail.
1150 */
1151struct ecm_db_iface_instance *ecm_interface_establish_and_ref(struct net_device *dev)
1152{
1153 int32_t dev_interface_num;
1154 char *dev_name;
1155 int32_t dev_type;
1156 int32_t dev_mtu;
1157 int32_t nss_interface_num;
1158 struct ecm_db_iface_instance *ii;
1159 union {
1160 struct ecm_db_interface_info_ethernet ethernet; /* type == ECM_DB_IFACE_TYPE_ETHERNET */
1161 struct ecm_db_interface_info_vlan vlan; /* type == ECM_DB_IFACE_TYPE_VLAN */
1162 struct ecm_db_interface_info_lag lag; /* type == ECM_DB_IFACE_TYPE_LAG */
1163 struct ecm_db_interface_info_bridge bridge; /* type == ECM_DB_IFACE_TYPE_BRIDGE */
1164 struct ecm_db_interface_info_pppoe pppoe; /* type == ECM_DB_IFACE_TYPE_PPPOE */
1165 struct ecm_db_interface_info_unknown unknown; /* type == ECM_DB_IFACE_TYPE_UNKNOWN */
1166 struct ecm_db_interface_info_loopback loopback; /* type == ECM_DB_IFACE_TYPE_LOOPBACK */
1167 struct ecm_db_interface_info_ipsec_tunnel ipsec_tunnel; /* type == ECM_DB_IFACE_TYPE_IPSEC_TUNNEL */
1168 struct ecm_db_interface_info_sit sit; /* type == ECM_DB_IFACE_TYPE_SIT */
1169 struct ecm_db_interface_info_tunipip6 tunipip6; /* type == ECM_DB_IFACE_TYPE_TUNIPIP6 */
1170 } type_info;
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001171
1172#ifdef ECM_INTERFACE_PPP_SUPPORT
Ben Menchaca84f36632014-02-28 20:57:38 +00001173 int channel_count;
1174 struct ppp_channel *ppp_chan[1];
1175 const struct ppp_channel_ops *ppp_chan_ops;
1176 int channel_protocol;
1177 struct pppoe_channel_ops *pppoe_chan_ops;
1178 struct pppoe_opt addressing;
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001179#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001180
1181 /*
1182 * Get basic information about the given device
1183 */
1184 dev_interface_num = dev->ifindex;
1185 dev_name = dev->name;
1186 dev_type = dev->type;
1187 dev_mtu = dev->mtu;
1188
1189 /*
1190 * Does the NSS recognise this interface?
1191 */
1192 nss_interface_num = nss_cmn_get_interface_number_by_dev(dev);
1193
1194 DEBUG_TRACE("Establish interface instance for device: %p is type: %d, name: %s, ifindex: %d, nss_if: %d, mtu: %d\n",
1195 dev, dev_type, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1196
1197 /*
1198 * Extract from the device more type-specific information
1199 */
1200 if (dev_type == ARPHRD_ETHER) {
1201 /*
1202 * Ethernet - but what sub type?
1203 */
1204
1205 /*
1206 * VLAN?
1207 */
1208 if (is_vlan_dev(dev)) {
1209 /*
1210 * VLAN master
1211 * GGG No locking needed here, ASSUMPTION is that real_dev is held for as long as we have dev.
1212 */
1213 memcpy(type_info.vlan.address, dev->dev_addr, 6);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301214 type_info.vlan.vlan_tag = vlan_dev_vlan_id(dev);
1215 type_info.vlan.vlan_tpid = VLAN_CTAG_TPID;
1216 DEBUG_TRACE("Net device: %p is VLAN, mac: %pM, vlan_id: %x vlan_tpid: %x\n",
1217 dev, type_info.vlan.address, type_info.vlan.vlan_tag, type_info.vlan.vlan_tpid);
Ben Menchaca84f36632014-02-28 20:57:38 +00001218
1219 /*
1220 * Establish this type of interface
1221 */
1222 ii = ecm_interface_vlan_interface_establish(&type_info.vlan, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1223 return ii;
1224 }
1225
1226 /*
1227 * BRIDGE?
1228 */
1229 if (ecm_front_end_is_bridge_device(dev)) {
1230 /*
1231 * Bridge
1232 */
1233 memcpy(type_info.bridge.address, dev->dev_addr, 6);
1234
1235 DEBUG_TRACE("Net device: %p is BRIDGE, mac: %pM\n",
1236 dev, type_info.bridge.address);
1237
1238 /*
1239 * Establish this type of interface
1240 */
1241 ii = ecm_interface_bridge_interface_establish(&type_info.bridge, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1242 return ii;
1243 }
1244
1245 /*
1246 * LAG?
1247 */
1248 if (ecm_front_end_is_lag_master(dev)) {
1249 /*
1250 * Link aggregation
1251 */
1252 memcpy(type_info.lag.address, dev->dev_addr, 6);
1253
1254 DEBUG_TRACE("Net device: %p is LAG, mac: %pM\n",
1255 dev, type_info.lag.address);
1256
1257 /*
1258 * Establish this type of interface
1259 */
1260 ii = ecm_interface_lag_interface_establish(&type_info.lag, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1261 return ii;
1262 }
1263
1264 /*
1265 * ETHERNET!
1266 * Just plain ethernet it seems
1267 */
1268 memcpy(type_info.ethernet.address, dev->dev_addr, 6);
1269 DEBUG_TRACE("Net device: %p is ETHERNET, mac: %pM\n",
1270 dev, type_info.ethernet.address);
1271
1272 /*
1273 * Establish this type of interface
1274 */
1275 ii = ecm_interface_ethernet_interface_establish(&type_info.ethernet, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1276 return ii;
1277 }
1278
1279 /*
1280 * LOOPBACK?
1281 */
1282 if (dev_type == ARPHRD_LOOPBACK) {
1283 DEBUG_TRACE("Net device: %p is LOOPBACK type: %d\n", dev, dev_type);
1284 type_info.loopback.os_specific_ident = dev_interface_num;
1285 ii = ecm_interface_loopback_interface_establish(&type_info.loopback, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1286 return ii;
1287 }
1288
1289 /*
1290 * IPSEC?
1291 */
1292 if (dev_type == ECM_ARPHRD_IPSEC_TUNNEL_TYPE) {
1293 DEBUG_TRACE("Net device: %p is IPSec tunnel type: %d\n", dev, dev_type);
1294 type_info.ipsec_tunnel.os_specific_ident = dev_interface_num;
1295 // GGG TODO Flesh this out with tunnel endpoint addressing detail
1296 ii = ecm_interface_ipsec_tunnel_interface_establish(&type_info.ipsec_tunnel, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1297 return ii;
1298 }
1299
Murat Sezgincc6eedf2014-05-09 23:59:19 -07001300#ifdef CONFIG_IPV6_SIT_6RD
Ben Menchaca84f36632014-02-28 20:57:38 +00001301 /*
1302 * SIT (6-in-4)?
1303 */
1304 if (dev_type == ARPHRD_SIT) {
1305 struct ip_tunnel *tunnel;
1306 struct ip_tunnel_6rd_parm *ip6rd;
1307 const struct iphdr *tiph;
1308
1309 DEBUG_TRACE("Net device: %p is SIT (6-in-4) type: %d\n", dev, dev_type);
1310
1311 tunnel = (struct ip_tunnel*)netdev_priv(dev);
1312 ip6rd = &tunnel->ip6rd;
1313
1314 /*
1315 * Get the Tunnel device IP header info
1316 */
1317 tiph = &tunnel->parms.iph ;
1318
1319 type_info.sit.prefixlen = ip6rd->prefixlen;
1320 type_info.sit.relay_prefix = ip6rd->relay_prefix;
1321 type_info.sit.relay_prefixlen = ip6rd->relay_prefixlen;
1322 ECM_NIN4_ADDR_TO_IP_ADDR(type_info.sit.saddr, tiph->saddr);
1323 ECM_NIN4_ADDR_TO_IP_ADDR(type_info.sit.daddr, tiph->daddr);
1324 type_info.sit.prefix[0] = ntohl(ip6rd->prefix.s6_addr32[0]);
1325 type_info.sit.prefix[1] = ntohl(ip6rd->prefix.s6_addr32[1]);
1326 type_info.sit.prefix[2] = ntohl(ip6rd->prefix.s6_addr32[2]);
1327 type_info.sit.prefix[3] = ntohl(ip6rd->prefix.s6_addr32[3]);
1328 type_info.sit.ttl = tiph->ttl;
1329 type_info.sit.tos = tiph->tos;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301330
Ben Menchaca84f36632014-02-28 20:57:38 +00001331 ii = ecm_interface_sit_interface_establish(&type_info.sit, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1332 return ii;
1333 }
Murat Sezgincc6eedf2014-05-09 23:59:19 -07001334#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001335
1336 /*
1337 * IPIP6 Tunnel?
1338 */
1339 if (dev_type == ARPHRD_TUNNEL6) {
1340 struct ip6_tnl *tunnel;
1341 struct flowi6 *fl6;
1342
1343 DEBUG_TRACE("Net device: %p is TUNIPIP6 type: %d\n", dev, dev_type);
1344
1345 /*
1346 * Get the tunnel device flow information (discover the output path of the tunnel)
1347 */
1348 tunnel = (struct ip6_tnl *)netdev_priv(dev);
1349 fl6 = &tunnel->fl.u.ip6;
1350
1351 ECM_NIN6_ADDR_TO_IP_ADDR(type_info.tunipip6.saddr, fl6->saddr);
1352 ECM_NIN6_ADDR_TO_IP_ADDR(type_info.tunipip6.daddr, fl6->daddr);
1353 type_info.tunipip6.hop_limit = tunnel->parms.hop_limit;
1354 type_info.tunipip6.flags = ntohl(tunnel->parms.flags);
1355 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 +05301356
Ben Menchaca84f36632014-02-28 20:57:38 +00001357 ii = ecm_interface_tunipip6_interface_establish(&type_info.tunipip6, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1358 return ii;
1359 }
1360
1361 /*
1362 * If this is NOT PPP then it is unknown to the ecm
1363 */
1364 if (dev_type != ARPHRD_PPP) {
1365 DEBUG_TRACE("Net device: %p is UNKNOWN type: %d\n", dev, dev_type);
1366 type_info.unknown.os_specific_ident = dev_interface_num;
1367
1368 /*
1369 * Establish this type of interface
1370 */
1371 ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1372 return ii;
1373 }
1374
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001375#ifndef ECM_INTERFACE_PPP_SUPPORT
1376 /*
1377 * PPP support is NOT provided for.
1378 * Interface is therefore unknown
1379 */
1380 DEBUG_TRACE("Net device: %p is UNKNOWN (PPP Unsupported) type: %d\n", dev, dev_type);
1381 type_info.unknown.os_specific_ident = dev_interface_num;
1382
1383 /*
1384 * Establish this type of interface
1385 */
1386 ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1387 return ii;
1388#else
Ben Menchaca84f36632014-02-28 20:57:38 +00001389 /*
1390 * PPP - but what is the channel type?
1391 * First: If this is multi-link then we do not support it
1392 */
1393 if (ppp_is_multilink(dev) > 0) {
1394 DEBUG_TRACE("Net device: %p is MULTILINK PPP - Unknown to the ECM\n", dev);
1395 type_info.unknown.os_specific_ident = dev_interface_num;
1396
1397 /*
1398 * Establish this type of interface
1399 */
1400 ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1401 return ii;
1402 }
1403
1404 DEBUG_TRACE("Net device: %p is PPP\n", dev);
1405
1406 /*
1407 * Get the PPP channel and then enquire what kind of channel it is
1408 * NOTE: Not multilink so only one channel to get.
1409 */
1410 channel_count = ppp_hold_channels(dev, ppp_chan, 1);
1411 if (channel_count != 1) {
1412 DEBUG_TRACE("Net device: %p PPP has %d channels - Unknown to the ECM\n", dev, channel_count);
1413 type_info.unknown.os_specific_ident = dev_interface_num;
1414
1415 /*
1416 * Establish this type of interface
1417 */
1418 ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1419 return ii;
1420 }
1421
1422 /*
1423 * Get channel protocol type
1424 */
1425 ppp_chan_ops = ppp_chan[0]->ops;
1426 channel_protocol = ppp_chan_ops->get_channel_protocol(ppp_chan[0]);
1427 if (channel_protocol != PX_PROTO_OE) {
1428 DEBUG_TRACE("Net device: %p PPP channel protocol: %d - Unknown to the ECM\n", dev, channel_protocol);
1429 type_info.unknown.os_specific_ident = dev_interface_num;
1430
1431 /*
1432 * Release the channel
1433 */
1434 ppp_release_channels(ppp_chan, 1);
1435
1436 /*
1437 * Establish this type of interface
1438 */
1439 ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1440 return ii;
1441 }
1442
1443 /*
1444 * PPPoE channel
1445 */
1446 DEBUG_TRACE("Net device: %p PPP channel is PPPoE\n", dev);
1447
1448 /*
1449 * Get PPPoE session information and the underlying device it is using.
1450 * NOTE: We know this is PPPoE so we can cast the ppp_chan_ops to pppoe_chan_ops and
1451 * use its channel specific methods.
1452 */
1453 pppoe_chan_ops = (struct pppoe_channel_ops *)ppp_chan_ops;
1454 pppoe_chan_ops->get_addressing(ppp_chan[0], &addressing);
1455
1456 type_info.pppoe.pppoe_session_id = (uint16_t)addressing.pa.sid;
1457 memcpy(type_info.pppoe.remote_mac, addressing.pa.remote, ETH_ALEN);
1458
1459 /*
1460 * Release the channel. Note that next_dev is still (correctly) held.
1461 */
1462 ppp_release_channels(ppp_chan, 1);
1463
1464 DEBUG_TRACE("Net device: %p PPPoE session: %x, remote mac: %pM\n",
1465 dev, type_info.pppoe.pppoe_session_id, type_info.pppoe.remote_mac);
1466
1467 /*
1468 * Establish this type of interface
1469 */
1470 ii = ecm_interface_pppoe_interface_establish(&type_info.pppoe, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1471 return ii;
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001472#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001473}
1474EXPORT_SYMBOL(ecm_interface_establish_and_ref);
1475
1476/*
1477 * ecm_interface_heirarchy_construct()
1478 * Construct an interface heirarchy.
1479 *
1480 * Using the given addressing, locate the interface heirarchy used to emit packets to that destination.
1481 * This is the heirarchy of interfaces a packet would transit to emit from the device.
1482 * For example, with this network arrangement:
1483 *
1484 * PPPoE--VLAN--BRIDGE--BRIDGE_PORT(LAG_MASTER)--LAG_SLAVE_0--10.22.33.11
1485 *
1486 * Given the IP address 10.22.33.11 this will create an interface heirarchy (in interracfes[]) of:
1487 * LAG_SLAVE_0 @ [ECM_DB_IFACE_HEIRARCHY_MAX - 5]
1488 * LAG_MASTER @ [ECM_DB_IFACE_HEIRARCHY_MAX - 4]
1489 * BRIDGE @ [ECM_DB_IFACE_HEIRARCHY_MAX - 3]
1490 * VLAN @ [ECM_DB_IFACE_HEIRARCHY_MAX - 2]
1491 * PPPOE @ [ECM_DB_IFACE_HEIRARCHY_MAX - 1]
1492 * The value returned is (ECM_DB_IFACE_HEIRARCHY_MAX - 5)
1493 *
1494 * IMPORTANT: This function will return any known interfaces in the database, when interfaces do not exist in the database
1495 * they will be created and added automatically to the database.
1496 *
1497 * GGG TODO Make this function work for IPv6!!!!!!!!!!!!!!
1498 */
1499int32_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)
1500{
1501 char __attribute__((unused)) src_addr_str[40];
1502 char __attribute__((unused)) dest_addr_str[40];
1503 int protocol;
1504 ip_addr_t src_addr;
1505 ip_addr_t dest_addr;
1506 struct ecm_interface_route src_rt;
1507 struct ecm_interface_route dest_rt;
1508 struct dst_entry *src_dst;
1509 struct dst_entry *dest_dst;
1510 struct net_device *src_dev;
1511 struct net_device *dest_dev;
1512 char *src_dev_name;
1513 char *dest_dev_name;
1514 int32_t src_dev_type;
1515 int32_t dest_dev_type;
1516 int32_t current_interface_index;
1517
1518 /*
1519 * Get a big endian of the IPv4 address we have been given as our starting point.
1520 */
1521 protocol = packet_protocol;
1522 ECM_IP_ADDR_COPY(src_addr, packet_src_addr);
1523 ECM_IP_ADDR_COPY(dest_addr, packet_dest_addr);
1524 ecm_ip_addr_to_string(src_addr_str, src_addr);
1525 ecm_ip_addr_to_string(dest_addr_str, dest_addr);
1526 DEBUG_TRACE("Construct interface heirarchy for from src_addr: %s to dest_addr: %s, protocol: %d\n", src_addr_str, dest_addr_str, protocol);
1527
1528 /*
1529 * Begin by finding the interface to which we reach the given addresses
1530 */
1531 if (!ecm_interface_find_route_by_addr(src_addr, &src_rt)) {
1532 DEBUG_WARN("Construct interface heirarchy failed from src_addr: %s to dest_addr: %s, protocol: %d\n", src_addr_str, dest_addr_str, protocol);
1533 return ECM_DB_IFACE_HEIRARCHY_MAX;
1534 }
1535 if (!ecm_interface_find_route_by_addr(dest_addr, &dest_rt)) {
1536 ecm_interface_route_release(&src_rt);
1537 DEBUG_WARN("Construct interface heirarchy failed from src_addr: %s to dest_addr: %s, protocol: %d\n", src_addr_str, dest_addr_str, protocol);
1538 return ECM_DB_IFACE_HEIRARCHY_MAX;
1539 }
1540
1541 /*
1542 * Get the dst entries
1543 */
1544 src_dst = src_rt.dst;
1545 dest_dst = dest_rt.dst;
1546
1547 /*
1548 * Get device from the destination entries
1549 */
1550 src_dev = src_dst->dev;
1551 dev_hold(src_dev);
1552 src_dev_name = src_dev->name;
1553 src_dev_type = src_dev->type;
1554
1555 dest_dev = dest_dst->dev;
1556 dev_hold(dest_dev);
1557 dest_dev_name = dest_dev->name;
1558 dest_dev_type = dest_dev->type;
1559
1560 /*
1561 * Release route (we hold devices for ourselves)
1562 */
1563 ecm_interface_route_release(&src_rt);
1564 ecm_interface_route_release(&dest_rt);
1565
1566 /*
1567 * Iterate until we are done or get to the max number of interfaces we can record.
1568 * NOTE: current_interface_index tracks the position of the first interface position in interfaces[]
1569 * because we add from the end first_interface grows downwards.
1570 */
1571 current_interface_index = ECM_DB_IFACE_HEIRARCHY_MAX;
1572 while (current_interface_index > 0) {
1573 struct ecm_db_iface_instance *ii;
1574 struct net_device *next_dev;
1575
1576 /*
1577 * Get the ecm db interface instance for the device at hand
1578 */
1579 ii = ecm_interface_establish_and_ref(dest_dev);
1580
1581 /*
1582 * If the interface could not be established then we abort
1583 */
1584 if (!ii) {
1585 DEBUG_WARN("Failed to establish interface: %p, name: %s\n", dest_dev, dest_dev_name);
1586 dev_put(src_dev);
1587 dev_put(dest_dev);
1588
1589 /*
1590 * Release the interfaces heirarchy we constructed to this point.
1591 */
1592 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1593 return ECM_DB_IFACE_HEIRARCHY_MAX;
1594 }
1595
1596 /*
1597 * Record the interface instance into the interfaces[]
1598 */
1599 current_interface_index--;
1600 interfaces[current_interface_index] = ii;
1601
1602 /*
1603 * Now we have to figure out what the next device will be (in the transmission path) the skb
1604 * will use to emit to the destination address.
1605 */
1606 do {
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001607#ifdef ECM_INTERFACE_PPP_SUPPORT
Ben Menchaca84f36632014-02-28 20:57:38 +00001608 int channel_count;
1609 struct ppp_channel *ppp_chan[1];
1610 const struct ppp_channel_ops *ppp_chan_ops;
1611 int channel_protocol;
1612 struct pppoe_channel_ops *pppoe_chan_ops;
1613 struct pppoe_opt addressing;
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001614#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001615
1616 DEBUG_TRACE("Net device: %p is type: %d, name: %s\n", dest_dev, dest_dev_type, dest_dev_name);
1617 next_dev = NULL;
1618
1619 if (dest_dev_type == ARPHRD_ETHER) {
1620 /*
1621 * Ethernet - but what sub type?
1622 */
1623
1624 /*
1625 * VLAN?
1626 */
1627 if (is_vlan_dev(dest_dev)) {
1628 /*
1629 * VLAN master
1630 * No locking needed here, ASSUMPTION is that real_dev is held for as long as we have dev.
1631 */
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301632 next_dev = vlan_dev_real_dev(dest_dev);
Ben Menchaca84f36632014-02-28 20:57:38 +00001633 dev_hold(next_dev);
1634 DEBUG_TRACE("Net device: %p is VLAN, slave dev: %p (%s)\n",
1635 dest_dev, next_dev, next_dev->name);
1636 break;
1637 }
1638
1639 /*
1640 * BRIDGE?
1641 */
1642 if (ecm_front_end_is_bridge_device(dest_dev)) {
1643 /*
1644 * Bridge
1645 * Figure out which port device the skb will go to using the dest_addr.
1646 */
1647 bool on_link;
1648 ip_addr_t gw_addr;
1649 uint8_t mac_addr[ETH_ALEN];
1650 if (!ecm_interface_mac_addr_get(dest_addr, mac_addr, &on_link, gw_addr)) {
1651 /*
1652 * Possible ARP does not know the address yet
1653 */
1654 DEBUG_WARN("Unable to obtain MAC address for " ECM_IP_ADDR_DOT_FMT "\n", ECM_IP_ADDR_TO_DOT(dest_addr));
1655 dev_put(src_dev);
1656 dev_put(dest_dev);
1657
1658 /*
1659 * Release the interfaces heirarchy we constructed to this point.
1660 */
1661 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1662 return ECM_DB_IFACE_HEIRARCHY_MAX;
1663 }
1664 next_dev = br_port_dev_get(dest_dev, mac_addr);
1665 if (!next_dev) {
1666 DEBUG_WARN("Unable to obtain output port for: %pM\n", mac_addr);
1667 dev_put(src_dev);
1668 dev_put(dest_dev);
1669
1670 /*
1671 * Release the interfaces heirarchy we constructed to this point.
1672 */
1673 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1674 return ECM_DB_IFACE_HEIRARCHY_MAX;
1675 }
1676 DEBUG_TRACE("Net device: %p is BRIDGE, next_dev: %p (%s)\n", dest_dev, next_dev, next_dev->name);
1677 break;
1678 }
1679
1680 /*
1681 * LAG?
1682 */
1683 if (ecm_front_end_is_lag_master(dest_dev)) {
1684 /*
1685 * Link aggregation
1686 * Figure out which slave device of the link aggregation will be used to reach the destination.
1687 */
1688 bool src_on_link;
1689 bool dest_on_link;
1690 ip_addr_t src_gw_addr;
1691 ip_addr_t dest_gw_addr;
1692 uint32_t src_addr_32;
1693 uint32_t dest_addr_32;
1694 uint8_t src_mac_addr[ETH_ALEN];
1695 uint8_t dest_mac_addr[ETH_ALEN];
1696
1697 if (!ecm_interface_mac_addr_get(src_addr, src_mac_addr, &src_on_link, src_gw_addr)) {
1698 /*
1699 * Possible ARP does not know the address yet
1700 */
1701 DEBUG_WARN("Unable to obtain MAC address for " ECM_IP_ADDR_DOT_FMT "\n", ECM_IP_ADDR_TO_DOT(src_addr));
1702 dev_put(src_dev);
1703 dev_put(dest_dev);
1704
1705 /*
1706 * Release the interfaces heirarchy we constructed to this point.
1707 */
1708 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1709 return ECM_DB_IFACE_HEIRARCHY_MAX;
1710 }
1711 if (!ecm_interface_mac_addr_get(dest_addr, dest_mac_addr, &dest_on_link, dest_gw_addr)) {
1712 /*
1713 * Possible ARP does not know the address yet
1714 */
1715 DEBUG_WARN("Unable to obtain MAC address for " ECM_IP_ADDR_DOT_FMT "\n", ECM_IP_ADDR_TO_DOT(dest_addr));
1716 dev_put(src_dev);
1717 dev_put(dest_dev);
1718
1719 /*
1720 * Release the interfaces heirarchy we constructed to this point.
1721 */
1722 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1723 return ECM_DB_IFACE_HEIRARCHY_MAX;
1724 }
1725
1726 ECM_IP_ADDR_TO_HIN4_ADDR(src_addr_32, src_addr);
1727 ECM_IP_ADDR_TO_HIN4_ADDR(dest_addr_32, dest_addr);
1728
1729 next_dev = bond_get_tx_dev(NULL, src_mac_addr, dest_mac_addr, &src_addr_32, &dest_addr_32, (uint16_t)protocol, dest_dev);
1730 if (next_dev) {
1731 dev_hold(next_dev);
1732 } else {
1733 DEBUG_WARN("Unable to obtain LAG output slave device\n");
1734 dev_put(src_dev);
1735 dev_put(dest_dev);
1736
1737 /*
1738 * Release the interfaces heirarchy we constructed to this point.
1739 */
1740 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1741 return ECM_DB_IFACE_HEIRARCHY_MAX;
1742 }
1743
1744 DEBUG_TRACE("Net device: %p is LAG, slave dev: %p (%s)\n", dest_dev, next_dev, next_dev->name);
1745
1746 break;
1747 }
1748
1749 /*
1750 * ETHERNET!
1751 * Just plain ethernet it seems.
1752 */
1753 DEBUG_TRACE("Net device: %p is ETHERNET\n", dest_dev);
1754 break;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301755 }
Ben Menchaca84f36632014-02-28 20:57:38 +00001756
1757 /*
1758 * LOOPBACK?
1759 */
1760 if (dest_dev_type == ARPHRD_LOOPBACK) {
1761 DEBUG_TRACE("Net device: %p is LOOPBACK type: %d\n", dest_dev, dest_dev_type);
1762 break;
1763 }
1764
1765 /*
1766 * IPSEC?
1767 */
1768 if (dest_dev_type == ECM_ARPHRD_IPSEC_TUNNEL_TYPE) {
1769 DEBUG_TRACE("Net device: %p is IPSec tunnel type: %d\n", dest_dev, dest_dev_type);
1770 // GGG TODO Figure out the next device the tunnel is using...
1771 break;
1772 }
1773
1774 /*
1775 * SIT (6-in-4)?
1776 */
1777 if (dest_dev_type == ARPHRD_SIT) {
1778 DEBUG_TRACE("Net device: %p is SIT (6-in-4) type: %d\n", dest_dev, dest_dev_type);
1779 break;
1780 }
1781
1782 /*
1783 * IPIP6 Tunnel?
1784 */
1785 if (dest_dev_type == ARPHRD_TUNNEL6) {
1786 DEBUG_TRACE("Net device: %p is TUNIPIP6 type: %d\n", dest_dev, dest_dev_type);
1787 break;
1788 }
1789
1790 /*
1791 * If this is NOT PPP then it is unknown to the ecm and we cannot figure out it's next device.
1792 */
1793 if (dest_dev_type != ARPHRD_PPP) {
1794 DEBUG_TRACE("Net device: %p is UNKNOWN type: %d\n", dest_dev, dest_dev_type);
1795 break;
1796 }
1797
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001798#ifndef ECM_INTERFACE_PPP_SUPPORT
1799 DEBUG_TRACE("Net device: %p is UNKNOWN (PPP Unsupported) type: %d\n", dest_dev, dest_dev_type);
1800#else
Ben Menchaca84f36632014-02-28 20:57:38 +00001801 /*
1802 * PPP - but what is the channel type?
1803 * First: If this is multi-link then we do not support it
1804 */
1805 if (ppp_is_multilink(dest_dev) > 0) {
1806 DEBUG_TRACE("Net device: %p is MULTILINK PPP - Unknown to the ECM\n", dest_dev);
1807 break;
1808 }
1809
1810 DEBUG_TRACE("Net device: %p is PPP\n", dest_dev);
1811
1812 /*
1813 * Get the PPP channel and then enquire what kind of channel it is
1814 * NOTE: Not multilink so only one channel to get.
1815 */
1816 channel_count = ppp_hold_channels(dest_dev, ppp_chan, 1);
1817 if (channel_count != 1) {
1818 DEBUG_TRACE("Net device: %p PPP has %d channels - Unknown to the ECM\n",
1819 dest_dev, channel_count);
1820 break;
1821 }
1822
1823 /*
1824 * Get channel protocol type
1825 */
1826 ppp_chan_ops = ppp_chan[0]->ops;
1827 channel_protocol = ppp_chan_ops->get_channel_protocol(ppp_chan[0]);
1828 if (channel_protocol != PX_PROTO_OE) {
1829 DEBUG_TRACE("Net device: %p PPP channel protocol: %d - Unknown to the ECM\n",
1830 dest_dev, channel_protocol);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301831
Ben Menchaca84f36632014-02-28 20:57:38 +00001832 /*
1833 * Release the channel
1834 */
1835 ppp_release_channels(ppp_chan, 1);
1836
1837 break;
1838 }
1839
1840 /*
1841 * PPPoE channel
1842 */
1843 DEBUG_TRACE("Net device: %p PPP channel is PPPoE\n", dest_dev);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301844
Ben Menchaca84f36632014-02-28 20:57:38 +00001845 /*
1846 * Get PPPoE session information and the underlying device it is using.
1847 * NOTE: We know this is PPPoE so we can cast the ppp_chan_ops to pppoe_chan_ops and
1848 * use its channel specific methods.
1849 */
1850 pppoe_chan_ops = (struct pppoe_channel_ops *)ppp_chan_ops;
1851 pppoe_chan_ops->get_addressing(ppp_chan[0], &addressing);
1852
1853 /*
1854 * Copy the dev hold into this, we will release the hold later
1855 */
1856 next_dev = addressing.dev;
1857
1858 DEBUG_TRACE("Net device: %p, next device: %p (%s)\n", dest_dev, next_dev, next_dev->name);
1859
1860 /*
1861 * Release the channel. Note that next_dev is still (correctly) held.
1862 */
1863 ppp_release_channels(ppp_chan, 1);
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001864#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001865 } while (false);
1866
1867 /*
Gareth Williamsa11d4352014-05-14 18:25:49 +01001868 * No longer need dest_dev as it may become next_dev
Ben Menchaca84f36632014-02-28 20:57:38 +00001869 */
Ben Menchaca84f36632014-02-28 20:57:38 +00001870 dev_put(dest_dev);
1871
1872 /*
1873 * Check out the next_dev, if any
1874 */
1875 if (!next_dev) {
1876 int32_t i __attribute__((unused));
1877 DEBUG_INFO("Completed interface heirarchy construct with first interface @: %d\n", current_interface_index);
1878#if DEBUG_LEVEL > 1
1879 for (i = current_interface_index; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
1880 DEBUG_TRACE("\tInterface @ %d: %p, type: %d, name: %s\n",
1881 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])));
1882 }
1883#endif
Gareth Williamsa11d4352014-05-14 18:25:49 +01001884
1885 /*
1886 * Release src_dev now
1887 */
1888 dev_put(src_dev);
1889
Ben Menchaca84f36632014-02-28 20:57:38 +00001890 return current_interface_index;
1891 }
1892
Gareth Williamsa11d4352014-05-14 18:25:49 +01001893 /*
1894 * dest_dev becomes next_dev
1895 */
Ben Menchaca84f36632014-02-28 20:57:38 +00001896 dest_dev = next_dev;
1897 dest_dev_name = dest_dev->name;
1898 dest_dev_type = dest_dev->type;
1899 }
1900
1901 DEBUG_WARN("Too many interfaces: %d\n", current_interface_index);
1902 DEBUG_ASSERT(current_interface_index == 0, "Bad logic handling current_interface_index: %d\n", current_interface_index);
1903 dev_put(src_dev);
1904 dev_put(dest_dev);
1905
1906 /*
1907 * Release the interfaces heirarchy we constructed to this point.
1908 */
1909 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1910 return ECM_DB_IFACE_HEIRARCHY_MAX;
1911}
1912EXPORT_SYMBOL(ecm_interface_heirarchy_construct);
1913
1914/*
1915 * ecm_interface_regenerate_connections()
1916 * Cause regeneration of all connections that are using the specified interface.
1917 */
1918static void ecm_interface_regenerate_connections(struct ecm_db_iface_instance *ii)
1919{
1920 struct ecm_db_connection_instance *ci;
1921
1922 DEBUG_TRACE("Regenerate connections using interface: %p\n", ii);
1923
1924 /*
1925 * Iterate the connections of this interface and cause each one to be re-generated.
1926 * GGG TODO NOTE: If this proves slow (need metrics here) we could just regenerate the "lot" with one very simple call.
1927 * 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
1928 * but at the cost of performance.
1929 */
1930 DEBUG_TRACE("%p: Regenerate 'from' connections\n", ii);
1931 ci = ecm_db_iface_connections_from_get_and_ref_first(ii);
1932 while (ci) {
1933 struct ecm_db_connection_instance *cin;
1934 cin = ecm_db_connection_iface_from_get_and_ref_next(ci);
1935
1936 DEBUG_TRACE("%p: Regenerate: %p", ii, ci);
1937 ecm_db_connection_classifier_generation_change(ci);
1938 ecm_db_connection_deref(ci);
1939 ci = cin;
1940 }
1941
1942 DEBUG_TRACE("%p: Regenerate 'to' connections\n", ii);
1943 ci = ecm_db_iface_connections_to_get_and_ref_first(ii);
1944 while (ci) {
1945 struct ecm_db_connection_instance *cin;
1946 cin = ecm_db_connection_iface_to_get_and_ref_next(ci);
1947
1948 DEBUG_TRACE("%p: Regenerate: %p", ii, ci);
1949 ecm_db_connection_classifier_generation_change(ci);
1950 ecm_db_connection_deref(ci);
1951 ci = cin;
1952 }
1953
1954 DEBUG_TRACE("%p: Regenerate 'from_nat' connections\n", ii);
1955 ci = ecm_db_iface_connections_nat_from_get_and_ref_first(ii);
1956 while (ci) {
1957 struct ecm_db_connection_instance *cin;
1958 cin = ecm_db_connection_iface_nat_from_get_and_ref_next(ci);
1959
1960 DEBUG_TRACE("%p: Regenerate: %p", ii, ci);
1961 ecm_db_connection_classifier_generation_change(ci);
1962 ecm_db_connection_deref(ci);
1963 ci = cin;
1964 }
1965
1966 DEBUG_TRACE("%p: Regenerate 'to_nat' connections\n", ii);
1967 ci = ecm_db_iface_connections_nat_to_get_and_ref_first(ii);
1968 while (ci) {
1969 struct ecm_db_connection_instance *cin;
1970 cin = ecm_db_connection_iface_nat_to_get_and_ref_next(ci);
1971
1972 DEBUG_TRACE("%p: Regenerate: %p", ii, ci);
1973 ecm_db_connection_classifier_generation_change(ci);
1974 ecm_db_connection_deref(ci);
1975 ci = cin;
1976 }
1977
1978 DEBUG_TRACE("%p: Regenerate COMPLETE\n", ii);
1979}
1980
1981/*
1982 * ecm_interface_dev_regenerate_connections()
1983 * Cause regeneration of all connections that are using the specified interface.
1984 */
1985static void ecm_interface_dev_regenerate_connections(struct net_device *dev)
1986{
1987 struct ecm_db_iface_instance *ii;
1988
1989 DEBUG_INFO("Regenerate connections for: %p (%s)\n", dev, dev->name);
1990
1991 /*
1992 * Establish the interface for the given device.
1993 * NOTE: The cute thing here is even if dev is previously unknown to us this will create an interface instance
1994 * 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.
1995 * However if the interface is known to us then we will get it returned by this function and process it accordingly.
1996 */
1997 ii = ecm_interface_establish_and_ref(dev);
1998 if (!ii) {
1999 DEBUG_WARN("%p: No interface instance could be established for this dev\n", dev);
2000 return;
2001 }
2002 ecm_interface_regenerate_connections(ii);
2003 DEBUG_TRACE("%p: Regenerate for %p: COMPLETE\n", dev, ii);
2004 ecm_db_iface_deref(ii);
2005}
2006
2007/*
2008 * ecm_interface_mtu_change()
2009 * MTU of interface has changed
2010 */
2011static void ecm_interface_mtu_change(struct net_device *dev)
2012{
2013 int mtu;
2014 struct ecm_db_iface_instance *ii;
2015
2016 mtu = dev->mtu;
2017 DEBUG_INFO("%p (%s): MTU Change to: %d\n", dev, dev->name, mtu);
2018
2019 /*
2020 * Establish the interface for the given device.
2021 */
2022 ii = ecm_interface_establish_and_ref(dev);
2023 if (!ii) {
2024 DEBUG_WARN("%p: No interface instance could be established for this dev\n", dev);
2025 return;
2026 }
2027
2028 /*
2029 * Change the mtu
2030 */
2031 ecm_db_iface_mtu_reset(ii, mtu);
2032 DEBUG_TRACE("%p (%s): MTU Changed to: %d\n", dev, dev->name, mtu);
2033 ecm_interface_regenerate_connections(ii);
2034 DEBUG_TRACE("%p: Regenerate for %p: COMPLETE\n", dev, ii);
2035 ecm_db_iface_deref(ii);
2036}
2037
2038/*
2039 * ecm_interface_netdev_notifier_callback()
2040 * Netdevice notifier callback to inform us of change of state of a netdevice
2041 */
2042static int ecm_interface_netdev_notifier_callback(struct notifier_block *this, unsigned long event, void *ptr)
2043{
2044 struct net_device *dev __attribute__ ((unused)) = (struct net_device *)ptr;
2045
2046 DEBUG_INFO("Net device notifier for: %p, name: %s, event: %lx\n", dev, dev->name, event);
2047
2048 switch (event) {
2049 case NETDEV_DOWN:
2050 DEBUG_INFO("Net device: %p, DOWN\n", dev);
2051 ecm_interface_dev_regenerate_connections(dev);
2052 break;
2053
2054 case NETDEV_CHANGE:
2055 DEBUG_INFO("Net device: %p, CHANGE\n", dev);
2056 if (!netif_carrier_ok(dev)) {
2057 DEBUG_INFO("Net device: %p, CARRIER BAD\n", dev);
2058 ecm_interface_dev_regenerate_connections(dev);
2059 }
2060 break;
2061
2062 case NETDEV_CHANGEMTU:
2063 DEBUG_INFO("Net device: %p, MTU CHANGE\n", dev);
2064 ecm_interface_mtu_change(dev);
2065 break;
2066
2067 default:
2068 DEBUG_TRACE("Net device: %p, UNHANDLED: %lx\n", dev, event);
2069 break;
2070 }
2071
2072 return NOTIFY_DONE;
2073}
2074
2075/*
2076 * struct notifier_block ecm_interface_netdev_notifier
2077 * Registration for net device changes of state.
2078 */
2079static struct notifier_block ecm_interface_netdev_notifier __read_mostly = {
2080 .notifier_call = ecm_interface_netdev_notifier_callback,
2081};
2082
2083/*
2084 * ecm_interface_get_terminate()
2085 */
2086static ssize_t ecm_interface_get_terminate(struct sys_device *dev,
2087 struct sysdev_attribute *attr,
2088 char *buf)
2089{
2090 ssize_t count;
2091 unsigned int n;
2092
2093 spin_lock_bh(&ecm_interface_lock);
2094 n = ecm_interface_terminate_pending;
2095 spin_unlock_bh(&ecm_interface_lock);
2096 count = snprintf(buf, (ssize_t)PAGE_SIZE, "%u\n", n);
2097 return count;
2098}
2099
2100/*
2101 * ecm_interface_set_terminate()
2102 * Writing anything to this 'file' will cause the default classifier to terminate
2103 */
2104static ssize_t ecm_interface_set_terminate(struct sys_device *dev,
2105 struct sysdev_attribute *attr,
2106 const char *buf, size_t count)
2107{
2108 DEBUG_INFO("Terminate\n");
2109
2110 /*
2111 * Are we already signalled to terminate?
2112 */
2113 spin_lock_bh(&ecm_interface_lock);
2114 if (ecm_interface_terminate_pending) {
2115 spin_unlock_bh(&ecm_interface_lock);
2116 return 0;
2117 }
2118
2119 ecm_interface_terminate_pending = true;
2120 ecm_interface_thread_refs--;
2121 DEBUG_ASSERT(ecm_interface_thread_refs >= 0, "Thread ref wrap %d\n", ecm_interface_thread_refs);
2122 wake_up_process(ecm_interface_thread);
2123 spin_unlock_bh(&ecm_interface_lock);
2124 return count;
2125}
2126
2127/*
2128 * ecm_interface_get_stop()
2129 */
2130static ssize_t ecm_interface_get_stop(struct sys_device *dev,
2131 struct sysdev_attribute *attr,
2132 char *buf)
2133{
2134 ssize_t count;
2135 int num;
2136
2137 /*
2138 * Operate under our locks
2139 */
2140 spin_lock_bh(&ecm_interface_lock);
2141 num = ecm_interface_stopped;
2142 spin_unlock_bh(&ecm_interface_lock);
2143
2144 count = snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", num);
2145 return count;
2146}
2147
2148/*
2149 * ecm_interface_set_stop()
2150 */
2151static ssize_t ecm_interface_set_stop(struct sys_device *dev,
2152 struct sysdev_attribute *attr,
2153 const char *buf, size_t count)
2154{
2155 char num_buf[12];
2156 int num;
2157
2158 /*
2159 * Get the number from buf into a properly z-termed number buffer
2160 */
2161 if (count > 11) {
2162 return 0;
2163 }
2164 memcpy(num_buf, buf, count);
2165 num_buf[count] = '\0';
2166 sscanf(num_buf, "%d", &num);
2167 DEBUG_TRACE("ecm_interface_stop = %d\n", num);
2168
2169 /*
2170 * Operate under our locks and stop further processing of packets
2171 */
2172 spin_lock_bh(&ecm_interface_lock);
2173 ecm_interface_stopped = num;
2174 spin_unlock_bh(&ecm_interface_lock);
2175
2176 return count;
2177}
2178
2179/*
2180 * SysFS attributes for the default classifier itself.
2181 */
2182static SYSDEV_ATTR(terminate, 0644, ecm_interface_get_terminate, ecm_interface_set_terminate);
2183static SYSDEV_ATTR(stop, 0644, ecm_interface_get_stop, ecm_interface_set_stop);
2184
2185/*
2186 * SysFS class of the ubicom default classifier
2187 * SysFS control points can be found at /sys/devices/system/ecm_front_end/ecm_front_endX/
2188 */
2189static struct sysdev_class ecm_interface_sysclass = {
2190 .name = "ecm_interface",
2191};
2192
2193/*
2194 * ecm_interface_thread_fn()
2195 * A thread to handle tasks that can only be done in thread context.
2196 */
2197static int ecm_interface_thread_fn(void *arg)
2198{
2199 int result;
2200
2201 DEBUG_INFO("Thread start\n");
2202
2203 /*
2204 * Get reference to this module - we release it when the thread exits
2205 */
2206 if (!try_module_get(THIS_MODULE)) {
2207 return -EINVAL;
2208 }
2209
2210 /*
2211 * Register the sysfs class
2212 */
2213 result = sysdev_class_register(&ecm_interface_sysclass);
2214 if (result) {
2215 DEBUG_ERROR("Failed to register SysFS class %d\n", result);
2216 goto task_cleanup_1;
2217 }
2218
2219 /*
2220 * Register SYSFS device control
2221 */
2222 memset(&ecm_interface_sys_dev, 0, sizeof(ecm_interface_sys_dev));
2223 ecm_interface_sys_dev.id = 0;
2224 ecm_interface_sys_dev.cls = &ecm_interface_sysclass;
2225 result = sysdev_register(&ecm_interface_sys_dev);
2226 if (result) {
2227 DEBUG_ERROR("Failed to register SysFS device %d\n", result);
2228 goto task_cleanup_2;
2229 }
2230
2231 /*
2232 * Create files, one for each parameter supported by this module
2233 */
2234 result = sysdev_create_file(&ecm_interface_sys_dev, &attr_terminate);
2235 if (result) {
2236 DEBUG_ERROR("Failed to register terminate file %d\n", result);
2237 goto task_cleanup_3;
2238 }
2239
2240 result = sysdev_create_file(&ecm_interface_sys_dev, &attr_stop);
2241 if (result) {
2242 DEBUG_ERROR("Failed to register stop file %d\n", result);
2243 goto task_cleanup_4;
2244 }
2245
2246 result = register_netdevice_notifier(&ecm_interface_netdev_notifier);
2247 if (result != 0) {
2248 DEBUG_ERROR("Failed to register netdevice notifier %d\n", result);
2249 goto task_cleanup_5;
2250 }
2251
2252 /*
2253 * Allow wakeup signals
2254 */
2255 allow_signal(SIGCONT);
2256 set_current_state(TASK_INTERRUPTIBLE);
2257
2258 spin_lock_bh(&ecm_interface_lock);
2259
2260 /*
2261 * Set thread refs to 1 - user must terminate us now.
2262 */
2263 ecm_interface_thread_refs = 1;
2264
2265 while (ecm_interface_thread_refs) {
2266 /*
2267 * Sleep and wait for an instruction
2268 */
2269 spin_unlock_bh(&ecm_interface_lock);
2270 DEBUG_TRACE("ecm_interface sleep\n");
2271 schedule();
2272 set_current_state(TASK_INTERRUPTIBLE);
2273 spin_lock_bh(&ecm_interface_lock);
2274 }
2275 DEBUG_INFO("ecm_interface terminate\n");
2276 DEBUG_ASSERT(ecm_interface_terminate_pending, "User has not requested terminate\n");
2277 spin_unlock_bh(&ecm_interface_lock);
2278
2279 result = 0;
2280
2281 unregister_netdevice_notifier(&ecm_interface_netdev_notifier);
2282task_cleanup_5:
2283 sysdev_remove_file(&ecm_interface_sys_dev, &attr_stop);
2284task_cleanup_4:
2285 sysdev_remove_file(&ecm_interface_sys_dev, &attr_terminate);
2286task_cleanup_3:
2287 sysdev_unregister(&ecm_interface_sys_dev);
2288task_cleanup_2:
2289 sysdev_class_unregister(&ecm_interface_sysclass);
2290task_cleanup_1:
2291
2292 module_put(THIS_MODULE);
2293 return result;
2294}
2295
2296/*
2297 * ecm_interface_init()
2298 */
2299static int __init ecm_interface_init(void)
2300{
2301 DEBUG_INFO("ECM Interface init\n");
2302
2303 /*
2304 * Initialise our global lock
2305 */
2306 spin_lock_init(&ecm_interface_lock);
2307
2308 /*
2309 * Create a thread to handle the start/stop of the database.
2310 * NOTE: We use a thread as some things we need to do cannot be done in this context
2311 */
2312 ecm_interface_thread = kthread_create(ecm_interface_thread_fn, NULL, "%s", "ecm_interface");
2313 if (!ecm_interface_thread) {
2314 return -EINVAL;
2315 }
2316 wake_up_process(ecm_interface_thread);
2317 return 0;
2318}
2319
2320/*
2321 * ecm_interface_exit()
2322 */
2323static void __exit ecm_interface_exit(void)
2324{
2325 DEBUG_INFO("ECM Interface exit\n");
2326 DEBUG_ASSERT(!ecm_interface_thread_refs, "Thread has refs %d\n", ecm_interface_thread_refs);
2327}
2328
2329module_init(ecm_interface_init)
2330module_exit(ecm_interface_exit)
2331
2332MODULE_AUTHOR("Qualcomm Atheros, Inc.");
2333MODULE_DESCRIPTION("ECM Interface");
2334#ifdef MODULE_LICENSE
2335MODULE_LICENSE("Dual BSD/GPL");
2336#endif
2337