blob: fdc3f26db0c6f388076c5c7b3cd8954a901a9c95 [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 */
Ben Menchaca84f36632014-02-28 20:57:38 +0000106
107/*
108 * ecm_interface_mac_addr_get_ipv6()
109 * Return mac for an IPv6 address
110 *
111 * GGG TODO Need to make sure this also works for local IP addresses too.
112 */
113static bool ecm_interface_mac_addr_get_ipv6(ip_addr_t addr, uint8_t *mac_addr, bool *on_link, ip_addr_t gw_addr)
114{
115 struct in6_addr daddr;
116 struct ecm_interface_route ecm_rt;
117 struct neighbour *neigh;
118 struct rt6_info *rt;
119 struct dst_entry *dst;
120
121 /*
122 * Get the MAC address that corresponds to IP address given.
123 * We look up the rt6_info entries and, from its neighbour structure, obtain the hardware address.
124 * This means we will also work if the neighbours are routers too.
125 */
126 ECM_IP_ADDR_TO_NIN6_ADDR(daddr, addr);
127 if (!ecm_interface_find_route_by_addr(addr, &ecm_rt)) {
128 return false;
129 }
130 DEBUG_ASSERT(!ecm_rt.v4_route, "Did not locate a v6 route!\n");
131
132 /*
133 * Is this destination on link or off-link via a gateway?
134 */
135 rt = ecm_rt.rt.rtv6;
136 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)) {
137 *on_link = false;
138 ECM_NIN6_ADDR_TO_IP_ADDR(gw_addr, rt->rt6i_gateway)
139 } else {
140 *on_link = true;
141 }
142
143 rcu_read_lock();
144 dst = ecm_rt.dst;
145 neigh = dst_get_neighbour_noref(dst);
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700146 if (neigh) {
147 neigh_hold(neigh);
148 } else {
149 neigh = neigh_lookup(&nd_tbl, &daddr, dst->dev);
150 }
Ben Menchaca84f36632014-02-28 20:57:38 +0000151 if (!neigh) {
152 rcu_read_unlock();
153 ecm_interface_route_release(&ecm_rt);
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700154 DEBUG_WARN("No neigh reference\n");
Ben Menchaca84f36632014-02-28 20:57:38 +0000155 return false;
156 }
157 if (!(neigh->nud_state & NUD_VALID)) {
158 rcu_read_unlock();
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700159 neigh_release(neigh);
Ben Menchaca84f36632014-02-28 20:57:38 +0000160 ecm_interface_route_release(&ecm_rt);
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700161 DEBUG_WARN("NUD invalid\n");
Ben Menchaca84f36632014-02-28 20:57:38 +0000162 return false;
163 }
164 if (!neigh->dev) {
165 rcu_read_unlock();
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700166 neigh_release(neigh);
Ben Menchaca84f36632014-02-28 20:57:38 +0000167 ecm_interface_route_release(&ecm_rt);
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700168 DEBUG_WARN("Neigh dev invalid\n");
Ben Menchaca84f36632014-02-28 20:57:38 +0000169 return false;
170 }
171
172 /*
173 * If neigh->dev is a loopback then addr is a local address in which case we take the MAC from given device
174 */
175 if (neigh->dev->flags & IFF_LOOPBACK) {
176 // GGG TODO Create an equivalent logic to that for ipv4, maybe need to create an ip6_dev_find()?
177 DEBUG_TRACE("local address " ECM_IP_ADDR_OCTAL_FMT " (found loopback)\n", ECM_IP_ADDR_TO_OCTAL(addr));
178 memset(mac_addr, 0, 6);
179 } else {
180 memcpy(mac_addr, neigh->ha, 6);
181 }
182 rcu_read_unlock();
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700183 neigh_release(neigh);
Ben Menchaca84f36632014-02-28 20:57:38 +0000184 ecm_interface_route_release(&ecm_rt);
185
186 DEBUG_TRACE(ECM_IP_ADDR_OCTAL_FMT " maps to %pM\n", ECM_IP_ADDR_TO_OCTAL(addr), mac_addr);
187 return true;
188}
189
190/*
191 * ecm_interface_mac_addr_get_ipv4()
192 * Return mac for an IPv4 address
193 */
194static bool ecm_interface_mac_addr_get_ipv4(ip_addr_t addr, uint8_t *mac_addr, bool *on_link, ip_addr_t gw_addr)
195{
196 struct neighbour *neigh;
197 struct ecm_interface_route ecm_rt;
198 struct rtable *rt;
199 struct dst_entry *dst;
200 __be32 ipv4_addr;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530201
Ben Menchaca84f36632014-02-28 20:57:38 +0000202 /*
203 * Get the MAC address that corresponds to IP address given.
204 * We look up the rtable entries and, from its neighbour structure, obtain the hardware address.
205 * This means we will also work if the neighbours are routers too.
206 * We also locate the MAC if the address is a local host address.
207 */
208 ECM_IP_ADDR_TO_NIN4_ADDR(ipv4_addr, addr);
209 if (!ecm_interface_find_route_by_addr(addr, &ecm_rt)) {
210 return false;
211 }
212 DEBUG_ASSERT(ecm_rt.v4_route, "Did not locate a v4 route!\n");
213
214 /*
215 * Is this destination on link or off-link via a gateway?
216 */
217 rt = ecm_rt.rt.rtv4;
218 if ((rt->rt_dst != rt->rt_gateway) || (rt->rt_flags & RTF_GATEWAY)) {
219 *on_link = false;
220 ECM_NIN4_ADDR_TO_IP_ADDR(gw_addr, rt->rt_gateway)
221 } else {
222 *on_link = true;
223 }
224
225 /*
226 * Get the neighbour entry for the address
227 */
228 rcu_read_lock();
229 dst = ecm_rt.dst;
230 neigh = dst_get_neighbour_noref(dst);
231 if (neigh) {
232 neigh_hold(neigh);
233 } else {
234 neigh = neigh_lookup(&arp_tbl, &ipv4_addr, dst->dev);
235 }
236 if (!neigh) {
237 rcu_read_unlock();
238 ecm_interface_route_release(&ecm_rt);
239 return false;
240 }
241 if (!(neigh->nud_state & NUD_VALID)) {
242 rcu_read_unlock();
243 neigh_release(neigh);
244 ecm_interface_route_release(&ecm_rt);
245 return false;
246 }
247 if (!neigh->dev) {
248 rcu_read_unlock();
249 neigh_release(neigh);
250 ecm_interface_route_release(&ecm_rt);
251 return false;
252 }
253
254 /*
255 * If the device is loopback this will be because the address is a local address
256 * In this case locate the device that has this local address and get its mac.
257 */
258 if (neigh->dev->type == ARPHRD_LOOPBACK) {
259 struct net_device *dev;
260
261 DEBUG_TRACE("%pI4 finds loopback device, dev: %p (%s)\n", &ipv4_addr, neigh->dev, neigh->dev->name);
262 rcu_read_unlock();
263 neigh_release(neigh);
264 ecm_interface_route_release(&ecm_rt);
265
266 /*
267 * Lookup the device that has this IP address assigned
268 */
269 dev = ip_dev_find(&init_net, ipv4_addr);
270 if (!dev) {
271 DEBUG_WARN("Unable to locate dev for: %pI4\n", &ipv4_addr);
272 return false;
273 }
274 memcpy(mac_addr, dev->dev_addr, (size_t)dev->addr_len);
275 DEBUG_TRACE("is local addr: %pI4, mac: %pM, dev ifindex: %d, dev: %p (%s), dev_type: %d\n",
276 &ipv4_addr, mac_addr, dev->ifindex, dev, dev->name, dev->type);
277 dev_put(dev);
278 return true;
279 }
280
281 if (!(neigh->dev->flags & IFF_NOARP)) {
282 memcpy(mac_addr, neigh->ha, (size_t)neigh->dev->addr_len);
283 } else {
284 DEBUG_TRACE("non-arp device: %p (%s, type: %d) to reach %pI4\n", neigh->dev, neigh->dev->name, neigh->dev->type, &ipv4_addr);
285 memset(mac_addr, 0, 6);
286 }
287 DEBUG_TRACE("addr: %pI4, mac: %pM, iif: %d, neigh dev ifindex: %d, dev: %p (%s), dev_type: %d\n",
288 &ipv4_addr, mac_addr, rt->rt_iif, neigh->dev->ifindex, neigh->dev, neigh->dev->name, neigh->dev->type);
289
290 rcu_read_unlock();
291 neigh_release(neigh);
292 ecm_interface_route_release(&ecm_rt);
293 return true;
294}
295
296/*
297 * ecm_interface_mac_addr_get()
298 * Return the mac address for the given IP address. Returns false on failure.
299 *
300 * 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.
301 *
302 * GGG TODO Make this function work for IPv6!!!!!!!!!!!!!!
303 */
304bool ecm_interface_mac_addr_get(ip_addr_t addr, uint8_t *mac_addr, bool *on_link, ip_addr_t gw_addr)
305{
306 if (ECM_IP_ADDR_IS_V4(addr)) {
307 return ecm_interface_mac_addr_get_ipv4(addr, mac_addr, on_link, gw_addr);
308 }
309
310 return ecm_interface_mac_addr_get_ipv6(addr, mac_addr, on_link, gw_addr);
311}
312EXPORT_SYMBOL(ecm_interface_mac_addr_get);
313
314/*
315 * ecm_interface_addr_find_route_by_addr_ipv4()
316 * Return the route for the given IP address. Returns NULL on failure.
317 */
318static bool ecm_interface_find_route_by_addr_ipv4(ip_addr_t addr, struct ecm_interface_route *ecm_rt)
319{
320 __be32 be_addr;
321
322 /*
323 * Get a route to the given IP address, this will allow us to also find the interface
324 * it is using to communicate with that IP address.
325 */
326 ECM_IP_ADDR_TO_NIN4_ADDR(be_addr, addr);
327 ecm_rt->rt.rtv4 = ip_route_output(&init_net, be_addr, 0, 0, 0);
328 if (IS_ERR(ecm_rt->rt.rtv4)) {
329 DEBUG_TRACE("No output route to: %pI4n\n", &be_addr);
330 return false;
331 }
332 DEBUG_TRACE("Output route to: %pI4n is: %p\n", &be_addr, ecm_rt->rt.rtv4);
333 ecm_rt->dst = (struct dst_entry *)ecm_rt->rt.rtv4;
334 ecm_rt->v4_route = true;
335 return true;
336}
337
338/*
339 * ecm_interface_addr_find_route_by_addr_ipv6()
340 * Return the route for the given IP address. Returns NULL on failure.
341 */
342static bool ecm_interface_find_route_by_addr_ipv6(ip_addr_t addr, struct ecm_interface_route *ecm_rt)
343{
344 struct in6_addr naddr;
345
346 ECM_IP_ADDR_TO_NIN6_ADDR(naddr, addr);
347
348 /*
349 * Get a route to the given IP address, this will allow us to also find the interface
350 * it is using to communicate with that IP address.
351 */
352 ecm_rt->rt.rtv6 = rt6_lookup(&init_net, &naddr, NULL, 0, 0);
353 if (!ecm_rt->rt.rtv6) {
354 DEBUG_TRACE("No output route to: " ECM_IP_ADDR_OCTAL_FMT "\n", ECM_IP_ADDR_TO_OCTAL(addr));
355 return NULL;
356 }
357 DEBUG_TRACE("Output route to: " ECM_IP_ADDR_OCTAL_FMT " is: %p\n", ECM_IP_ADDR_TO_OCTAL(addr), ecm_rt->rt.rtv6);
358 ecm_rt->dst = (struct dst_entry *)ecm_rt->rt.rtv6;
359 ecm_rt->v4_route = false;
360 return true;
361}
362
363/*
364 * ecm_interface_addr_find_route_by_addr()
365 * Return the route (in the given parameter) for the given IP address. Returns false on failure.
366 *
367 * Route is the device on which the addr is reachable, which may be loopback for local addresses.
368 *
369 * Returns true if the route was able to be located. The route must be released using ecm_interface_route_release().
370 */
371bool ecm_interface_find_route_by_addr(ip_addr_t addr, struct ecm_interface_route *ecm_rt)
372{
373 char __attribute__((unused)) addr_str[40];
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530374
Ben Menchaca84f36632014-02-28 20:57:38 +0000375 ecm_ip_addr_to_string(addr_str, addr);
376 DEBUG_TRACE("Locate route to: %s\n", addr_str);
377
378 if (ECM_IP_ADDR_IS_V4(addr)) {
379 return ecm_interface_find_route_by_addr_ipv4(addr, ecm_rt);
380 }
381
382 return ecm_interface_find_route_by_addr_ipv6(addr, ecm_rt);
383}
384EXPORT_SYMBOL(ecm_interface_find_route_by_addr);
385
386/*
387 * ecm_interface_route_release()
388 * Release an ecm route
389 */
390void ecm_interface_route_release(struct ecm_interface_route *rt)
391{
392 dst_release(rt->dst);
393}
394EXPORT_SYMBOL(ecm_interface_route_release);
395
396/*
Ben Menchaca84f36632014-02-28 20:57:38 +0000397 * ecm_interface_vlan_interface_establish()
398 * Returns a reference to a iface of the VLAN type, possibly creating one if necessary.
399 * Returns NULL on failure or a reference to interface.
400 */
401static struct ecm_db_iface_instance *ecm_interface_vlan_interface_establish(struct ecm_db_interface_info_vlan *type_info,
402 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
403{
404 struct ecm_db_iface_instance *nii;
405 struct ecm_db_iface_instance *ii;
406
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530407 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",
408 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 +0000409
410 /*
411 * Locate the iface
412 */
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530413 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 +0000414 if (ii) {
415 DEBUG_TRACE("%p: iface established\n", ii);
416 return ii;
417 }
418
419 /*
420 * No iface - create one
421 */
422 nii = ecm_db_iface_alloc();
423 if (!nii) {
424 DEBUG_WARN("Failed to establish iface\n");
425 return NULL;
426 }
427
428 /*
429 * Add iface into the database, atomically to avoid races creating the same thing
430 */
431 spin_lock_bh(&ecm_interface_lock);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530432 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 +0000433 if (ii) {
434 spin_unlock_bh(&ecm_interface_lock);
435 ecm_db_iface_deref(nii);
436 return ii;
437 }
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530438 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 -0500439 mtu, dev_interface_num, nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000440 spin_unlock_bh(&ecm_interface_lock);
441
442 DEBUG_TRACE("%p: vlan iface established\n", nii);
443 return nii;
444}
445
446/*
447 * ecm_interface_bridge_interface_establish()
448 * Returns a reference to a iface of the BRIDGE type, possibly creating one if necessary.
449 * Returns NULL on failure or a reference to interface.
450 */
451static struct ecm_db_iface_instance *ecm_interface_bridge_interface_establish(struct ecm_db_interface_info_bridge *type_info,
452 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
453{
454 struct ecm_db_iface_instance *nii;
455 struct ecm_db_iface_instance *ii;
456
457 DEBUG_INFO("Establish BRIDGE iface: %s with address: %pM, MTU: %d, if num: %d, nss if id: %d\n",
458 dev_name, type_info->address, mtu, dev_interface_num, nss_interface_num);
459
460 /*
461 * Locate the iface
462 */
463 ii = ecm_db_iface_find_and_ref_bridge(type_info->address);
464 if (ii) {
465 DEBUG_TRACE("%p: iface established\n", ii);
466 return ii;
467 }
468
469 /*
470 * No iface - create one
471 */
472 nii = ecm_db_iface_alloc();
473 if (!nii) {
474 DEBUG_WARN("Failed to establish iface\n");
475 return NULL;
476 }
477
478 /*
479 * Add iface into the database, atomically to avoid races creating the same thing
480 */
481 spin_lock_bh(&ecm_interface_lock);
482 ii = ecm_db_iface_find_and_ref_bridge(type_info->address);
483 if (ii) {
484 spin_unlock_bh(&ecm_interface_lock);
485 ecm_db_iface_deref(nii);
486 return ii;
487 }
488 ecm_db_iface_add_bridge(nii, type_info->address, dev_name,
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500489 mtu, dev_interface_num, nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000490 spin_unlock_bh(&ecm_interface_lock);
491
492 DEBUG_TRACE("%p: bridge iface established\n", nii);
493 return nii;
494}
495
496/*
497 * ecm_interface_lag_interface_establish()
498 * Returns a reference to a iface of the LAG type, possibly creating one if necessary.
499 * Returns NULL on failure or a reference to interface.
500 */
501static struct ecm_db_iface_instance *ecm_interface_lag_interface_establish(struct ecm_db_interface_info_lag *type_info,
502 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
503{
504 struct ecm_db_iface_instance *nii;
505 struct ecm_db_iface_instance *ii;
506
507 DEBUG_INFO("Establish LAG iface: %s with address: %pM, MTU: %d, if num: %d, nss if id: %d\n",
508 dev_name, type_info->address, mtu, dev_interface_num, nss_interface_num);
509
510 /*
511 * Locate the iface
512 */
513 ii = ecm_db_iface_find_and_ref_lag(type_info->address);
514 if (ii) {
515 DEBUG_TRACE("%p: iface established\n", ii);
516 return ii;
517 }
518
519 /*
520 * No iface - create one
521 */
522 nii = ecm_db_iface_alloc();
523 if (!nii) {
524 DEBUG_WARN("Failed to establish iface\n");
525 return NULL;
526 }
527
528 /*
529 * Add iface into the database, atomically to avoid races creating the same thing
530 */
531 spin_lock_bh(&ecm_interface_lock);
532 ii = ecm_db_iface_find_and_ref_lag(type_info->address);
533 if (ii) {
534 spin_unlock_bh(&ecm_interface_lock);
535 ecm_db_iface_deref(nii);
536 return ii;
537 }
538 ecm_db_iface_add_lag(nii, type_info->address, dev_name,
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500539 mtu, dev_interface_num, nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000540 spin_unlock_bh(&ecm_interface_lock);
541
542 DEBUG_TRACE("%p: lag iface established\n", nii);
543 return nii;
544}
545
546/*
547 * ecm_interface_ethernet_interface_establish()
548 * Returns a reference to a iface of the ETHERNET type, possibly creating one if necessary.
549 * Returns NULL on failure or a reference to interface.
550 */
551static struct ecm_db_iface_instance *ecm_interface_ethernet_interface_establish(struct ecm_db_interface_info_ethernet *type_info,
552 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
553{
554 struct ecm_db_iface_instance *nii;
555 struct ecm_db_iface_instance *ii;
556
557 DEBUG_INFO("Establish ETHERNET iface: %s with address: %pM, MTU: %d, if num: %d, nss if id: %d\n",
558 dev_name, type_info->address, mtu, dev_interface_num, nss_interface_num);
559
560 /*
561 * Locate the iface
562 */
563 ii = ecm_db_iface_find_and_ref_ethernet(type_info->address);
564 if (ii) {
565 DEBUG_TRACE("%p: iface established\n", ii);
566 return ii;
567 }
568
569 /*
570 * No iface - create one
571 */
572 nii = ecm_db_iface_alloc();
573 if (!nii) {
574 DEBUG_WARN("Failed to establish iface\n");
575 return NULL;
576 }
577
578 /*
579 * Add iface into the database, atomically to avoid races creating the same thing
580 */
581 spin_lock_bh(&ecm_interface_lock);
582 ii = ecm_db_iface_find_and_ref_ethernet(type_info->address);
583 if (ii) {
584 spin_unlock_bh(&ecm_interface_lock);
585 ecm_db_iface_deref(nii);
586 return ii;
587 }
588 ecm_db_iface_add_ethernet(nii, type_info->address, dev_name,
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500589 mtu, dev_interface_num, nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000590 spin_unlock_bh(&ecm_interface_lock);
591
592 DEBUG_TRACE("%p: ethernet iface established\n", nii);
593 return nii;
594}
595
Gareth Williamsc5b9d712014-05-09 20:40:07 +0100596#ifdef ECM_INTERFACE_PPP_SUPPORT
Ben Menchaca84f36632014-02-28 20:57:38 +0000597/*
598 * ecm_interface_pppoe_interface_establish()
599 * Returns a reference to a iface of the PPPoE type, possibly creating one if necessary.
600 * Returns NULL on failure or a reference to interface.
601 */
602static struct ecm_db_iface_instance *ecm_interface_pppoe_interface_establish(struct ecm_db_interface_info_pppoe *type_info,
603 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
604{
605 struct ecm_db_iface_instance *nii;
606 struct ecm_db_iface_instance *ii;
607
608 DEBUG_INFO("Establish PPPoE iface: %s with session id: %u, remote mac: %pM, MTU: %d, if num: %d, nss if id: %d\n",
609 dev_name, type_info->pppoe_session_id, type_info->remote_mac, mtu, dev_interface_num, nss_interface_num);
610
611 /*
612 * Locate the iface
613 */
614 ii = ecm_db_iface_find_and_ref_pppoe(type_info->pppoe_session_id, type_info->remote_mac);
615 if (ii) {
616 DEBUG_TRACE("%p: iface established\n", ii);
617 return ii;
618 }
619
620 /*
621 * No iface - create one
622 */
623 nii = ecm_db_iface_alloc();
624 if (!nii) {
625 DEBUG_WARN("Failed to establish iface\n");
626 return NULL;
627 }
628
629 /*
630 * Add iface into the database, atomically to avoid races creating the same thing
631 */
632 spin_lock_bh(&ecm_interface_lock);
633 ii = ecm_db_iface_find_and_ref_pppoe(type_info->pppoe_session_id, type_info->remote_mac);
634 if (ii) {
635 spin_unlock_bh(&ecm_interface_lock);
636 ecm_db_iface_deref(nii);
637 return ii;
638 }
639 ecm_db_iface_add_pppoe(nii, type_info->pppoe_session_id, type_info->remote_mac, dev_name,
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500640 mtu, dev_interface_num, nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000641 spin_unlock_bh(&ecm_interface_lock);
642
643 DEBUG_TRACE("%p: pppoe iface established\n", nii);
644 return nii;
645}
Gareth Williamsc5b9d712014-05-09 20:40:07 +0100646#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000647
648/*
649 * ecm_interface_unknown_interface_establish()
650 * Returns a reference to a iface of the UNKNOWN type, possibly creating one if necessary.
651 * Returns NULL on failure or a reference to interface.
652 */
653static struct ecm_db_iface_instance *ecm_interface_unknown_interface_establish(struct ecm_db_interface_info_unknown *type_info,
654 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
655{
656 struct ecm_db_iface_instance *nii;
657 struct ecm_db_iface_instance *ii;
658
659 DEBUG_INFO("Establish UNKNOWN iface: %s with os_specific_ident: %u, MTU: %d, if num: %d, nss if id: %d\n",
660 dev_name, type_info->os_specific_ident, mtu, dev_interface_num, nss_interface_num);
661
662 /*
663 * Locate the iface
664 */
665 ii = ecm_db_iface_find_and_ref_unknown(type_info->os_specific_ident);
666 if (ii) {
667 DEBUG_TRACE("%p: iface established\n", ii);
668 return ii;
669 }
670
671 /*
672 * No iface - create one
673 */
674 nii = ecm_db_iface_alloc();
675 if (!nii) {
676 DEBUG_WARN("Failed to establish iface\n");
677 return NULL;
678 }
679
680 /*
681 * Add iface into the database, atomically to avoid races creating the same thing
682 */
683 spin_lock_bh(&ecm_interface_lock);
684 ii = ecm_db_iface_find_and_ref_unknown(type_info->os_specific_ident);
685 if (ii) {
686 spin_unlock_bh(&ecm_interface_lock);
687 ecm_db_iface_deref(nii);
688 return ii;
689 }
690 ecm_db_iface_add_unknown(nii, type_info->os_specific_ident, dev_name,
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500691 mtu, dev_interface_num, nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000692 spin_unlock_bh(&ecm_interface_lock);
693
694 DEBUG_TRACE("%p: unknown iface established\n", nii);
695 return nii;
696}
697
698/*
699 * ecm_interface_loopback_interface_establish()
700 * Returns a reference to a iface of the LOOPBACK type, possibly creating one if necessary.
701 * Returns NULL on failure or a reference to interface.
702 */
703static struct ecm_db_iface_instance *ecm_interface_loopback_interface_establish(struct ecm_db_interface_info_loopback *type_info,
704 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
705{
706 struct ecm_db_iface_instance *nii;
707 struct ecm_db_iface_instance *ii;
708
709 DEBUG_INFO("Establish LOOPBACK iface: %s with os_specific_ident: %u, MTU: %d, if num: %d, nss if id: %d\n",
710 dev_name, type_info->os_specific_ident, mtu, dev_interface_num, nss_interface_num);
711
712 /*
713 * Locate the iface
714 */
715 ii = ecm_db_iface_find_and_ref_loopback(type_info->os_specific_ident);
716 if (ii) {
717 DEBUG_TRACE("%p: iface established\n", ii);
718 return ii;
719 }
720
721 /*
722 * No iface - create one
723 */
724 nii = ecm_db_iface_alloc();
725 if (!nii) {
726 DEBUG_WARN("Failed to establish iface\n");
727 return NULL;
728 }
729
730 /*
731 * Add iface into the database, atomically to avoid races creating the same thing
732 */
733 spin_lock_bh(&ecm_interface_lock);
734 ii = ecm_db_iface_find_and_ref_loopback(type_info->os_specific_ident);
735 if (ii) {
736 spin_unlock_bh(&ecm_interface_lock);
737 ecm_db_iface_deref(nii);
738 return ii;
739 }
740 ecm_db_iface_add_loopback(nii, type_info->os_specific_ident, dev_name,
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500741 mtu, dev_interface_num, nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000742 spin_unlock_bh(&ecm_interface_lock);
743
744 DEBUG_TRACE("%p: loopback iface established\n", nii);
745 return nii;
746}
747
748/*
749 * ecm_interface_ipsec_tunnel_interface_establish()
750 * Returns a reference to a iface of the IPSEC_TUNNEL type, possibly creating one if necessary.
751 * Returns NULL on failure or a reference to interface.
752 *
753 * NOTE: GGG TODO THIS NEEDS TO TAKE A PROPER APPROACH TO IPSEC TUNNELS USING ENDPOINT ADDRESSING AS THE TYPE INFO KEYS
754 */
755static struct ecm_db_iface_instance *ecm_interface_ipsec_tunnel_interface_establish(struct ecm_db_interface_info_ipsec_tunnel *type_info,
756 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
757{
758 struct ecm_db_iface_instance *nii;
759 struct ecm_db_iface_instance *ii;
760
761 DEBUG_INFO("Establish IPSEC_TUNNEL iface: %s with os_specific_ident: %u, MTU: %d, if num: %d, nss if id: %d\n",
762 dev_name, type_info->os_specific_ident, mtu, dev_interface_num, nss_interface_num);
763
764 /*
765 * Locate the iface
766 */
767 ii = ecm_db_iface_find_and_ref_ipsec_tunnel(type_info->os_specific_ident);
768 if (ii) {
769 DEBUG_TRACE("%p: iface established\n", ii);
770 return ii;
771 }
772
773 /*
774 * No iface - create one
775 */
776 nii = ecm_db_iface_alloc();
777 if (!nii) {
778 DEBUG_WARN("Failed to establish iface\n");
779 return NULL;
780 }
781
782 /*
783 * Add iface into the database, atomically to avoid races creating the same thing
784 */
785 spin_lock_bh(&ecm_interface_lock);
786 ii = ecm_db_iface_find_and_ref_ipsec_tunnel(type_info->os_specific_ident);
787 if (ii) {
788 spin_unlock_bh(&ecm_interface_lock);
789 ecm_db_iface_deref(nii);
790 return ii;
791 }
792 ecm_db_iface_add_ipsec_tunnel(nii, type_info->os_specific_ident, dev_name,
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500793 mtu, dev_interface_num, nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000794 spin_unlock_bh(&ecm_interface_lock);
795
796 DEBUG_TRACE("%p: ipsec_tunnel iface established\n", nii);
797 return nii;
798}
799
Murat Sezgincc6eedf2014-05-09 23:59:19 -0700800#ifdef CONFIG_IPV6_SIT_6RD
Ben Menchaca84f36632014-02-28 20:57:38 +0000801/*
802 * ecm_interface_sit_interface_establish()
803 * Returns a reference to a iface of the SIT type, possibly creating one if necessary.
804 * Returns NULL on failure or a reference to interface.
805 */
806static struct ecm_db_iface_instance *ecm_interface_sit_interface_establish(struct ecm_db_interface_info_sit *type_info,
807 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
808{
809 struct ecm_db_iface_instance *nii;
810 struct ecm_db_iface_instance *ii;
811
812 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",
813 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);
814
815 /*
816 * Locate the iface
817 */
818 ii = ecm_db_iface_find_and_ref_sit(type_info->saddr, type_info->daddr);
819 if (ii) {
820 DEBUG_TRACE("%p: iface established\n", ii);
821 return ii;
822 }
823
824 /*
825 * No iface - create one
826 */
827 nii = ecm_db_iface_alloc();
828 if (!nii) {
829 DEBUG_WARN("Failed to establish iface\n");
830 return NULL;
831 }
832
833 /*
834 * Add iface into the database, atomically to avoid races creating the same thing
835 */
836 spin_lock_bh(&ecm_interface_lock);
837 ii = ecm_db_iface_find_and_ref_sit(type_info->saddr, type_info->daddr);
838 if (ii) {
839 spin_unlock_bh(&ecm_interface_lock);
840 ecm_db_iface_deref(nii);
841 return ii;
842 }
843 ecm_db_iface_add_sit(nii, type_info, dev_name, mtu, dev_interface_num,
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500844 nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000845 spin_unlock_bh(&ecm_interface_lock);
846
847 DEBUG_TRACE("%p: sit iface established\n", nii);
848 return nii;
849}
Murat Sezgincc6eedf2014-05-09 23:59:19 -0700850#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000851
852/*
853 * ecm_interface_tunipip6_interface_establish()
854 * Returns a reference to a iface of the TUNIPIP6 type, possibly creating one if necessary.
855 * Returns NULL on failure or a reference to interface.
856 */
857static struct ecm_db_iface_instance *ecm_interface_tunipip6_interface_establish(struct ecm_db_interface_info_tunipip6 *type_info,
858 char *dev_name, int32_t dev_interface_num, int32_t nss_interface_num, int32_t mtu)
859{
860 struct ecm_db_iface_instance *nii;
861 struct ecm_db_iface_instance *ii;
862
863 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",
864 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);
865
866 /*
867 * Locate the iface
868 */
869 ii = ecm_db_iface_find_and_ref_tunipip6(type_info->saddr, type_info->daddr);
870 if (ii) {
871 DEBUG_TRACE("%p: iface established\n", ii);
872 return ii;
873 }
874
875 /*
876 * No iface - create one
877 */
878 nii = ecm_db_iface_alloc();
879 if (!nii) {
880 DEBUG_WARN("Failed to establish iface\n");
881 return NULL;
882 }
883
884 /*
885 * Add iface into the database, atomically to avoid races creating the same thing
886 */
887 spin_lock_bh(&ecm_interface_lock);
888 ii = ecm_db_iface_find_and_ref_tunipip6(type_info->saddr, type_info->daddr);
889 if (ii) {
890 spin_unlock_bh(&ecm_interface_lock);
891 ecm_db_iface_deref(nii);
892 return ii;
893 }
894 ecm_db_iface_add_tunipip6(nii, type_info, dev_name, mtu, dev_interface_num,
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500895 nss_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +0000896 spin_unlock_bh(&ecm_interface_lock);
897
898 DEBUG_TRACE("%p: tunipip6 iface established\n", nii);
899 return nii;
900}
901
902/*
903 * ecm_interface_establish_and_ref()
904 * Establish an interface instance for the given interface detail.
905 */
906struct ecm_db_iface_instance *ecm_interface_establish_and_ref(struct net_device *dev)
907{
908 int32_t dev_interface_num;
909 char *dev_name;
910 int32_t dev_type;
911 int32_t dev_mtu;
912 int32_t nss_interface_num;
913 struct ecm_db_iface_instance *ii;
914 union {
915 struct ecm_db_interface_info_ethernet ethernet; /* type == ECM_DB_IFACE_TYPE_ETHERNET */
916 struct ecm_db_interface_info_vlan vlan; /* type == ECM_DB_IFACE_TYPE_VLAN */
917 struct ecm_db_interface_info_lag lag; /* type == ECM_DB_IFACE_TYPE_LAG */
918 struct ecm_db_interface_info_bridge bridge; /* type == ECM_DB_IFACE_TYPE_BRIDGE */
919 struct ecm_db_interface_info_pppoe pppoe; /* type == ECM_DB_IFACE_TYPE_PPPOE */
920 struct ecm_db_interface_info_unknown unknown; /* type == ECM_DB_IFACE_TYPE_UNKNOWN */
921 struct ecm_db_interface_info_loopback loopback; /* type == ECM_DB_IFACE_TYPE_LOOPBACK */
922 struct ecm_db_interface_info_ipsec_tunnel ipsec_tunnel; /* type == ECM_DB_IFACE_TYPE_IPSEC_TUNNEL */
923 struct ecm_db_interface_info_sit sit; /* type == ECM_DB_IFACE_TYPE_SIT */
924 struct ecm_db_interface_info_tunipip6 tunipip6; /* type == ECM_DB_IFACE_TYPE_TUNIPIP6 */
925 } type_info;
Gareth Williamsc5b9d712014-05-09 20:40:07 +0100926
927#ifdef ECM_INTERFACE_PPP_SUPPORT
Ben Menchaca84f36632014-02-28 20:57:38 +0000928 int channel_count;
929 struct ppp_channel *ppp_chan[1];
Murat Sezgin788f9572014-05-23 10:42:28 -0700930 const struct ppp_channel_ops *ppp_chan_ops;
Ben Menchaca84f36632014-02-28 20:57:38 +0000931 int channel_protocol;
Murat Sezgin788f9572014-05-23 10:42:28 -0700932 struct pppoe_channel_ops *pppoe_chan_ops;
Ben Menchaca84f36632014-02-28 20:57:38 +0000933 struct pppoe_opt addressing;
Gareth Williamsc5b9d712014-05-09 20:40:07 +0100934#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000935
936 /*
937 * Get basic information about the given device
938 */
939 dev_interface_num = dev->ifindex;
940 dev_name = dev->name;
941 dev_type = dev->type;
942 dev_mtu = dev->mtu;
943
944 /*
945 * Does the NSS recognise this interface?
946 */
947 nss_interface_num = nss_cmn_get_interface_number_by_dev(dev);
948
949 DEBUG_TRACE("Establish interface instance for device: %p is type: %d, name: %s, ifindex: %d, nss_if: %d, mtu: %d\n",
950 dev, dev_type, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
951
952 /*
953 * Extract from the device more type-specific information
954 */
955 if (dev_type == ARPHRD_ETHER) {
956 /*
957 * Ethernet - but what sub type?
958 */
959
960 /*
961 * VLAN?
962 */
963 if (is_vlan_dev(dev)) {
964 /*
965 * VLAN master
966 * GGG No locking needed here, ASSUMPTION is that real_dev is held for as long as we have dev.
967 */
968 memcpy(type_info.vlan.address, dev->dev_addr, 6);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530969 type_info.vlan.vlan_tag = vlan_dev_vlan_id(dev);
970 type_info.vlan.vlan_tpid = VLAN_CTAG_TPID;
971 DEBUG_TRACE("Net device: %p is VLAN, mac: %pM, vlan_id: %x vlan_tpid: %x\n",
972 dev, type_info.vlan.address, type_info.vlan.vlan_tag, type_info.vlan.vlan_tpid);
Ben Menchaca84f36632014-02-28 20:57:38 +0000973
974 /*
975 * Establish this type of interface
976 */
977 ii = ecm_interface_vlan_interface_establish(&type_info.vlan, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
978 return ii;
979 }
980
981 /*
982 * BRIDGE?
983 */
984 if (ecm_front_end_is_bridge_device(dev)) {
985 /*
986 * Bridge
987 */
988 memcpy(type_info.bridge.address, dev->dev_addr, 6);
989
990 DEBUG_TRACE("Net device: %p is BRIDGE, mac: %pM\n",
991 dev, type_info.bridge.address);
992
993 /*
994 * Establish this type of interface
995 */
996 ii = ecm_interface_bridge_interface_establish(&type_info.bridge, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
997 return ii;
998 }
999
1000 /*
1001 * LAG?
1002 */
1003 if (ecm_front_end_is_lag_master(dev)) {
1004 /*
1005 * Link aggregation
1006 */
1007 memcpy(type_info.lag.address, dev->dev_addr, 6);
1008
1009 DEBUG_TRACE("Net device: %p is LAG, mac: %pM\n",
1010 dev, type_info.lag.address);
1011
1012 /*
1013 * Establish this type of interface
1014 */
1015 ii = ecm_interface_lag_interface_establish(&type_info.lag, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1016 return ii;
1017 }
1018
1019 /*
1020 * ETHERNET!
1021 * Just plain ethernet it seems
1022 */
1023 memcpy(type_info.ethernet.address, dev->dev_addr, 6);
1024 DEBUG_TRACE("Net device: %p is ETHERNET, mac: %pM\n",
1025 dev, type_info.ethernet.address);
1026
1027 /*
1028 * Establish this type of interface
1029 */
1030 ii = ecm_interface_ethernet_interface_establish(&type_info.ethernet, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1031 return ii;
1032 }
1033
1034 /*
1035 * LOOPBACK?
1036 */
1037 if (dev_type == ARPHRD_LOOPBACK) {
1038 DEBUG_TRACE("Net device: %p is LOOPBACK type: %d\n", dev, dev_type);
1039 type_info.loopback.os_specific_ident = dev_interface_num;
1040 ii = ecm_interface_loopback_interface_establish(&type_info.loopback, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1041 return ii;
1042 }
1043
1044 /*
1045 * IPSEC?
1046 */
1047 if (dev_type == ECM_ARPHRD_IPSEC_TUNNEL_TYPE) {
1048 DEBUG_TRACE("Net device: %p is IPSec tunnel type: %d\n", dev, dev_type);
1049 type_info.ipsec_tunnel.os_specific_ident = dev_interface_num;
1050 // GGG TODO Flesh this out with tunnel endpoint addressing detail
1051 ii = ecm_interface_ipsec_tunnel_interface_establish(&type_info.ipsec_tunnel, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1052 return ii;
1053 }
1054
Murat Sezgincc6eedf2014-05-09 23:59:19 -07001055#ifdef CONFIG_IPV6_SIT_6RD
Ben Menchaca84f36632014-02-28 20:57:38 +00001056 /*
1057 * SIT (6-in-4)?
1058 */
1059 if (dev_type == ARPHRD_SIT) {
1060 struct ip_tunnel *tunnel;
1061 struct ip_tunnel_6rd_parm *ip6rd;
1062 const struct iphdr *tiph;
1063
1064 DEBUG_TRACE("Net device: %p is SIT (6-in-4) type: %d\n", dev, dev_type);
1065
1066 tunnel = (struct ip_tunnel*)netdev_priv(dev);
1067 ip6rd = &tunnel->ip6rd;
1068
1069 /*
1070 * Get the Tunnel device IP header info
1071 */
1072 tiph = &tunnel->parms.iph ;
1073
1074 type_info.sit.prefixlen = ip6rd->prefixlen;
1075 type_info.sit.relay_prefix = ip6rd->relay_prefix;
1076 type_info.sit.relay_prefixlen = ip6rd->relay_prefixlen;
1077 ECM_NIN4_ADDR_TO_IP_ADDR(type_info.sit.saddr, tiph->saddr);
1078 ECM_NIN4_ADDR_TO_IP_ADDR(type_info.sit.daddr, tiph->daddr);
1079 type_info.sit.prefix[0] = ntohl(ip6rd->prefix.s6_addr32[0]);
1080 type_info.sit.prefix[1] = ntohl(ip6rd->prefix.s6_addr32[1]);
1081 type_info.sit.prefix[2] = ntohl(ip6rd->prefix.s6_addr32[2]);
1082 type_info.sit.prefix[3] = ntohl(ip6rd->prefix.s6_addr32[3]);
1083 type_info.sit.ttl = tiph->ttl;
1084 type_info.sit.tos = tiph->tos;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301085
Ben Menchaca84f36632014-02-28 20:57:38 +00001086 ii = ecm_interface_sit_interface_establish(&type_info.sit, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1087 return ii;
1088 }
Murat Sezgincc6eedf2014-05-09 23:59:19 -07001089#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001090
1091 /*
1092 * IPIP6 Tunnel?
1093 */
1094 if (dev_type == ARPHRD_TUNNEL6) {
1095 struct ip6_tnl *tunnel;
1096 struct flowi6 *fl6;
1097
1098 DEBUG_TRACE("Net device: %p is TUNIPIP6 type: %d\n", dev, dev_type);
1099
1100 /*
1101 * Get the tunnel device flow information (discover the output path of the tunnel)
1102 */
1103 tunnel = (struct ip6_tnl *)netdev_priv(dev);
1104 fl6 = &tunnel->fl.u.ip6;
1105
1106 ECM_NIN6_ADDR_TO_IP_ADDR(type_info.tunipip6.saddr, fl6->saddr);
1107 ECM_NIN6_ADDR_TO_IP_ADDR(type_info.tunipip6.daddr, fl6->daddr);
1108 type_info.tunipip6.hop_limit = tunnel->parms.hop_limit;
1109 type_info.tunipip6.flags = ntohl(tunnel->parms.flags);
1110 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 +05301111
Ben Menchaca84f36632014-02-28 20:57:38 +00001112 ii = ecm_interface_tunipip6_interface_establish(&type_info.tunipip6, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1113 return ii;
1114 }
1115
1116 /*
1117 * If this is NOT PPP then it is unknown to the ecm
1118 */
1119 if (dev_type != ARPHRD_PPP) {
1120 DEBUG_TRACE("Net device: %p is UNKNOWN type: %d\n", dev, dev_type);
1121 type_info.unknown.os_specific_ident = dev_interface_num;
1122
1123 /*
1124 * Establish this type of interface
1125 */
1126 ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1127 return ii;
1128 }
1129
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001130#ifndef ECM_INTERFACE_PPP_SUPPORT
1131 /*
1132 * PPP support is NOT provided for.
1133 * Interface is therefore unknown
1134 */
1135 DEBUG_TRACE("Net device: %p is UNKNOWN (PPP Unsupported) type: %d\n", dev, dev_type);
1136 type_info.unknown.os_specific_ident = dev_interface_num;
1137
1138 /*
1139 * Establish this type of interface
1140 */
1141 ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1142 return ii;
1143#else
Ben Menchaca84f36632014-02-28 20:57:38 +00001144 /*
1145 * PPP - but what is the channel type?
1146 * First: If this is multi-link then we do not support it
1147 */
1148 if (ppp_is_multilink(dev) > 0) {
1149 DEBUG_TRACE("Net device: %p is MULTILINK PPP - Unknown to the ECM\n", dev);
1150 type_info.unknown.os_specific_ident = dev_interface_num;
1151
1152 /*
1153 * Establish this type of interface
1154 */
1155 ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1156 return ii;
1157 }
1158
1159 DEBUG_TRACE("Net device: %p is PPP\n", dev);
1160
1161 /*
1162 * Get the PPP channel and then enquire what kind of channel it is
1163 * NOTE: Not multilink so only one channel to get.
1164 */
1165 channel_count = ppp_hold_channels(dev, ppp_chan, 1);
1166 if (channel_count != 1) {
Murat Sezgin788f9572014-05-23 10:42:28 -07001167 DEBUG_TRACE("Net device: %p PPP has %d channels - Unknown to the ECM\n", dev, channel_count);
Ben Menchaca84f36632014-02-28 20:57:38 +00001168 type_info.unknown.os_specific_ident = dev_interface_num;
1169
1170 /*
1171 * Establish this type of interface
1172 */
1173 ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1174 return ii;
1175 }
1176
1177 /*
1178 * Get channel protocol type
1179 */
Murat Sezgin788f9572014-05-23 10:42:28 -07001180 ppp_chan_ops = ppp_chan[0]->ops;
1181 channel_protocol = ppp_chan_ops->get_channel_protocol(ppp_chan[0]);
Ben Menchaca84f36632014-02-28 20:57:38 +00001182 if (channel_protocol != PX_PROTO_OE) {
1183 DEBUG_TRACE("Net device: %p PPP channel protocol: %d - Unknown to the ECM\n", dev, channel_protocol);
1184 type_info.unknown.os_specific_ident = dev_interface_num;
1185
1186 /*
1187 * Release the channel
1188 */
1189 ppp_release_channels(ppp_chan, 1);
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 }
1197
1198 /*
1199 * PPPoE channel
1200 */
1201 DEBUG_TRACE("Net device: %p PPP channel is PPPoE\n", dev);
1202
1203 /*
1204 * Get PPPoE session information and the underlying device it is using.
Murat Sezgin788f9572014-05-23 10:42:28 -07001205 * NOTE: We know this is PPPoE so we can cast the ppp_chan_ops to pppoe_chan_ops and
1206 * use its channel specific methods.
Ben Menchaca84f36632014-02-28 20:57:38 +00001207 */
Murat Sezgin788f9572014-05-23 10:42:28 -07001208 pppoe_chan_ops = (struct pppoe_channel_ops *)ppp_chan_ops;
1209 pppoe_chan_ops->get_addressing(ppp_chan[0], &addressing);
1210
1211 type_info.pppoe.pppoe_session_id = (uint16_t)addressing.pa.sid;
Ben Menchaca84f36632014-02-28 20:57:38 +00001212 memcpy(type_info.pppoe.remote_mac, addressing.pa.remote, ETH_ALEN);
1213
1214 /*
1215 * Release the channel. Note that next_dev is still (correctly) held.
1216 */
1217 ppp_release_channels(ppp_chan, 1);
1218
1219 DEBUG_TRACE("Net device: %p PPPoE session: %x, remote mac: %pM\n",
1220 dev, type_info.pppoe.pppoe_session_id, type_info.pppoe.remote_mac);
1221
1222 /*
1223 * Establish this type of interface
1224 */
1225 ii = ecm_interface_pppoe_interface_establish(&type_info.pppoe, dev_name, dev_interface_num, nss_interface_num, dev_mtu);
1226 return ii;
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001227#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001228}
1229EXPORT_SYMBOL(ecm_interface_establish_and_ref);
1230
1231/*
1232 * ecm_interface_heirarchy_construct()
1233 * Construct an interface heirarchy.
1234 *
1235 * Using the given addressing, locate the interface heirarchy used to emit packets to that destination.
1236 * This is the heirarchy of interfaces a packet would transit to emit from the device.
1237 * For example, with this network arrangement:
1238 *
1239 * PPPoE--VLAN--BRIDGE--BRIDGE_PORT(LAG_MASTER)--LAG_SLAVE_0--10.22.33.11
1240 *
1241 * Given the IP address 10.22.33.11 this will create an interface heirarchy (in interracfes[]) of:
1242 * LAG_SLAVE_0 @ [ECM_DB_IFACE_HEIRARCHY_MAX - 5]
1243 * LAG_MASTER @ [ECM_DB_IFACE_HEIRARCHY_MAX - 4]
1244 * BRIDGE @ [ECM_DB_IFACE_HEIRARCHY_MAX - 3]
1245 * VLAN @ [ECM_DB_IFACE_HEIRARCHY_MAX - 2]
1246 * PPPOE @ [ECM_DB_IFACE_HEIRARCHY_MAX - 1]
1247 * The value returned is (ECM_DB_IFACE_HEIRARCHY_MAX - 5)
1248 *
1249 * IMPORTANT: This function will return any known interfaces in the database, when interfaces do not exist in the database
1250 * they will be created and added automatically to the database.
1251 *
1252 * GGG TODO Make this function work for IPv6!!!!!!!!!!!!!!
1253 */
1254int32_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)
1255{
1256 char __attribute__((unused)) src_addr_str[40];
1257 char __attribute__((unused)) dest_addr_str[40];
1258 int protocol;
1259 ip_addr_t src_addr;
1260 ip_addr_t dest_addr;
1261 struct ecm_interface_route src_rt;
1262 struct ecm_interface_route dest_rt;
1263 struct dst_entry *src_dst;
1264 struct dst_entry *dest_dst;
1265 struct net_device *src_dev;
1266 struct net_device *dest_dev;
1267 char *src_dev_name;
1268 char *dest_dev_name;
1269 int32_t src_dev_type;
1270 int32_t dest_dev_type;
1271 int32_t current_interface_index;
1272
1273 /*
1274 * Get a big endian of the IPv4 address we have been given as our starting point.
1275 */
1276 protocol = packet_protocol;
1277 ECM_IP_ADDR_COPY(src_addr, packet_src_addr);
1278 ECM_IP_ADDR_COPY(dest_addr, packet_dest_addr);
1279 ecm_ip_addr_to_string(src_addr_str, src_addr);
1280 ecm_ip_addr_to_string(dest_addr_str, dest_addr);
1281 DEBUG_TRACE("Construct interface heirarchy for from src_addr: %s to dest_addr: %s, protocol: %d\n", src_addr_str, dest_addr_str, protocol);
1282
1283 /*
1284 * Begin by finding the interface to which we reach the given addresses
1285 */
1286 if (!ecm_interface_find_route_by_addr(src_addr, &src_rt)) {
1287 DEBUG_WARN("Construct interface heirarchy failed from src_addr: %s to dest_addr: %s, protocol: %d\n", src_addr_str, dest_addr_str, protocol);
1288 return ECM_DB_IFACE_HEIRARCHY_MAX;
1289 }
1290 if (!ecm_interface_find_route_by_addr(dest_addr, &dest_rt)) {
1291 ecm_interface_route_release(&src_rt);
1292 DEBUG_WARN("Construct interface heirarchy failed from src_addr: %s to dest_addr: %s, protocol: %d\n", src_addr_str, dest_addr_str, protocol);
1293 return ECM_DB_IFACE_HEIRARCHY_MAX;
1294 }
1295
1296 /*
1297 * Get the dst entries
1298 */
1299 src_dst = src_rt.dst;
1300 dest_dst = dest_rt.dst;
1301
1302 /*
1303 * Get device from the destination entries
1304 */
1305 src_dev = src_dst->dev;
1306 dev_hold(src_dev);
1307 src_dev_name = src_dev->name;
1308 src_dev_type = src_dev->type;
1309
1310 dest_dev = dest_dst->dev;
1311 dev_hold(dest_dev);
1312 dest_dev_name = dest_dev->name;
1313 dest_dev_type = dest_dev->type;
1314
1315 /*
1316 * Release route (we hold devices for ourselves)
1317 */
1318 ecm_interface_route_release(&src_rt);
1319 ecm_interface_route_release(&dest_rt);
1320
1321 /*
1322 * Iterate until we are done or get to the max number of interfaces we can record.
1323 * NOTE: current_interface_index tracks the position of the first interface position in interfaces[]
1324 * because we add from the end first_interface grows downwards.
1325 */
1326 current_interface_index = ECM_DB_IFACE_HEIRARCHY_MAX;
1327 while (current_interface_index > 0) {
1328 struct ecm_db_iface_instance *ii;
1329 struct net_device *next_dev;
1330
1331 /*
1332 * Get the ecm db interface instance for the device at hand
1333 */
1334 ii = ecm_interface_establish_and_ref(dest_dev);
1335
1336 /*
1337 * If the interface could not be established then we abort
1338 */
1339 if (!ii) {
1340 DEBUG_WARN("Failed to establish interface: %p, name: %s\n", dest_dev, dest_dev_name);
1341 dev_put(src_dev);
1342 dev_put(dest_dev);
1343
1344 /*
1345 * Release the interfaces heirarchy we constructed to this point.
1346 */
1347 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1348 return ECM_DB_IFACE_HEIRARCHY_MAX;
1349 }
1350
1351 /*
1352 * Record the interface instance into the interfaces[]
1353 */
1354 current_interface_index--;
1355 interfaces[current_interface_index] = ii;
1356
1357 /*
1358 * Now we have to figure out what the next device will be (in the transmission path) the skb
1359 * will use to emit to the destination address.
1360 */
1361 do {
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001362#ifdef ECM_INTERFACE_PPP_SUPPORT
Ben Menchaca84f36632014-02-28 20:57:38 +00001363 int channel_count;
1364 struct ppp_channel *ppp_chan[1];
Murat Sezgin788f9572014-05-23 10:42:28 -07001365 const struct ppp_channel_ops *ppp_chan_ops;
Ben Menchaca84f36632014-02-28 20:57:38 +00001366 int channel_protocol;
Murat Sezgin788f9572014-05-23 10:42:28 -07001367 struct pppoe_channel_ops *pppoe_chan_ops;
Ben Menchaca84f36632014-02-28 20:57:38 +00001368 struct pppoe_opt addressing;
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001369#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001370
1371 DEBUG_TRACE("Net device: %p is type: %d, name: %s\n", dest_dev, dest_dev_type, dest_dev_name);
1372 next_dev = NULL;
1373
1374 if (dest_dev_type == ARPHRD_ETHER) {
1375 /*
1376 * Ethernet - but what sub type?
1377 */
1378
1379 /*
1380 * VLAN?
1381 */
1382 if (is_vlan_dev(dest_dev)) {
1383 /*
1384 * VLAN master
1385 * No locking needed here, ASSUMPTION is that real_dev is held for as long as we have dev.
1386 */
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301387 next_dev = vlan_dev_real_dev(dest_dev);
Ben Menchaca84f36632014-02-28 20:57:38 +00001388 dev_hold(next_dev);
1389 DEBUG_TRACE("Net device: %p is VLAN, slave dev: %p (%s)\n",
1390 dest_dev, next_dev, next_dev->name);
1391 break;
1392 }
1393
1394 /*
1395 * BRIDGE?
1396 */
1397 if (ecm_front_end_is_bridge_device(dest_dev)) {
1398 /*
1399 * Bridge
1400 * Figure out which port device the skb will go to using the dest_addr.
1401 */
1402 bool on_link;
1403 ip_addr_t gw_addr;
1404 uint8_t mac_addr[ETH_ALEN];
1405 if (!ecm_interface_mac_addr_get(dest_addr, mac_addr, &on_link, gw_addr)) {
1406 /*
1407 * Possible ARP does not know the address yet
1408 */
1409 DEBUG_WARN("Unable to obtain MAC address for " ECM_IP_ADDR_DOT_FMT "\n", ECM_IP_ADDR_TO_DOT(dest_addr));
1410 dev_put(src_dev);
1411 dev_put(dest_dev);
1412
1413 /*
1414 * Release the interfaces heirarchy we constructed to this point.
1415 */
1416 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1417 return ECM_DB_IFACE_HEIRARCHY_MAX;
1418 }
1419 next_dev = br_port_dev_get(dest_dev, mac_addr);
1420 if (!next_dev) {
1421 DEBUG_WARN("Unable to obtain output port for: %pM\n", mac_addr);
1422 dev_put(src_dev);
1423 dev_put(dest_dev);
1424
1425 /*
1426 * Release the interfaces heirarchy we constructed to this point.
1427 */
1428 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1429 return ECM_DB_IFACE_HEIRARCHY_MAX;
1430 }
1431 DEBUG_TRACE("Net device: %p is BRIDGE, next_dev: %p (%s)\n", dest_dev, next_dev, next_dev->name);
1432 break;
1433 }
1434
1435 /*
1436 * LAG?
1437 */
1438 if (ecm_front_end_is_lag_master(dest_dev)) {
1439 /*
1440 * Link aggregation
1441 * Figure out which slave device of the link aggregation will be used to reach the destination.
1442 */
1443 bool src_on_link;
1444 bool dest_on_link;
1445 ip_addr_t src_gw_addr;
1446 ip_addr_t dest_gw_addr;
1447 uint32_t src_addr_32;
1448 uint32_t dest_addr_32;
1449 uint8_t src_mac_addr[ETH_ALEN];
1450 uint8_t dest_mac_addr[ETH_ALEN];
1451
1452 if (!ecm_interface_mac_addr_get(src_addr, src_mac_addr, &src_on_link, src_gw_addr)) {
1453 /*
1454 * Possible ARP does not know the address yet
1455 */
1456 DEBUG_WARN("Unable to obtain MAC address for " ECM_IP_ADDR_DOT_FMT "\n", ECM_IP_ADDR_TO_DOT(src_addr));
1457 dev_put(src_dev);
1458 dev_put(dest_dev);
1459
1460 /*
1461 * Release the interfaces heirarchy we constructed to this point.
1462 */
1463 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1464 return ECM_DB_IFACE_HEIRARCHY_MAX;
1465 }
1466 if (!ecm_interface_mac_addr_get(dest_addr, dest_mac_addr, &dest_on_link, dest_gw_addr)) {
1467 /*
1468 * Possible ARP does not know the address yet
1469 */
1470 DEBUG_WARN("Unable to obtain MAC address for " ECM_IP_ADDR_DOT_FMT "\n", ECM_IP_ADDR_TO_DOT(dest_addr));
1471 dev_put(src_dev);
1472 dev_put(dest_dev);
1473
1474 /*
1475 * Release the interfaces heirarchy we constructed to this point.
1476 */
1477 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1478 return ECM_DB_IFACE_HEIRARCHY_MAX;
1479 }
1480
1481 ECM_IP_ADDR_TO_HIN4_ADDR(src_addr_32, src_addr);
1482 ECM_IP_ADDR_TO_HIN4_ADDR(dest_addr_32, dest_addr);
1483
1484 next_dev = bond_get_tx_dev(NULL, src_mac_addr, dest_mac_addr, &src_addr_32, &dest_addr_32, (uint16_t)protocol, dest_dev);
1485 if (next_dev) {
1486 dev_hold(next_dev);
1487 } else {
1488 DEBUG_WARN("Unable to obtain LAG output slave device\n");
1489 dev_put(src_dev);
1490 dev_put(dest_dev);
1491
1492 /*
1493 * Release the interfaces heirarchy we constructed to this point.
1494 */
1495 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1496 return ECM_DB_IFACE_HEIRARCHY_MAX;
1497 }
1498
1499 DEBUG_TRACE("Net device: %p is LAG, slave dev: %p (%s)\n", dest_dev, next_dev, next_dev->name);
1500
1501 break;
1502 }
1503
1504 /*
1505 * ETHERNET!
1506 * Just plain ethernet it seems.
1507 */
1508 DEBUG_TRACE("Net device: %p is ETHERNET\n", dest_dev);
1509 break;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301510 }
Ben Menchaca84f36632014-02-28 20:57:38 +00001511
1512 /*
1513 * LOOPBACK?
1514 */
1515 if (dest_dev_type == ARPHRD_LOOPBACK) {
1516 DEBUG_TRACE("Net device: %p is LOOPBACK type: %d\n", dest_dev, dest_dev_type);
1517 break;
1518 }
1519
1520 /*
1521 * IPSEC?
1522 */
1523 if (dest_dev_type == ECM_ARPHRD_IPSEC_TUNNEL_TYPE) {
1524 DEBUG_TRACE("Net device: %p is IPSec tunnel type: %d\n", dest_dev, dest_dev_type);
1525 // GGG TODO Figure out the next device the tunnel is using...
1526 break;
1527 }
1528
1529 /*
1530 * SIT (6-in-4)?
1531 */
1532 if (dest_dev_type == ARPHRD_SIT) {
1533 DEBUG_TRACE("Net device: %p is SIT (6-in-4) type: %d\n", dest_dev, dest_dev_type);
1534 break;
1535 }
1536
1537 /*
1538 * IPIP6 Tunnel?
1539 */
1540 if (dest_dev_type == ARPHRD_TUNNEL6) {
1541 DEBUG_TRACE("Net device: %p is TUNIPIP6 type: %d\n", dest_dev, dest_dev_type);
1542 break;
1543 }
1544
1545 /*
1546 * If this is NOT PPP then it is unknown to the ecm and we cannot figure out it's next device.
1547 */
1548 if (dest_dev_type != ARPHRD_PPP) {
1549 DEBUG_TRACE("Net device: %p is UNKNOWN type: %d\n", dest_dev, dest_dev_type);
1550 break;
1551 }
1552
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001553#ifndef ECM_INTERFACE_PPP_SUPPORT
1554 DEBUG_TRACE("Net device: %p is UNKNOWN (PPP Unsupported) type: %d\n", dest_dev, dest_dev_type);
1555#else
Ben Menchaca84f36632014-02-28 20:57:38 +00001556 /*
1557 * PPP - but what is the channel type?
1558 * First: If this is multi-link then we do not support it
1559 */
1560 if (ppp_is_multilink(dest_dev) > 0) {
1561 DEBUG_TRACE("Net device: %p is MULTILINK PPP - Unknown to the ECM\n", dest_dev);
1562 break;
1563 }
1564
1565 DEBUG_TRACE("Net device: %p is PPP\n", dest_dev);
1566
1567 /*
1568 * Get the PPP channel and then enquire what kind of channel it is
1569 * NOTE: Not multilink so only one channel to get.
1570 */
1571 channel_count = ppp_hold_channels(dest_dev, ppp_chan, 1);
1572 if (channel_count != 1) {
1573 DEBUG_TRACE("Net device: %p PPP has %d channels - Unknown to the ECM\n",
1574 dest_dev, channel_count);
1575 break;
1576 }
1577
1578 /*
1579 * Get channel protocol type
1580 */
Murat Sezgin788f9572014-05-23 10:42:28 -07001581 ppp_chan_ops = ppp_chan[0]->ops;
1582 channel_protocol = ppp_chan_ops->get_channel_protocol(ppp_chan[0]);
Ben Menchaca84f36632014-02-28 20:57:38 +00001583 if (channel_protocol != PX_PROTO_OE) {
1584 DEBUG_TRACE("Net device: %p PPP channel protocol: %d - Unknown to the ECM\n",
1585 dest_dev, channel_protocol);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301586
Ben Menchaca84f36632014-02-28 20:57:38 +00001587 /*
1588 * Release the channel
1589 */
1590 ppp_release_channels(ppp_chan, 1);
1591
1592 break;
1593 }
1594
1595 /*
1596 * PPPoE channel
1597 */
1598 DEBUG_TRACE("Net device: %p PPP channel is PPPoE\n", dest_dev);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301599
Ben Menchaca84f36632014-02-28 20:57:38 +00001600 /*
1601 * Get PPPoE session information and the underlying device it is using.
Murat Sezgin788f9572014-05-23 10:42:28 -07001602 * NOTE: We know this is PPPoE so we can cast the ppp_chan_ops to pppoe_chan_ops and
1603 * use its channel specific methods.
Ben Menchaca84f36632014-02-28 20:57:38 +00001604 */
Murat Sezgin788f9572014-05-23 10:42:28 -07001605 pppoe_chan_ops = (struct pppoe_channel_ops *)ppp_chan_ops;
1606 pppoe_chan_ops->get_addressing(ppp_chan[0], &addressing);
Ben Menchaca84f36632014-02-28 20:57:38 +00001607
1608 /*
1609 * Copy the dev hold into this, we will release the hold later
1610 */
1611 next_dev = addressing.dev;
1612
1613 DEBUG_TRACE("Net device: %p, next device: %p (%s)\n", dest_dev, next_dev, next_dev->name);
1614
1615 /*
1616 * Release the channel. Note that next_dev is still (correctly) held.
1617 */
1618 ppp_release_channels(ppp_chan, 1);
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001619#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001620 } while (false);
1621
1622 /*
Gareth Williamsa11d4352014-05-14 18:25:49 +01001623 * No longer need dest_dev as it may become next_dev
Ben Menchaca84f36632014-02-28 20:57:38 +00001624 */
Ben Menchaca84f36632014-02-28 20:57:38 +00001625 dev_put(dest_dev);
1626
1627 /*
1628 * Check out the next_dev, if any
1629 */
1630 if (!next_dev) {
1631 int32_t i __attribute__((unused));
1632 DEBUG_INFO("Completed interface heirarchy construct with first interface @: %d\n", current_interface_index);
1633#if DEBUG_LEVEL > 1
1634 for (i = current_interface_index; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
1635 DEBUG_TRACE("\tInterface @ %d: %p, type: %d, name: %s\n",
1636 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])));
1637 }
1638#endif
Gareth Williamsa11d4352014-05-14 18:25:49 +01001639
1640 /*
1641 * Release src_dev now
1642 */
1643 dev_put(src_dev);
1644
Ben Menchaca84f36632014-02-28 20:57:38 +00001645 return current_interface_index;
1646 }
1647
Gareth Williamsa11d4352014-05-14 18:25:49 +01001648 /*
1649 * dest_dev becomes next_dev
1650 */
Ben Menchaca84f36632014-02-28 20:57:38 +00001651 dest_dev = next_dev;
1652 dest_dev_name = dest_dev->name;
1653 dest_dev_type = dest_dev->type;
1654 }
1655
1656 DEBUG_WARN("Too many interfaces: %d\n", current_interface_index);
1657 DEBUG_ASSERT(current_interface_index == 0, "Bad logic handling current_interface_index: %d\n", current_interface_index);
1658 dev_put(src_dev);
1659 dev_put(dest_dev);
1660
1661 /*
1662 * Release the interfaces heirarchy we constructed to this point.
1663 */
1664 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
1665 return ECM_DB_IFACE_HEIRARCHY_MAX;
1666}
1667EXPORT_SYMBOL(ecm_interface_heirarchy_construct);
1668
1669/*
1670 * ecm_interface_regenerate_connections()
1671 * Cause regeneration of all connections that are using the specified interface.
1672 */
1673static void ecm_interface_regenerate_connections(struct ecm_db_iface_instance *ii)
1674{
1675 struct ecm_db_connection_instance *ci;
1676
1677 DEBUG_TRACE("Regenerate connections using interface: %p\n", ii);
1678
1679 /*
1680 * Iterate the connections of this interface and cause each one to be re-generated.
1681 * GGG TODO NOTE: If this proves slow (need metrics here) we could just regenerate the "lot" with one very simple call.
1682 * 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
1683 * but at the cost of performance.
1684 */
1685 DEBUG_TRACE("%p: Regenerate 'from' connections\n", ii);
1686 ci = ecm_db_iface_connections_from_get_and_ref_first(ii);
1687 while (ci) {
1688 struct ecm_db_connection_instance *cin;
1689 cin = ecm_db_connection_iface_from_get_and_ref_next(ci);
1690
1691 DEBUG_TRACE("%p: Regenerate: %p", ii, ci);
1692 ecm_db_connection_classifier_generation_change(ci);
1693 ecm_db_connection_deref(ci);
1694 ci = cin;
1695 }
1696
1697 DEBUG_TRACE("%p: Regenerate 'to' connections\n", ii);
1698 ci = ecm_db_iface_connections_to_get_and_ref_first(ii);
1699 while (ci) {
1700 struct ecm_db_connection_instance *cin;
1701 cin = ecm_db_connection_iface_to_get_and_ref_next(ci);
1702
1703 DEBUG_TRACE("%p: Regenerate: %p", ii, ci);
1704 ecm_db_connection_classifier_generation_change(ci);
1705 ecm_db_connection_deref(ci);
1706 ci = cin;
1707 }
1708
1709 DEBUG_TRACE("%p: Regenerate 'from_nat' connections\n", ii);
1710 ci = ecm_db_iface_connections_nat_from_get_and_ref_first(ii);
1711 while (ci) {
1712 struct ecm_db_connection_instance *cin;
1713 cin = ecm_db_connection_iface_nat_from_get_and_ref_next(ci);
1714
1715 DEBUG_TRACE("%p: Regenerate: %p", ii, ci);
1716 ecm_db_connection_classifier_generation_change(ci);
1717 ecm_db_connection_deref(ci);
1718 ci = cin;
1719 }
1720
1721 DEBUG_TRACE("%p: Regenerate 'to_nat' connections\n", ii);
1722 ci = ecm_db_iface_connections_nat_to_get_and_ref_first(ii);
1723 while (ci) {
1724 struct ecm_db_connection_instance *cin;
1725 cin = ecm_db_connection_iface_nat_to_get_and_ref_next(ci);
1726
1727 DEBUG_TRACE("%p: Regenerate: %p", ii, ci);
1728 ecm_db_connection_classifier_generation_change(ci);
1729 ecm_db_connection_deref(ci);
1730 ci = cin;
1731 }
1732
1733 DEBUG_TRACE("%p: Regenerate COMPLETE\n", ii);
1734}
1735
1736/*
1737 * ecm_interface_dev_regenerate_connections()
1738 * Cause regeneration of all connections that are using the specified interface.
1739 */
1740static void ecm_interface_dev_regenerate_connections(struct net_device *dev)
1741{
1742 struct ecm_db_iface_instance *ii;
1743
1744 DEBUG_INFO("Regenerate connections for: %p (%s)\n", dev, dev->name);
1745
1746 /*
1747 * Establish the interface for the given device.
1748 * NOTE: The cute thing here is even if dev is previously unknown to us this will create an interface instance
1749 * 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.
1750 * However if the interface is known to us then we will get it returned by this function and process it accordingly.
1751 */
1752 ii = ecm_interface_establish_and_ref(dev);
1753 if (!ii) {
1754 DEBUG_WARN("%p: No interface instance could be established for this dev\n", dev);
1755 return;
1756 }
1757 ecm_interface_regenerate_connections(ii);
1758 DEBUG_TRACE("%p: Regenerate for %p: COMPLETE\n", dev, ii);
1759 ecm_db_iface_deref(ii);
1760}
1761
1762/*
1763 * ecm_interface_mtu_change()
1764 * MTU of interface has changed
1765 */
1766static void ecm_interface_mtu_change(struct net_device *dev)
1767{
1768 int mtu;
1769 struct ecm_db_iface_instance *ii;
1770
1771 mtu = dev->mtu;
1772 DEBUG_INFO("%p (%s): MTU Change to: %d\n", dev, dev->name, mtu);
1773
1774 /*
1775 * Establish the interface for the given device.
1776 */
1777 ii = ecm_interface_establish_and_ref(dev);
1778 if (!ii) {
1779 DEBUG_WARN("%p: No interface instance could be established for this dev\n", dev);
1780 return;
1781 }
1782
1783 /*
1784 * Change the mtu
1785 */
1786 ecm_db_iface_mtu_reset(ii, mtu);
1787 DEBUG_TRACE("%p (%s): MTU Changed to: %d\n", dev, dev->name, mtu);
1788 ecm_interface_regenerate_connections(ii);
1789 DEBUG_TRACE("%p: Regenerate for %p: COMPLETE\n", dev, ii);
1790 ecm_db_iface_deref(ii);
1791}
1792
1793/*
1794 * ecm_interface_netdev_notifier_callback()
1795 * Netdevice notifier callback to inform us of change of state of a netdevice
1796 */
1797static int ecm_interface_netdev_notifier_callback(struct notifier_block *this, unsigned long event, void *ptr)
1798{
1799 struct net_device *dev __attribute__ ((unused)) = (struct net_device *)ptr;
1800
1801 DEBUG_INFO("Net device notifier for: %p, name: %s, event: %lx\n", dev, dev->name, event);
1802
1803 switch (event) {
1804 case NETDEV_DOWN:
1805 DEBUG_INFO("Net device: %p, DOWN\n", dev);
1806 ecm_interface_dev_regenerate_connections(dev);
1807 break;
1808
1809 case NETDEV_CHANGE:
1810 DEBUG_INFO("Net device: %p, CHANGE\n", dev);
1811 if (!netif_carrier_ok(dev)) {
1812 DEBUG_INFO("Net device: %p, CARRIER BAD\n", dev);
1813 ecm_interface_dev_regenerate_connections(dev);
1814 }
1815 break;
1816
1817 case NETDEV_CHANGEMTU:
1818 DEBUG_INFO("Net device: %p, MTU CHANGE\n", dev);
1819 ecm_interface_mtu_change(dev);
1820 break;
1821
1822 default:
1823 DEBUG_TRACE("Net device: %p, UNHANDLED: %lx\n", dev, event);
1824 break;
1825 }
1826
1827 return NOTIFY_DONE;
1828}
1829
1830/*
1831 * struct notifier_block ecm_interface_netdev_notifier
1832 * Registration for net device changes of state.
1833 */
1834static struct notifier_block ecm_interface_netdev_notifier __read_mostly = {
1835 .notifier_call = ecm_interface_netdev_notifier_callback,
1836};
1837
1838/*
Ben Menchaca84f36632014-02-28 20:57:38 +00001839 * ecm_interface_get_stop()
1840 */
1841static ssize_t ecm_interface_get_stop(struct sys_device *dev,
1842 struct sysdev_attribute *attr,
1843 char *buf)
1844{
1845 ssize_t count;
1846 int num;
1847
1848 /*
1849 * Operate under our locks
1850 */
1851 spin_lock_bh(&ecm_interface_lock);
1852 num = ecm_interface_stopped;
1853 spin_unlock_bh(&ecm_interface_lock);
1854
1855 count = snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", num);
1856 return count;
1857}
1858
Nicolas Costaf46c33b2014-05-15 10:02:00 -05001859void ecm_interface_stop(int num)
1860{
1861 /*
1862 * Operate under our locks and stop further processing of packets
1863 */
1864 spin_lock_bh(&ecm_interface_lock);
1865 ecm_interface_stopped = num;
1866 spin_unlock_bh(&ecm_interface_lock);
1867
1868}
1869EXPORT_SYMBOL(ecm_interface_stop);
1870
1871
Ben Menchaca84f36632014-02-28 20:57:38 +00001872/*
1873 * ecm_interface_set_stop()
1874 */
1875static ssize_t ecm_interface_set_stop(struct sys_device *dev,
1876 struct sysdev_attribute *attr,
1877 const char *buf, size_t count)
1878{
1879 char num_buf[12];
1880 int num;
1881
1882 /*
1883 * Get the number from buf into a properly z-termed number buffer
1884 */
1885 if (count > 11) {
1886 return 0;
1887 }
1888 memcpy(num_buf, buf, count);
1889 num_buf[count] = '\0';
1890 sscanf(num_buf, "%d", &num);
1891 DEBUG_TRACE("ecm_interface_stop = %d\n", num);
1892
Nicolas Costaf46c33b2014-05-15 10:02:00 -05001893 ecm_interface_stop(num);
Ben Menchaca84f36632014-02-28 20:57:38 +00001894
1895 return count;
1896}
1897
1898/*
1899 * SysFS attributes for the default classifier itself.
1900 */
Ben Menchaca84f36632014-02-28 20:57:38 +00001901static SYSDEV_ATTR(stop, 0644, ecm_interface_get_stop, ecm_interface_set_stop);
1902
1903/*
1904 * SysFS class of the ubicom default classifier
1905 * SysFS control points can be found at /sys/devices/system/ecm_front_end/ecm_front_endX/
1906 */
1907static struct sysdev_class ecm_interface_sysclass = {
1908 .name = "ecm_interface",
1909};
1910
1911/*
Nicolas Costaf46c33b2014-05-15 10:02:00 -05001912 * ecm_interface_init()
Ben Menchaca84f36632014-02-28 20:57:38 +00001913 */
Nicolas Costaf46c33b2014-05-15 10:02:00 -05001914int ecm_interface_init(void)
Ben Menchaca84f36632014-02-28 20:57:38 +00001915{
1916 int result;
Nicolas Costaf46c33b2014-05-15 10:02:00 -05001917 DEBUG_INFO("ECM Interface init\n");
Ben Menchaca84f36632014-02-28 20:57:38 +00001918
1919 /*
Nicolas Costaf46c33b2014-05-15 10:02:00 -05001920 * Initialise our global lock
Ben Menchaca84f36632014-02-28 20:57:38 +00001921 */
Nicolas Costaf46c33b2014-05-15 10:02:00 -05001922 spin_lock_init(&ecm_interface_lock);
Ben Menchaca84f36632014-02-28 20:57:38 +00001923
1924 /*
1925 * Register the sysfs class
1926 */
1927 result = sysdev_class_register(&ecm_interface_sysclass);
1928 if (result) {
1929 DEBUG_ERROR("Failed to register SysFS class %d\n", result);
Nicolas Costaf46c33b2014-05-15 10:02:00 -05001930 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00001931 }
1932
1933 /*
1934 * Register SYSFS device control
1935 */
1936 memset(&ecm_interface_sys_dev, 0, sizeof(ecm_interface_sys_dev));
1937 ecm_interface_sys_dev.id = 0;
1938 ecm_interface_sys_dev.cls = &ecm_interface_sysclass;
1939 result = sysdev_register(&ecm_interface_sys_dev);
1940 if (result) {
1941 DEBUG_ERROR("Failed to register SysFS device %d\n", result);
Nicolas Costaf46c33b2014-05-15 10:02:00 -05001942 goto task_cleanup_1;
Ben Menchaca84f36632014-02-28 20:57:38 +00001943 }
1944
1945 /*
1946 * Create files, one for each parameter supported by this module
1947 */
Ben Menchaca84f36632014-02-28 20:57:38 +00001948 result = sysdev_create_file(&ecm_interface_sys_dev, &attr_stop);
1949 if (result) {
1950 DEBUG_ERROR("Failed to register stop file %d\n", result);
Nicolas Costaf46c33b2014-05-15 10:02:00 -05001951 goto task_cleanup_2;
Ben Menchaca84f36632014-02-28 20:57:38 +00001952 }
1953
1954 result = register_netdevice_notifier(&ecm_interface_netdev_notifier);
1955 if (result != 0) {
1956 DEBUG_ERROR("Failed to register netdevice notifier %d\n", result);
Nicolas Costaf46c33b2014-05-15 10:02:00 -05001957 goto task_cleanup_2;
Ben Menchaca84f36632014-02-28 20:57:38 +00001958 }
1959
Nicolas Costaf46c33b2014-05-15 10:02:00 -05001960 return 0;
Ben Menchaca84f36632014-02-28 20:57:38 +00001961
Ben Menchaca84f36632014-02-28 20:57:38 +00001962task_cleanup_2:
Nicolas Costaf46c33b2014-05-15 10:02:00 -05001963 sysdev_unregister(&ecm_interface_sys_dev);
Ben Menchaca84f36632014-02-28 20:57:38 +00001964task_cleanup_1:
Nicolas Costaf46c33b2014-05-15 10:02:00 -05001965 sysdev_class_unregister(&ecm_interface_sysclass);
Ben Menchaca84f36632014-02-28 20:57:38 +00001966
Ben Menchaca84f36632014-02-28 20:57:38 +00001967 return result;
1968}
Nicolas Costaf46c33b2014-05-15 10:02:00 -05001969EXPORT_SYMBOL(ecm_interface_init);
Ben Menchaca84f36632014-02-28 20:57:38 +00001970
1971/*
1972 * ecm_interface_exit()
1973 */
Nicolas Costaf46c33b2014-05-15 10:02:00 -05001974void ecm_interface_exit(void)
Ben Menchaca84f36632014-02-28 20:57:38 +00001975{
1976 DEBUG_INFO("ECM Interface exit\n");
Nicolas Costaf46c33b2014-05-15 10:02:00 -05001977
1978 spin_lock_bh(&ecm_interface_lock);
1979 ecm_interface_terminate_pending = true;
1980 spin_unlock_bh(&ecm_interface_lock);
1981
1982 unregister_netdevice_notifier(&ecm_interface_netdev_notifier);
1983 sysdev_unregister(&ecm_interface_sys_dev);
1984 sysdev_class_unregister(&ecm_interface_sysclass);
Ben Menchaca84f36632014-02-28 20:57:38 +00001985}
Nicolas Costaf46c33b2014-05-15 10:02:00 -05001986EXPORT_SYMBOL(ecm_interface_exit);