blob: f95850d670abb6a70a8f11c85e5eb1fe421f1d01 [file] [log] [blame]
Ben Menchaca84f36632014-02-28 20:57:38 +00001/*
2 **************************************************************************
Murat Sezgined9c1c62017-07-14 16:57:23 -07003 * Copyright (c) 2014-2018 The Linux Foundation. All rights reserved.
Ben Menchaca84f36632014-02-28 20:57:38 +00004 * 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
Murat Sezginb3731e82014-11-26 12:20:59 -080017#include <linux/version.h>
Ben Menchaca84f36632014-02-28 20:57:38 +000018#include <linux/types.h>
19#include <linux/ip.h>
20#include <linux/tcp.h>
21#include <linux/module.h>
22#include <linux/skbuff.h>
23#include <linux/icmp.h>
Ben Menchaca84f36632014-02-28 20:57:38 +000024#include <linux/kthread.h>
Ben Menchaca84f36632014-02-28 20:57:38 +000025#include <linux/pkt_sched.h>
26#include <linux/string.h>
27#include <net/ip6_route.h>
28#include <net/ip6_fib.h>
29#include <net/ipv6.h>
30#include <net/route.h>
Gareth Williams46f4b5f2014-06-01 23:35:23 +010031#include <net/ip_fib.h>
Ben Menchaca84f36632014-02-28 20:57:38 +000032#include <net/ip.h>
33#include <net/tcp.h>
34#include <asm/unaligned.h>
35#include <asm/uaccess.h> /* for put_user */
36#include <linux/inet.h>
37#include <linux/in6.h>
38#include <linux/in.h>
39#include <linux/udp.h>
40#include <linux/tcp.h>
Murat Sezgina205b042016-07-19 14:18:14 -070041#include <linux/kernel.h>
42#include <linux/netlink.h>
43#include <linux/rtnetlink.h>
44#include <linux/socket.h>
45#include <linux/wireless.h>
46
Murat Sezgin8c345822015-05-27 15:35:38 -070047#if defined(ECM_DB_XREF_ENABLE) && defined(ECM_BAND_STEERING_ENABLE)
ratheesh kannoth37e35b02015-03-26 11:25:02 +053048#include <linux/if_bridge.h>
Murat Sezgin8c345822015-05-27 15:35:38 -070049#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000050#include <linux/inetdevice.h>
Murat Sezginc1402562015-03-12 12:32:20 -070051#if defined(ECM_INTERFACE_TUNIPIP6_ENABLE) || defined(ECM_INTERFACE_SIT_ENABLE)
Tushar Mathur39f63f62015-06-19 14:31:14 +053052#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 9, 0))
Ben Menchaca84f36632014-02-28 20:57:38 +000053#include <net/ipip.h>
Tushar Mathur39f63f62015-06-19 14:31:14 +053054#else
55#include <net/ip_tunnels.h>
56#endif
Murat Sezginb3731e82014-11-26 12:20:59 -080057#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000058#include <net/ip6_tunnel.h>
Gareth Williams43fc0852014-05-26 19:10:00 +010059#include <net/addrconf.h>
Ben Menchaca84f36632014-02-28 20:57:38 +000060#include <linux/if_arp.h>
61#include <linux/netfilter_ipv4.h>
62#include <linux/netfilter_bridge.h>
63#include <linux/if_bridge.h>
64#include <net/arp.h>
65#include <net/netfilter/nf_conntrack.h>
66#include <net/netfilter/nf_conntrack_acct.h>
67#include <net/netfilter/nf_conntrack_helper.h>
68#include <net/netfilter/nf_conntrack_l4proto.h>
69#include <net/netfilter/nf_conntrack_l3proto.h>
70#include <net/netfilter/nf_conntrack_zones.h>
71#include <net/netfilter/nf_conntrack_core.h>
ratheesh kannotha6d25952016-04-11 12:23:26 +053072#include <linux/netfilter_ipv6/ip6_tables.h>
Ben Menchaca84f36632014-02-28 20:57:38 +000073#include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
74#include <net/netfilter/ipv4/nf_defrag_ipv4.h>
Gareth Williams141d2382014-11-25 11:35:19 -080075#ifdef ECM_INTERFACE_VLAN_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +000076#include <linux/../../net/8021q/vlan.h>
77#include <linux/if_vlan.h>
Gareth Williams141d2382014-11-25 11:35:19 -080078#endif
Murat Sezgina683edd2015-01-20 10:48:30 -080079#ifdef ECM_INTERFACE_PPP_ENABLE
80#include <linux/if_pppox.h>
ratheesh kannotha32fdd12015-09-09 08:02:58 +053081#ifdef ECM_INTERFACE_L2TPV2_ENABLE
ratheesh kannoth08b8e442015-10-02 00:24:55 +053082#include <linux/if_pppol2tp.h>
ratheesh kannotha32fdd12015-09-09 08:02:58 +053083#endif
Shyam Sunder23f2e542015-09-28 14:56:49 +053084#ifdef ECM_INTERFACE_PPTP_ENABLE
85#include <linux/netfilter/nf_conntrack_proto_gre.h>
86#endif
Murat Sezgina683edd2015-01-20 10:48:30 -080087#endif
ratheesh kannothcfdcb332015-12-24 07:19:18 +053088#ifdef ECM_INTERFACE_MAP_T_ENABLE
89#include <nat46-core.h>
90#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000091
92/*
93 * Debug output levels
94 * 0 = OFF
95 * 1 = ASSERTS / ERRORS
96 * 2 = 1 + WARN
97 * 3 = 2 + INFO
98 * 4 = 3 + TRACE
99 */
100#define DEBUG_LEVEL ECM_INTERFACE_DEBUG_LEVEL
101
Shyam Sunder6358b862015-05-04 15:06:24 +0530102#ifdef ECM_MULTICAST_ENABLE
103#include <mc_ecm.h>
104#endif
105
Ben Menchaca84f36632014-02-28 20:57:38 +0000106#include "ecm_types.h"
107#include "ecm_db_types.h"
Gareth Williamsd5618a82015-05-20 11:13:32 +0100108#include "ecm_state.h"
Ben Menchaca84f36632014-02-28 20:57:38 +0000109#include "ecm_tracker.h"
110#include "ecm_classifier.h"
111#include "ecm_front_end_types.h"
112#include "ecm_tracker_datagram.h"
113#include "ecm_tracker_udp.h"
114#include "ecm_tracker_tcp.h"
115#include "ecm_db.h"
116#include "ecm_interface.h"
117
Murat Sezgina205b042016-07-19 14:18:14 -0700118/*
119 * Wifi event handler structure.
120 */
121struct ecm_interface_wifi_event {
122 struct task_struct *thread;
123 struct socket *sock;
124};
125
126static struct ecm_interface_wifi_event __ewn;
127
Gareth Williams8ac34292015-03-17 14:06:58 +0000128#ifdef ECM_IPV6_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000129/*
Gareth Williamsadf425f2014-05-26 19:29:02 +0100130 * TODO: Remove once the Linux image and headers get propogated.
131 */
132struct net_device *ipv6_dev_find(struct net *net, struct in6_addr *addr, int strict);
Murat Sezgin49465a42014-11-24 15:37:48 -0800133#endif
Gareth Williamsadf425f2014-05-26 19:29:02 +0100134
135/*
Ben Menchaca84f36632014-02-28 20:57:38 +0000136 * Locking - concurrency control
137 */
Murat Sezgin908ecb32015-05-10 20:54:36 -0700138static DEFINE_SPINLOCK(ecm_interface_lock); /* Protect against SMP access between netfilter, events and private threaded function. */
Ben Menchaca84f36632014-02-28 20:57:38 +0000139
140/*
141 * Management thread control
142 */
143static bool ecm_interface_terminate_pending = false; /* True when the user has signalled we should quit */
Ben Menchaca84f36632014-02-28 20:57:38 +0000144
145/*
Murat Sezgineebedb92017-11-17 17:14:32 -0800146 * Source interface check flag.
147 * If it is enabled, the acceleration engine will check the flow's interface to see
148 * whether it matches with the rule's source interface or not.
149 */
150int ecm_interface_src_check;
151
152static struct ctl_table_header *ecm_interface_ctl_table_header; /* Sysctl table header */
153
154/*
Murat Sezginb3731e82014-11-26 12:20:59 -0800155 * ecm_interface_get_and_hold_dev_master()
156 * Returns the master device of a net device if any.
157 */
158struct net_device *ecm_interface_get_and_hold_dev_master(struct net_device *dev)
159{
160 struct net_device *master;
161#if (LINUX_VERSION_CODE > KERNEL_VERSION(3,6,0))
162 rcu_read_lock();
163 master = netdev_master_upper_dev_get_rcu(dev);
164 if (!master) {
165 rcu_read_unlock();
166 return NULL;
167 }
168 dev_hold(master);
169 rcu_read_unlock();
170#else
171 master = dev->master;
172 if (!master) {
173 return NULL;
174 }
175 dev_hold(master);
176#endif
177 return master;
178}
179EXPORT_SYMBOL(ecm_interface_get_and_hold_dev_master);
180
181/*
Shyam Sunder9db20852016-03-09 19:04:49 +0530182 * ecm_interface_vlan_real_dev()
183 * Return immediate VLAN net device or Physical device pointer
184 */
185static inline struct net_device *ecm_interface_vlan_real_dev(struct net_device *vlan_dev)
186{
187#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 6, 0))
188 return vlan_dev_next_dev(vlan_dev);
189#else
190 return vlan_dev_real_dev(vlan_dev);
191#endif
192}
193
194/*
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100195 * ecm_interface_dev_find_by_local_addr_ipv4()
Shyam Sunder9db20852016-03-09 19:04:49 +0530196 * Return a hold to the device for the given local IP address. Returns NULL on failure.
Gareth Williamsadf425f2014-05-26 19:29:02 +0100197 */
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100198static struct net_device *ecm_interface_dev_find_by_local_addr_ipv4(ip_addr_t addr)
Gareth Williamsadf425f2014-05-26 19:29:02 +0100199{
200 __be32 be_addr;
201 struct net_device *dev;
202
203 ECM_IP_ADDR_TO_NIN4_ADDR(be_addr, addr);
204 dev = ip_dev_find(&init_net, be_addr);
205 return dev;
206}
207
Gareth Williams8ac34292015-03-17 14:06:58 +0000208#ifdef ECM_IPV6_ENABLE
Gareth Williamsadf425f2014-05-26 19:29:02 +0100209/*
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100210 * ecm_interface_dev_find_by_local_addr_ipv6()
211 * Return a hold to the device for the given local IP address. Returns NULL on failure.
Gareth Williamsadf425f2014-05-26 19:29:02 +0100212 */
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100213static struct net_device *ecm_interface_dev_find_by_local_addr_ipv6(ip_addr_t addr)
Gareth Williamsadf425f2014-05-26 19:29:02 +0100214{
215 struct in6_addr addr6;
216 struct net_device *dev;
217
218 ECM_IP_ADDR_TO_NIN6_ADDR(addr6, addr);
219 dev = (struct net_device *)ipv6_dev_find(&init_net, &addr6, 1);
220 return dev;
221}
Murat Sezgin49465a42014-11-24 15:37:48 -0800222#endif
Gareth Williamsadf425f2014-05-26 19:29:02 +0100223
224/*
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100225 * ecm_interface_dev_find_by_local_addr()
226 * Return the device on which the local address resides.
Gareth Williamsadf425f2014-05-26 19:29:02 +0100227 *
228 * Returns a hold to the device or NULL on failure.
229 */
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100230struct net_device *ecm_interface_dev_find_by_local_addr(ip_addr_t addr)
Gareth Williamsadf425f2014-05-26 19:29:02 +0100231{
232 char __attribute__((unused)) addr_str[40];
233
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100234 DEBUG_ECM_IP_ADDR_TO_STRING(addr_str, addr);
Gareth Williamsadf425f2014-05-26 19:29:02 +0100235 DEBUG_TRACE("Locate dev for: %s\n", addr_str);
236
237 if (ECM_IP_ADDR_IS_V4(addr)) {
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100238 return ecm_interface_dev_find_by_local_addr_ipv4(addr);
Gareth Williamsadf425f2014-05-26 19:29:02 +0100239 }
240
Gareth Williams8ac34292015-03-17 14:06:58 +0000241#ifdef ECM_IPV6_ENABLE
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100242 return ecm_interface_dev_find_by_local_addr_ipv6(addr);
Murat Sezgin49465a42014-11-24 15:37:48 -0800243#else
244 return NULL;
245#endif
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100246}
247EXPORT_SYMBOL(ecm_interface_dev_find_by_local_addr);
248
249/*
250 * ecm_interface_dev_find_by_addr()
251 * Return the net device on which the given IP address resides. Returns NULL on faiure.
252 *
253 * NOTE: The device may be the device upon which has a default gateway to reach the address.
254 * from_local_addr is true when the device was found by a local address search.
255 */
256struct net_device *ecm_interface_dev_find_by_addr(ip_addr_t addr, bool *from_local_addr)
257{
258 char __attribute__((unused)) addr_str[40];
259 struct ecm_interface_route ecm_rt;
260 struct net_device *dev;
261 struct dst_entry *dst;
262
263 DEBUG_ECM_IP_ADDR_TO_STRING(addr_str, addr);
264
265 /*
266 * Is the address a local IP?
267 */
268 DEBUG_TRACE("find net device for address: %s\n", addr_str);
269 dev = ecm_interface_dev_find_by_local_addr(addr);
270 if (dev) {
271 *from_local_addr = true;
272 DEBUG_TRACE("addr: %s is local: %p (%s)\n", addr_str, dev, dev->name);
273 return dev;
274 }
275
276 DEBUG_TRACE("addr: %s is not local\n", addr_str);
277
278 /*
279 * Try a route to the address instead
280 * NOTE: This will locate a route entry in the route destination *cache*.
281 */
282 if (!ecm_interface_find_route_by_addr(addr, &ecm_rt)) {
283 DEBUG_WARN("addr: %s - no dev locatable\n", addr_str);
284 return NULL;
285 }
286
287 *from_local_addr = false;
288 dst = ecm_rt.dst;
289 dev = dst->dev;
290 dev_hold(dev);
291 ecm_interface_route_release(&ecm_rt);
292 DEBUG_TRACE("dest_addr: %s uses dev: %p(%s)\n", addr_str, dev, dev->name);
293 return dev;
Gareth Williamsadf425f2014-05-26 19:29:02 +0100294}
295EXPORT_SYMBOL(ecm_interface_dev_find_by_addr);
296
Gareth Williams8ac34292015-03-17 14:06:58 +0000297#ifdef ECM_IPV6_ENABLE
Gareth Williamsadf425f2014-05-26 19:29:02 +0100298/*
Ben Menchaca84f36632014-02-28 20:57:38 +0000299 * ecm_interface_mac_addr_get_ipv6()
300 * Return mac for an IPv6 address
301 *
302 * GGG TODO Need to make sure this also works for local IP addresses too.
303 */
304static bool ecm_interface_mac_addr_get_ipv6(ip_addr_t addr, uint8_t *mac_addr, bool *on_link, ip_addr_t gw_addr)
305{
306 struct in6_addr daddr;
307 struct ecm_interface_route ecm_rt;
308 struct neighbour *neigh;
309 struct rt6_info *rt;
310 struct dst_entry *dst;
311
312 /*
313 * Get the MAC address that corresponds to IP address given.
314 * We look up the rt6_info entries and, from its neighbour structure, obtain the hardware address.
315 * This means we will also work if the neighbours are routers too.
316 */
317 ECM_IP_ADDR_TO_NIN6_ADDR(daddr, addr);
318 if (!ecm_interface_find_route_by_addr(addr, &ecm_rt)) {
Kiran Kumar C. S. K7d178222014-06-27 18:47:29 +0530319 *on_link = false;
Ben Menchaca84f36632014-02-28 20:57:38 +0000320 return false;
321 }
322 DEBUG_ASSERT(!ecm_rt.v4_route, "Did not locate a v6 route!\n");
323
324 /*
325 * Is this destination on link or off-link via a gateway?
326 */
327 rt = ecm_rt.rt.rtv6;
328 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)) {
329 *on_link = false;
330 ECM_NIN6_ADDR_TO_IP_ADDR(gw_addr, rt->rt6i_gateway)
331 } else {
332 *on_link = true;
333 }
334
335 rcu_read_lock();
336 dst = ecm_rt.dst;
Murat Sezgine9b84582015-01-27 17:34:14 -0800337#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3,6,0))
Ben Menchaca84f36632014-02-28 20:57:38 +0000338 neigh = dst_get_neighbour_noref(dst);
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700339 if (neigh) {
340 neigh_hold(neigh);
Murat Sezgine9b84582015-01-27 17:34:14 -0800341 }
342#else
343 neigh = dst_neigh_lookup(dst, &daddr);
344#endif
345 if (!neigh) {
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700346 neigh = neigh_lookup(&nd_tbl, &daddr, dst->dev);
347 }
Murat Sezgine9b84582015-01-27 17:34:14 -0800348
Ben Menchaca84f36632014-02-28 20:57:38 +0000349 if (!neigh) {
350 rcu_read_unlock();
351 ecm_interface_route_release(&ecm_rt);
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700352 DEBUG_WARN("No neigh reference\n");
Ben Menchaca84f36632014-02-28 20:57:38 +0000353 return false;
354 }
355 if (!(neigh->nud_state & NUD_VALID)) {
356 rcu_read_unlock();
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700357 neigh_release(neigh);
Ben Menchaca84f36632014-02-28 20:57:38 +0000358 ecm_interface_route_release(&ecm_rt);
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700359 DEBUG_WARN("NUD invalid\n");
Ben Menchaca84f36632014-02-28 20:57:38 +0000360 return false;
361 }
362 if (!neigh->dev) {
363 rcu_read_unlock();
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700364 neigh_release(neigh);
Ben Menchaca84f36632014-02-28 20:57:38 +0000365 ecm_interface_route_release(&ecm_rt);
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700366 DEBUG_WARN("Neigh dev invalid\n");
Ben Menchaca84f36632014-02-28 20:57:38 +0000367 return false;
368 }
369
370 /*
371 * If neigh->dev is a loopback then addr is a local address in which case we take the MAC from given device
372 */
373 if (neigh->dev->flags & IFF_LOOPBACK) {
374 // GGG TODO Create an equivalent logic to that for ipv4, maybe need to create an ip6_dev_find()?
375 DEBUG_TRACE("local address " ECM_IP_ADDR_OCTAL_FMT " (found loopback)\n", ECM_IP_ADDR_TO_OCTAL(addr));
376 memset(mac_addr, 0, 6);
377 } else {
378 memcpy(mac_addr, neigh->ha, 6);
379 }
380 rcu_read_unlock();
Murat Sezgindcbcdb52014-05-15 16:06:13 -0700381 neigh_release(neigh);
Ben Menchaca84f36632014-02-28 20:57:38 +0000382 ecm_interface_route_release(&ecm_rt);
383
384 DEBUG_TRACE(ECM_IP_ADDR_OCTAL_FMT " maps to %pM\n", ECM_IP_ADDR_TO_OCTAL(addr), mac_addr);
385 return true;
386}
Murat Sezgin5dae8832015-12-03 14:23:19 -0800387
388/*
389 * ecm_interface_find_gateway_ipv6()
390 * Finds the ipv6 gateway ip address of a given ipv6 address.
391 */
392static bool ecm_interface_find_gateway_ipv6(ip_addr_t addr, ip_addr_t gw_addr)
393{
394 struct ecm_interface_route ecm_rt;
395 struct rt6_info *rt;
396
397 /*
398 * Find the ipv6 route of the given ip address to look up
399 * whether we have a gateway to reach to that ip address or not.
400 */
401 if (!ecm_interface_find_route_by_addr(addr, &ecm_rt)) {
402 return false;
403 }
404 DEBUG_ASSERT(!ecm_rt.v4_route, "Did not locate a v6 route!\n");
405 DEBUG_TRACE("Found route\n");
406
407 /*
408 * Is this destination reachable via a gateway?
409 */
410 rt = ecm_rt.rt.rtv6;
411 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)) {
Murat Sezgin313f2222016-08-11 12:22:10 -0700412 ecm_interface_route_release(&ecm_rt);
Murat Sezgin5dae8832015-12-03 14:23:19 -0800413 return false;
414 }
415
416 ECM_NIN6_ADDR_TO_IP_ADDR(gw_addr, rt->rt6i_gateway)
Murat Sezgin313f2222016-08-11 12:22:10 -0700417 ecm_interface_route_release(&ecm_rt);
Murat Sezgin5dae8832015-12-03 14:23:19 -0800418 return true;
419}
Murat Sezgin49465a42014-11-24 15:37:48 -0800420#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000421
422/*
Murat Sezgin5dae8832015-12-03 14:23:19 -0800423 * ecm_interface_find_gateway_ipv4()
424 * Finds the ipv4 gateway address of a given ipv4 address.
425 */
426static bool ecm_interface_find_gateway_ipv4(ip_addr_t addr, ip_addr_t gw_addr)
427{
428 struct ecm_interface_route ecm_rt;
429 struct rtable *rt;
430
431 /*
432 * Find the ipv4 route of the given ip address to look up
433 * whether we have a gateway to reach to that ip address or not.
434 */
435 if (!ecm_interface_find_route_by_addr(addr, &ecm_rt)) {
436 return false;
437 }
438 DEBUG_ASSERT(ecm_rt.v4_route, "Did not locate a v4 route!\n");
439 DEBUG_TRACE("Found route\n");
440
441 /*
442 * Is this destination reachable via a gateway?
443 */
444 rt = ecm_rt.rt.rtv4;
445#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 6, 0))
446 if (!(rt->rt_dst != rt->rt_gateway) && !(rt->rt_flags & RTF_GATEWAY)) {
447#else
448 if (!rt->rt_uses_gateway && !(rt->rt_flags & RTF_GATEWAY)) {
449#endif
Murat Sezgin313f2222016-08-11 12:22:10 -0700450 ecm_interface_route_release(&ecm_rt);
Murat Sezgin5dae8832015-12-03 14:23:19 -0800451 return false;
452 }
453
454 ECM_NIN4_ADDR_TO_IP_ADDR(gw_addr, rt->rt_gateway)
Murat Sezgin313f2222016-08-11 12:22:10 -0700455 ecm_interface_route_release(&ecm_rt);
Murat Sezgin5dae8832015-12-03 14:23:19 -0800456 return true;
457}
458
459/*
460 * ecm_interface_find_gateway()
461 * Finds the gateway ip address of a given ECM ip address type.
462 */
463bool ecm_interface_find_gateway(ip_addr_t addr, ip_addr_t gw_addr)
464{
465 if (ECM_IP_ADDR_IS_V4(addr)) {
466 return ecm_interface_find_gateway_ipv4(addr, gw_addr);
467 }
468
469#ifdef ECM_IPV6_ENABLE
470 return ecm_interface_find_gateway_ipv6(addr, gw_addr);
471#else
472 return false;
473#endif
474}
475EXPORT_SYMBOL(ecm_interface_find_gateway);
476
477/*
Ben Menchaca84f36632014-02-28 20:57:38 +0000478 * ecm_interface_mac_addr_get_ipv4()
479 * Return mac for an IPv4 address
480 */
481static bool ecm_interface_mac_addr_get_ipv4(ip_addr_t addr, uint8_t *mac_addr, bool *on_link, ip_addr_t gw_addr)
482{
483 struct neighbour *neigh;
484 struct ecm_interface_route ecm_rt;
485 struct rtable *rt;
486 struct dst_entry *dst;
487 __be32 ipv4_addr;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530488
Ben Menchaca84f36632014-02-28 20:57:38 +0000489 /*
490 * Get the MAC address that corresponds to IP address given.
491 * We look up the rtable entries and, from its neighbour structure, obtain the hardware address.
492 * This means we will also work if the neighbours are routers too.
493 * We also locate the MAC if the address is a local host address.
494 */
495 ECM_IP_ADDR_TO_NIN4_ADDR(ipv4_addr, addr);
496 if (!ecm_interface_find_route_by_addr(addr, &ecm_rt)) {
Kiran Kumar C. S. K7d178222014-06-27 18:47:29 +0530497 *on_link = false;
Ben Menchaca84f36632014-02-28 20:57:38 +0000498 return false;
499 }
500 DEBUG_ASSERT(ecm_rt.v4_route, "Did not locate a v4 route!\n");
Murat Sezginb3731e82014-11-26 12:20:59 -0800501 DEBUG_TRACE("Found route\n");
Ben Menchaca84f36632014-02-28 20:57:38 +0000502
503 /*
504 * Is this destination on link or off-link via a gateway?
505 */
506 rt = ecm_rt.rt.rtv4;
Murat Sezginb3731e82014-11-26 12:20:59 -0800507#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3,6,0))
Ben Menchaca84f36632014-02-28 20:57:38 +0000508 if ((rt->rt_dst != rt->rt_gateway) || (rt->rt_flags & RTF_GATEWAY)) {
Murat Sezginb3731e82014-11-26 12:20:59 -0800509#else
510 if (rt->rt_uses_gateway || (rt->rt_flags & RTF_GATEWAY)) {
511#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000512 *on_link = false;
513 ECM_NIN4_ADDR_TO_IP_ADDR(gw_addr, rt->rt_gateway)
514 } else {
515 *on_link = true;
516 }
517
518 /*
519 * Get the neighbour entry for the address
520 */
521 rcu_read_lock();
522 dst = ecm_rt.dst;
Murat Sezginb3731e82014-11-26 12:20:59 -0800523#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3,6,0))
Ben Menchaca84f36632014-02-28 20:57:38 +0000524 neigh = dst_get_neighbour_noref(dst);
525 if (neigh) {
526 neigh_hold(neigh);
Murat Sezginb3731e82014-11-26 12:20:59 -0800527 }
528#else
529 neigh = dst_neigh_lookup(dst, &ipv4_addr);
530#endif
531 if (!neigh) {
Ben Menchaca84f36632014-02-28 20:57:38 +0000532 neigh = neigh_lookup(&arp_tbl, &ipv4_addr, dst->dev);
533 }
534 if (!neigh) {
535 rcu_read_unlock();
536 ecm_interface_route_release(&ecm_rt);
Murat Sezginb3731e82014-11-26 12:20:59 -0800537 DEBUG_WARN("no neigh\n");
Ben Menchaca84f36632014-02-28 20:57:38 +0000538 return false;
539 }
540 if (!(neigh->nud_state & NUD_VALID)) {
541 rcu_read_unlock();
542 neigh_release(neigh);
543 ecm_interface_route_release(&ecm_rt);
Murat Sezginb3731e82014-11-26 12:20:59 -0800544 DEBUG_WARN("neigh nud state is not valid\n");
Ben Menchaca84f36632014-02-28 20:57:38 +0000545 return false;
546 }
547 if (!neigh->dev) {
548 rcu_read_unlock();
549 neigh_release(neigh);
550 ecm_interface_route_release(&ecm_rt);
Murat Sezginb3731e82014-11-26 12:20:59 -0800551 DEBUG_WARN("neigh has no device\n");
Ben Menchaca84f36632014-02-28 20:57:38 +0000552 return false;
553 }
554
555 /*
556 * If the device is loopback this will be because the address is a local address
557 * In this case locate the device that has this local address and get its mac.
558 */
559 if (neigh->dev->type == ARPHRD_LOOPBACK) {
560 struct net_device *dev;
561
562 DEBUG_TRACE("%pI4 finds loopback device, dev: %p (%s)\n", &ipv4_addr, neigh->dev, neigh->dev->name);
563 rcu_read_unlock();
564 neigh_release(neigh);
565 ecm_interface_route_release(&ecm_rt);
566
567 /*
568 * Lookup the device that has this IP address assigned
569 */
570 dev = ip_dev_find(&init_net, ipv4_addr);
571 if (!dev) {
572 DEBUG_WARN("Unable to locate dev for: %pI4\n", &ipv4_addr);
573 return false;
574 }
575 memcpy(mac_addr, dev->dev_addr, (size_t)dev->addr_len);
576 DEBUG_TRACE("is local addr: %pI4, mac: %pM, dev ifindex: %d, dev: %p (%s), dev_type: %d\n",
577 &ipv4_addr, mac_addr, dev->ifindex, dev, dev->name, dev->type);
578 dev_put(dev);
579 return true;
580 }
581
582 if (!(neigh->dev->flags & IFF_NOARP)) {
583 memcpy(mac_addr, neigh->ha, (size_t)neigh->dev->addr_len);
584 } else {
585 DEBUG_TRACE("non-arp device: %p (%s, type: %d) to reach %pI4\n", neigh->dev, neigh->dev->name, neigh->dev->type, &ipv4_addr);
586 memset(mac_addr, 0, 6);
587 }
588 DEBUG_TRACE("addr: %pI4, mac: %pM, iif: %d, neigh dev ifindex: %d, dev: %p (%s), dev_type: %d\n",
589 &ipv4_addr, mac_addr, rt->rt_iif, neigh->dev->ifindex, neigh->dev, neigh->dev->name, neigh->dev->type);
590
591 rcu_read_unlock();
592 neigh_release(neigh);
593 ecm_interface_route_release(&ecm_rt);
594 return true;
595}
596
597/*
598 * ecm_interface_mac_addr_get()
599 * Return the mac address for the given IP address. Returns false on failure.
Ben Menchaca84f36632014-02-28 20:57:38 +0000600 */
601bool ecm_interface_mac_addr_get(ip_addr_t addr, uint8_t *mac_addr, bool *on_link, ip_addr_t gw_addr)
602{
603 if (ECM_IP_ADDR_IS_V4(addr)) {
604 return ecm_interface_mac_addr_get_ipv4(addr, mac_addr, on_link, gw_addr);
605 }
606
Gareth Williams8ac34292015-03-17 14:06:58 +0000607#ifdef ECM_IPV6_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000608 return ecm_interface_mac_addr_get_ipv6(addr, mac_addr, on_link, gw_addr);
Murat Sezgin49465a42014-11-24 15:37:48 -0800609#else
610 return false;
611#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000612}
613EXPORT_SYMBOL(ecm_interface_mac_addr_get);
614
Murat Sezgin5dae8832015-12-03 14:23:19 -0800615#ifdef ECM_IPV6_ENABLE
616/*
617 * ecm_interface_mac_addr_get_ipv6_no_route()
618 * Finds the mac address of a node from its ip address reachable via
619 * the given device. It looks up the mac address in the neighbour entries.
620 * It doesn't do any route lookup to find the dst entry.
621 */
622static bool ecm_interface_mac_addr_get_ipv6_no_route(struct net_device *dev, ip_addr_t addr, uint8_t *mac_addr)
623{
624 struct in6_addr daddr;
625 struct neighbour *neigh;
626 struct net_device *local_dev;
627
628 memset(mac_addr, 0, ETH_ALEN);
629
630 /*
631 * Get the MAC address that corresponds to IP address given.
632 */
633 ECM_IP_ADDR_TO_NIN6_ADDR(daddr, addr);
634 local_dev = ipv6_dev_find(&init_net, &daddr, 1);
635 if (local_dev) {
636 DEBUG_TRACE("%pi6 is a local address\n", &daddr);
637 memcpy(mac_addr, dev->dev_addr, ETH_ALEN);
638 dev_put(local_dev);
639 return true;
640 }
641
642 rcu_read_lock();
643 neigh = neigh_lookup(&nd_tbl, &daddr, dev);
644 if (!neigh) {
645 rcu_read_unlock();
646 DEBUG_WARN("No neigh reference\n");
647 return false;
648 }
649 if (!(neigh->nud_state & NUD_VALID)) {
650 neigh_release(neigh);
651 rcu_read_unlock();
652 DEBUG_WARN("NUD invalid\n");
653 return false;
654 }
655 if (!neigh->dev) {
656 neigh_release(neigh);
657 rcu_read_unlock();
658 DEBUG_WARN("Neigh dev invalid\n");
659 return false;
660 }
661
662 if (neigh->dev->flags & IFF_NOARP) {
663 neigh_release(neigh);
664 rcu_read_unlock();
665 DEBUG_TRACE("dest MAC is zero: %pM\n", mac_addr);
666 return true;
667 }
668
669 memcpy(mac_addr, neigh->ha, (size_t)neigh->dev->addr_len);
670 neigh_release(neigh);
671 rcu_read_unlock();
672 DEBUG_TRACE(ECM_IP_ADDR_OCTAL_FMT " maps to %pM\n", ECM_IP_ADDR_TO_OCTAL(addr), mac_addr);
673 return true;
674}
675#endif
676
677/*
678 * ecm_interface_mac_addr_get_ipv4_no_route()
679 * Finds the mac address of a node from its ip address reachable via
680 * the given device. It looks up the mac address in the neighbour entries.
681 * It doesn't do any route lookup to find the dst entry.
682 */
683static bool ecm_interface_mac_addr_get_ipv4_no_route(struct net_device *dev, ip_addr_t ip_addr, uint8_t *mac_addr)
684{
685 struct neighbour *neigh;
686 __be32 be_addr;
687 struct net_device *local_dev;
688
689 memset(mac_addr, 0, ETH_ALEN);
690
691 ECM_IP_ADDR_TO_NIN4_ADDR(be_addr, ip_addr);
692 local_dev = ip_dev_find(&init_net, be_addr);
693 if (local_dev) {
694 DEBUG_TRACE("%pI4n is a local address\n", &be_addr);
695 memcpy(mac_addr, dev->dev_addr, ETH_ALEN);
696 dev_put(local_dev);
697 return true;
698 }
699
700 rcu_read_lock();
701 neigh = neigh_lookup(&arp_tbl, &be_addr, dev);
702 if (!neigh) {
703 rcu_read_unlock();
704 DEBUG_WARN("no neigh\n");
705 return false;
706 }
707 if (!(neigh->nud_state & NUD_VALID)) {
708 neigh_release(neigh);
709 rcu_read_unlock();
710 DEBUG_WARN("neigh nud state is not valid\n");
711 return false;
712 }
713 if (!neigh->dev) {
714 neigh_release(neigh);
715 rcu_read_unlock();
716 DEBUG_WARN("neigh has no device\n");
717 return false;
718 }
719
720 if (neigh->dev->flags & IFF_NOARP) {
721 neigh_release(neigh);
722 rcu_read_unlock();
723 DEBUG_TRACE("dest MAC is zero: %pM\n", mac_addr);
724 return true;
725 }
726
727 memcpy(mac_addr, neigh->ha, (size_t)neigh->dev->addr_len);
728 neigh_release(neigh);
729 rcu_read_unlock();
730 DEBUG_TRACE("dest MAC: %pM\n", mac_addr);
731 return true;
732
733}
734
735/*
736 * ecm_interface_mac_addr_get_no_route()
737 * Return the mac address for the given IP address reacahble via the given device.
738 * Return false on failure, true on success.
739 */
740bool ecm_interface_mac_addr_get_no_route(struct net_device *dev, ip_addr_t addr, uint8_t *mac_addr)
741{
742 if (ECM_IP_ADDR_IS_V4(addr)) {
743 return ecm_interface_mac_addr_get_ipv4_no_route(dev, addr, mac_addr);
744 }
745
746#ifdef ECM_IPV6_ENABLE
747 return ecm_interface_mac_addr_get_ipv6_no_route(dev, addr, mac_addr);
748#else
749 return false;
750#endif
751}
752EXPORT_SYMBOL(ecm_interface_mac_addr_get_no_route);
753
Shyam Sunder6358b862015-05-04 15:06:24 +0530754#ifdef ECM_MULTICAST_ENABLE
755/*
756 * ecm_interface_multicast_check_for_br_dev()
757 * Find a bridge dev is present or not in an
758 * array of Ifindexs
759 */
760bool ecm_interface_multicast_check_for_br_dev(uint32_t dest_if[], uint8_t max_if)
761{
762 struct net_device *br_dev;
763 int i;
764
765 for (i = 0; i < max_if; i++) {
766 br_dev = dev_get_by_index(&init_net, dest_if[i]);
767 if (!br_dev) {
ratheesh kannothc5df16c2018-03-16 21:07:23 +0530768 /*
769 * Interface got deleted; but is yet to be updated in MFC table
770 */
771 DEBUG_WARN("Could not find a valid netdev here\n");
Shyam Sunder6358b862015-05-04 15:06:24 +0530772 continue;
773 }
774
775 if (ecm_front_end_is_bridge_device(br_dev)) {
776 dev_put(br_dev);
777 return true;
778 }
779 dev_put(br_dev);
780 }
781 return false;
782}
783EXPORT_SYMBOL(ecm_interface_multicast_check_for_br_dev);
Shyam Sundera2e08ee2015-06-18 21:32:13 +0530784
785/*
ratheesh kannothc5df16c2018-03-16 21:07:23 +0530786 * ecm_interface_multicast_is_iface_type()
787 * Checks if interface of type exist in mc_if_index
788 */
789bool ecm_interface_multicast_is_iface_type(int32_t mc_if_index[], int32_t max_if_index, unsigned short type)
790{
791 int32_t i;
792 struct net_device *dev;
793
794 for (i = 0; i < max_if_index; i++) {
795
796 if (!mc_if_index[i]) {
797 break;
798 }
799
800 dev = dev_get_by_index(&init_net, mc_if_index[i]);
801 if (!dev) {
802 DEBUG_WARN("Could not find a valid interface with index = %d\n", mc_if_index[i]);
803 continue;
804 }
805
806 if (dev->type == type) {
807 DEBUG_TRACE("Interface dev = %s of type %u\n", dev->name, type);
808 dev_put(dev);
809 return true;
810 }
811
812 dev_put(dev);
813 }
814
815 return false;
816}
817
818/*
Shyam Sundera2e08ee2015-06-18 21:32:13 +0530819 * ecm_interface_multicast_check_for_src_if_index()
820 * Find if a source netdev ifindex is matching with list of
821 * multicast destination netdev ifindex. If find a match then
822 * returns a new list of destination netdev ifindex excluding
823 * the ifindex of source netdev.
824 */
825int32_t ecm_interface_multicast_check_for_src_ifindex(int32_t mc_if_index[], int32_t max_if_index, int32_t if_num)
826{
827 int32_t i;
828 int32_t valid_index;
829
830 for (i = 0, valid_index = 0; i < max_if_index; i++) {
831 if (mc_if_index[i] == 0) {
832 break;
833 }
834
835 if (mc_if_index[i] != if_num) {
836 mc_if_index[valid_index] = mc_if_index[i];
837 valid_index++;
838 continue;
839 }
840 }
841
842 return valid_index;
843}
844EXPORT_SYMBOL(ecm_interface_multicast_check_for_src_ifindex);
Shyam Sunder6358b862015-05-04 15:06:24 +0530845#endif
846
Ben Menchaca84f36632014-02-28 20:57:38 +0000847/*
848 * ecm_interface_addr_find_route_by_addr_ipv4()
849 * Return the route for the given IP address. Returns NULL on failure.
850 */
851static bool ecm_interface_find_route_by_addr_ipv4(ip_addr_t addr, struct ecm_interface_route *ecm_rt)
852{
853 __be32 be_addr;
854
855 /*
856 * Get a route to the given IP address, this will allow us to also find the interface
857 * it is using to communicate with that IP address.
858 */
859 ECM_IP_ADDR_TO_NIN4_ADDR(be_addr, addr);
860 ecm_rt->rt.rtv4 = ip_route_output(&init_net, be_addr, 0, 0, 0);
861 if (IS_ERR(ecm_rt->rt.rtv4)) {
862 DEBUG_TRACE("No output route to: %pI4n\n", &be_addr);
863 return false;
864 }
865 DEBUG_TRACE("Output route to: %pI4n is: %p\n", &be_addr, ecm_rt->rt.rtv4);
866 ecm_rt->dst = (struct dst_entry *)ecm_rt->rt.rtv4;
867 ecm_rt->v4_route = true;
868 return true;
869}
870
Gareth Williams8ac34292015-03-17 14:06:58 +0000871#ifdef ECM_IPV6_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000872/*
873 * ecm_interface_addr_find_route_by_addr_ipv6()
874 * Return the route for the given IP address. Returns NULL on failure.
875 */
876static bool ecm_interface_find_route_by_addr_ipv6(ip_addr_t addr, struct ecm_interface_route *ecm_rt)
877{
878 struct in6_addr naddr;
879
880 ECM_IP_ADDR_TO_NIN6_ADDR(naddr, addr);
881
882 /*
883 * Get a route to the given IP address, this will allow us to also find the interface
884 * it is using to communicate with that IP address.
885 */
886 ecm_rt->rt.rtv6 = rt6_lookup(&init_net, &naddr, NULL, 0, 0);
887 if (!ecm_rt->rt.rtv6) {
888 DEBUG_TRACE("No output route to: " ECM_IP_ADDR_OCTAL_FMT "\n", ECM_IP_ADDR_TO_OCTAL(addr));
889 return NULL;
890 }
891 DEBUG_TRACE("Output route to: " ECM_IP_ADDR_OCTAL_FMT " is: %p\n", ECM_IP_ADDR_TO_OCTAL(addr), ecm_rt->rt.rtv6);
892 ecm_rt->dst = (struct dst_entry *)ecm_rt->rt.rtv6;
893 ecm_rt->v4_route = false;
894 return true;
895}
Murat Sezgin49465a42014-11-24 15:37:48 -0800896#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000897
898/*
899 * ecm_interface_addr_find_route_by_addr()
900 * Return the route (in the given parameter) for the given IP address. Returns false on failure.
901 *
902 * Route is the device on which the addr is reachable, which may be loopback for local addresses.
903 *
904 * Returns true if the route was able to be located. The route must be released using ecm_interface_route_release().
905 */
906bool ecm_interface_find_route_by_addr(ip_addr_t addr, struct ecm_interface_route *ecm_rt)
907{
908 char __attribute__((unused)) addr_str[40];
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530909
Gareth Williams46f4b5f2014-06-01 23:35:23 +0100910 DEBUG_ECM_IP_ADDR_TO_STRING(addr_str, addr);
Ben Menchaca84f36632014-02-28 20:57:38 +0000911 DEBUG_TRACE("Locate route to: %s\n", addr_str);
912
913 if (ECM_IP_ADDR_IS_V4(addr)) {
914 return ecm_interface_find_route_by_addr_ipv4(addr, ecm_rt);
915 }
916
Gareth Williams8ac34292015-03-17 14:06:58 +0000917#ifdef ECM_IPV6_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000918 return ecm_interface_find_route_by_addr_ipv6(addr, ecm_rt);
Murat Sezgin49465a42014-11-24 15:37:48 -0800919#else
920 return false;
921#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000922}
923EXPORT_SYMBOL(ecm_interface_find_route_by_addr);
924
925/*
926 * ecm_interface_route_release()
927 * Release an ecm route
928 */
929void ecm_interface_route_release(struct ecm_interface_route *rt)
930{
931 dst_release(rt->dst);
932}
933EXPORT_SYMBOL(ecm_interface_route_release);
934
Murat Sezgin188b4a32015-06-03 10:58:59 -0700935#ifdef ECM_IPV6_ENABLE
936/*
937 * ecm_interface_send_neighbour_solicitation()
938 * Issue an IPv6 Neighbour soliciation request.
939 */
940void ecm_interface_send_neighbour_solicitation(struct net_device *dev, ip_addr_t addr)
941{
942 struct in6_addr dst_addr, src_addr;
943 struct in6_addr mc_dst_addr;
944 struct rt6_info *rt6i;
945 struct neighbour *neigh;
Murat Sezgin188b4a32015-06-03 10:58:59 -0700946 struct net *netf = dev_net(dev);
947 int ret;
948
Murat Sezgin188b4a32015-06-03 10:58:59 -0700949 /*
950 * Find source and destination addresses in Linux format. We need
951 * mcast destination address as well.
952 */
953 ECM_IP_ADDR_TO_NIN6_ADDR(dst_addr, addr);
954 addrconf_addr_solict_mult(&dst_addr, &mc_dst_addr);
Murat Sezgin96ed0342017-05-19 09:48:57 -0700955 ret = ipv6_dev_get_saddr(netf, dev, &mc_dst_addr, 0, &src_addr);
Murat Sezgin188b4a32015-06-03 10:58:59 -0700956
957 /*
Murat Sezgin188b4a32015-06-03 10:58:59 -0700958 * Find the route entry
959 */
960 rt6i = rt6_lookup(netf, &dst_addr, NULL, 0, 0);
961 if (!rt6i) {
Murat Sezginf21210e2016-04-04 13:58:20 -0700962 DEBUG_TRACE("IPv6 Route lookup failure for destination IPv6 address " ECM_IP_ADDR_OCTAL_FMT "\n", ECM_IP_ADDR_TO_OCTAL(addr));
Murat Sezgin188b4a32015-06-03 10:58:59 -0700963 return;
964 }
965
966 /*
967 * Find the neighbor entry
968 */
969#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3,6,0))
970 neigh = rt6i->dst.ops->neigh_lookup(&rt6i->dst, &dst_addr);
971#else
972 neigh = rt6i->dst.ops->neigh_lookup(&rt6i->dst, NULL, &dst_addr);
973#endif
974 if (neigh == NULL) {
Murat Sezginf21210e2016-04-04 13:58:20 -0700975 DEBUG_TRACE("Neighbour lookup failure for destination IPv6 address " ECM_IP_ADDR_OCTAL_FMT "\n", ECM_IP_ADDR_TO_OCTAL(addr));
Murat Sezgin188b4a32015-06-03 10:58:59 -0700976 dst_release(&rt6i->dst);
977 return;
978 }
979
980 /*
981 * Issue a Neighbour soliciation request
982 */
983 DEBUG_TRACE("Issue Neighbour solicitation request\n");
Murat Sezgine1c51d82016-02-10 16:42:58 -0800984#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0))
Murat Sezgin188b4a32015-06-03 10:58:59 -0700985 ndisc_send_ns(dev, neigh, &dst_addr, &mc_dst_addr, &src_addr);
Murat Sezgine1c51d82016-02-10 16:42:58 -0800986#else
987 ndisc_send_ns(dev, &dst_addr, &mc_dst_addr, &src_addr);
988#endif
Murat Sezgin188b4a32015-06-03 10:58:59 -0700989 neigh_release(neigh);
990 dst_release(&rt6i->dst);
991}
992EXPORT_SYMBOL(ecm_interface_send_neighbour_solicitation);
993#endif
994
995/*
996 * ecm_interface_send_arp_request()
997 * Issue and ARP request.
998 */
999void ecm_interface_send_arp_request(struct net_device *dest_dev, ip_addr_t dest_addr, bool on_link, ip_addr_t gw_addr)
1000{
1001 /*
1002 * Possible ARP does not know the address yet
1003 */
Murat Sezgin4c093212016-03-24 14:59:02 -07001004 struct neighbour *neigh;
Murat Sezgin188b4a32015-06-03 10:58:59 -07001005 __be32 ipv4_addr;
Murat Sezgin188b4a32015-06-03 10:58:59 -07001006
1007 /*
Murat Sezgin987493e2016-04-15 12:33:47 -07001008 * Convert the ECM IP address type to network order IPv4 address.
Murat Sezgin188b4a32015-06-03 10:58:59 -07001009 */
1010 ECM_IP_ADDR_TO_NIN4_ADDR(ipv4_addr, dest_addr);
Murat Sezgin188b4a32015-06-03 10:58:59 -07001011
1012 /*
1013 * If we have a GW for this address, then we have to send ARP request to the GW
1014 */
1015 if (!on_link && !ECM_IP_ADDR_IS_NULL(gw_addr)) {
1016 ECM_IP_ADDR_TO_NIN4_ADDR(ipv4_addr, gw_addr);
1017 }
1018
Murat Sezgin4c093212016-03-24 14:59:02 -07001019 /*
1020 * If we don't have this neighbor, create it before sending the arp request,
1021 * so that when we receive the arp reply we update the neigh entry.
1022 */
1023 neigh = neigh_lookup(&arp_tbl, &ipv4_addr, dest_dev);
1024 if (!neigh) {
Murat Sezgin987493e2016-04-15 12:33:47 -07001025 neigh = neigh_create(&arp_tbl, &ipv4_addr, dest_dev);
1026 if (IS_ERR(neigh)) {
1027 DEBUG_WARN("Unable to create ARP request neigh for %pI4\n", &ipv4_addr);
1028 return;
1029 }
Murat Sezgin4c093212016-03-24 14:59:02 -07001030 }
Murat Sezgin188b4a32015-06-03 10:58:59 -07001031
Murat Sezgin987493e2016-04-15 12:33:47 -07001032 DEBUG_TRACE("Send ARP for %pI4\n", &ipv4_addr);
1033 neigh_event_send(neigh, NULL);
1034 neigh_release(neigh);
Murat Sezgin188b4a32015-06-03 10:58:59 -07001035}
1036EXPORT_SYMBOL(ecm_interface_send_arp_request);
1037
Xiaoping Fanc7735462015-08-09 18:57:26 -07001038/*
1039 * ecm_interface_ipv4_neigh_get()
1040 * Returns neighbour reference for a given IP address which must be released when you are done with it.
1041 *
1042 * Returns NULL on fail.
1043 */
1044struct neighbour *ecm_interface_ipv4_neigh_get(ip_addr_t addr)
1045{
1046 struct neighbour *neigh;
1047 struct rtable *rt;
1048 struct dst_entry *dst;
1049 __be32 ipv4_addr;
1050
1051 ECM_IP_ADDR_TO_NIN4_ADDR(ipv4_addr, addr);
1052 rt = ip_route_output(&init_net, ipv4_addr, 0, 0, 0);
1053 if (IS_ERR(rt)) {
1054 return NULL;
1055 }
1056 dst = (struct dst_entry *)rt;
1057 neigh = dst_neigh_lookup(dst, &ipv4_addr);
1058 ip_rt_put(rt);
1059 return neigh;
1060}
1061
1062#ifdef ECM_IPV6_ENABLE
1063/*
1064 * ecm_interface_ipv6_neigh_get()
1065 * Returns neighbour reference for a given IP address which must be released when you are done with it.
1066 *
1067 * Returns NULL on fail.
1068 */
1069struct neighbour *ecm_interface_ipv6_neigh_get(ip_addr_t addr)
1070{
1071 struct neighbour *neigh;
1072 struct rt6_info *rt;
1073 struct dst_entry *dst;
1074 struct in6_addr ipv6_addr;
1075
1076 ECM_IP_ADDR_TO_NIN6_ADDR(ipv6_addr, addr);
1077 rt = rt6_lookup(&init_net, &ipv6_addr, NULL, 0, 0);
1078 if (!rt) {
1079 return NULL;
1080 }
1081 dst = (struct dst_entry *)rt;
1082 neigh = dst_neigh_lookup(dst, &ipv6_addr);
1083 dst_release(dst);
1084 return neigh;
1085}
1086#endif
1087
ratheesh kannotha32fdd12015-09-09 08:02:58 +05301088/*
Shyam Sunder2ca02492016-08-05 20:55:12 +05301089 * ecm_interface_is_pptp()
ratheesh kannotha32fdd12015-09-09 08:02:58 +05301090 * skip pptp tunnel encapsulated traffic
1091 *
Shyam Sunder23f2e542015-09-28 14:56:49 +05301092 * ECM does not handle PPTP,
ratheesh kannotha32fdd12015-09-09 08:02:58 +05301093 * this function detects packets of that type so they can be skipped over to improve their throughput.
1094 */
Shyam Sunder2ca02492016-08-05 20:55:12 +05301095bool ecm_interface_is_pptp(struct sk_buff *skb, const struct net_device *out)
ratheesh kannotha32fdd12015-09-09 08:02:58 +05301096{
ratheesh kannotha32fdd12015-09-09 08:02:58 +05301097 struct net_device *in;
ratheesh kannotha32fdd12015-09-09 08:02:58 +05301098
ratheesh kannothf4801a02016-12-09 22:46:39 +05301099 /*
1100 * skip first pass of l2tp/pptp tunnel encapsulated traffic
1101 */
ratheesh kannotha32fdd12015-09-09 08:02:58 +05301102 if (out->type == ARPHRD_PPP) {
ratheesh kannothf4801a02016-12-09 22:46:39 +05301103 if (out->priv_flags & IFF_PPP_PPTP) {
ratheesh kannotha32fdd12015-09-09 08:02:58 +05301104 return true;
1105 }
ratheesh kannotha32fdd12015-09-09 08:02:58 +05301106 }
1107
1108 in = dev_get_by_index(&init_net, skb->skb_iif);
ratheesh kannoth08b8e442015-10-02 00:24:55 +05301109 if (!in) {
1110 return true;
1111 }
1112
1113 if (in->type == ARPHRD_PPP) {
ratheesh kannothf4801a02016-12-09 22:46:39 +05301114 if (in->priv_flags & IFF_PPP_PPTP) {
ratheesh kannotha32fdd12015-09-09 08:02:58 +05301115 dev_put(in);
1116 return true;
1117 }
Shyam Sunder23f2e542015-09-28 14:56:49 +05301118 }
1119
1120 dev_put(in);
1121 return false;
1122}
1123
Shyam Sunder2ca02492016-08-05 20:55:12 +05301124#ifdef ECM_INTERFACE_PPP_ENABLE
Shyam Sunder23f2e542015-09-28 14:56:49 +05301125/*
Shyam Sunder2ca02492016-08-05 20:55:12 +05301126 * ecm_interface_is_l2tp_packet_by_version()
Shyam Sunder23f2e542015-09-28 14:56:49 +05301127 * Check version of l2tp tunnel encapsulated traffic
1128 *
1129 * ECM does not handle l2tp,
1130 * this function detects packets of that type so they can be skipped over to improve their throughput.
1131 */
Shyam Sunder2ca02492016-08-05 20:55:12 +05301132bool ecm_interface_is_l2tp_packet_by_version(struct sk_buff *skb, const struct net_device *out, int ver)
Shyam Sunder23f2e542015-09-28 14:56:49 +05301133{
ratheesh kannothf4801a02016-12-09 22:46:39 +05301134 uint32_t flag = 0;
Shyam Sunder23f2e542015-09-28 14:56:49 +05301135 struct net_device *in;
1136
ratheesh kannothf4801a02016-12-09 22:46:39 +05301137 switch (ver) {
1138 case 2:
1139 flag = IFF_PPP_L2TPV2;
1140 break;
1141 case 3:
1142 flag = IFF_PPP_L2TPV3;
1143 break;
1144 default:
1145 break;
1146 }
1147
1148 /*
1149 * skip first pass of l2tp/pptp tunnel encapsulated traffic
1150 */
Shyam Sunder23f2e542015-09-28 14:56:49 +05301151 if (out->type == ARPHRD_PPP) {
ratheesh kannothf4801a02016-12-09 22:46:39 +05301152 if (out->priv_flags & flag) {
Shyam Sunder23f2e542015-09-28 14:56:49 +05301153 return true;
1154 }
Shyam Sunder23f2e542015-09-28 14:56:49 +05301155 }
1156
1157 in = dev_get_by_index(&init_net, skb->skb_iif);
1158 if (!in) {
1159 return true;
1160 }
1161
1162 if (in->type == ARPHRD_PPP) {
ratheesh kannothf4801a02016-12-09 22:46:39 +05301163 if (in->priv_flags & flag) {
Shyam Sunder23f2e542015-09-28 14:56:49 +05301164 dev_put(in);
1165 return true;
1166 }
ratheesh kannotha32fdd12015-09-09 08:02:58 +05301167 }
1168
ratheesh kannoth08b8e442015-10-02 00:24:55 +05301169 dev_put(in);
ratheesh kannotha32fdd12015-09-09 08:02:58 +05301170 return false;
1171}
ratheesh kannotha32fdd12015-09-09 08:02:58 +05301172
Xiaoping Fan80e406b2015-01-29 16:15:31 -08001173/*
Shyam Sunder2ca02492016-08-05 20:55:12 +05301174 * ecm_interface_is_l2tp_pptp()
Xiaoping Fan80e406b2015-01-29 16:15:31 -08001175 * skip l2tp/pptp tunnel encapsulated traffic
1176 *
1177 * ECM does not handle L2TP or PPTP encapsulated packets,
1178 * this function detects packets of that type so they can be skipped over to improve their throughput.
1179 */
Shyam Sunder2ca02492016-08-05 20:55:12 +05301180bool ecm_interface_is_l2tp_pptp(struct sk_buff *skb, const struct net_device *out)
Xiaoping Fan80e406b2015-01-29 16:15:31 -08001181{
ratheesh kannothf4801a02016-12-09 22:46:39 +05301182 struct net_device *in;
Xiaoping Fan80e406b2015-01-29 16:15:31 -08001183
1184 /*
1185 * skip first pass of l2tp/pptp tunnel encapsulated traffic
1186 */
1187 if (out->type == ARPHRD_PPP) {
ratheesh kannothf4801a02016-12-09 22:46:39 +05301188 if (out->priv_flags & (IFF_PPP_L2TPV2 | IFF_PPP_L2TPV3 |
1189 IFF_PPP_PPTP)) {
1190 return true;
Xiaoping Fan80e406b2015-01-29 16:15:31 -08001191 }
1192 }
1193
ratheesh kannothf4801a02016-12-09 22:46:39 +05301194 in = dev_get_by_index(&init_net, skb->skb_iif);
1195 if (!in) {
Xiaoping Fan80e406b2015-01-29 16:15:31 -08001196 return true;
1197 }
1198
ratheesh kannothf4801a02016-12-09 22:46:39 +05301199 if (in->type == ARPHRD_PPP) {
1200 if (in->priv_flags & (IFF_PPP_L2TPV2 | IFF_PPP_L2TPV3 |
1201 IFF_PPP_PPTP)) {
1202 dev_put(in);
1203 return true;
1204 }
1205 }
1206
1207 dev_put(in);
Xiaoping Fan80e406b2015-01-29 16:15:31 -08001208 return false;
ratheesh kannothf4801a02016-12-09 22:46:39 +05301209
Xiaoping Fan80e406b2015-01-29 16:15:31 -08001210}
1211#endif
1212
Gareth Williams141d2382014-11-25 11:35:19 -08001213#ifdef ECM_INTERFACE_VLAN_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001214/*
Ben Menchaca84f36632014-02-28 20:57:38 +00001215 * ecm_interface_vlan_interface_establish()
1216 * Returns a reference to a iface of the VLAN type, possibly creating one if necessary.
1217 * Returns NULL on failure or a reference to interface.
1218 */
1219static struct ecm_db_iface_instance *ecm_interface_vlan_interface_establish(struct ecm_db_interface_info_vlan *type_info,
Murat Sezgin91c5d712015-06-12 15:16:22 -07001220 char *dev_name, int32_t dev_interface_num, int32_t ae_interface_num, int32_t mtu)
Ben Menchaca84f36632014-02-28 20:57:38 +00001221{
1222 struct ecm_db_iface_instance *nii;
1223 struct ecm_db_iface_instance *ii;
1224
Murat Sezgin91c5d712015-06-12 15:16:22 -07001225 DEBUG_INFO("Establish VLAN iface: %s with address: %pM, vlan tag: %u, vlan_tpid: %x MTU: %d, if num: %d, accel engine if id: %d\n",
1226 dev_name, type_info->address, type_info->vlan_tag, type_info->vlan_tpid, mtu, dev_interface_num, ae_interface_num);
Ben Menchaca84f36632014-02-28 20:57:38 +00001227
1228 /*
1229 * Locate the iface
1230 */
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301231 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 +00001232 if (ii) {
1233 DEBUG_TRACE("%p: iface established\n", ii);
1234 return ii;
1235 }
1236
1237 /*
1238 * No iface - create one
1239 */
1240 nii = ecm_db_iface_alloc();
1241 if (!nii) {
1242 DEBUG_WARN("Failed to establish iface\n");
1243 return NULL;
1244 }
1245
1246 /*
1247 * Add iface into the database, atomically to avoid races creating the same thing
1248 */
1249 spin_lock_bh(&ecm_interface_lock);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301250 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 +00001251 if (ii) {
1252 spin_unlock_bh(&ecm_interface_lock);
1253 ecm_db_iface_deref(nii);
1254 return ii;
1255 }
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301256 ecm_db_iface_add_vlan(nii, type_info->address, type_info->vlan_tag, type_info->vlan_tpid, dev_name,
Murat Sezgin91c5d712015-06-12 15:16:22 -07001257 mtu, dev_interface_num, ae_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +00001258 spin_unlock_bh(&ecm_interface_lock);
1259
1260 DEBUG_TRACE("%p: vlan iface established\n", nii);
1261 return nii;
1262}
Gareth Williams141d2382014-11-25 11:35:19 -08001263#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001264
1265/*
1266 * ecm_interface_bridge_interface_establish()
1267 * Returns a reference to a iface of the BRIDGE type, possibly creating one if necessary.
1268 * Returns NULL on failure or a reference to interface.
1269 */
1270static struct ecm_db_iface_instance *ecm_interface_bridge_interface_establish(struct ecm_db_interface_info_bridge *type_info,
Murat Sezgin91c5d712015-06-12 15:16:22 -07001271 char *dev_name, int32_t dev_interface_num, int32_t ae_interface_num, int32_t mtu)
Ben Menchaca84f36632014-02-28 20:57:38 +00001272{
1273 struct ecm_db_iface_instance *nii;
1274 struct ecm_db_iface_instance *ii;
1275
Murat Sezgin91c5d712015-06-12 15:16:22 -07001276 DEBUG_INFO("Establish BRIDGE iface: %s with address: %pM, MTU: %d, if num: %d, accel engine if id: %d\n",
1277 dev_name, type_info->address, mtu, dev_interface_num, ae_interface_num);
Ben Menchaca84f36632014-02-28 20:57:38 +00001278
1279 /*
1280 * Locate the iface
1281 */
1282 ii = ecm_db_iface_find_and_ref_bridge(type_info->address);
1283 if (ii) {
1284 DEBUG_TRACE("%p: iface established\n", ii);
1285 return ii;
1286 }
1287
1288 /*
1289 * No iface - create one
1290 */
1291 nii = ecm_db_iface_alloc();
1292 if (!nii) {
1293 DEBUG_WARN("Failed to establish iface\n");
1294 return NULL;
1295 }
1296
1297 /*
1298 * Add iface into the database, atomically to avoid races creating the same thing
1299 */
1300 spin_lock_bh(&ecm_interface_lock);
1301 ii = ecm_db_iface_find_and_ref_bridge(type_info->address);
1302 if (ii) {
1303 spin_unlock_bh(&ecm_interface_lock);
1304 ecm_db_iface_deref(nii);
1305 return ii;
1306 }
1307 ecm_db_iface_add_bridge(nii, type_info->address, dev_name,
Murat Sezgin91c5d712015-06-12 15:16:22 -07001308 mtu, dev_interface_num, ae_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +00001309 spin_unlock_bh(&ecm_interface_lock);
1310
1311 DEBUG_TRACE("%p: bridge iface established\n", nii);
1312 return nii;
1313}
1314
Murat Sezgin910c9662015-03-11 16:15:06 -07001315#ifdef ECM_INTERFACE_BOND_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001316/*
1317 * ecm_interface_lag_interface_establish()
1318 * Returns a reference to a iface of the LAG type, possibly creating one if necessary.
1319 * Returns NULL on failure or a reference to interface.
1320 */
1321static struct ecm_db_iface_instance *ecm_interface_lag_interface_establish(struct ecm_db_interface_info_lag *type_info,
Murat Sezgin91c5d712015-06-12 15:16:22 -07001322 char *dev_name, int32_t dev_interface_num, int32_t ae_interface_num, int32_t mtu)
Ben Menchaca84f36632014-02-28 20:57:38 +00001323{
1324 struct ecm_db_iface_instance *nii;
1325 struct ecm_db_iface_instance *ii;
1326
Murat Sezgin91c5d712015-06-12 15:16:22 -07001327 DEBUG_INFO("Establish LAG iface: %s with address: %pM, MTU: %d, if num: %d, accel engine if id: %d\n",
1328 dev_name, type_info->address, mtu, dev_interface_num, ae_interface_num);
Ben Menchaca84f36632014-02-28 20:57:38 +00001329
1330 /*
1331 * Locate the iface
1332 */
1333 ii = ecm_db_iface_find_and_ref_lag(type_info->address);
1334 if (ii) {
1335 DEBUG_TRACE("%p: iface established\n", ii);
1336 return ii;
1337 }
1338
1339 /*
1340 * No iface - create one
1341 */
1342 nii = ecm_db_iface_alloc();
1343 if (!nii) {
1344 DEBUG_WARN("Failed to establish iface\n");
1345 return NULL;
1346 }
1347
1348 /*
1349 * Add iface into the database, atomically to avoid races creating the same thing
1350 */
1351 spin_lock_bh(&ecm_interface_lock);
1352 ii = ecm_db_iface_find_and_ref_lag(type_info->address);
1353 if (ii) {
1354 spin_unlock_bh(&ecm_interface_lock);
1355 ecm_db_iface_deref(nii);
1356 return ii;
1357 }
1358 ecm_db_iface_add_lag(nii, type_info->address, dev_name,
Murat Sezgin91c5d712015-06-12 15:16:22 -07001359 mtu, dev_interface_num, ae_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +00001360 spin_unlock_bh(&ecm_interface_lock);
1361
1362 DEBUG_TRACE("%p: lag iface established\n", nii);
1363 return nii;
1364}
Murat Sezgin910c9662015-03-11 16:15:06 -07001365#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001366
1367/*
1368 * ecm_interface_ethernet_interface_establish()
1369 * Returns a reference to a iface of the ETHERNET type, possibly creating one if necessary.
1370 * Returns NULL on failure or a reference to interface.
1371 */
1372static struct ecm_db_iface_instance *ecm_interface_ethernet_interface_establish(struct ecm_db_interface_info_ethernet *type_info,
Murat Sezgin91c5d712015-06-12 15:16:22 -07001373 char *dev_name, int32_t dev_interface_num, int32_t ae_interface_num, int32_t mtu)
Ben Menchaca84f36632014-02-28 20:57:38 +00001374{
1375 struct ecm_db_iface_instance *nii;
1376 struct ecm_db_iface_instance *ii;
1377
Murat Sezgin91c5d712015-06-12 15:16:22 -07001378 DEBUG_INFO("Establish ETHERNET iface: %s with address: %pM, MTU: %d, if num: %d, accel engine if id: %d\n",
1379 dev_name, type_info->address, mtu, dev_interface_num, ae_interface_num);
Ben Menchaca84f36632014-02-28 20:57:38 +00001380
1381 /*
1382 * Locate the iface
1383 */
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05301384 ii = ecm_db_iface_ifidx_find_and_ref_ethernet(type_info->address, dev_interface_num);
1385
Ben Menchaca84f36632014-02-28 20:57:38 +00001386 if (ii) {
1387 DEBUG_TRACE("%p: iface established\n", ii);
Murat Sezgin5f2947a2016-06-28 12:09:33 -07001388 /*
1389 * Update the accel engine interface identifier, just in case it was changed.
1390 */
1391 ecm_db_iface_ae_interface_identifier_set(ii, ae_interface_num);
Ben Menchaca84f36632014-02-28 20:57:38 +00001392 return ii;
1393 }
1394
1395 /*
1396 * No iface - create one
1397 */
1398 nii = ecm_db_iface_alloc();
1399 if (!nii) {
1400 DEBUG_WARN("Failed to establish iface\n");
1401 return NULL;
1402 }
1403
1404 /*
1405 * Add iface into the database, atomically to avoid races creating the same thing
1406 */
1407 spin_lock_bh(&ecm_interface_lock);
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05301408 ii = ecm_db_iface_ifidx_find_and_ref_ethernet(type_info->address, dev_interface_num);
Ben Menchaca84f36632014-02-28 20:57:38 +00001409 if (ii) {
1410 spin_unlock_bh(&ecm_interface_lock);
1411 ecm_db_iface_deref(nii);
1412 return ii;
1413 }
1414 ecm_db_iface_add_ethernet(nii, type_info->address, dev_name,
Murat Sezgin91c5d712015-06-12 15:16:22 -07001415 mtu, dev_interface_num, ae_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +00001416 spin_unlock_bh(&ecm_interface_lock);
1417
1418 DEBUG_TRACE("%p: ethernet iface established\n", nii);
1419 return nii;
1420}
1421
ratheesh kannotha32fdd12015-09-09 08:02:58 +05301422#ifdef ECM_INTERFACE_PPPOE_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001423/*
1424 * ecm_interface_pppoe_interface_establish()
1425 * Returns a reference to a iface of the PPPoE type, possibly creating one if necessary.
1426 * Returns NULL on failure or a reference to interface.
1427 */
1428static struct ecm_db_iface_instance *ecm_interface_pppoe_interface_establish(struct ecm_db_interface_info_pppoe *type_info,
Murat Sezgin91c5d712015-06-12 15:16:22 -07001429 char *dev_name, int32_t dev_interface_num, int32_t ae_interface_num, int32_t mtu)
Ben Menchaca84f36632014-02-28 20:57:38 +00001430{
1431 struct ecm_db_iface_instance *nii;
1432 struct ecm_db_iface_instance *ii;
1433
Murat Sezgin91c5d712015-06-12 15:16:22 -07001434 DEBUG_INFO("Establish PPPoE iface: %s with session id: %u, remote mac: %pM, MTU: %d, if num: %d, accel engine if id: %d\n",
1435 dev_name, type_info->pppoe_session_id, type_info->remote_mac, mtu, dev_interface_num, ae_interface_num);
Ben Menchaca84f36632014-02-28 20:57:38 +00001436
1437 /*
1438 * Locate the iface
1439 */
1440 ii = ecm_db_iface_find_and_ref_pppoe(type_info->pppoe_session_id, type_info->remote_mac);
1441 if (ii) {
1442 DEBUG_TRACE("%p: iface established\n", ii);
1443 return ii;
1444 }
1445
1446 /*
1447 * No iface - create one
1448 */
1449 nii = ecm_db_iface_alloc();
1450 if (!nii) {
1451 DEBUG_WARN("Failed to establish iface\n");
1452 return NULL;
1453 }
1454
1455 /*
1456 * Add iface into the database, atomically to avoid races creating the same thing
1457 */
1458 spin_lock_bh(&ecm_interface_lock);
1459 ii = ecm_db_iface_find_and_ref_pppoe(type_info->pppoe_session_id, type_info->remote_mac);
1460 if (ii) {
1461 spin_unlock_bh(&ecm_interface_lock);
1462 ecm_db_iface_deref(nii);
1463 return ii;
1464 }
1465 ecm_db_iface_add_pppoe(nii, type_info->pppoe_session_id, type_info->remote_mac, dev_name,
Murat Sezgin91c5d712015-06-12 15:16:22 -07001466 mtu, dev_interface_num, ae_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +00001467 spin_unlock_bh(&ecm_interface_lock);
1468
1469 DEBUG_TRACE("%p: pppoe iface established\n", nii);
1470 return nii;
1471}
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001472#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001473
ratheesh kannothcfdcb332015-12-24 07:19:18 +05301474#ifdef ECM_INTERFACE_MAP_T_ENABLE
1475/*
1476 * ecm_interface_map_t_interface_establish()
1477 * Returns a reference to a iface of the PPPoE type, possibly creating one if necessary.
1478 * Returns NULL on failure or a reference to interface.
1479 */
1480static struct ecm_db_iface_instance *ecm_interface_map_t_interface_establish(struct ecm_db_interface_info_map_t *type_info,
1481 char *dev_name, int32_t dev_interface_num, int32_t ae_interface_num, int32_t mtu)
1482{
1483 struct ecm_db_iface_instance *nii;
1484 struct ecm_db_iface_instance *ii;
1485
1486 DEBUG_TRACE("Establish MAP-T iface: %s MTU: %d, if num: %d, accel engine if id: %d\n",
1487 dev_name, mtu, dev_interface_num, ae_interface_num);
1488
1489 /*
1490 * Locate the iface
1491 */
1492 ii = ecm_db_iface_find_and_ref_map_t(type_info->if_index);
1493 if (ii) {
1494 DEBUG_TRACE("%p: iface established\n", ii);
1495 ecm_db_iface_update_ae_interface_identifier(ii, ae_interface_num);
1496 return ii;
1497 }
1498
1499 /*
1500 * No iface - create one
1501 */
1502 nii = ecm_db_iface_alloc();
1503 if (!nii) {
1504 DEBUG_WARN("Failed to establish iface\n");
1505 return NULL;
1506 }
1507
1508 /*
1509 * Add iface into the database, atomically to avoid races creating the same thing
1510 */
1511 spin_lock_bh(&ecm_interface_lock);
1512 ii = ecm_db_iface_find_and_ref_map_t(type_info->if_index);
1513 if (ii) {
1514 spin_unlock_bh(&ecm_interface_lock);
1515 ecm_db_iface_deref(nii);
1516 ecm_db_iface_update_ae_interface_identifier(ii, ae_interface_num);
1517 return ii;
1518 }
1519 ecm_db_iface_add_map_t(nii, type_info, dev_name,
1520 mtu, dev_interface_num, ae_interface_num, NULL, nii);
1521 spin_unlock_bh(&ecm_interface_lock);
1522
1523 DEBUG_TRACE("%p: map_t iface established\n", nii);
1524 return nii;
1525}
1526#endif
1527
ratheesh kannotha32fdd12015-09-09 08:02:58 +05301528#ifdef ECM_INTERFACE_L2TPV2_ENABLE
1529/*
1530 * ecm_interface_pppol2tpv2_interface_establish()
1531 * Returns a reference to a iface of the PPPoL2TPV2 type, possibly creating one if necessary.
1532 * Returns NULL on failure or a reference to interface.
1533 */
1534static struct ecm_db_iface_instance *ecm_interface_pppol2tpv2_interface_establish(struct ecm_db_interface_info_pppol2tpv2 *type_info,
1535 char *dev_name, int32_t dev_interface_num, int32_t ae_interface_num, int32_t mtu)
1536{
1537 struct ecm_db_iface_instance *nii;
1538 struct ecm_db_iface_instance *ii;
1539
1540 DEBUG_INFO("Establish PPPol2tp iface: %s with tunnel id=%u session id %u\n", dev_name, type_info->l2tp.tunnel.tunnel_id,
1541 type_info->l2tp.session.session_id);
1542 /*
1543 * Locate the iface
1544 */
1545 ii = ecm_db_iface_find_and_ref_pppol2tpv2(type_info->l2tp.tunnel.tunnel_id, type_info->l2tp.session.session_id);
1546 if (ii) {
1547 DEBUG_TRACE("%p: iface established\n", ii);
ratheesh kannothed721852015-09-28 12:39:52 +05301548 ecm_db_iface_update_ae_interface_identifier(ii, ae_interface_num);
ratheesh kannotha32fdd12015-09-09 08:02:58 +05301549 return ii;
1550 }
1551
1552 /*
1553 * No iface - create one
1554 */
1555 nii = ecm_db_iface_alloc();
1556 if (!nii) {
1557 DEBUG_WARN("Failed to establish iface\n");
1558 return NULL;
1559 }
1560
1561 /*
1562 * Add iface into the database, atomically to avoid races creating the same thing
1563 */
1564 spin_lock_bh(&ecm_interface_lock);
1565 ii = ecm_db_iface_find_and_ref_pppol2tpv2(type_info->l2tp.tunnel.tunnel_id, type_info->l2tp.session.session_id);
1566 if (ii) {
1567 spin_unlock_bh(&ecm_interface_lock);
1568 ecm_db_iface_deref(nii);
ratheesh kannothed721852015-09-28 12:39:52 +05301569 ecm_db_iface_update_ae_interface_identifier(ii, ae_interface_num);
ratheesh kannotha32fdd12015-09-09 08:02:58 +05301570 return ii;
1571 }
1572
1573 ecm_db_iface_add_pppol2tpv2(nii, type_info, dev_name, mtu, dev_interface_num, ae_interface_num, NULL, nii);
1574 spin_unlock_bh(&ecm_interface_lock);
1575
1576 DEBUG_TRACE("%p: pppol2tpv2 iface established\n", nii);
1577 return nii;
1578}
1579
1580#endif
1581
Shyam Sunder23f2e542015-09-28 14:56:49 +05301582#ifdef ECM_INTERFACE_PPTP_ENABLE
1583/*
1584 * ecm_interface_pptp_interface_establish()
1585 * Returns a reference to a iface of the PPTP type, possibly creating one if necessary.
1586 * Returns NULL on failure or a reference to interface.
1587 */
1588static struct ecm_db_iface_instance *ecm_interface_pptp_interface_establish(struct ecm_db_interface_info_pptp *type_info,
1589 char *dev_name, int32_t dev_interface_num, int32_t ae_interface_num, int32_t mtu)
1590{
1591 struct ecm_db_iface_instance *nii;
1592 struct ecm_db_iface_instance *ii;
1593
1594 DEBUG_INFO("Establish PPTP iface: %s with local call id %u peer call id %u\n", dev_name, type_info->src_call_id,
1595 type_info->dst_call_id);
1596 /*
1597 * Locate the iface
1598 */
1599 ii = ecm_db_iface_find_and_ref_pptp(type_info->src_call_id, type_info->dst_call_id);
1600 if (ii) {
1601 DEBUG_TRACE("%p: iface established\n", ii);
1602 ecm_db_iface_update_ae_interface_identifier(ii, ae_interface_num);
1603 return ii;
1604 }
1605
1606 /*
1607 * No iface - create one
1608 */
1609 nii = ecm_db_iface_alloc();
1610 if (!nii) {
1611 DEBUG_WARN("Failed to establish iface\n");
1612 return NULL;
1613 }
1614
1615 /*
1616 * Add iface into the database, atomically to avoid races creating the same thing
1617 */
1618 spin_lock_bh(&ecm_interface_lock);
1619 ii = ecm_db_iface_find_and_ref_pptp(type_info->src_call_id, type_info->dst_call_id);
1620 if (ii) {
1621 spin_unlock_bh(&ecm_interface_lock);
1622 ecm_db_iface_deref(nii);
1623 ecm_db_iface_update_ae_interface_identifier(ii, ae_interface_num);
1624 return ii;
1625 }
1626
1627 ecm_db_iface_add_pptp(nii, type_info, dev_name, mtu, dev_interface_num, ae_interface_num, NULL, nii);
1628 spin_unlock_bh(&ecm_interface_lock);
1629
1630 DEBUG_TRACE("%p: pptp iface established\n", nii);
1631 return nii;
1632}
1633#endif
1634
Ben Menchaca84f36632014-02-28 20:57:38 +00001635/*
1636 * ecm_interface_unknown_interface_establish()
1637 * Returns a reference to a iface of the UNKNOWN type, possibly creating one if necessary.
1638 * Returns NULL on failure or a reference to interface.
1639 */
1640static struct ecm_db_iface_instance *ecm_interface_unknown_interface_establish(struct ecm_db_interface_info_unknown *type_info,
Murat Sezgin91c5d712015-06-12 15:16:22 -07001641 char *dev_name, int32_t dev_interface_num, int32_t ae_interface_num, int32_t mtu)
Ben Menchaca84f36632014-02-28 20:57:38 +00001642{
1643 struct ecm_db_iface_instance *nii;
1644 struct ecm_db_iface_instance *ii;
1645
Murat Sezgin91c5d712015-06-12 15:16:22 -07001646 DEBUG_INFO("Establish UNKNOWN iface: %s with os_specific_ident: %u, MTU: %d, if num: %d, accel engine if id: %d\n",
1647 dev_name, type_info->os_specific_ident, mtu, dev_interface_num, ae_interface_num);
Ben Menchaca84f36632014-02-28 20:57:38 +00001648
1649 /*
1650 * Locate the iface
1651 */
1652 ii = ecm_db_iface_find_and_ref_unknown(type_info->os_specific_ident);
1653 if (ii) {
1654 DEBUG_TRACE("%p: iface established\n", ii);
1655 return ii;
1656 }
1657
1658 /*
1659 * No iface - create one
1660 */
1661 nii = ecm_db_iface_alloc();
1662 if (!nii) {
1663 DEBUG_WARN("Failed to establish iface\n");
1664 return NULL;
1665 }
1666
1667 /*
1668 * Add iface into the database, atomically to avoid races creating the same thing
1669 */
1670 spin_lock_bh(&ecm_interface_lock);
1671 ii = ecm_db_iface_find_and_ref_unknown(type_info->os_specific_ident);
1672 if (ii) {
1673 spin_unlock_bh(&ecm_interface_lock);
1674 ecm_db_iface_deref(nii);
1675 return ii;
1676 }
1677 ecm_db_iface_add_unknown(nii, type_info->os_specific_ident, dev_name,
Murat Sezgin91c5d712015-06-12 15:16:22 -07001678 mtu, dev_interface_num, ae_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +00001679 spin_unlock_bh(&ecm_interface_lock);
1680
1681 DEBUG_TRACE("%p: unknown iface established\n", nii);
1682 return nii;
1683}
1684
1685/*
1686 * ecm_interface_loopback_interface_establish()
1687 * Returns a reference to a iface of the LOOPBACK type, possibly creating one if necessary.
1688 * Returns NULL on failure or a reference to interface.
1689 */
1690static struct ecm_db_iface_instance *ecm_interface_loopback_interface_establish(struct ecm_db_interface_info_loopback *type_info,
Murat Sezgin91c5d712015-06-12 15:16:22 -07001691 char *dev_name, int32_t dev_interface_num, int32_t ae_interface_num, int32_t mtu)
Ben Menchaca84f36632014-02-28 20:57:38 +00001692{
1693 struct ecm_db_iface_instance *nii;
1694 struct ecm_db_iface_instance *ii;
1695
Murat Sezgin91c5d712015-06-12 15:16:22 -07001696 DEBUG_INFO("Establish LOOPBACK iface: %s with os_specific_ident: %u, MTU: %d, if num: %d, accel engine if id: %d\n",
1697 dev_name, type_info->os_specific_ident, mtu, dev_interface_num, ae_interface_num);
Ben Menchaca84f36632014-02-28 20:57:38 +00001698
1699 /*
1700 * Locate the iface
1701 */
1702 ii = ecm_db_iface_find_and_ref_loopback(type_info->os_specific_ident);
1703 if (ii) {
1704 DEBUG_TRACE("%p: iface established\n", ii);
1705 return ii;
1706 }
1707
1708 /*
1709 * No iface - create one
1710 */
1711 nii = ecm_db_iface_alloc();
1712 if (!nii) {
1713 DEBUG_WARN("Failed to establish iface\n");
1714 return NULL;
1715 }
1716
1717 /*
1718 * Add iface into the database, atomically to avoid races creating the same thing
1719 */
1720 spin_lock_bh(&ecm_interface_lock);
1721 ii = ecm_db_iface_find_and_ref_loopback(type_info->os_specific_ident);
1722 if (ii) {
1723 spin_unlock_bh(&ecm_interface_lock);
1724 ecm_db_iface_deref(nii);
1725 return ii;
1726 }
1727 ecm_db_iface_add_loopback(nii, type_info->os_specific_ident, dev_name,
Murat Sezgin91c5d712015-06-12 15:16:22 -07001728 mtu, dev_interface_num, ae_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +00001729 spin_unlock_bh(&ecm_interface_lock);
1730
1731 DEBUG_TRACE("%p: loopback iface established\n", nii);
1732 return nii;
1733}
1734
Murat Sezgin69a27532015-03-12 14:09:40 -07001735#ifdef ECM_INTERFACE_IPSEC_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001736/*
1737 * ecm_interface_ipsec_tunnel_interface_establish()
1738 * Returns a reference to a iface of the IPSEC_TUNNEL type, possibly creating one if necessary.
1739 * Returns NULL on failure or a reference to interface.
1740 *
1741 * NOTE: GGG TODO THIS NEEDS TO TAKE A PROPER APPROACH TO IPSEC TUNNELS USING ENDPOINT ADDRESSING AS THE TYPE INFO KEYS
1742 */
1743static struct ecm_db_iface_instance *ecm_interface_ipsec_tunnel_interface_establish(struct ecm_db_interface_info_ipsec_tunnel *type_info,
Murat Sezgin91c5d712015-06-12 15:16:22 -07001744 char *dev_name, int32_t dev_interface_num, int32_t ae_interface_num, int32_t mtu)
Ben Menchaca84f36632014-02-28 20:57:38 +00001745{
1746 struct ecm_db_iface_instance *nii;
1747 struct ecm_db_iface_instance *ii;
1748
Murat Sezgin91c5d712015-06-12 15:16:22 -07001749 DEBUG_INFO("Establish IPSEC_TUNNEL iface: %s with os_specific_ident: %u, MTU: %d, if num: %d, accel engine if id: %d\n",
1750 dev_name, type_info->os_specific_ident, mtu, dev_interface_num, ae_interface_num);
Ben Menchaca84f36632014-02-28 20:57:38 +00001751
1752 /*
1753 * Locate the iface
1754 */
1755 ii = ecm_db_iface_find_and_ref_ipsec_tunnel(type_info->os_specific_ident);
1756 if (ii) {
1757 DEBUG_TRACE("%p: iface established\n", ii);
1758 return ii;
1759 }
1760
1761 /*
1762 * No iface - create one
1763 */
1764 nii = ecm_db_iface_alloc();
1765 if (!nii) {
1766 DEBUG_WARN("Failed to establish iface\n");
1767 return NULL;
1768 }
1769
1770 /*
1771 * Add iface into the database, atomically to avoid races creating the same thing
1772 */
1773 spin_lock_bh(&ecm_interface_lock);
1774 ii = ecm_db_iface_find_and_ref_ipsec_tunnel(type_info->os_specific_ident);
1775 if (ii) {
1776 spin_unlock_bh(&ecm_interface_lock);
1777 ecm_db_iface_deref(nii);
1778 return ii;
1779 }
1780 ecm_db_iface_add_ipsec_tunnel(nii, type_info->os_specific_ident, dev_name,
Murat Sezgin91c5d712015-06-12 15:16:22 -07001781 mtu, dev_interface_num, ae_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +00001782 spin_unlock_bh(&ecm_interface_lock);
1783
1784 DEBUG_TRACE("%p: ipsec_tunnel iface established\n", nii);
1785 return nii;
1786}
Murat Sezgin69a27532015-03-12 14:09:40 -07001787#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001788
Murat Sezginb3731e82014-11-26 12:20:59 -08001789#ifdef ECM_INTERFACE_SIT_ENABLE
Murat Sezginbde55f92015-03-11 16:44:11 -07001790#ifdef CONFIG_IPV6_SIT_6RD
Ben Menchaca84f36632014-02-28 20:57:38 +00001791/*
1792 * ecm_interface_sit_interface_establish()
1793 * Returns a reference to a iface of the SIT type, possibly creating one if necessary.
1794 * Returns NULL on failure or a reference to interface.
1795 */
1796static struct ecm_db_iface_instance *ecm_interface_sit_interface_establish(struct ecm_db_interface_info_sit *type_info,
Murat Sezgin91c5d712015-06-12 15:16:22 -07001797 char *dev_name, int32_t dev_interface_num, int32_t ae_interface_num, int32_t mtu)
Ben Menchaca84f36632014-02-28 20:57:38 +00001798{
1799 struct ecm_db_iface_instance *nii;
1800 struct ecm_db_iface_instance *ii;
1801
Murat Sezgin91c5d712015-06-12 15:16:22 -07001802 DEBUG_INFO("Establish SIT iface: %s with saddr: " ECM_IP_ADDR_OCTAL_FMT ", daddr: " ECM_IP_ADDR_OCTAL_FMT ", MTU: %d, if num: %d, accel engine if id: %d\n",
1803 dev_name, ECM_IP_ADDR_TO_OCTAL(type_info->saddr), ECM_IP_ADDR_TO_OCTAL(type_info->daddr), mtu, dev_interface_num, ae_interface_num);
Ben Menchaca84f36632014-02-28 20:57:38 +00001804
1805 /*
1806 * Locate the iface
1807 */
Murat Sezgined9c1c62017-07-14 16:57:23 -07001808 ii = ecm_db_iface_find_and_ref_sit(type_info->saddr, type_info->daddr, ae_interface_num);
Ben Menchaca84f36632014-02-28 20:57:38 +00001809 if (ii) {
1810 DEBUG_TRACE("%p: iface established\n", ii);
1811 return ii;
1812 }
1813
1814 /*
1815 * No iface - create one
1816 */
1817 nii = ecm_db_iface_alloc();
1818 if (!nii) {
1819 DEBUG_WARN("Failed to establish iface\n");
1820 return NULL;
1821 }
1822
1823 /*
1824 * Add iface into the database, atomically to avoid races creating the same thing
1825 */
1826 spin_lock_bh(&ecm_interface_lock);
Murat Sezgined9c1c62017-07-14 16:57:23 -07001827 ii = ecm_db_iface_find_and_ref_sit(type_info->saddr, type_info->daddr, ae_interface_num);
Ben Menchaca84f36632014-02-28 20:57:38 +00001828 if (ii) {
1829 spin_unlock_bh(&ecm_interface_lock);
1830 ecm_db_iface_deref(nii);
1831 return ii;
1832 }
1833 ecm_db_iface_add_sit(nii, type_info, dev_name, mtu, dev_interface_num,
Murat Sezgin91c5d712015-06-12 15:16:22 -07001834 ae_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +00001835 spin_unlock_bh(&ecm_interface_lock);
1836
1837 DEBUG_TRACE("%p: sit iface established\n", nii);
1838 return nii;
1839}
Murat Sezgincc6eedf2014-05-09 23:59:19 -07001840#endif
Murat Sezginb3731e82014-11-26 12:20:59 -08001841#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001842
Murat Sezginc1402562015-03-12 12:32:20 -07001843#ifdef ECM_INTERFACE_TUNIPIP6_ENABLE
Gareth Williams8ac34292015-03-17 14:06:58 +00001844#ifdef ECM_IPV6_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001845/*
1846 * ecm_interface_tunipip6_interface_establish()
1847 * Returns a reference to a iface of the TUNIPIP6 type, possibly creating one if necessary.
1848 * Returns NULL on failure or a reference to interface.
1849 */
1850static struct ecm_db_iface_instance *ecm_interface_tunipip6_interface_establish(struct ecm_db_interface_info_tunipip6 *type_info,
Murat Sezgin91c5d712015-06-12 15:16:22 -07001851 char *dev_name, int32_t dev_interface_num, int32_t ae_interface_num, int32_t mtu)
Ben Menchaca84f36632014-02-28 20:57:38 +00001852{
1853 struct ecm_db_iface_instance *nii;
1854 struct ecm_db_iface_instance *ii;
1855
Murat Sezgin91c5d712015-06-12 15:16:22 -07001856 DEBUG_INFO("Establish TUNIPIP6 iface: %s with saddr: " ECM_IP_ADDR_OCTAL_FMT ", daddr: " ECM_IP_ADDR_OCTAL_FMT ", MTU: %d, if num: %d, accel engine if id: %d\n",
1857 dev_name, ECM_IP_ADDR_TO_OCTAL(type_info->saddr), ECM_IP_ADDR_TO_OCTAL(type_info->daddr), mtu, dev_interface_num, ae_interface_num);
Ben Menchaca84f36632014-02-28 20:57:38 +00001858
1859 /*
1860 * Locate the iface
1861 */
1862 ii = ecm_db_iface_find_and_ref_tunipip6(type_info->saddr, type_info->daddr);
1863 if (ii) {
1864 DEBUG_TRACE("%p: iface established\n", ii);
1865 return ii;
1866 }
1867
1868 /*
1869 * No iface - create one
1870 */
1871 nii = ecm_db_iface_alloc();
1872 if (!nii) {
1873 DEBUG_WARN("Failed to establish iface\n");
1874 return NULL;
1875 }
1876
1877 /*
1878 * Add iface into the database, atomically to avoid races creating the same thing
1879 */
1880 spin_lock_bh(&ecm_interface_lock);
1881 ii = ecm_db_iface_find_and_ref_tunipip6(type_info->saddr, type_info->daddr);
1882 if (ii) {
1883 spin_unlock_bh(&ecm_interface_lock);
1884 ecm_db_iface_deref(nii);
1885 return ii;
1886 }
1887 ecm_db_iface_add_tunipip6(nii, type_info, dev_name, mtu, dev_interface_num,
Murat Sezgin91c5d712015-06-12 15:16:22 -07001888 ae_interface_num, NULL, nii);
Ben Menchaca84f36632014-02-28 20:57:38 +00001889 spin_unlock_bh(&ecm_interface_lock);
1890
1891 DEBUG_TRACE("%p: tunipip6 iface established\n", nii);
1892 return nii;
1893}
Murat Sezginc1402562015-03-12 12:32:20 -07001894#endif
Gareth Williams8ac34292015-03-17 14:06:58 +00001895#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001896
1897/*
1898 * ecm_interface_establish_and_ref()
1899 * Establish an interface instance for the given interface detail.
1900 */
Murat Sezgin91c5d712015-06-12 15:16:22 -07001901struct ecm_db_iface_instance *ecm_interface_establish_and_ref(struct ecm_front_end_connection_instance *feci,
ratheesh kannotha32fdd12015-09-09 08:02:58 +05301902 struct net_device *dev, struct sk_buff *skb)
Ben Menchaca84f36632014-02-28 20:57:38 +00001903{
1904 int32_t dev_interface_num;
1905 char *dev_name;
1906 int32_t dev_type;
1907 int32_t dev_mtu;
Murat Sezgin91c5d712015-06-12 15:16:22 -07001908 int32_t ae_interface_num;
Ben Menchaca84f36632014-02-28 20:57:38 +00001909 struct ecm_db_iface_instance *ii;
1910 union {
1911 struct ecm_db_interface_info_ethernet ethernet; /* type == ECM_DB_IFACE_TYPE_ETHERNET */
Gareth Williams141d2382014-11-25 11:35:19 -08001912#ifdef ECM_INTERFACE_VLAN_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001913 struct ecm_db_interface_info_vlan vlan; /* type == ECM_DB_IFACE_TYPE_VLAN */
Gareth Williams141d2382014-11-25 11:35:19 -08001914#endif
Murat Sezgin910c9662015-03-11 16:15:06 -07001915#ifdef ECM_INTERFACE_BOND_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001916 struct ecm_db_interface_info_lag lag; /* type == ECM_DB_IFACE_TYPE_LAG */
Murat Sezgin910c9662015-03-11 16:15:06 -07001917#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001918 struct ecm_db_interface_info_bridge bridge; /* type == ECM_DB_IFACE_TYPE_BRIDGE */
ratheesh kannotha32fdd12015-09-09 08:02:58 +05301919#ifdef ECM_INTERFACE_PPPOE_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001920 struct ecm_db_interface_info_pppoe pppoe; /* type == ECM_DB_IFACE_TYPE_PPPOE */
Murat Sezginaad635c2015-03-06 16:11:41 -08001921#endif
ratheesh kannotha32fdd12015-09-09 08:02:58 +05301922#ifdef ECM_INTERFACE_L2TPV2_ENABLE
1923 struct ecm_db_interface_info_pppol2tpv2 pppol2tpv2; /* type == ECM_DB_IFACE_TYPE_PPPOL2TPV2 */
1924#endif
Shyam Sunder23f2e542015-09-28 14:56:49 +05301925#ifdef ECM_INTERFACE_PPTP_ENABLE
1926 struct ecm_db_interface_info_pptp pptp; /* type == ECM_DB_IFACE_TYPE_PPTP */
1927#endif
ratheesh kannothcfdcb332015-12-24 07:19:18 +05301928#ifdef ECM_INTERFACE_MAP_T_ENABLE
1929 struct ecm_db_interface_info_map_t map_t; /* type == ECM_DB_IFACE_TYPE_MAP_T */
1930#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001931 struct ecm_db_interface_info_unknown unknown; /* type == ECM_DB_IFACE_TYPE_UNKNOWN */
1932 struct ecm_db_interface_info_loopback loopback; /* type == ECM_DB_IFACE_TYPE_LOOPBACK */
Murat Sezgin69a27532015-03-12 14:09:40 -07001933#ifdef ECM_INTERFACE_IPSEC_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001934 struct ecm_db_interface_info_ipsec_tunnel ipsec_tunnel; /* type == ECM_DB_IFACE_TYPE_IPSEC_TUNNEL */
Murat Sezgin69a27532015-03-12 14:09:40 -07001935#endif
Murat Sezginbde55f92015-03-11 16:44:11 -07001936#ifdef ECM_INTERFACE_SIT_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001937 struct ecm_db_interface_info_sit sit; /* type == ECM_DB_IFACE_TYPE_SIT */
Murat Sezginbde55f92015-03-11 16:44:11 -07001938#endif
Murat Sezginc1402562015-03-12 12:32:20 -07001939#ifdef ECM_INTERFACE_TUNIPIP6_ENABLE
Gareth Williams8ac34292015-03-17 14:06:58 +00001940#ifdef ECM_IPV6_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001941 struct ecm_db_interface_info_tunipip6 tunipip6; /* type == ECM_DB_IFACE_TYPE_TUNIPIP6 */
Murat Sezginc1402562015-03-12 12:32:20 -07001942#endif
Gareth Williams8ac34292015-03-17 14:06:58 +00001943#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001944 } type_info;
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001945
Gareth Williamsdbb2bfd2014-11-20 16:42:09 -08001946#ifdef ECM_INTERFACE_PPP_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001947 int channel_count;
1948 struct ppp_channel *ppp_chan[1];
Ben Menchaca84f36632014-02-28 20:57:38 +00001949 int channel_protocol;
ratheesh kannotha32fdd12015-09-09 08:02:58 +05301950#ifdef ECM_INTERFACE_PPPOE_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001951 struct pppoe_opt addressing;
Gareth Williamsc5b9d712014-05-09 20:40:07 +01001952#endif
Shyam Sunder23f2e542015-09-28 14:56:49 +05301953#ifdef ECM_INTERFACE_PPTP_ENABLE
1954 int protocol = IPPROTO_IP;
1955 struct pptp_opt opt;
1956 struct iphdr *v4_hdr = NULL;
1957 if (skb) {
1958 v4_hdr = ip_hdr(skb);
1959 protocol = v4_hdr->protocol;
1960 }
ratheesh kannotha32fdd12015-09-09 08:02:58 +05301961#endif
Shyam Sunder23f2e542015-09-28 14:56:49 +05301962#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001963 /*
1964 * Get basic information about the given device
1965 */
1966 dev_interface_num = dev->ifindex;
1967 dev_name = dev->name;
1968 dev_type = dev->type;
1969 dev_mtu = dev->mtu;
1970
1971 /*
Murat Sezgin91c5d712015-06-12 15:16:22 -07001972 * Does the accel engine recognise this interface?
Ben Menchaca84f36632014-02-28 20:57:38 +00001973 */
Murat Sezgin91c5d712015-06-12 15:16:22 -07001974 ae_interface_num = feci->ae_interface_number_by_dev_get(dev);
Ben Menchaca84f36632014-02-28 20:57:38 +00001975
Murat Sezgin91c5d712015-06-12 15:16:22 -07001976 DEBUG_TRACE("Establish interface instance for device: %p is type: %d, name: %s, ifindex: %d, ae_if: %d, mtu: %d\n",
1977 dev, dev_type, dev_name, dev_interface_num, ae_interface_num, dev_mtu);
Ben Menchaca84f36632014-02-28 20:57:38 +00001978
1979 /*
1980 * Extract from the device more type-specific information
1981 */
1982 if (dev_type == ARPHRD_ETHER) {
Shyam Sunder39e25672015-09-03 14:28:09 +05301983
Ben Menchaca84f36632014-02-28 20:57:38 +00001984 /*
1985 * Ethernet - but what sub type?
1986 */
1987
Gareth Williams141d2382014-11-25 11:35:19 -08001988#ifdef ECM_INTERFACE_VLAN_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001989 /*
1990 * VLAN?
1991 */
1992 if (is_vlan_dev(dev)) {
1993 /*
1994 * VLAN master
1995 * GGG No locking needed here, ASSUMPTION is that real_dev is held for as long as we have dev.
1996 */
1997 memcpy(type_info.vlan.address, dev->dev_addr, 6);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301998 type_info.vlan.vlan_tag = vlan_dev_vlan_id(dev);
Amit Gupta8975f9d2017-07-12 20:34:36 +05301999#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0))
Murat Sezginb2676062015-06-12 17:05:31 -07002000 type_info.vlan.vlan_tpid = ETH_P_8021Q;
Amit Gupta8975f9d2017-07-12 20:34:36 +05302001#else
2002 type_info.vlan.vlan_tpid = ntohs(vlan_dev_vlan_proto(dev));
2003#endif
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302004 DEBUG_TRACE("Net device: %p is VLAN, mac: %pM, vlan_id: %x vlan_tpid: %x\n",
2005 dev, type_info.vlan.address, type_info.vlan.vlan_tag, type_info.vlan.vlan_tpid);
Ben Menchaca84f36632014-02-28 20:57:38 +00002006
2007 /*
2008 * Establish this type of interface
2009 */
Murat Sezgin91c5d712015-06-12 15:16:22 -07002010 ii = ecm_interface_vlan_interface_establish(&type_info.vlan, dev_name, dev_interface_num, ae_interface_num, dev_mtu);
Shyam Sunder39e25672015-09-03 14:28:09 +05302011 goto identifier_update;
Ben Menchaca84f36632014-02-28 20:57:38 +00002012 }
Gareth Williams141d2382014-11-25 11:35:19 -08002013#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00002014
2015 /*
2016 * BRIDGE?
2017 */
2018 if (ecm_front_end_is_bridge_device(dev)) {
2019 /*
2020 * Bridge
2021 */
2022 memcpy(type_info.bridge.address, dev->dev_addr, 6);
2023
2024 DEBUG_TRACE("Net device: %p is BRIDGE, mac: %pM\n",
2025 dev, type_info.bridge.address);
2026
2027 /*
2028 * Establish this type of interface
2029 */
Murat Sezgin91c5d712015-06-12 15:16:22 -07002030 ii = ecm_interface_bridge_interface_establish(&type_info.bridge, dev_name, dev_interface_num, ae_interface_num, dev_mtu);
Shyam Sunder39e25672015-09-03 14:28:09 +05302031 goto identifier_update;
Ben Menchaca84f36632014-02-28 20:57:38 +00002032 }
2033
Murat Sezgin910c9662015-03-11 16:15:06 -07002034#ifdef ECM_INTERFACE_BOND_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00002035 /*
2036 * LAG?
2037 */
2038 if (ecm_front_end_is_lag_master(dev)) {
2039 /*
2040 * Link aggregation
2041 */
2042 memcpy(type_info.lag.address, dev->dev_addr, 6);
2043
2044 DEBUG_TRACE("Net device: %p is LAG, mac: %pM\n",
2045 dev, type_info.lag.address);
2046
2047 /*
2048 * Establish this type of interface
2049 */
Murat Sezgin91c5d712015-06-12 15:16:22 -07002050 ii = ecm_interface_lag_interface_establish(&type_info.lag, dev_name, dev_interface_num, ae_interface_num, dev_mtu);
Shyam Sunder39e25672015-09-03 14:28:09 +05302051 goto identifier_update;
Ben Menchaca84f36632014-02-28 20:57:38 +00002052 }
Murat Sezgin910c9662015-03-11 16:15:06 -07002053#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00002054
Murat Sezgin31effef2017-11-13 15:09:34 -08002055#ifdef ECM_INTERFACE_GRE_ENABLE
2056 /*
2057 * GRE TAP?
2058 */
2059 if (dev->priv_flags & (IFF_GRE_V4_TAP | IFF_GRE_V6_TAP)) {
2060 /*
2061 * GRE TAP interface is handled as ethernet interface, however it is possible
2062 * that the acceleration engine may not be ready yet to handle the connection.
2063 * In this case the acceleration engine interface is not found for this type and
2064 * we should wait until it is ready.
2065 */
2066 if (ae_interface_num < 0) {
2067 DEBUG_TRACE("GRE interface is not ready yet\n");
2068 return NULL;
2069 }
2070 }
2071#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00002072 /*
2073 * ETHERNET!
2074 * Just plain ethernet it seems
2075 */
2076 memcpy(type_info.ethernet.address, dev->dev_addr, 6);
2077 DEBUG_TRACE("Net device: %p is ETHERNET, mac: %pM\n",
2078 dev, type_info.ethernet.address);
2079
2080 /*
2081 * Establish this type of interface
2082 */
Murat Sezgin91c5d712015-06-12 15:16:22 -07002083 ii = ecm_interface_ethernet_interface_establish(&type_info.ethernet, dev_name, dev_interface_num, ae_interface_num, dev_mtu);
Shyam Sunder39e25672015-09-03 14:28:09 +05302084
2085identifier_update:
2086 if (ii) {
2087 /*
2088 * An interface identifier/ifindex can be change after network restart. Below
2089 * functtion will check interface_identifier present in 'ii' with new dev_interface_num.
2090 * If differ then update new ifindex and update the interface identifier hash table.
2091 */
2092 ecm_db_iface_identifier_hash_table_entry_check_and_update(ii, dev_interface_num);
2093 }
2094
Ben Menchaca84f36632014-02-28 20:57:38 +00002095 return ii;
2096 }
2097
2098 /*
2099 * LOOPBACK?
2100 */
2101 if (dev_type == ARPHRD_LOOPBACK) {
2102 DEBUG_TRACE("Net device: %p is LOOPBACK type: %d\n", dev, dev_type);
2103 type_info.loopback.os_specific_ident = dev_interface_num;
Murat Sezgin91c5d712015-06-12 15:16:22 -07002104 ii = ecm_interface_loopback_interface_establish(&type_info.loopback, dev_name, dev_interface_num, ae_interface_num, dev_mtu);
Ben Menchaca84f36632014-02-28 20:57:38 +00002105 return ii;
2106 }
2107
Murat Sezgin69a27532015-03-12 14:09:40 -07002108#ifdef ECM_INTERFACE_IPSEC_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00002109 /*
2110 * IPSEC?
2111 */
2112 if (dev_type == ECM_ARPHRD_IPSEC_TUNNEL_TYPE) {
2113 DEBUG_TRACE("Net device: %p is IPSec tunnel type: %d\n", dev, dev_type);
2114 type_info.ipsec_tunnel.os_specific_ident = dev_interface_num;
Ankit Dhanuka6d5014a2014-06-22 17:21:44 +05302115
Ben Menchaca84f36632014-02-28 20:57:38 +00002116 // GGG TODO Flesh this out with tunnel endpoint addressing detail
Murat Sezgin91c5d712015-06-12 15:16:22 -07002117 ii = ecm_interface_ipsec_tunnel_interface_establish(&type_info.ipsec_tunnel, dev_name, dev_interface_num, ae_interface_num, dev_mtu);
Ben Menchaca84f36632014-02-28 20:57:38 +00002118 return ii;
2119 }
Murat Sezgin69a27532015-03-12 14:09:40 -07002120#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00002121
ratheesh kannothcfdcb332015-12-24 07:19:18 +05302122#ifdef ECM_INTERFACE_MAP_T_ENABLE
2123 if (dev_type == ARPHRD_NONE) {
2124 if (is_map_t_dev(dev)) {
2125 type_info.map_t.if_index = dev_interface_num;
2126 ii = ecm_interface_map_t_interface_establish(&type_info.map_t, dev_name, dev_interface_num, ae_interface_num, dev_mtu);
2127 return ii;
2128 }
2129
2130 }
2131#endif
2132
Murat Sezginb3731e82014-11-26 12:20:59 -08002133#ifdef ECM_INTERFACE_SIT_ENABLE
Murat Sezginbde55f92015-03-11 16:44:11 -07002134#ifdef CONFIG_IPV6_SIT_6RD
Ben Menchaca84f36632014-02-28 20:57:38 +00002135 /*
2136 * SIT (6-in-4)?
2137 */
2138 if (dev_type == ARPHRD_SIT) {
2139 struct ip_tunnel *tunnel;
2140 struct ip_tunnel_6rd_parm *ip6rd;
2141 const struct iphdr *tiph;
Murat Sezgined9c1c62017-07-14 16:57:23 -07002142 int interface_type;
Ben Menchaca84f36632014-02-28 20:57:38 +00002143
2144 DEBUG_TRACE("Net device: %p is SIT (6-in-4) type: %d\n", dev, dev_type);
2145
2146 tunnel = (struct ip_tunnel*)netdev_priv(dev);
2147 ip6rd = &tunnel->ip6rd;
2148
2149 /*
2150 * Get the Tunnel device IP header info
2151 */
2152 tiph = &tunnel->parms.iph ;
2153
2154 type_info.sit.prefixlen = ip6rd->prefixlen;
2155 type_info.sit.relay_prefix = ip6rd->relay_prefix;
2156 type_info.sit.relay_prefixlen = ip6rd->relay_prefixlen;
2157 ECM_NIN4_ADDR_TO_IP_ADDR(type_info.sit.saddr, tiph->saddr);
2158 ECM_NIN4_ADDR_TO_IP_ADDR(type_info.sit.daddr, tiph->daddr);
2159 type_info.sit.prefix[0] = ntohl(ip6rd->prefix.s6_addr32[0]);
2160 type_info.sit.prefix[1] = ntohl(ip6rd->prefix.s6_addr32[1]);
2161 type_info.sit.prefix[2] = ntohl(ip6rd->prefix.s6_addr32[2]);
2162 type_info.sit.prefix[3] = ntohl(ip6rd->prefix.s6_addr32[3]);
2163 type_info.sit.ttl = tiph->ttl;
2164 type_info.sit.tos = tiph->tos;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302165
Murat Sezgined9c1c62017-07-14 16:57:23 -07002166 interface_type = feci->ae_interface_type_get(feci, dev_type);
2167 ae_interface_num = feci->ae_interface_number_by_dev_type_get(dev, interface_type);
2168
Murat Sezgin91c5d712015-06-12 15:16:22 -07002169 ii = ecm_interface_sit_interface_establish(&type_info.sit, dev_name, dev_interface_num, ae_interface_num, dev_mtu);
Ben Menchaca84f36632014-02-28 20:57:38 +00002170 return ii;
2171 }
Murat Sezgincc6eedf2014-05-09 23:59:19 -07002172#endif
Murat Sezginb3731e82014-11-26 12:20:59 -08002173#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00002174
Murat Sezginc1402562015-03-12 12:32:20 -07002175#ifdef ECM_INTERFACE_TUNIPIP6_ENABLE
Gareth Williams8ac34292015-03-17 14:06:58 +00002176#ifdef ECM_IPV6_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00002177 /*
2178 * IPIP6 Tunnel?
2179 */
2180 if (dev_type == ARPHRD_TUNNEL6) {
2181 struct ip6_tnl *tunnel;
2182 struct flowi6 *fl6;
2183
2184 DEBUG_TRACE("Net device: %p is TUNIPIP6 type: %d\n", dev, dev_type);
2185
2186 /*
2187 * Get the tunnel device flow information (discover the output path of the tunnel)
2188 */
2189 tunnel = (struct ip6_tnl *)netdev_priv(dev);
2190 fl6 = &tunnel->fl.u.ip6;
2191
2192 ECM_NIN6_ADDR_TO_IP_ADDR(type_info.tunipip6.saddr, fl6->saddr);
2193 ECM_NIN6_ADDR_TO_IP_ADDR(type_info.tunipip6.daddr, fl6->daddr);
2194 type_info.tunipip6.hop_limit = tunnel->parms.hop_limit;
2195 type_info.tunipip6.flags = ntohl(tunnel->parms.flags);
2196 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 +05302197
Murat Sezgin91c5d712015-06-12 15:16:22 -07002198 ii = ecm_interface_tunipip6_interface_establish(&type_info.tunipip6, dev_name, dev_interface_num, ae_interface_num, dev_mtu);
Ben Menchaca84f36632014-02-28 20:57:38 +00002199 return ii;
2200 }
Murat Sezginc1402562015-03-12 12:32:20 -07002201#endif
Gareth Williams8ac34292015-03-17 14:06:58 +00002202#endif
2203
Ben Menchaca84f36632014-02-28 20:57:38 +00002204 /*
2205 * If this is NOT PPP then it is unknown to the ecm
2206 */
2207 if (dev_type != ARPHRD_PPP) {
2208 DEBUG_TRACE("Net device: %p is UNKNOWN type: %d\n", dev, dev_type);
2209 type_info.unknown.os_specific_ident = dev_interface_num;
2210
2211 /*
2212 * Establish this type of interface
2213 */
Murat Sezgin91c5d712015-06-12 15:16:22 -07002214 ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, ae_interface_num, dev_mtu);
Ben Menchaca84f36632014-02-28 20:57:38 +00002215 return ii;
2216 }
2217
Gareth Williamsdbb2bfd2014-11-20 16:42:09 -08002218#ifndef ECM_INTERFACE_PPP_ENABLE
Gareth Williamsc5b9d712014-05-09 20:40:07 +01002219 /*
ratheesh kannothf4801a02016-12-09 22:46:39 +05302220 * PPP Support is NOT provided for.
Gareth Williamsc5b9d712014-05-09 20:40:07 +01002221 * Interface is therefore unknown
2222 */
2223 DEBUG_TRACE("Net device: %p is UNKNOWN (PPP Unsupported) type: %d\n", dev, dev_type);
2224 type_info.unknown.os_specific_ident = dev_interface_num;
2225
2226 /*
2227 * Establish this type of interface
2228 */
Murat Sezgin91c5d712015-06-12 15:16:22 -07002229 ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, ae_interface_num, dev_mtu);
Gareth Williamsc5b9d712014-05-09 20:40:07 +01002230 return ii;
2231#else
ratheesh kannotha32fdd12015-09-09 08:02:58 +05302232
2233#ifdef ECM_INTERFACE_L2TPV2_ENABLE
2234 /*
2235 * ppp_xmit lock is held by linux kernel for l2tp packet in transmit
2236 * direction. we need to check for l2tp packet and avoid calls to
2237 * ppp_is_multilink() and ppp_hold_channels() which acquire same lock
2238 */
ratheesh kannothf4801a02016-12-09 22:46:39 +05302239
2240 if ((dev->priv_flags & IFF_PPP_L2TPV2) && ppp_is_xmit_locked(dev)) {
Murat Sezgindb0c5d82017-02-22 11:43:03 -08002241 if (skb && (skb->skb_iif == dev->ifindex)) {
ratheesh kannoth08b8e442015-10-02 00:24:55 +05302242 struct pppol2tp_common_addr info;
ratheesh kannotha32fdd12015-09-09 08:02:58 +05302243
ratheesh kannoth08b8e442015-10-02 00:24:55 +05302244 if (__ppp_is_multilink(dev) > 0) {
2245 DEBUG_TRACE("Net device: %p is MULTILINK PPP - Unknown to the ECM\n", dev);
2246 type_info.unknown.os_specific_ident = dev_interface_num;
ratheesh kannotha32fdd12015-09-09 08:02:58 +05302247
ratheesh kannoth08b8e442015-10-02 00:24:55 +05302248 /*
2249 * Establish this type of interface
2250 */
2251 ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, ae_interface_num, dev_mtu);
2252 return ii;
2253 }
2254 channel_count = __ppp_hold_channels(dev, ppp_chan, 1);
2255 if (channel_count != 1) {
2256 DEBUG_TRACE("Net device: %p PPP has %d channels - ECM cannot handle this (interface becomes Unknown type)\n",
2257 dev, channel_count);
2258 type_info.unknown.os_specific_ident = dev_interface_num;
2259
2260 /*
2261 * Establish this type of interface
2262 */
2263 ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, ae_interface_num, dev_mtu);
2264 return ii;
2265 }
2266
2267 if (pppol2tp_channel_addressing_get(ppp_chan[0], &info)) {
2268 ppp_release_channels(ppp_chan, 1);
ratheesh kannothed721852015-09-28 12:39:52 +05302269 return NULL;
2270 }
ratheesh kannotha32fdd12015-09-09 08:02:58 +05302271
ratheesh kannoth08b8e442015-10-02 00:24:55 +05302272 type_info.pppol2tpv2.l2tp.tunnel.tunnel_id = info.local_tunnel_id;
2273 type_info.pppol2tpv2.l2tp.tunnel.peer_tunnel_id = info.remote_tunnel_id;
2274 type_info.pppol2tpv2.l2tp.session.session_id = info.local_session_id;
2275 type_info.pppol2tpv2.l2tp.session.peer_session_id = info.remote_session_id;
2276 type_info.pppol2tpv2.udp.sport = ntohs(info.local_addr.sin_port);
2277 type_info.pppol2tpv2.udp.dport = ntohs(info.remote_addr.sin_port);
2278 type_info.pppol2tpv2.ip.saddr = ntohl(info.local_addr.sin_addr.s_addr);
2279 type_info.pppol2tpv2.ip.daddr = ntohl(info.remote_addr.sin_addr.s_addr);
ratheesh kannothed721852015-09-28 12:39:52 +05302280
2281 /*
ratheesh kannoth08b8e442015-10-02 00:24:55 +05302282 * Release the channel. Note that next_dev is still (correctly) held.
ratheesh kannothed721852015-09-28 12:39:52 +05302283 */
ratheesh kannoth08b8e442015-10-02 00:24:55 +05302284 ppp_release_channels(ppp_chan, 1);
ratheesh kannotha32fdd12015-09-09 08:02:58 +05302285
ratheesh kannoth08b8e442015-10-02 00:24:55 +05302286 DEBUG_TRACE("Net device: %p PPPo2L2TP session: %d,n", dev, type_info.pppol2tpv2.l2tp.session.peer_session_id);
ratheesh kannothed721852015-09-28 12:39:52 +05302287
2288 /*
2289 * Establish this type of interface
2290 */
2291 ii = ecm_interface_pppol2tpv2_interface_establish(&type_info.pppol2tpv2, dev_name, dev_interface_num, ae_interface_num, dev_mtu);
2292 return ii;
ratheesh kannotha32fdd12015-09-09 08:02:58 +05302293 }
ratheesh kannotha32fdd12015-09-09 08:02:58 +05302294 }
2295#endif
2296
Shyam Sunder23f2e542015-09-28 14:56:49 +05302297#ifdef ECM_INTERFACE_PPTP_ENABLE
2298 if ((protocol == IPPROTO_GRE) && skb && v4_hdr) {
2299 struct gre_hdr_pptp *gre_hdr;
2300 uint16_t proto;
2301 int ret;
2302
2303 skb_pull(skb, sizeof(struct iphdr));
2304 gre_hdr = (struct gre_hdr_pptp *)(skb->data);
2305 proto = ntohs(gre_hdr->protocol);
2306 if ((gre_hdr->version == GRE_VERSION_PPTP) && (proto == GRE_PROTOCOL_PPTP)) {
2307 ret = pptp_session_find(&opt, gre_hdr->call_id, v4_hdr->daddr);
2308 if (ret < 0) {
2309 skb_push(skb, sizeof(struct iphdr));
2310 DEBUG_WARN("PPTP session info not found\n");
2311 return NULL;
2312 }
2313
2314 /*
2315 * Get PPTP session info
2316 */
2317 type_info.pptp.src_call_id = ntohs(opt.src_addr.call_id);
2318 type_info.pptp.dst_call_id = ntohs(opt.dst_addr.call_id);
2319 type_info.pptp.src_ip = ntohl(opt.src_addr.sin_addr.s_addr);
2320 type_info.pptp.dst_ip = ntohl(opt.dst_addr.sin_addr.s_addr);
2321
2322 skb_push(skb, sizeof(struct iphdr));
2323
2324 /*
2325 * Establish this type of interface
2326 */
2327 ii = ecm_interface_pptp_interface_establish(&type_info.pptp, dev_name, dev_interface_num, ae_interface_num, dev_mtu);
Shyam Sunder65f013e2015-12-14 18:04:54 +05302328 if (ii) {
2329 /*
2330 * The ifindex of a virtual netdevice like a PPTP session can change if it is destroyed
2331 * and comes up again. Detect if the ifindex has changed and update it if required
2332 */
2333 ecm_db_iface_identifier_hash_table_entry_check_and_update(ii, dev_interface_num);
2334 }
Shyam Sunder23f2e542015-09-28 14:56:49 +05302335 return ii;
2336 }
2337
2338 skb_push(skb, sizeof(struct iphdr));
2339
2340 DEBUG_TRACE("Unknown GRE protocol \n");
2341 type_info.unknown.os_specific_ident = dev_interface_num;
2342
2343 /*
2344 * Establish this type of interface
2345 */
2346 ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, ae_interface_num, dev_mtu);
2347 return ii;
2348 }
2349#endif
2350
Ben Menchaca84f36632014-02-28 20:57:38 +00002351 /*
2352 * PPP - but what is the channel type?
2353 * First: If this is multi-link then we do not support it
2354 */
2355 if (ppp_is_multilink(dev) > 0) {
2356 DEBUG_TRACE("Net device: %p is MULTILINK PPP - Unknown to the ECM\n", dev);
2357 type_info.unknown.os_specific_ident = dev_interface_num;
2358
2359 /*
2360 * Establish this type of interface
2361 */
Murat Sezgin91c5d712015-06-12 15:16:22 -07002362 ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, ae_interface_num, dev_mtu);
Ben Menchaca84f36632014-02-28 20:57:38 +00002363 return ii;
2364 }
2365
2366 DEBUG_TRACE("Net device: %p is PPP\n", dev);
2367
2368 /*
2369 * Get the PPP channel and then enquire what kind of channel it is
2370 * NOTE: Not multilink so only one channel to get.
2371 */
2372 channel_count = ppp_hold_channels(dev, ppp_chan, 1);
2373 if (channel_count != 1) {
Gareth Williams6f96a4b2014-05-29 19:41:21 +01002374 DEBUG_TRACE("Net device: %p PPP has %d channels - ECM cannot handle this (interface becomes Unknown type)\n",
2375 dev, channel_count);
Ben Menchaca84f36632014-02-28 20:57:38 +00002376 type_info.unknown.os_specific_ident = dev_interface_num;
2377
2378 /*
2379 * Establish this type of interface
2380 */
Murat Sezgin91c5d712015-06-12 15:16:22 -07002381 ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, ae_interface_num, dev_mtu);
Ben Menchaca84f36632014-02-28 20:57:38 +00002382 return ii;
2383 }
2384
2385 /*
2386 * Get channel protocol type
Gareth Williams6f96a4b2014-05-29 19:41:21 +01002387 * NOTE: Not all PPP channels support channel specific methods.
Ben Menchaca84f36632014-02-28 20:57:38 +00002388 */
Gareth Williams6f96a4b2014-05-29 19:41:21 +01002389 channel_protocol = ppp_channel_get_protocol(ppp_chan[0]);
ratheesh kannotha32fdd12015-09-09 08:02:58 +05302390
2391#ifdef ECM_INTERFACE_L2TPV2_ENABLE
2392 if (channel_protocol == PX_PROTO_OL2TP) {
ratheesh kannoth08b8e442015-10-02 00:24:55 +05302393 struct pppol2tp_common_addr info;
Ben Menchaca84f36632014-02-28 20:57:38 +00002394
ratheesh kannoth08b8e442015-10-02 00:24:55 +05302395 if (pppol2tp_channel_addressing_get(ppp_chan[0], &info)) {
ratheesh kannotha32fdd12015-09-09 08:02:58 +05302396 ppp_release_channels(ppp_chan, 1);
2397 return NULL;
2398 }
2399
ratheesh kannoth08b8e442015-10-02 00:24:55 +05302400 type_info.pppol2tpv2.l2tp.tunnel.tunnel_id = info.local_tunnel_id;
2401 type_info.pppol2tpv2.l2tp.tunnel.peer_tunnel_id = info.remote_tunnel_id;
2402 type_info.pppol2tpv2.l2tp.session.session_id = info.local_session_id;
2403 type_info.pppol2tpv2.l2tp.session.peer_session_id = info.remote_session_id;
2404 type_info.pppol2tpv2.udp.sport = ntohs(info.local_addr.sin_port);
2405 type_info.pppol2tpv2.udp.dport = ntohs(info.remote_addr.sin_port);
2406 type_info.pppol2tpv2.ip.saddr = ntohl(info.local_addr.sin_addr.s_addr);
2407 type_info.pppol2tpv2.ip.daddr = ntohl(info.remote_addr.sin_addr.s_addr);
ratheesh kannotha32fdd12015-09-09 08:02:58 +05302408
2409 /*
2410 * Release the channel. Note that next_dev is still (correctly) held.
Ben Menchaca84f36632014-02-28 20:57:38 +00002411 */
2412 ppp_release_channels(ppp_chan, 1);
2413
ratheesh kannotha32fdd12015-09-09 08:02:58 +05302414 DEBUG_TRACE("Net device: %p PPPo2L2TP session: %d,n", dev, type_info.pppol2tpv2.l2tp.session.peer_session_id);
2415
Ben Menchaca84f36632014-02-28 20:57:38 +00002416 /*
2417 * Establish this type of interface
2418 */
ratheesh kannotha32fdd12015-09-09 08:02:58 +05302419 ii = ecm_interface_pppol2tpv2_interface_establish(&type_info.pppol2tpv2, dev_name, dev_interface_num, ae_interface_num, dev_mtu);
Ben Menchaca84f36632014-02-28 20:57:38 +00002420 return ii;
2421 }
ratheesh kannotha32fdd12015-09-09 08:02:58 +05302422#endif
2423#ifdef ECM_INTERFACE_PPPOE_ENABLE
2424 if (channel_protocol == PX_PROTO_OE) {
2425
2426 /*
2427 * PPPoE channel
2428 */
2429 DEBUG_TRACE("Net device: %p PPP channel is PPPoE\n", dev);
2430
2431 /*
2432 * Get PPPoE session information and the underlying device it is using.
2433 */
2434 pppoe_channel_addressing_get(ppp_chan[0], &addressing);
2435 type_info.pppoe.pppoe_session_id = (uint16_t)ntohs((uint16_t)addressing.pa.sid);
2436 memcpy(type_info.pppoe.remote_mac, addressing.pa.remote, ETH_ALEN);
2437 dev_put(addressing.dev);
2438
2439 /*
2440 * Release the channel. Note that next_dev is still (correctly) held.
2441 */
2442 ppp_release_channels(ppp_chan, 1);
2443
2444 DEBUG_TRACE("Net device: %p PPPoE session: %x, remote mac: %pM\n",
2445 dev, type_info.pppoe.pppoe_session_id, type_info.pppoe.remote_mac);
2446
2447 /*
2448 * Establish this type of interface
2449 */
2450 ii = ecm_interface_pppoe_interface_establish(&type_info.pppoe, dev_name, dev_interface_num, ae_interface_num, dev_mtu);
2451 return ii;
2452 }
2453#endif
Shyam Sunder23f2e542015-09-28 14:56:49 +05302454
2455#ifdef ECM_INTERFACE_PPTP_ENABLE
2456 if (channel_protocol == PX_PROTO_PPTP) {
2457 pptp_channel_addressing_get(&opt, ppp_chan[0]);
2458
2459 /*
2460 * Get PPTP session info
2461 */
2462 type_info.pptp.src_call_id = ntohs(opt.src_addr.call_id);
2463 type_info.pptp.dst_call_id = ntohs(opt.dst_addr.call_id);
2464 type_info.pptp.src_ip = ntohl(opt.src_addr.sin_addr.s_addr);
2465 type_info.pptp.dst_ip = ntohl(opt.dst_addr.sin_addr.s_addr);
2466
2467 DEBUG_TRACE("Net device: %p PPTP source call id: %d,n", dev, type_info.pptp.src_call_id);
2468 ppp_release_channels(ppp_chan, 1);
2469
2470 /*
2471 * Establish this type of interface
2472 */
2473 ii = ecm_interface_pptp_interface_establish(&type_info.pptp, dev_name, dev_interface_num, ae_interface_num, dev_mtu);
Shyam Sunder65f013e2015-12-14 18:04:54 +05302474 if (ii) {
2475 /*
2476 * The ifindex of a virtual netdevice like a PPTP session can change if it is destroyed
2477 * and comes up again. Detect if the ifindex has changed and update it if required
2478 */
2479 ecm_db_iface_identifier_hash_table_entry_check_and_update(ii, dev_interface_num);
2480 }
Shyam Sunder23f2e542015-09-28 14:56:49 +05302481 return ii;
2482 }
2483#endif
ratheesh kannotha32fdd12015-09-09 08:02:58 +05302484 DEBUG_TRACE("Net device: %p PPP channel protocol: %d - Unknown to the ECM\n", dev, channel_protocol);
2485 type_info.unknown.os_specific_ident = dev_interface_num;
Ben Menchaca84f36632014-02-28 20:57:38 +00002486
2487 /*
ratheesh kannotha32fdd12015-09-09 08:02:58 +05302488 * Release the channel
Ben Menchaca84f36632014-02-28 20:57:38 +00002489 */
2490 ppp_release_channels(ppp_chan, 1);
2491
Ben Menchaca84f36632014-02-28 20:57:38 +00002492 /*
2493 * Establish this type of interface
2494 */
ratheesh kannotha32fdd12015-09-09 08:02:58 +05302495 ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, ae_interface_num, dev_mtu);
Ben Menchaca84f36632014-02-28 20:57:38 +00002496 return ii;
Gareth Williamsc5b9d712014-05-09 20:40:07 +01002497#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00002498}
2499EXPORT_SYMBOL(ecm_interface_establish_and_ref);
2500
Shyam Sunder6358b862015-05-04 15:06:24 +05302501#ifdef ECM_MULTICAST_ENABLE
2502/*
2503 * ecm_interface_multicast_heirarchy_construct_single()
2504 * Create and return an interface heirarchy for a single interface for a multicast connection
2505 *
2506 * src_addr IP source address
2507 * dest_addr IP Destination address/Group Address
2508 * interface Pointer to a single multicast interface heirarchy
2509 * given_dest_dev Netdev pointer for destination interface
2510 * br_slave_dev Netdev pointer to a bridge slave device. It could be NULL in case of pure
2511 * routed flow without any bridge interface in destination dev list.
ratheesh kannotha32fdd12015-09-09 08:02:58 +05302512 * skb sk_buff
Shyam Sunder6358b862015-05-04 15:06:24 +05302513 */
Shyam Sunder81836832015-07-09 19:18:25 +05302514static uint32_t ecm_interface_multicast_heirarchy_construct_single(struct ecm_front_end_connection_instance *feci, ip_addr_t src_addr,
2515 ip_addr_t dest_addr, struct ecm_db_iface_instance *interface,
2516 struct net_device *given_dest_dev, struct net_device *br_slave_dev,
ratheesh kannotha32fdd12015-09-09 08:02:58 +05302517 uint8_t *src_node_addr, bool is_routed, __be16 *layer4hdr, struct sk_buff *skb)
Shyam Sunder6358b862015-05-04 15:06:24 +05302518{
2519 struct ecm_db_iface_instance *to_list_single[ECM_DB_IFACE_HEIRARCHY_MAX];
2520 struct ecm_db_iface_instance **ifaces;
2521 struct ecm_db_iface_instance *ii_temp;
2522 struct net_device *dest_dev;
2523 int32_t current_interface_index;
2524 int32_t interfaces_cnt = 0;
2525 int32_t dest_dev_type;
2526
2527 dest_dev = given_dest_dev;
2528 dev_hold(dest_dev);
2529 dest_dev_type = dest_dev->type;
2530 current_interface_index = ECM_DB_IFACE_HEIRARCHY_MAX;
2531
2532 while (current_interface_index > 0) {
2533 struct ecm_db_iface_instance *ii;
2534 struct net_device *next_dev;
2535
2536 /*
2537 * Get the ecm db interface instance for the device at hand
2538 */
ratheesh kannotha32fdd12015-09-09 08:02:58 +05302539 ii = ecm_interface_establish_and_ref(feci, dest_dev, skb);
Shyam Sunder6358b862015-05-04 15:06:24 +05302540 interfaces_cnt++;
2541
2542 /*
2543 * If the interface could not be established then we abort
2544 */
2545 if (!ii) {
2546 DEBUG_WARN("Failed to establish interface: %p, name: %s\n", dest_dev, dest_dev->name);
2547 dev_put(dest_dev);
2548
2549 /*
2550 * Release the interfaces heirarchy we constructed to this point.
2551 */
2552 ecm_db_multicast_copy_if_heirarchy(to_list_single, interface);
2553 ecm_db_connection_interfaces_deref(to_list_single, current_interface_index);
2554 return ECM_DB_IFACE_HEIRARCHY_MAX;
2555 }
2556
2557 /*
2558 * Record the interface instance into the *ifaces
2559 */
2560 current_interface_index--;
2561 ii_temp = ecm_db_multicast_if_instance_get_at_index(interface, current_interface_index);
2562 ifaces = (struct ecm_db_iface_instance **)ii_temp;
2563 *ifaces = ii;
2564
2565 /*
2566 * Now we have to figure out what the next device will be (in the transmission path)
2567 */
2568 do {
Kiran Kumar C.S.Kd43bc3f2015-08-04 16:51:03 +05302569#ifdef ECM_INTERFACE_PPP_ENABLE
Shyam Sunder6358b862015-05-04 15:06:24 +05302570 int channel_count;
2571 struct ppp_channel *ppp_chan[1];
2572 int channel_protocol;
2573 struct pppoe_opt addressing;
2574#endif
2575 DEBUG_TRACE("Net device: %p is type: %d, name: %s\n", dest_dev, dest_dev_type, dest_dev->name);
2576 next_dev = NULL;
2577
2578 if (dest_dev_type == ARPHRD_ETHER) {
2579 /*
2580 * Ethernet - but what sub type?
2581 */
2582
2583 /*
2584 * VLAN?
2585 */
2586 if (is_vlan_dev(dest_dev)) {
2587 /*
2588 * VLAN master
2589 * No locking needed here, ASSUMPTION is that real_dev is held for as long as we have dev.
2590 */
Shyam Sunder9db20852016-03-09 19:04:49 +05302591 next_dev = ecm_interface_vlan_real_dev(dest_dev);
Shyam Sunder6358b862015-05-04 15:06:24 +05302592 dev_hold(next_dev);
2593 DEBUG_TRACE("Net device: %p is VLAN, slave dev: %p (%s)\n",
2594 dest_dev, next_dev, next_dev->name);
2595 break;
2596 }
2597
2598 /*
2599 * BRIDGE?
2600 */
2601 if (ecm_front_end_is_bridge_device(dest_dev)) {
2602 if (!ecm_front_end_is_bridge_port(br_slave_dev)) {
2603 DEBUG_ASSERT(NULL, "%p: expected only bridge slave here\n", interface);
2604
2605 /*
2606 * Release the interfaces heirarchy we constructed to this point.
2607 */
2608 ecm_db_multicast_copy_if_heirarchy(to_list_single, interface);
2609 ecm_db_connection_interfaces_deref(to_list_single, current_interface_index);
2610 dev_put(dest_dev);
2611 return ECM_DB_IFACE_HEIRARCHY_MAX;
2612 }
2613
2614 next_dev = br_slave_dev;
2615 if (!next_dev) {
2616 DEBUG_WARN("Unable to obtain output port \n");
2617
2618 /*
2619 * Release the interfaces heirarchy we constructed to this point.
2620 */
2621 ecm_db_multicast_copy_if_heirarchy(to_list_single, interface);
2622 ecm_db_connection_interfaces_deref(to_list_single, current_interface_index);
2623 dev_put(dest_dev);
2624 return ECM_DB_IFACE_HEIRARCHY_MAX;
2625 }
2626 DEBUG_TRACE("Net device: %p is BRIDGE, next_dev: %p (%s)\n", dest_dev, next_dev, next_dev->name);
2627 dev_hold(next_dev);
2628 break;
2629 }
2630
Shyam Sunder81836832015-07-09 19:18:25 +05302631#ifdef ECM_INTERFACE_BOND_ENABLE
Shyam Sunder6358b862015-05-04 15:06:24 +05302632 /*
2633 * LAG?
2634 */
2635 if (ecm_front_end_is_lag_master(dest_dev)) {
2636 /*
2637 * Link aggregation
2638 * Figure out which slave device of the link aggregation will be used to reach the destination.
2639 */
2640 uint32_t src_addr_32 = 0;
2641 uint32_t dest_addr_32 = 0;
Suman Ghoshf14d2172015-07-31 14:38:10 +05302642 struct in6_addr src_addr6;
2643 struct in6_addr dest_addr6;
Shyam Sunder6358b862015-05-04 15:06:24 +05302644 uint8_t src_mac_addr[ETH_ALEN];
2645 uint8_t dest_mac_addr[ETH_ALEN];
2646
2647 memset(src_mac_addr, 0, ETH_ALEN);
2648 memset(dest_mac_addr, 0, ETH_ALEN);
2649
Shyam Sunder81836832015-07-09 19:18:25 +05302650 if (ECM_IP_ADDR_IS_V4(src_addr)) {
2651 ECM_IP_ADDR_TO_NIN4_ADDR(src_addr_32, src_addr);
2652 ECM_IP_ADDR_TO_NIN4_ADDR(dest_addr_32, dest_addr);
2653 }
Shyam Sunder6358b862015-05-04 15:06:24 +05302654
Shyam Sunder81836832015-07-09 19:18:25 +05302655 if (!is_routed) {
2656 memcpy(src_mac_addr, src_node_addr, ETH_ALEN);
Shyam Sunder6358b862015-05-04 15:06:24 +05302657 } else {
Shyam Sunder81836832015-07-09 19:18:25 +05302658 struct net_device *dest_dev_master;
2659
2660 /*
2661 * Use appropriate source MAC address for routed packets
2662 */
2663 dest_dev_master = ecm_interface_get_and_hold_dev_master(dest_dev);
2664 if (dest_dev_master) {
2665 memcpy(src_mac_addr, dest_dev_master->dev_addr, ETH_ALEN);
2666 dev_put(dest_dev_master);
2667 } else {
2668 memcpy(src_mac_addr, dest_dev->dev_addr, ETH_ALEN);
2669 }
Shyam Sunder6358b862015-05-04 15:06:24 +05302670 }
2671
2672 /*
2673 * Create Destination MAC address using IP multicast destination address
2674 */
2675 ecm_translate_multicast_mac(dest_addr, dest_mac_addr);
2676
Shyam Sunder81836832015-07-09 19:18:25 +05302677 if (ECM_IP_ADDR_IS_V4(src_addr)) {
2678 next_dev = bond_get_tx_dev(NULL, src_mac_addr, dest_mac_addr,
2679 &src_addr_32, &dest_addr_32,
Suman Ghoshfb8e7702015-08-20 15:27:57 +05302680 htons((uint16_t)ETH_P_IP), dest_dev, layer4hdr);
Shyam Sunder81836832015-07-09 19:18:25 +05302681 } else {
Suman Ghoshf14d2172015-07-31 14:38:10 +05302682 ECM_IP_ADDR_TO_NIN6_ADDR(src_addr6, src_addr);
2683 ECM_IP_ADDR_TO_NIN6_ADDR(dest_addr6, dest_addr);
Shyam Sunder81836832015-07-09 19:18:25 +05302684 next_dev = bond_get_tx_dev(NULL, src_mac_addr, dest_mac_addr,
Suman Ghoshf14d2172015-07-31 14:38:10 +05302685 src_addr6.s6_addr, dest_addr6.s6_addr,
Shyam Sundere60540c2016-04-29 15:06:35 +05302686 htons((uint16_t)ETH_P_IPV6), dest_dev, layer4hdr);
Shyam Sunder81836832015-07-09 19:18:25 +05302687 }
2688
Shyam Sunder6358b862015-05-04 15:06:24 +05302689 if (!(next_dev && netif_carrier_ok(next_dev))) {
2690 DEBUG_WARN("Unable to obtain LAG output slave device\n");
2691 dev_put(dest_dev);
2692
2693 /*
2694 * Release the interfaces heirarchy we constructed to this point.
2695 */
2696 ecm_db_multicast_copy_if_heirarchy(to_list_single, interface);
2697 ecm_db_connection_interfaces_deref(to_list_single, current_interface_index);
2698 return ECM_DB_IFACE_HEIRARCHY_MAX;
2699 }
2700
2701 dev_hold(next_dev);
2702 DEBUG_TRACE("Net device: %p is LAG, slave dev: %p (%s)\n", dest_dev, next_dev, next_dev->name);
2703 break;
2704 }
2705#endif
2706
2707 /*
2708 * ETHERNET!
2709 * Just plain ethernet it seems.
2710 */
2711 DEBUG_TRACE("Net device: %p is ETHERNET\n", dest_dev);
2712 break;
2713 }
2714
2715 /*
2716 * LOOPBACK?
2717 */
2718 if (dest_dev_type == ARPHRD_LOOPBACK) {
2719 DEBUG_TRACE("Net device: %p is LOOPBACK type: %d\n", dest_dev, dest_dev_type);
2720 break;
2721 }
2722
2723 /*
2724 * IPSEC?
2725 */
2726 if (dest_dev_type == ECM_ARPHRD_IPSEC_TUNNEL_TYPE) {
2727 DEBUG_TRACE("Net device: %p is IPSec tunnel type: %d\n", dest_dev, dest_dev_type);
2728 /*
2729 * TODO Figure out the next device the tunnel is using...
2730 */
2731 break;
2732 }
2733
2734 /*
2735 * SIT (6-in-4)?
2736 */
2737 if (dest_dev_type == ARPHRD_SIT) {
2738 DEBUG_TRACE("Net device: %p is SIT (6-in-4) type: %d\n", dest_dev, dest_dev_type);
2739 /*
2740 * TODO Figure out the next device the tunnel is using...
2741 */
2742 break;
2743 }
2744
2745 /*
2746 * IPIP6 Tunnel?
2747 */
2748 if (dest_dev_type == ARPHRD_TUNNEL6) {
2749 DEBUG_TRACE("Net device: %p is TUNIPIP6 type: %d\n", dest_dev, dest_dev_type);
2750 /*
2751 * TODO Figure out the next device the tunnel is using...
2752 */
2753 break;
2754 }
2755
2756 /*
2757 * If this is NOT PPP then it is unknown to the ecm and we cannot figure out it's next device.
2758 */
2759 if (dest_dev_type != ARPHRD_PPP) {
2760 DEBUG_TRACE("Net device: %p is UNKNOWN type: %d\n", dest_dev, dest_dev_type);
2761 break;
2762 }
2763
Kiran Kumar C.S.Kd43bc3f2015-08-04 16:51:03 +05302764#ifndef ECM_INTERFACE_PPP_ENABLE
Shyam Sunder6358b862015-05-04 15:06:24 +05302765 DEBUG_TRACE("Net device: %p is UNKNOWN (PPP Unsupported) type: %d\n", dest_dev, dest_dev_type);
2766#else
2767 /*
2768 * PPP - but what is the channel type?
2769 * First: If this is multi-link then we do not support it
2770 */
2771 if (ppp_is_multilink(dest_dev) > 0) {
2772 DEBUG_TRACE("Net device: %p is MULTILINK PPP - Unknown to the ECM\n", dest_dev);
2773 break;
2774 }
2775
2776 DEBUG_TRACE("Net device: %p is PPP\n", dest_dev);
2777
2778 /*
2779 * Get the PPP channel and then enquire what kind of channel it is
2780 * NOTE: Not multilink so only one channel to get.
2781 */
2782 channel_count = ppp_hold_channels(dest_dev, ppp_chan, 1);
2783 if (channel_count != 1) {
2784 DEBUG_TRACE("Net device: %p PPP has %d channels - Unknown to the ECM\n",
2785 dest_dev, channel_count);
2786 break;
2787 }
2788
2789 /*
2790 * Get channel protocol type
2791 * NOTE: Not all PPP channels support channel specific methods.
2792 */
2793 channel_protocol = ppp_channel_get_protocol(ppp_chan[0]);
2794 if (channel_protocol != PX_PROTO_OE) {
2795 DEBUG_TRACE("Net device: %p PPP channel protocol: %d - Unknown to the ECM\n",
2796 dest_dev, channel_protocol);
2797
2798 /*
2799 * Release the channel
2800 */
2801 ppp_release_channels(ppp_chan, 1);
2802
2803 break;
2804 }
2805
2806 /*
2807 * PPPoE channel
2808 */
2809 DEBUG_TRACE("Net device: %p PPP channel is PPPoE\n", dest_dev);
2810
2811 /*
2812 * Get PPPoE session information and the underlying device it is using.
2813 */
2814 pppoe_channel_addressing_get(ppp_chan[0], &addressing);
2815
2816 /*
2817 * Copy the dev hold into this, we will release the hold later
2818 */
2819 next_dev = addressing.dev;
2820
Shyam Sunder6358b862015-05-04 15:06:24 +05302821 /*
2822 * Release the channel. Note that next_dev is still (correctly) held.
2823 */
2824 ppp_release_channels(ppp_chan, 1);
2825#endif
2826 } while (false);
2827
2828 /*
2829 * No longer need dest_dev as it may become next_dev
2830 */
2831 dev_put(dest_dev);
2832
2833 /*
2834 * Check out the next_dev, if any
2835 */
2836 if (!next_dev) {
2837 int32_t i __attribute__((unused));
2838 DEBUG_INFO("Completed interface heirarchy construct with first interface @: %d\n", current_interface_index);
2839#if DEBUG_LEVEL > 1
2840 ecm_db_multicast_copy_if_heirarchy(to_list_single, interface);
2841 for (i = current_interface_index; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
2842 DEBUG_TRACE("\tInterface @ %d: %p, type: %d, name: %s\n", \
Murat Sezgin3d9a7642018-05-15 16:24:09 -07002843 i, to_list_single[i], ecm_db_iface_type_get(to_list_single[i]), \
2844 ecm_db_interface_type_to_string(ecm_db_iface_type_get(to_list_single[i])));
Shyam Sunder6358b862015-05-04 15:06:24 +05302845 }
2846#endif
2847 return current_interface_index;
2848 }
2849
2850 /*
2851 * dest_dev becomes next_dev
2852 */
2853 dest_dev = next_dev;
2854 dest_dev_type = dest_dev->type;
2855 }
2856
2857 dev_put(dest_dev);
2858
2859 ecm_db_multicast_copy_if_heirarchy(to_list_single, interface);
2860 ecm_db_connection_interfaces_deref(to_list_single, current_interface_index);
2861 return ECM_DB_IFACE_HEIRARCHY_MAX;
2862}
2863
2864/*
2865 * ecm_interface_multicast_heirarchy_construct_routed()
2866 * Create destination interface heirarchy for a routed multicast connectiona
2867 *
2868 * interfaces Pointer to the 2-D array of multicast interface heirarchies
2869 * in_dev Pointer to the source netdev
2870 * packet_src_addr Source IP of the multicast flow
2871 * packet_dest_addr Group(dest) IP of the multicast flow
2872 * max_dst Maximum number of netdev joined the multicast group
2873 * dst_if_index_base An array of if index joined the multicast group
2874 * interface_first_base An array of the index of the first interface in the list
2875 */
Murat Sezgin91c5d712015-06-12 15:16:22 -07002876int32_t ecm_interface_multicast_heirarchy_construct_routed(struct ecm_front_end_connection_instance *feci,
2877 struct ecm_db_iface_instance *interfaces,
2878 struct net_device *in_dev,
2879 ip_addr_t packet_src_addr,
2880 ip_addr_t packet_dest_addr, uint8_t max_if,
2881 uint32_t *dst_if_index_base,
Shyam Sundera2e08ee2015-06-18 21:32:13 +05302882 uint32_t *interface_first_base, bool mfc_update,
ratheesh kannotha32fdd12015-09-09 08:02:58 +05302883 __be16 *layer4hdr, struct sk_buff *skb)
Shyam Sunder6358b862015-05-04 15:06:24 +05302884{
2885 struct ecm_db_iface_instance *to_list_single[ECM_DB_IFACE_HEIRARCHY_MAX];
2886 struct ecm_db_iface_instance *ifaces;
2887 struct net_device *dest_dev = NULL;
2888 struct net_device *br_dev_src = NULL;
2889 uint32_t *dst_if_index;
2890 uint32_t *interface_first;
2891 uint32_t br_if;
2892 uint32_t valid_if;
Shyam Sunder41637872015-06-11 21:19:05 +05302893 int32_t if_num;
Shyam Sunder6358b862015-05-04 15:06:24 +05302894 int32_t dest_dev_type;
2895 int if_index;
2896 int ii_cnt;
2897 int total_ii_count = 0;
2898 bool src_dev_is_bridge = false;
2899
2900 DEBUG_TRACE("Construct interface heirarchy for dest_addr: " ECM_IP_ADDR_DOT_FMT " src_addr: " ECM_IP_ADDR_DOT_FMT "total destination ifs %d\n",
2901 ECM_IP_ADDR_TO_DOT(packet_dest_addr), ECM_IP_ADDR_TO_DOT(packet_src_addr), max_if);
2902
2903 /*
2904 * Check if the source net_dev is a bridge slave.
2905 */
Shyam Sundera2e08ee2015-06-18 21:32:13 +05302906 if (in_dev && !mfc_update) {
Shyam Sunder6358b862015-05-04 15:06:24 +05302907 if (ecm_front_end_is_bridge_port(in_dev)) {
2908 src_dev_is_bridge = true;
Karthik Hariharan3e964a32015-09-22 21:40:52 +05302909 br_dev_src = ecm_interface_get_and_hold_dev_master(in_dev);
2910 DEBUG_ASSERT(br_dev_src, "Expected a master\n");
Shyam Sunder6358b862015-05-04 15:06:24 +05302911
2912 /*
2913 * The source net_dev found as bridge slave. In case of routed interface
2914 * heirarchy MFC is not aware of any other bridge slave has joined the same
2915 * multicast group as a destination interface. Therfore we assume there
2916 * are bridge slaves present in multicast destination interface list
2917 * and increase the max_if by one.
2918 */
2919 max_if++;
2920 }
2921 }
2922
2923 ii_cnt = 0;
2924 br_if = if_num = 0;
2925
2926 /*
2927 * This loop is for creating the destination interface hierarchy list.
2928 * We take the destination interface array we got from MFC (in form of ifindex array)
2929 * as input for this.
2930 */
2931 for (if_index = 0, valid_if = 0; if_index < max_if; if_index++) {
2932 dst_if_index = ecm_db_multicast_if_first_get_at_index(dst_if_index_base, if_index);
2933
2934 if (*dst_if_index == ECM_INTERFACE_LOOPBACK_DEV_INDEX) {
2935 continue;
2936 }
2937
2938 dest_dev = dev_get_by_index(&init_net, *dst_if_index);
2939 if (!dest_dev) {
2940 if (!src_dev_is_bridge) {
2941 int i;
2942
2943 /*
2944 * If already constructed any interface heirarchies before hitting
2945 * this error condition then Deref all interface heirarchies.
2946 */
2947 if (valid_if > 0) {
2948 for (i = 0; i < valid_if; i++) {
2949 ifaces = ecm_db_multicast_if_heirarchy_get(interfaces, i);
2950 ecm_db_multicast_copy_if_heirarchy(to_list_single, ifaces);
2951 ecm_db_connection_interfaces_deref(to_list_single, interface_first_base[i]);
2952 }
2953 }
2954
2955 /*
2956 * If valid netdev not found, Return 0
2957 */
2958 return 0;
2959 }
Karthik Hariharan3e964a32015-09-22 21:40:52 +05302960
Shyam Sunder6358b862015-05-04 15:06:24 +05302961 dest_dev = br_dev_src;
Karthik Hariharan3e964a32015-09-22 21:40:52 +05302962
Shyam Sunder6358b862015-05-04 15:06:24 +05302963 }
2964
2965 dest_dev_type = dest_dev->type;
2966
2967 if (ecm_front_end_is_bridge_device(dest_dev)) {
2968 struct net_device *mc_br_slave_dev = NULL;
2969 uint32_t mc_max_dst = ECM_DB_MULTICAST_IF_MAX;
2970 uint32_t mc_dst_if_index[ECM_DB_MULTICAST_IF_MAX];
2971
2972 if (ECM_IP_ADDR_IS_V4(packet_src_addr)) {
2973 if_num = mc_bridge_ipv4_get_if(dest_dev, htonl((packet_src_addr[0])), htonl(packet_dest_addr[0]), mc_max_dst, mc_dst_if_index);
2974 } else {
2975 struct in6_addr origin6;
2976 struct in6_addr group6;
2977 ECM_IP_ADDR_TO_NIN6_ADDR(origin6, packet_src_addr);
2978 ECM_IP_ADDR_TO_NIN6_ADDR(group6, packet_dest_addr);
2979 if_num = mc_bridge_ipv6_get_if(dest_dev, &origin6, &group6, mc_max_dst, mc_dst_if_index);
2980 }
2981
Shyam Sunder81836832015-07-09 19:18:25 +05302982 if ((if_num < 0) || (if_num > ECM_DB_MULTICAST_IF_MAX)) {
2983 int i;
2984 DEBUG_WARN("MCS is not ready\n");
2985
2986 /*
2987 * If already constructed any interface heirarchies before hitting
2988 * this error condition then Deref all interface heirarchies.
2989 */
2990 if (valid_if > 0) {
2991 for (i = 0; i < valid_if; i++) {
2992 ifaces = ecm_db_multicast_if_heirarchy_get(interfaces, i);
2993 ecm_db_multicast_copy_if_heirarchy(to_list_single, ifaces);
2994 ecm_db_connection_interfaces_deref(to_list_single, interface_first_base[i]);
2995 }
2996 }
2997
Shyam Sunder41637872015-06-11 21:19:05 +05302998 dev_put(dest_dev);
2999 return 0;
3000 }
3001
Shyam Sundera450b582016-07-22 14:44:14 +05303002 if (in_dev && !mfc_update) {
Shyam Sunder06588292016-04-18 19:57:39 +05303003 if_num = ecm_interface_multicast_check_for_src_ifindex(mc_dst_if_index, if_num, in_dev->ifindex);
3004 }
Shyam Sundera2e08ee2015-06-18 21:32:13 +05303005
Shyam Sunder6358b862015-05-04 15:06:24 +05303006 for (br_if = 0; br_if < if_num; br_if++) {
3007 mc_br_slave_dev = dev_get_by_index(&init_net, mc_dst_if_index[br_if]);
3008 if (!mc_br_slave_dev) {
3009 continue;
3010 }
3011
3012 if ((valid_if + br_if) > ECM_DB_MULTICAST_IF_MAX) {
3013 int i;
3014
3015 /*
3016 * If already constructed any interface heirarchies before hitting
3017 * this error condition then Deref all interface heirarchies.
3018 */
3019 for (i = 0; i < (valid_if + br_if); i++) {
3020 ifaces = ecm_db_multicast_if_heirarchy_get(interfaces, i);
3021 ecm_db_multicast_copy_if_heirarchy(to_list_single, ifaces);
3022 ecm_db_connection_interfaces_deref(to_list_single, interface_first_base[i]);
3023 }
3024
3025 dev_put(dest_dev);
3026 dev_put(mc_br_slave_dev);
3027 return 0;
3028 }
3029
3030 ifaces = ecm_db_multicast_if_heirarchy_get(interfaces, valid_if + br_if);
3031 /*
3032 * Construct a single interface heirarchy of a multicast dev.
3033 */
ratheesh kannotha32fdd12015-09-09 08:02:58 +05303034 ii_cnt = ecm_interface_multicast_heirarchy_construct_single(feci, packet_src_addr, packet_dest_addr, ifaces, dest_dev, mc_br_slave_dev, NULL, true, layer4hdr, skb);
Shyam Sunder6358b862015-05-04 15:06:24 +05303035 if (ii_cnt == ECM_DB_IFACE_HEIRARCHY_MAX) {
3036
3037 /*
3038 * If already constructed any interface heirarchies before hitting
3039 * this error condition then Deref all interface heirarchies.
3040 */
3041 if ((valid_if + br_if) > 0) {
3042 int i;
3043 for (i = 0; i < (valid_if + br_if); i++) {
3044 ifaces = ecm_db_multicast_if_heirarchy_get(interfaces, i);
3045 ecm_db_multicast_copy_if_heirarchy(to_list_single, ifaces);
3046 ecm_db_connection_interfaces_deref(to_list_single, interface_first_base[i]);
3047 }
3048 }
3049
3050 dev_put(dest_dev);
3051 dev_put(mc_br_slave_dev);
3052 return 0;
3053 }
3054
3055 interface_first = ecm_db_multicast_if_first_get_at_index(interface_first_base, (valid_if + br_if));
3056 *interface_first = ii_cnt;
3057 total_ii_count += ii_cnt;
3058 dev_put(mc_br_slave_dev);
3059 }
3060
3061 valid_if += br_if;
3062
3063 } else {
3064
3065 DEBUG_ASSERT(valid_if < ECM_DB_MULTICAST_IF_MAX, "Bad array index size %d\n", valid_if);
3066 ifaces = ecm_db_multicast_if_heirarchy_get(interfaces, valid_if);
3067 /*
3068 * Construct a single interface heirarchy of a multicast dev.
3069 */
ratheesh kannotha32fdd12015-09-09 08:02:58 +05303070 ii_cnt = ecm_interface_multicast_heirarchy_construct_single(feci, packet_src_addr, packet_dest_addr, ifaces, dest_dev, NULL, NULL, true, layer4hdr, skb);
Shyam Sunder6358b862015-05-04 15:06:24 +05303071 if (ii_cnt == ECM_DB_IFACE_HEIRARCHY_MAX) {
3072
3073 /*
3074 * If already constructed any interface heirarchies before hitting
3075 * this error condition then Deref all interface heirarchies.
3076 */
3077 if (valid_if > 0) {
3078 int i;
3079 for (i = 0; i < valid_if; i++) {
3080 ifaces = ecm_db_multicast_if_heirarchy_get(interfaces, i);
3081 ecm_db_multicast_copy_if_heirarchy(to_list_single, ifaces);
3082 ecm_db_connection_interfaces_deref(to_list_single, interface_first_base[i]);
3083 }
3084 }
3085
3086 dev_put(dest_dev);
3087 return 0;
3088 }
3089
3090 interface_first = ecm_db_multicast_if_first_get_at_index(interface_first_base, valid_if);
3091 *interface_first = ii_cnt;
3092 total_ii_count += ii_cnt;
3093 valid_if++;
3094 }
3095
3096 dev_put(dest_dev);
3097 }
3098 return total_ii_count;
3099}
3100EXPORT_SYMBOL(ecm_interface_multicast_heirarchy_construct_routed);
3101
3102/*
3103 * ecm_interface_multicast_heirarchy_construct_bridged()
3104 * This function called when the Hyfi bridge snooper has IGMP/IMLD updates, this function
3105 * creates destination interface heirarchy for a bridged multicast connection.
3106 *
3107 * interfaces Pointer to the 2-D array of multicast interface heirarchies
3108 * dest_dev Pointer to the destination dev, here dest_dev is always a bridge type
3109 * packet_src_addr Source IP of the multicast flow
3110 * packet_dest_addr Group(dest) IP of the multicast flow
3111 * mc_max_dst Maximum number of bridge slaves joined the multicast group
3112 * mc_dst_if_index_base An array of if index joined the multicast group
3113 * interface_first_base An array of the index of the first interface in the list
3114 */
Murat Sezgin91c5d712015-06-12 15:16:22 -07003115int32_t ecm_interface_multicast_heirarchy_construct_bridged(struct ecm_front_end_connection_instance *feci,
Shyam Sunder81836832015-07-09 19:18:25 +05303116 struct ecm_db_iface_instance *interfaces, struct net_device *dest_dev,
3117 ip_addr_t packet_src_addr, ip_addr_t packet_dest_addr, uint8_t mc_max_dst,
Suman Ghoshfb8e7702015-08-20 15:27:57 +05303118 int *mc_dst_if_index_base, uint32_t *interface_first_base, uint8_t *src_node_addr,
ratheesh kannotha32fdd12015-09-09 08:02:58 +05303119 __be16 *layer4hdr, struct sk_buff *skb)
Shyam Sunder6358b862015-05-04 15:06:24 +05303120{
3121 struct ecm_db_iface_instance *to_list_single[ECM_DB_IFACE_HEIRARCHY_MAX];
3122 struct ecm_db_iface_instance *ifaces;
3123 struct net_device *mc_br_slave_dev = NULL;
3124 uint32_t *interface_first;
3125 int *mc_dst_if_index;
3126 int valid_if;
3127 int ii_cnt = 0;
3128 int br_if;
3129 int total_ii_cnt = 0;
3130
3131 /*
3132 * Go through the newly joined interface index one by one and
3133 * create an interface heirarchy for each valid interface.
3134 */
3135 for (br_if = 0, valid_if = 0; br_if < mc_max_dst; br_if++) {
3136 mc_dst_if_index = (int *)ecm_db_multicast_if_num_get_at_index(mc_dst_if_index_base, br_if);
3137 mc_br_slave_dev = dev_get_by_index(&init_net, *mc_dst_if_index);
3138 if (!mc_br_slave_dev) {
3139
3140 /*
3141 * If already constructed any interface heirarchies before hitting
3142 * this error condition then Deref all interface heirarchies.
3143 */
3144 if (valid_if > 0) {
3145 int i;
3146 for (i = 0; i < valid_if; i++) {
3147 ifaces = ecm_db_multicast_if_heirarchy_get(interfaces, i);
3148 ecm_db_multicast_copy_if_heirarchy(to_list_single, ifaces);
3149 ecm_db_connection_interfaces_deref(to_list_single, interface_first_base[i]);
3150 }
3151 }
3152
3153 /*
3154 * If valid netdev not found, Return 0
3155 */
3156 return 0;
3157 }
3158
3159 if (valid_if > ECM_DB_MULTICAST_IF_MAX) {
3160 int i;
3161
3162 /*
3163 * If already constructed any interface heirarchies before hitting
3164 * this error condition then Deref all interface heirarchies.
3165 */
3166 for (i = 0; i < valid_if; i++) {
3167 ifaces = ecm_db_multicast_if_heirarchy_get(interfaces, i);
3168 ecm_db_multicast_copy_if_heirarchy(to_list_single, ifaces);
3169 ecm_db_connection_interfaces_deref(to_list_single, interface_first_base[i]);
3170 }
3171
3172 dev_put(mc_br_slave_dev);
3173 return 0;
3174 }
3175
3176 ifaces = ecm_db_multicast_if_heirarchy_get(interfaces, valid_if);
3177
3178 /*
3179 * Construct a single interface heirarchy of a multicast dev.
3180 */
ratheesh kannotha32fdd12015-09-09 08:02:58 +05303181 ii_cnt = ecm_interface_multicast_heirarchy_construct_single(feci, packet_src_addr, packet_dest_addr, ifaces, dest_dev, mc_br_slave_dev, src_node_addr, false, layer4hdr, skb);
Shyam Sunder6358b862015-05-04 15:06:24 +05303182 if (ii_cnt == ECM_DB_IFACE_HEIRARCHY_MAX) {
3183
3184 /*
3185 * If already constructed any interface heirarchies before hitting
3186 * this error condition then Deref all interface heirarchies.
3187 */
3188 if (valid_if > 0) {
3189 int i;
3190 for (i = 0; i < valid_if; i++) {
3191 ifaces = ecm_db_multicast_if_heirarchy_get(interfaces, i);
3192 ecm_db_multicast_copy_if_heirarchy(to_list_single, ifaces);
3193 ecm_db_connection_interfaces_deref(to_list_single, interface_first_base[i]);
3194 }
3195 }
3196
3197 dev_put(mc_br_slave_dev);
3198 return 0;
3199 }
3200
3201 interface_first = ecm_db_multicast_if_first_get_at_index(interface_first_base, valid_if);
3202 *interface_first = ii_cnt;
3203 total_ii_cnt += ii_cnt;
3204 valid_if++;
3205 dev_put(mc_br_slave_dev);
3206 }
3207
Shyam Sunder280b34a2016-06-22 19:30:22 +05303208 return valid_if;
Shyam Sunder6358b862015-05-04 15:06:24 +05303209}
3210EXPORT_SYMBOL(ecm_interface_multicast_heirarchy_construct_bridged);
Shyam Sunder6358b862015-05-04 15:06:24 +05303211
Ben Menchaca84f36632014-02-28 20:57:38 +00003212/*
Murat Sezgin5dae8832015-12-03 14:23:19 -08003213 * ecm_interface_multicast_get_next_node_mac_address()
3214 * Get the MAC address of the next node for multicast flows
3215 *
3216 * TODO: This function will be removed when the multicast flow code
3217 * is fixed to use the new interface hierarchy construction model.
3218 *
Murat Sezgin3aea6c92015-11-13 13:14:12 -08003219 */
Murat Sezgin5dae8832015-12-03 14:23:19 -08003220static bool ecm_interface_multicast_get_next_node_mac_address(
Murat Sezgin3aea6c92015-11-13 13:14:12 -08003221 ip_addr_t dest_addr, struct net_device *dest_dev, int ip_version,
3222 uint8_t *mac_addr)
3223{
3224 bool on_link;
3225 ip_addr_t gw_addr = ECM_IP_ADDR_NULL;
3226
3227 if (!ecm_interface_mac_addr_get(dest_addr, mac_addr, &on_link, gw_addr)) {
3228 if (ip_version == 4) {
3229 DEBUG_WARN("Unable to obtain MAC address for " ECM_IP_ADDR_DOT_FMT "\n",
3230 ECM_IP_ADDR_TO_DOT(dest_addr));
3231 ecm_interface_send_arp_request(dest_dev, dest_addr, on_link, gw_addr);
3232 }
Murat Sezgin5dae8832015-12-03 14:23:19 -08003233#ifdef ECM_IPV6_ENABLE
Murat Sezgin3aea6c92015-11-13 13:14:12 -08003234 if (ip_version == 6) {
3235 DEBUG_WARN("Unable to obtain MAC address for " ECM_IP_ADDR_OCTAL_FMT "\n",
3236 ECM_IP_ADDR_TO_OCTAL(dest_addr));
3237 ecm_interface_send_neighbour_solicitation(dest_dev, dest_addr);
3238 }
Murat Sezgin5dae8832015-12-03 14:23:19 -08003239#endif
3240 return false;
3241 }
Murat Sezgin3aea6c92015-11-13 13:14:12 -08003242
Murat Sezgin5dae8832015-12-03 14:23:19 -08003243 return true;
3244}
Murat Sezgin8f70b312016-02-02 23:33:10 -08003245#endif
Murat Sezgin5dae8832015-12-03 14:23:19 -08003246
3247/*
3248 * ecm_interface_get_next_node_mac_address()
3249 * Get the MAC address of the next node
3250 */
Suman Ghosh37af2642018-03-22 13:05:33 +05303251static bool ecm_interface_get_next_node_mac_address(ip_addr_t dest_addr,
3252 struct net_device *dest_dev,
3253 int ip_version, uint8_t *mac_addr)
Murat Sezgin5dae8832015-12-03 14:23:19 -08003254{
Suman Ghosh37af2642018-03-22 13:05:33 +05303255 ip_addr_t gw_addr = ECM_IP_ADDR_NULL;
3256 bool on_link = true;
Murat Sezgin00627c12016-02-05 16:53:21 -08003257
Suman Ghosh37af2642018-03-22 13:05:33 +05303258 if (ecm_interface_mac_addr_get_no_route(dest_dev, dest_addr, mac_addr)) {
3259 return true;
Murat Sezgin3aea6c92015-11-13 13:14:12 -08003260 }
3261
Suman Ghosh37af2642018-03-22 13:05:33 +05303262 /*
3263 * MAC address look up failed. The host IP address may not be in the
3264 * neighbour table. So, let's send an ARP or neighbour solicitation
3265 * request to this host IP address, so in the subsequent lookups it can be
3266 * found.
3267 *
3268 * If we have a gateway address, try one more time with that address.
3269 * If it fails, send the request with the current dest_addr or
3270 * found gateway address.
3271 */
3272 if (ecm_interface_find_gateway(dest_addr, gw_addr)) {
3273 on_link = false;
3274 if (ecm_interface_mac_addr_get_no_route(dest_dev, gw_addr, mac_addr)) {
3275 DEBUG_TRACE("Found the mac address for the gateway\n");
3276 return true;
3277 }
3278 }
3279
3280 if (ip_version == 4) {
3281 DEBUG_WARN("Unable to obtain MAC address for " ECM_IP_ADDR_DOT_FMT " send ARP request\n",
3282 ECM_IP_ADDR_TO_DOT(dest_addr));
3283 ecm_interface_send_arp_request(dest_dev, dest_addr, on_link, gw_addr);
3284 }
3285
3286#ifdef ECM_IPV6_ENABLE
3287 if (ip_version == 6) {
3288 DEBUG_WARN("Unable to obtain MAC address for " ECM_IP_ADDR_OCTAL_FMT " send solicitation request\n",
3289 ECM_IP_ADDR_TO_OCTAL(dest_addr));
3290 ecm_interface_send_neighbour_solicitation(dest_dev, dest_addr);
3291 }
3292#endif
3293
3294 return false;
Murat Sezgin3aea6c92015-11-13 13:14:12 -08003295}
3296
3297/*
3298 * ecm_interface_should_update_egress_device_bridged()
3299 * Determine if the egress port should be re-evaluated in the bridged case
3300 *
3301 * This will be done if:
3302 * - The egress port is the one provided from the front-end
3303 * - The egress port is not a bridge, but is a slave of the bridge
3304 * - Not routed
3305 *
3306 * If these conditions hold, this function will hold a reference to the bridge
3307 * port and return it to the caller. Otherwise no reference will be held and
3308 * it will return NULL.
3309 */
3310static struct net_device *ecm_interface_should_update_egress_device_bridged(
3311 struct net_device *given_dest_dev, struct net_device *dest_dev,
3312 bool is_routed)
3313{
3314 struct net_device *bridge;
3315
3316 /*
3317 * Determine if we should attempt to fetch the bridge device
3318 */
3319 if (!given_dest_dev || is_routed || (dest_dev != given_dest_dev) ||
3320 ecm_front_end_is_bridge_device(given_dest_dev))
3321 return NULL;
3322
3323 bridge = ecm_interface_get_and_hold_dev_master(given_dest_dev);
3324
3325 if (!bridge)
3326 return NULL;
3327
Murat Sezgin3aea6c92015-11-13 13:14:12 -08003328 if (!ecm_front_end_is_bridge_device(bridge)) {
3329 /*
3330 * Master is not a bridge - free the reference and return
3331 */
3332 dev_put(bridge);
3333 return NULL;
3334 }
3335
3336 /*
3337 * Reference is held to bridge and must be freed by caller
3338 */
3339 return bridge;
3340}
3341
3342/*
Ben Menchaca84f36632014-02-28 20:57:38 +00003343 * ecm_interface_heirarchy_construct()
3344 * Construct an interface heirarchy.
3345 *
3346 * Using the given addressing, locate the interface heirarchy used to emit packets to that destination.
3347 * This is the heirarchy of interfaces a packet would transit to emit from the device.
Gareth Williams46f4b5f2014-06-01 23:35:23 +01003348 *
3349 * We will use the given src/dest devices when is_routed is false.
Murat Sezgin5dae8832015-12-03 14:23:19 -08003350 * When is_routed is true we will use the construct and the other devices (which is the src device of the
3351 * construct device) whcih were obtained from the skb's route field and passed to this function..
Gareth Williams46f4b5f2014-06-01 23:35:23 +01003352 *
Ben Menchaca84f36632014-02-28 20:57:38 +00003353 * For example, with this network arrangement:
3354 *
3355 * PPPoE--VLAN--BRIDGE--BRIDGE_PORT(LAG_MASTER)--LAG_SLAVE_0--10.22.33.11
3356 *
Gareth Williams43fc0852014-05-26 19:10:00 +01003357 * Given the packet_dest_addr IP address 10.22.33.11 this will create an interface heirarchy (in interracfes[]) of:
Ben Menchaca84f36632014-02-28 20:57:38 +00003358 * LAG_SLAVE_0 @ [ECM_DB_IFACE_HEIRARCHY_MAX - 5]
3359 * LAG_MASTER @ [ECM_DB_IFACE_HEIRARCHY_MAX - 4]
3360 * BRIDGE @ [ECM_DB_IFACE_HEIRARCHY_MAX - 3]
3361 * VLAN @ [ECM_DB_IFACE_HEIRARCHY_MAX - 2]
3362 * PPPOE @ [ECM_DB_IFACE_HEIRARCHY_MAX - 1]
3363 * The value returned is (ECM_DB_IFACE_HEIRARCHY_MAX - 5)
3364 *
3365 * IMPORTANT: This function will return any known interfaces in the database, when interfaces do not exist in the database
3366 * they will be created and added automatically to the database.
Ben Menchaca84f36632014-02-28 20:57:38 +00003367 */
Murat Sezgin91c5d712015-06-12 15:16:22 -07003368int32_t ecm_interface_heirarchy_construct(struct ecm_front_end_connection_instance *feci,
3369 struct ecm_db_iface_instance *interfaces[],
Murat Sezgin5dae8832015-12-03 14:23:19 -08003370 struct net_device *const_if, struct net_device *other_if,
Murat Sezginf92db492016-07-15 11:33:15 -07003371 ip_addr_t lookup_src_addr,
3372 ip_addr_t lookup_dest_addr,
3373 ip_addr_t real_dest_addr,
Murat Sezgin5dae8832015-12-03 14:23:19 -08003374 int ip_version, int packet_protocol,
3375 struct net_device *given_dest_dev,
3376 bool is_routed, struct net_device *given_src_dev,
3377 uint8_t *dest_node_addr, uint8_t *src_node_addr,
3378 __be16 *layer4hdr, struct sk_buff *skb)
3379{
3380 int protocol;
3381 ip_addr_t src_addr;
3382 ip_addr_t dest_addr;
3383 struct net_device *dest_dev;
3384 char *dest_dev_name;
3385 int32_t dest_dev_type;
3386 struct net_device *src_dev;
3387 char *src_dev_name;
3388 int32_t src_dev_type;
3389 int32_t current_interface_index;
3390 bool from_local_addr;
3391 bool next_dest_addr_valid;
3392 bool next_dest_node_addr_valid = false;
3393 ip_addr_t next_dest_addr;
3394 uint8_t next_dest_node_addr[ETH_ALEN] = {0};
Murat Sezgin70c44cd2016-03-02 11:32:10 -08003395 struct net_device *bridge;
Suman Ghosh9bb0abb2018-03-19 01:08:54 +05303396 struct net_device *top_dev = NULL;
Murat Sezgin545cf7d2016-03-04 09:48:21 -08003397 uint32_t serial = ecm_db_connection_serial_get(feci->ci);
Murat Sezgin5dae8832015-12-03 14:23:19 -08003398
3399 /*
3400 * Get a big endian of the IPv4 address we have been given as our starting point.
3401 */
3402 protocol = packet_protocol;
Murat Sezginf92db492016-07-15 11:33:15 -07003403 ECM_IP_ADDR_COPY(src_addr, lookup_src_addr);
3404 ECM_IP_ADDR_COPY(dest_addr, lookup_dest_addr);
Murat Sezgin5dae8832015-12-03 14:23:19 -08003405
3406 if (ip_version == 4) {
Murat Sezgin545cf7d2016-03-04 09:48:21 -08003407 DEBUG_TRACE("Construct interface heirarchy for from src_addr: " ECM_IP_ADDR_DOT_FMT " to dest_addr: " ECM_IP_ADDR_DOT_FMT ", protocol: %d (serial %u)\n",
3408 ECM_IP_ADDR_TO_DOT(src_addr), ECM_IP_ADDR_TO_DOT(dest_addr), protocol,
3409 serial);
Murat Sezgin5dae8832015-12-03 14:23:19 -08003410#ifdef ECM_IPV6_ENABLE
3411 } else if (ip_version == 6) {
Murat Sezgin545cf7d2016-03-04 09:48:21 -08003412 DEBUG_TRACE("Construct interface heirarchy for from src_addr: " ECM_IP_ADDR_OCTAL_FMT " to dest_addr: " ECM_IP_ADDR_OCTAL_FMT ", protocol: %d (serial %u)\n",
3413 ECM_IP_ADDR_TO_OCTAL(src_addr), ECM_IP_ADDR_TO_OCTAL(dest_addr), protocol,
3414 serial);
Murat Sezgin5dae8832015-12-03 14:23:19 -08003415#endif
3416 } else {
3417 DEBUG_WARN("Wrong IP protocol: %d\n", ip_version);
3418 return ECM_DB_IFACE_HEIRARCHY_MAX;
3419 }
3420
3421 /*
3422 * Get device to reach the given destination address.
3423 * If the heirarchy is for a routed connection we must use the devices obtained from the skb's route information..
3424 * If the heirarchy is NOT for a routed connection we try the given_dest_dev.
3425 */
3426 from_local_addr = false;
3427 if (!is_routed) {
3428 dest_dev = given_dest_dev;
3429 dev_hold(dest_dev);
3430 } else {
3431 dest_dev = ecm_interface_dev_find_by_local_addr(dest_addr);
3432 if (dest_dev) {
3433 from_local_addr = true;
3434 } else {
3435 dest_dev = const_if;
3436 dev_hold(dest_dev);
3437 }
3438 }
3439
3440 /*
3441 * If the address is a local address and protocol is an IP tunnel
3442 * then this connection is a tunnel endpoint made to this device.
3443 * In which case we circumvent all proper procedure and just hack the devices to make stuff work.
3444 *
3445 * TODO THIS MUST BE FIXED - WE MUST USE THE INTERFACE HIERARCHY FOR ITS INTENDED PURPOSE TO
3446 * PARSE THE DEVICES AND WORK OUT THE PROPER INTERFACES INVOLVED.
3447 * E.G. IF WE TRIED TO RUN A TUNNEL OVER A VLAN OR QINQ THIS WILL BREAK AS WE DON'T DISCOVER THAT HIERARCHY
3448 */
3449 if (dest_dev && from_local_addr) {
3450 if (((ip_version == 4) && (protocol == IPPROTO_IPV6)) ||
Murat Sezgin31effef2017-11-13 15:09:34 -08003451 ((ip_version == 6) && (protocol == IPPROTO_IPIP))
3452#ifdef ECM_INTERFACE_GRE_ENABLE
3453 || ((protocol == IPPROTO_GRE) && (given_dest_dev->priv_flags & (IFF_GRE_V4_TAP | IFF_GRE_V6_TAP)))) {
3454#else
3455 {
3456#endif
Murat Sezgin5dae8832015-12-03 14:23:19 -08003457 dev_put(dest_dev);
3458 dest_dev = given_dest_dev;
3459 if (dest_dev) {
3460 dev_hold(dest_dev);
3461 if (ip_version == 4) {
3462 DEBUG_TRACE("HACK: %s tunnel packet with dest_addr: " ECM_IP_ADDR_DOT_FMT " uses dev: %p(%s)\n", "IPV6", ECM_IP_ADDR_TO_DOT(dest_addr), dest_dev, dest_dev->name);
3463 } else {
3464 DEBUG_TRACE("HACK: %s tunnel packet with dest_addr: " ECM_IP_ADDR_OCTAL_FMT " uses dev: %p(%s)\n", "IPIP", ECM_IP_ADDR_TO_OCTAL(dest_addr), dest_dev, dest_dev->name);
3465 }
3466 }
3467 }
3468 }
3469
3470#ifdef ECM_INTERFACE_L2TPV2_ENABLE
ratheesh kannothf4801a02016-12-09 22:46:39 +05303471
Murat Sezgin5dae8832015-12-03 14:23:19 -08003472 /*
3473 * if the address is a local address and indev=l2tp.
3474 */
ratheesh kannothf4801a02016-12-09 22:46:39 +05303475 if ((given_src_dev->type == ARPHRD_PPP) && (given_src_dev->priv_flags & IFF_PPP_L2TPV2) && ppp_is_xmit_locked(given_src_dev)) {
Murat Sezgin5dae8832015-12-03 14:23:19 -08003476 dev_put(dest_dev);
3477 dest_dev = given_dest_dev;
3478 if (dest_dev) {
3479 dev_hold(dest_dev);
3480 DEBUG_TRACE("l2tp packet tunnel packet with dest_addr: " ECM_IP_ADDR_OCTAL_FMT " uses dev: %p(%s)\n", ECM_IP_ADDR_TO_OCTAL(dest_addr), dest_dev, dest_dev->name);
3481 }
3482 }
3483#endif
3484
3485#ifdef ECM_INTERFACE_PPTP_ENABLE
3486 /*
3487 * if the address is a local address and indev=PPTP.
3488 */
3489 if (protocol == IPPROTO_GRE && given_dest_dev && given_dest_dev->type == ARPHRD_PPP) {
3490 dev_put(dest_dev);
3491 dest_dev = given_dest_dev;
3492 if (dest_dev) {
3493 dev_hold(dest_dev);
3494 DEBUG_TRACE("PPTP packet tunnel packet with dest_addr: " ECM_IP_ADDR_OCTAL_FMT " uses dev: %p(%s)\n", ECM_IP_ADDR_TO_OCTAL(dest_addr), dest_dev, dest_dev->name);
3495 }
3496 }
3497#endif
3498
3499 if (!dest_dev) {
3500 DEBUG_WARN("dest_addr: " ECM_IP_ADDR_OCTAL_FMT " - cannot locate device\n", ECM_IP_ADDR_TO_OCTAL(dest_addr));
3501 return ECM_DB_IFACE_HEIRARCHY_MAX;
3502 }
3503 dest_dev_name = dest_dev->name;
3504 dest_dev_type = dest_dev->type;
3505
3506 /*
3507 * Get device to reach the given source address.
3508 * If the heirarchy is for a routed connection we must use the devices obtained from the skb's route information..
3509 * If the heirarchy is NOT for a routed connection we try the given_src_dev.
3510 */
3511 from_local_addr = false;
3512 if (!is_routed) {
3513 src_dev = given_src_dev;
3514 dev_hold(src_dev);
3515 } else {
3516 src_dev = ecm_interface_dev_find_by_local_addr(src_addr);
3517 if (src_dev) {
3518 from_local_addr = true;
3519 } else {
3520 src_dev = other_if;
3521 dev_hold(src_dev);
3522 }
3523 }
3524
3525 /*
3526 * If the address is a local address and protocol is an IP tunnel
3527 * then this connection is a tunnel endpoint made to this device.
3528 * In which case we circumvent all proper procedure and just hack the devices to make stuff work.
3529 *
3530 * TODO THIS MUST BE FIXED - WE MUST USE THE INTERFACE HIERARCHY FOR ITS INTENDED PURPOSE TO
3531 * PARSE THE DEVICES AND WORK OUT THE PROPER INTERFACES INVOLVED.
3532 * E.G. IF WE TRIED TO RUN A TUNNEL OVER A VLAN OR QINQ THIS WILL BREAK AS WE DON'T DISCOVER THAT HIERARCHY
3533 */
3534 if (src_dev && from_local_addr) {
3535 if (((ip_version == 4) && (protocol == IPPROTO_IPV6)) ||
Murat Sezgin31effef2017-11-13 15:09:34 -08003536 ((ip_version == 6) && (protocol == IPPROTO_IPIP))
3537#ifdef ECM_INTERFACE_GRE_ENABLE
3538 || ((protocol == IPPROTO_GRE) && (given_src_dev->priv_flags & (IFF_GRE_V4_TAP | IFF_GRE_V6_TAP)))) {
3539#else
3540 {
3541#endif
Murat Sezgin5dae8832015-12-03 14:23:19 -08003542 dev_put(src_dev);
3543 src_dev = given_src_dev;
3544 if (src_dev) {
3545 dev_hold(src_dev);
3546 if (ip_version == 4) {
3547 DEBUG_TRACE("HACK: %s tunnel packet with src_addr: " ECM_IP_ADDR_DOT_FMT " uses dev: %p(%s)\n", "IPV6", ECM_IP_ADDR_TO_DOT(src_addr), src_dev, src_dev->name);
3548 } else {
3549 DEBUG_TRACE("HACK: %s tunnel packet with src_addr: " ECM_IP_ADDR_OCTAL_FMT " uses dev: %p(%s)\n", "IPIP", ECM_IP_ADDR_TO_OCTAL(src_addr), src_dev, src_dev->name);
3550 }
3551 }
3552 }
3553 }
3554
3555 if (!src_dev) {
3556 DEBUG_WARN("src_addr: " ECM_IP_ADDR_OCTAL_FMT " - cannot locate device\n", ECM_IP_ADDR_TO_OCTAL(src_addr));
3557 dev_put(dest_dev);
3558 return ECM_DB_IFACE_HEIRARCHY_MAX;
3559 }
3560 src_dev_name = src_dev->name;
3561 src_dev_type = src_dev->type;
3562
3563 /*
3564 * Check if source and dest dev are same.
Murat Sezgin5dae8832015-12-03 14:23:19 -08003565 */
3566 if (src_dev == dest_dev) {
ratheesh kannotha6d25952016-04-11 12:23:26 +05303567 bool skip = false;
3568
Murat Sezgin5dae8832015-12-03 14:23:19 -08003569 DEBUG_TRACE("Protocol is :%d source dev and dest dev are same\n", protocol);
ratheesh kannotha6d25952016-04-11 12:23:26 +05303570
3571 switch (ip_version) {
3572 case 4:
3573 if ((protocol == IPPROTO_IPV6) || (protocol == IPPROTO_ESP)) {
3574 skip = true;
3575 break;
3576 }
3577
3578 if ((protocol == IPPROTO_UDP) && (udp_hdr(skb)->dest == htons(4500))) {
3579 skip = true;
3580 break;
3581 }
3582
3583 break;
3584
3585 case 6:
ratheesh kannotha6d25952016-04-11 12:23:26 +05303586 if ((protocol == IPPROTO_IPIP) || (protocol == IPPROTO_ESP)) {
3587 skip = true;
3588 break;
3589 }
3590
3591 break;
3592
3593 default:
3594 DEBUG_WARN("IP version = %d, Protocol = %d: Corrupted packet entered ecm\n", ip_version, protocol);
3595 skip = true;
3596 break;
3597 }
3598
3599 if (skip) {
Murat Sezgin5dae8832015-12-03 14:23:19 -08003600 /*
3601 * This happens from the input hook
3602 * We do not want to create a connection entry for this
3603 * TODO YES WE DO.
3604 * TODO THIS CONCERNS ME AS THIS SHOULD BE CAUGHT MUCH
3605 * EARLIER IN THE FRONT END IF POSSIBLE TO AVOID PERFORMANCE PENALTIES.
3606 * WE HAVE DONE A TREMENDOUS AMOUT OF WORK TO GET TO THIS POINT.
3607 * WE WILL ABORT HERE AND THIS WILL BE REPEATED FOR EVERY PACKET.
3608 * IN KEEPING WITH THE ECM DESIGN IT IS BETTER TO CREATE A CONNECTION AND RECORD IN THE HIERARCHY
3609 * ENOUGH INFORMATION TO ENSURE THAT ACCELERATION IS NOT BROKEN / DOES NOT OCCUR AT ALL.
3610 * THAT WAY WE DO A HEAVYWEIGHT ESTABLISHING OF A CONNECTION ONCE AND NEVER AGAIN...
3611 */
3612 dev_put(src_dev);
3613 dev_put(dest_dev);
3614 return ECM_DB_IFACE_HEIRARCHY_MAX;
3615 }
Murat Sezgin70c44cd2016-03-02 11:32:10 -08003616 }
Murat Sezgin5dae8832015-12-03 14:23:19 -08003617
Murat Sezgin70c44cd2016-03-02 11:32:10 -08003618 bridge = ecm_interface_should_update_egress_device_bridged(
3619 given_dest_dev, dest_dev, is_routed);
Murat Sezgin5dae8832015-12-03 14:23:19 -08003620
Murat Sezgin70c44cd2016-03-02 11:32:10 -08003621 if (bridge) {
Murat Sezgin70c44cd2016-03-02 11:32:10 -08003622 struct net_device *new_dest_dev;
Murat Sezginb9bd5e02016-08-05 14:55:07 -07003623 new_dest_dev = br_port_dev_get(bridge, dest_node_addr, skb, serial);
3624 if (new_dest_dev) {
3625 dev_put(dest_dev);
3626 if (new_dest_dev != given_dest_dev) {
3627 DEBUG_INFO("Adjusted port for %pM is %s (given was %s)\n",
3628 dest_node_addr, new_dest_dev->name,
3629 given_dest_dev->name);
Murat Sezgin5dae8832015-12-03 14:23:19 -08003630
Murat Sezginb9bd5e02016-08-05 14:55:07 -07003631 dest_dev = new_dest_dev;
3632 dest_dev_name = dest_dev->name;
3633 dest_dev_type = dest_dev->type;
Murat Sezgin5dae8832015-12-03 14:23:19 -08003634 }
Murat Sezgin5dae8832015-12-03 14:23:19 -08003635 }
Murat Sezgin70c44cd2016-03-02 11:32:10 -08003636 dev_put(bridge);
Murat Sezgin5dae8832015-12-03 14:23:19 -08003637 }
3638
3639 next_dest_addr_valid = true;
3640 ECM_IP_ADDR_COPY(next_dest_addr, dest_addr);
3641
3642 /*
3643 * Iterate until we are done or get to the max number of interfaces we can record.
3644 * NOTE: current_interface_index tracks the position of the first interface position in interfaces[]
3645 * because we add from the end first_interface grows downwards.
3646 */
3647 current_interface_index = ECM_DB_IFACE_HEIRARCHY_MAX;
3648 while (current_interface_index > 0) {
3649 struct ecm_db_iface_instance *ii;
3650 struct net_device *next_dev;
3651 /*
3652 * Get the ecm db interface instance for the device at hand
3653 */
3654 ii = ecm_interface_establish_and_ref(feci, dest_dev, skb);
3655
3656 /*
3657 * If the interface could not be established then we abort
3658 */
3659 if (!ii) {
3660 DEBUG_WARN("Failed to establish interface: %p, name: %s\n", dest_dev, dest_dev_name);
3661 dev_put(src_dev);
3662 dev_put(dest_dev);
3663
3664 /*
3665 * Release the interfaces heirarchy we constructed to this point.
3666 */
3667 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
3668 return ECM_DB_IFACE_HEIRARCHY_MAX;
3669 }
3670
3671 /*
3672 * Record the interface instance into the interfaces[]
3673 */
3674 current_interface_index--;
3675 interfaces[current_interface_index] = ii;
3676
3677 /*
3678 * Now we have to figure out what the next device will be (in the transmission path) the skb
3679 * will use to emit to the destination address.
3680 */
3681 do {
3682#ifdef ECM_INTERFACE_PPP_ENABLE
3683 int channel_count;
3684 struct ppp_channel *ppp_chan[1];
3685 int channel_protocol;
3686#ifdef ECM_INTERFACE_PPPOE_ENABLE
3687 struct pppoe_opt addressing;
3688#endif
3689#endif
3690
3691 DEBUG_TRACE("Net device: %p is type: %d, name: %s\n", dest_dev, dest_dev_type, dest_dev_name);
3692 next_dev = NULL;
3693
3694 if (dest_dev_type == ARPHRD_ETHER) {
3695 /*
3696 * Ethernet - but what sub type?
3697 */
3698
3699#ifdef ECM_INTERFACE_VLAN_ENABLE
3700 /*
3701 * VLAN?
3702 */
3703 if (is_vlan_dev(dest_dev)) {
3704 /*
3705 * VLAN master
3706 * No locking needed here, ASSUMPTION is that real_dev is held for as long as we have dev.
3707 */
Shyam Sunder9db20852016-03-09 19:04:49 +05303708 next_dev = ecm_interface_vlan_real_dev(dest_dev);
Murat Sezgin5dae8832015-12-03 14:23:19 -08003709 dev_hold(next_dev);
3710 DEBUG_TRACE("Net device: %p is VLAN, slave dev: %p (%s)\n",
3711 dest_dev, next_dev, next_dev->name);
Shyam Sunder2e9528b2016-07-05 14:45:55 +05303712 if (current_interface_index == (ECM_DB_IFACE_HEIRARCHY_MAX - 1)) {
Suman Ghosh9bb0abb2018-03-19 01:08:54 +05303713 top_dev = dest_dev;
Shyam Sunder2e9528b2016-07-05 14:45:55 +05303714 }
Murat Sezgin5dae8832015-12-03 14:23:19 -08003715 break;
3716 }
3717#endif
3718
3719 /*
3720 * BRIDGE?
3721 */
3722 if (ecm_front_end_is_bridge_device(dest_dev)) {
3723 /*
3724 * Bridge
3725 * Figure out which port device the skb will go to using the dest_addr.
3726 */
3727 uint8_t mac_addr[ETH_ALEN];
3728
3729 if (next_dest_node_addr_valid) {
3730 memcpy(mac_addr, next_dest_node_addr, ETH_ALEN);
3731 } else if (!next_dest_addr_valid) {
3732 dev_put(src_dev);
3733 dev_put(dest_dev);
3734
3735 /*
3736 * Release the interfaces heirarchy we constructed to this point.
3737 */
3738 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
3739 return ECM_DB_IFACE_HEIRARCHY_MAX;
3740 } else {
3741 if (!ecm_interface_get_next_node_mac_address(dest_addr, dest_dev, ip_version, mac_addr)) {
3742 dev_put(src_dev);
3743 dev_put(dest_dev);
3744
3745 /*
3746 * Release the interfaces heirarchy we constructed to this point.
3747 */
3748 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
3749 return ECM_DB_IFACE_HEIRARCHY_MAX;
3750 }
3751 }
3752
Murat Sezgin545cf7d2016-03-04 09:48:21 -08003753 next_dev = br_port_dev_get(dest_dev,
3754 mac_addr, skb, serial);
Murat Sezgin5dae8832015-12-03 14:23:19 -08003755
3756 if (!next_dev) {
3757 DEBUG_WARN("Unable to obtain output port for: %pM\n", mac_addr);
3758 dev_put(src_dev);
3759 dev_put(dest_dev);
3760
3761 /*
3762 * Release the interfaces heirarchy we constructed to this point.
3763 */
3764 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
3765 return ECM_DB_IFACE_HEIRARCHY_MAX;
3766 }
3767 DEBUG_TRACE("Net device: %p is BRIDGE, next_dev: %p (%s)\n", dest_dev, next_dev, next_dev->name);
Suman Ghosh9bb0abb2018-03-19 01:08:54 +05303768 if (current_interface_index == (ECM_DB_IFACE_HEIRARCHY_MAX - 1)) {
3769 top_dev = dest_dev;
3770 }
Murat Sezgin5dae8832015-12-03 14:23:19 -08003771 break;
3772 }
3773
3774#ifdef ECM_INTERFACE_BOND_ENABLE
3775 /*
3776 * LAG?
3777 */
3778 if (ecm_front_end_is_lag_master(dest_dev)) {
3779 /*
3780 * Link aggregation
3781 * Figure out whiich slave device of the link aggregation will be used to reach the destination.
3782 */
3783 uint32_t src_addr_32 = 0;
3784 uint32_t dest_addr_32 = 0;
3785 struct in6_addr src_addr6;
3786 struct in6_addr dest_addr6;
3787 uint8_t src_mac_addr[ETH_ALEN];
3788 uint8_t dest_mac_addr[ETH_ALEN];
3789
3790 memset(src_mac_addr, 0, ETH_ALEN);
3791 memset(dest_mac_addr, 0, ETH_ALEN);
3792
3793 if (ip_version == 4) {
3794 ECM_IP_ADDR_TO_NIN4_ADDR(src_addr_32, src_addr);
Murat Sezginf92db492016-07-15 11:33:15 -07003795 ECM_IP_ADDR_TO_NIN4_ADDR(dest_addr_32, real_dest_addr);
Murat Sezgin5dae8832015-12-03 14:23:19 -08003796 }
3797
3798 if (!is_routed) {
3799 memcpy(src_mac_addr, src_node_addr, ETH_ALEN);
3800 memcpy(dest_mac_addr, dest_node_addr, ETH_ALEN);
3801 } else {
Murat Sezgin7be87d22016-01-29 17:41:37 -08003802 struct net_device *master_dev;
Murat Sezgin5dae8832015-12-03 14:23:19 -08003803
3804 /*
Murat Sezgin7be87d22016-01-29 17:41:37 -08003805 * Use appropriate source MAC address for routed packets and
3806 * find proper interface to find the destination mac address and
3807 * from which to issue ARP or neighbour solicitation packet.
Murat Sezgin5dae8832015-12-03 14:23:19 -08003808 */
Murat Sezgin7be87d22016-01-29 17:41:37 -08003809 master_dev = ecm_interface_get_and_hold_dev_master(dest_dev);
3810 if (master_dev) {
3811 memcpy(src_mac_addr, master_dev->dev_addr, ETH_ALEN);
Murat Sezgin5dae8832015-12-03 14:23:19 -08003812 } else {
Murat Sezgin7be87d22016-01-29 17:41:37 -08003813 master_dev = dest_dev;
Suman Ghosh9bb0abb2018-03-19 01:08:54 +05303814 if (top_dev) {
3815 master_dev = top_dev;
Shyam Sunder2e9528b2016-07-05 14:45:55 +05303816 }
Suman Ghosh9bb0abb2018-03-19 01:08:54 +05303817 memcpy(src_mac_addr, master_dev->dev_addr, ETH_ALEN);
Murat Sezgin7be87d22016-01-29 17:41:37 -08003818 dev_hold(master_dev);
Murat Sezgin5dae8832015-12-03 14:23:19 -08003819 }
3820
3821 /*
3822 * Determine destination MAC address for this routed packet
3823 */
3824 if (next_dest_node_addr_valid) {
3825 memcpy(dest_mac_addr, next_dest_node_addr, ETH_ALEN);
3826 } else if (!next_dest_addr_valid) {
3827 dev_put(src_dev);
3828 dev_put(dest_dev);
Murat Sezgin7be87d22016-01-29 17:41:37 -08003829 dev_put(master_dev);
Murat Sezgin5dae8832015-12-03 14:23:19 -08003830 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
3831 return ECM_DB_IFACE_HEIRARCHY_MAX;
3832 } else {
Murat Sezgin7be87d22016-01-29 17:41:37 -08003833 if (!ecm_interface_mac_addr_get_no_route(master_dev, dest_addr, dest_mac_addr)) {
Murat Sezgin5dae8832015-12-03 14:23:19 -08003834 ip_addr_t gw_addr = ECM_IP_ADDR_NULL;
3835 /*
3836 * Try one more time with gateway ip address if it exists.
3837 */
3838 if (!ecm_interface_find_gateway(dest_addr, gw_addr)) {
3839 goto lag_fail;
3840 }
3841
3842 if (ip_version == 4) {
3843 DEBUG_TRACE("Have a gw address " ECM_IP_ADDR_DOT_FMT "\n", ECM_IP_ADDR_TO_DOT(gw_addr));
3844 }
3845#ifdef ECM_IPV6_ENABLE
3846
3847 if (ip_version == 6) {
3848 DEBUG_TRACE("Have a gw address " ECM_IP_ADDR_OCTAL_FMT "\n", ECM_IP_ADDR_TO_OCTAL(gw_addr));
3849 }
3850#endif
Murat Sezgin7be87d22016-01-29 17:41:37 -08003851 if (ecm_interface_mac_addr_get_no_route(master_dev, gw_addr, dest_mac_addr)) {
Murat Sezgin5dae8832015-12-03 14:23:19 -08003852 DEBUG_TRACE("Found the mac address for gateway\n");
Murat Sezgin7be87d22016-01-29 17:41:37 -08003853 dev_put(master_dev);
Murat Sezgin5dae8832015-12-03 14:23:19 -08003854 goto lag_success;
3855 }
3856
3857 if (ip_version == 4) {
Murat Sezgin7be87d22016-01-29 17:41:37 -08003858 ecm_interface_send_arp_request(master_dev, dest_addr, false, gw_addr);
Murat Sezgin5dae8832015-12-03 14:23:19 -08003859
3860 DEBUG_WARN("Unable to obtain any MAC address for " ECM_IP_ADDR_DOT_FMT "\n", ECM_IP_ADDR_TO_DOT(dest_addr));
3861 }
3862#ifdef ECM_IPV6_ENABLE
3863 if (ip_version == 6) {
Murat Sezgin7be87d22016-01-29 17:41:37 -08003864 ecm_interface_send_neighbour_solicitation(master_dev, dest_addr);
Murat Sezgin5dae8832015-12-03 14:23:19 -08003865
3866 DEBUG_WARN("Unable to obtain any MAC address for " ECM_IP_ADDR_OCTAL_FMT "\n", ECM_IP_ADDR_TO_OCTAL(dest_addr));
3867 }
3868#endif
3869lag_fail:
3870 dev_put(src_dev);
3871 dev_put(dest_dev);
Murat Sezgin7be87d22016-01-29 17:41:37 -08003872 dev_put(master_dev);
Murat Sezgin5dae8832015-12-03 14:23:19 -08003873
3874 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
3875 return ECM_DB_IFACE_HEIRARCHY_MAX;
3876 }
3877 }
Suman Ghosh11c6f9e2018-03-01 20:40:39 +05303878 dev_put(master_dev);
Murat Sezgin5dae8832015-12-03 14:23:19 -08003879 }
3880lag_success:
3881 if (ip_version == 4) {
3882 next_dev = bond_get_tx_dev(NULL, src_mac_addr, dest_mac_addr,
3883 &src_addr_32, &dest_addr_32,
3884 htons((uint16_t)ETH_P_IP), dest_dev, layer4hdr);
3885 } else if (ip_version == 6) {
3886 ECM_IP_ADDR_TO_NIN6_ADDR(src_addr6, src_addr);
Murat Sezginf92db492016-07-15 11:33:15 -07003887 ECM_IP_ADDR_TO_NIN6_ADDR(dest_addr6, real_dest_addr);
Murat Sezgin5dae8832015-12-03 14:23:19 -08003888 next_dev = bond_get_tx_dev(NULL, src_mac_addr, dest_mac_addr,
3889 src_addr6.s6_addr, dest_addr6.s6_addr,
Shyam Sundere60540c2016-04-29 15:06:35 +05303890 htons((uint16_t)ETH_P_IPV6), dest_dev, layer4hdr);
Murat Sezgin5dae8832015-12-03 14:23:19 -08003891 }
3892
3893 if (next_dev && netif_carrier_ok(next_dev)) {
3894 dev_hold(next_dev);
3895 } else {
3896 DEBUG_WARN("Unable to obtain LAG output slave device\n");
3897 dev_put(src_dev);
3898 dev_put(dest_dev);
3899
3900 /*
3901 * Release the interfaces heirarchy we constructed to this point.
3902 */
3903 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
3904 return ECM_DB_IFACE_HEIRARCHY_MAX;
3905 }
3906
3907 DEBUG_TRACE("Net device: %p is LAG, slave dev: %p (%s)\n", dest_dev, next_dev, next_dev->name);
3908 break;
3909 }
3910#endif
3911
3912 /*
3913 * ETHERNET!
3914 * Just plain ethernet it seems.
3915 */
3916 DEBUG_TRACE("Net device: %p is ETHERNET\n", dest_dev);
3917 break;
3918 }
3919
3920 /*
3921 * LOOPBACK?
3922 */
3923 if (dest_dev_type == ARPHRD_LOOPBACK) {
3924 DEBUG_TRACE("Net device: %p is LOOPBACK type: %d\n", dest_dev, dest_dev_type);
3925 break;
3926 }
3927
3928 /*
3929 * IPSEC?
3930 */
3931 if (dest_dev_type == ECM_ARPHRD_IPSEC_TUNNEL_TYPE) {
3932 DEBUG_TRACE("Net device: %p is IPSec tunnel type: %d\n", dest_dev, dest_dev_type);
3933 /* TODO Figure out the next device the tunnel is using... */
3934 break;
3935 }
3936
3937 /*
3938 * SIT (6-in-4)?
3939 */
3940 if (dest_dev_type == ARPHRD_SIT) {
3941 DEBUG_TRACE("Net device: %p is SIT (6-in-4) type: %d\n", dest_dev, dest_dev_type);
3942 /* TODO Figure out the next device the tunnel is using... */
3943 break;
3944 }
3945
3946 /*
3947 * IPIP6 Tunnel?
3948 */
3949 if (dest_dev_type == ARPHRD_TUNNEL6) {
3950 DEBUG_TRACE("Net device: %p is TUNIPIP6 type: %d\n", dest_dev, dest_dev_type);
3951 /* TODO Figure out the next device the tunnel is using... */
3952 break;
3953 }
3954
ratheesh kannothcfdcb332015-12-24 07:19:18 +05303955#ifdef ECM_INTERFACE_MAP_T_ENABLE
3956 /*
3957 * MAP-T xlate ?
3958 */
3959 if (dest_dev_type == ARPHRD_NONE) {
3960 if (is_map_t_dev(dest_dev)) {
3961 DEBUG_TRACE("Net device: %p is MAP-T type: %d\n", dest_dev, dest_dev_type);
3962 break;
3963 }
3964 }
3965#endif
3966
Murat Sezgin5dae8832015-12-03 14:23:19 -08003967 /*
3968 * If this is NOT PPP then it is unknown to the ecm and we cannot figure out it's next device.
3969 */
3970 if (dest_dev_type != ARPHRD_PPP) {
3971 DEBUG_TRACE("Net device: %p is UNKNOWN type: %d\n", dest_dev, dest_dev_type);
3972 break;
3973 }
3974
3975#ifndef ECM_INTERFACE_PPP_ENABLE
3976 DEBUG_TRACE("Net device: %p is UNKNOWN (PPP Unsupported) type: %d\n", dest_dev, dest_dev_type);
3977#else
3978 DEBUG_TRACE("Net device: %p is PPP\n", dest_dev);
3979
3980#ifdef ECM_INTERFACE_L2TPV2_ENABLE
ratheesh kannothf4801a02016-12-09 22:46:39 +05303981 if ((given_src_dev->priv_flags & IFF_PPP_L2TPV2) && ppp_is_xmit_locked(given_src_dev)) {
Murat Sezgin5dae8832015-12-03 14:23:19 -08003982 if (skb->skb_iif == dest_dev->ifindex) {
3983 DEBUG_TRACE("Net device: %p PPP channel is PPPoL2TPV2\n", dest_dev);
3984 break;
3985 }
3986 }
3987#endif
3988
3989#ifdef ECM_INTERFACE_PPTP_ENABLE
3990 if (protocol == IPPROTO_GRE && dest_dev && dest_dev->type == ARPHRD_PPP) {
3991 DEBUG_TRACE("Net device: %p PPP channel is PPTP\n", dest_dev);
3992 break;
3993 }
3994#endif
3995 /*
3996 * PPP - but what is the channel type?
3997 * First: If this is multi-link then we do not support it
3998 */
3999 if (ppp_is_multilink(dest_dev) > 0) {
4000 DEBUG_TRACE("Net device: %p is MULTILINK PPP - Unknown to the ECM\n", dest_dev);
4001 break;
4002 }
4003
4004 /*
4005 * Get the PPP channel and then enquire what kind of channel it is
4006 * NOTE: Not multilink so only one channel to get.
4007 */
4008 channel_count = ppp_hold_channels(dest_dev, ppp_chan, 1);
4009 if (channel_count != 1) {
4010 DEBUG_TRACE("Net device: %p PPP has %d channels - Unknown to the ECM\n",
4011 dest_dev, channel_count);
4012 break;
4013 }
4014
4015 /*
4016 * Get channel protocol type
4017 * NOTE: Not all PPP channels support channel specific methods.
4018 */
4019 channel_protocol = ppp_channel_get_protocol(ppp_chan[0]);
4020
4021#ifdef ECM_INTERFACE_L2TPV2_ENABLE
4022 if (channel_protocol == PX_PROTO_OL2TP) {
4023
4024 /*
4025 * PPPoL2TPV2 channel
4026 */
4027 ppp_release_channels(ppp_chan, 1);
4028 DEBUG_TRACE("Net device: %p PPP channel is PPPoL2TPV2\n", dest_dev);
4029
4030 /*
4031 * Release the channel. Note that next_dev not held.
4032 */
4033 break;
4034 }
4035#endif
4036#ifdef ECM_INTERFACE_PPPOE_ENABLE
4037 if (channel_protocol == PX_PROTO_OE) {
4038 /*
4039 * PPPoE channel
4040 */
4041 DEBUG_TRACE("Net device: %p PPP channel is PPPoE\n", dest_dev);
4042
4043 /*
4044 * Get PPPoE session information and the underlying device it is using.
4045 */
4046 pppoe_channel_addressing_get(ppp_chan[0], &addressing);
4047
4048 /*
4049 * Copy the dev hold into this, we will release the hold later
4050 */
4051 next_dev = addressing.dev;
4052 next_dest_addr_valid = false;
4053 next_dest_node_addr_valid = true;
4054 memcpy(next_dest_node_addr, addressing.pa.remote, ETH_ALEN);
4055
4056 /*
4057 * Release the channel. Note that next_dev is still (correctly) held.
4058 */
4059 ppp_release_channels(ppp_chan, 1);
4060 break;
4061 }
4062#endif
4063
4064 DEBUG_TRACE("Net device: %p PPP channel protocol: %d - Unknown to the ECM\n",
4065 dest_dev, channel_protocol);
4066
4067 /*
4068 * Release the channel
4069 */
4070 ppp_release_channels(ppp_chan, 1);
4071
4072#endif
4073 } while (false);
4074
4075 /*
4076 * No longer need dest_dev as it may become next_dev
4077 */
4078 dev_put(dest_dev);
4079
4080 /*
4081 * Check out the next_dev, if any
4082 */
4083 if (!next_dev) {
4084 int32_t i __attribute__((unused));
4085 DEBUG_INFO("Completed interface heirarchy construct with first interface @: %d\n", current_interface_index);
4086#if DEBUG_LEVEL > 1
4087 for (i = current_interface_index; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
4088 DEBUG_TRACE("\tInterface @ %d: %p, type: %d, name: %s\n",
Murat Sezgin3d9a7642018-05-15 16:24:09 -07004089 i, interfaces[i], ecm_db_iface_type_get(interfaces[i]), ecm_db_interface_type_to_string(ecm_db_iface_type_get(interfaces[i])));
Murat Sezgin5dae8832015-12-03 14:23:19 -08004090
4091 }
4092#endif
4093
4094 /*
4095 * Release src_dev now
4096 */
4097 dev_put(src_dev);
4098 return current_interface_index;
4099 }
4100
4101 /*
4102 * dest_dev becomes next_dev
4103 */
4104 dest_dev = next_dev;
4105 dest_dev_name = dest_dev->name;
4106 dest_dev_type = dest_dev->type;
4107 }
4108
4109 DEBUG_WARN("Too many interfaces: %d\n", current_interface_index);
4110 DEBUG_ASSERT(current_interface_index == 0, "Bad logic handling current_interface_index: %d\n", current_interface_index);
4111 dev_put(src_dev);
4112 dev_put(dest_dev);
4113
4114 /*
4115 * Release the interfaces heirarchy we constructed to this point.
4116 */
4117 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
4118 return ECM_DB_IFACE_HEIRARCHY_MAX;
4119}
4120EXPORT_SYMBOL(ecm_interface_heirarchy_construct);
4121
4122#ifdef ECM_MULTICAST_ENABLE
4123/*
4124 * ecm_interface_multicast_from_heirarchy_construct()
4125 * Construct an interface heirarchy.
4126 *
4127 * TODO: This function will be removed later and ecm_interface_heirarchy_construct() function
4128 * will be used when the multicast code is fixed to use the new interface hierarchy
4129 * construction model which uses the skb's route information instead of doing
4130 * the route lookup based on the IP addresses.
4131 *
4132 * Using the given addressing, locate the interface heirarchy used to emit packets to that destination.
4133 * This is the heirarchy of interfaces a packet would transit to emit from the device.
4134 *
4135 * We will use the given src/dest devices when is_routed is false.
4136 * When is_routed is true we will try routing tables first, failing back to any given.
4137 *
4138 * For example, with this network arrangement:
4139 *
4140 * PPPoE--VLAN--BRIDGE--BRIDGE_PORT(LAG_MASTER)--LAG_SLAVE_0--10.22.33.11
4141 *
4142 * Given the packet_dest_addr IP address 10.22.33.11 this will create an interface heirarchy (in interracfes[]) of:
4143 * LAG_SLAVE_0 @ [ECM_DB_IFACE_HEIRARCHY_MAX - 5]
4144 * LAG_MASTER @ [ECM_DB_IFACE_HEIRARCHY_MAX - 4]
4145 * BRIDGE @ [ECM_DB_IFACE_HEIRARCHY_MAX - 3]
4146 * VLAN @ [ECM_DB_IFACE_HEIRARCHY_MAX - 2]
4147 * PPPOE @ [ECM_DB_IFACE_HEIRARCHY_MAX - 1]
4148 * The value returned is (ECM_DB_IFACE_HEIRARCHY_MAX - 5)
4149 *
4150 * IMPORTANT: This function will return any known interfaces in the database, when interfaces do not exist in the database
4151 * they will be created and added automatically to the database.
4152 */
4153int32_t ecm_interface_multicast_from_heirarchy_construct(struct ecm_front_end_connection_instance *feci,
4154 struct ecm_db_iface_instance *interfaces[],
Murat Sezgin188b4a32015-06-03 10:58:59 -07004155 ip_addr_t packet_src_addr,
4156 ip_addr_t packet_dest_addr,
4157 int ip_version, int packet_protocol,
4158 struct net_device *given_dest_dev,
4159 bool is_routed, struct net_device *given_src_dev,
Suman Ghoshfb8e7702015-08-20 15:27:57 +05304160 uint8_t *dest_node_addr, uint8_t *src_node_addr,
ratheesh kannotha32fdd12015-09-09 08:02:58 +05304161 __be16 *layer4hdr, struct sk_buff *skb)
Ben Menchaca84f36632014-02-28 20:57:38 +00004162{
Ben Menchaca84f36632014-02-28 20:57:38 +00004163 int protocol;
4164 ip_addr_t src_addr;
4165 ip_addr_t dest_addr;
Ben Menchaca84f36632014-02-28 20:57:38 +00004166 struct net_device *dest_dev;
Ben Menchaca84f36632014-02-28 20:57:38 +00004167 char *dest_dev_name;
Ben Menchaca84f36632014-02-28 20:57:38 +00004168 int32_t dest_dev_type;
Gareth Williams46f4b5f2014-06-01 23:35:23 +01004169 struct net_device *src_dev;
4170 char *src_dev_name;
4171 int32_t src_dev_type;
Ben Menchaca84f36632014-02-28 20:57:38 +00004172 int32_t current_interface_index;
Gareth Williams46f4b5f2014-06-01 23:35:23 +01004173 bool from_local_addr;
Murat Sezgin7ef29962015-08-14 10:53:24 -07004174 bool next_dest_addr_valid;
Murat Sezgin3aea6c92015-11-13 13:14:12 -08004175 bool next_dest_node_addr_valid = false;
Murat Sezgin7ef29962015-08-14 10:53:24 -07004176 ip_addr_t next_dest_addr;
4177 uint8_t next_dest_node_addr[ETH_ALEN] = {0};
Murat Sezgin70c44cd2016-03-02 11:32:10 -08004178 struct net_device *bridge;
Murat Sezgin545cf7d2016-03-04 09:48:21 -08004179 uint32_t serial = ecm_db_connection_serial_get(feci->ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00004180
4181 /*
4182 * Get a big endian of the IPv4 address we have been given as our starting point.
4183 */
4184 protocol = packet_protocol;
4185 ECM_IP_ADDR_COPY(src_addr, packet_src_addr);
4186 ECM_IP_ADDR_COPY(dest_addr, packet_dest_addr);
Murat Sezgin188b4a32015-06-03 10:58:59 -07004187
4188 if (ip_version == 4) {
Murat Sezgin545cf7d2016-03-04 09:48:21 -08004189 DEBUG_TRACE("Construct interface heirarchy for from src_addr: " ECM_IP_ADDR_DOT_FMT " to dest_addr: " ECM_IP_ADDR_DOT_FMT ", protocol: %d (serial %u)\n",
4190 ECM_IP_ADDR_TO_DOT(src_addr), ECM_IP_ADDR_TO_DOT(dest_addr), protocol,
4191 serial);
Murat Sezgin188b4a32015-06-03 10:58:59 -07004192#ifdef ECM_IPV6_ENABLE
4193 } else if (ip_version == 6) {
Murat Sezgin545cf7d2016-03-04 09:48:21 -08004194 DEBUG_TRACE("Construct interface heirarchy for from src_addr: " ECM_IP_ADDR_OCTAL_FMT " to dest_addr: " ECM_IP_ADDR_OCTAL_FMT ", protocol: %d (serial %u)\n",
4195 ECM_IP_ADDR_TO_OCTAL(src_addr), ECM_IP_ADDR_TO_OCTAL(dest_addr), protocol,
4196 serial);
Murat Sezgin188b4a32015-06-03 10:58:59 -07004197#endif
4198 } else {
4199 DEBUG_WARN("Wrong IP protocol: %d\n", ip_version);
4200 return ECM_DB_IFACE_HEIRARCHY_MAX;
4201 }
Ben Menchaca84f36632014-02-28 20:57:38 +00004202
4203 /*
Gareth Williams46f4b5f2014-06-01 23:35:23 +01004204 * Get device to reach the given destination address.
4205 * If the heirarchy is for a routed connection we must try route lookup first, falling back to any given_dest_dev.
4206 * If the heirarchy is NOT for a routed connection we try the given_dest_dev first, followed by routed lookup.
Ben Menchaca84f36632014-02-28 20:57:38 +00004207 */
Gareth Williams46f4b5f2014-06-01 23:35:23 +01004208 from_local_addr = false;
4209 if (is_routed) {
4210 dest_dev = ecm_interface_dev_find_by_addr(dest_addr, &from_local_addr);
4211 if (!dest_dev && given_dest_dev) {
4212 /*
4213 * Fall back to any given
4214 */
4215 dest_dev = given_dest_dev;
4216 dev_hold(dest_dev);
Gareth Williams43fc0852014-05-26 19:10:00 +01004217 }
Gareth Williams46f4b5f2014-06-01 23:35:23 +01004218 } else if (given_dest_dev) {
4219 dest_dev = given_dest_dev;
4220 dev_hold(dest_dev);
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05304221 } else {
4222 /*
Gareth Williams46f4b5f2014-06-01 23:35:23 +01004223 * Fall back to routed look up
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05304224 */
Gareth Williams46f4b5f2014-06-01 23:35:23 +01004225 dest_dev = ecm_interface_dev_find_by_addr(dest_addr, &from_local_addr);
Gareth Williams43fc0852014-05-26 19:10:00 +01004226 }
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05304227
Gareth Williams46f4b5f2014-06-01 23:35:23 +01004228 /*
4229 * GGG ALERT: If the address is a local address and protocol is an IP tunnel
4230 * then this connection is a tunnel endpoint made to this device.
4231 * In which case we circumvent all proper procedure and just hack the devices to make stuff work.
4232 * GGG TODO THIS MUST BE FIXED - WE MUST USE THE INTERFACE HIERARCHY FOR ITS INTENDED PURPOSE TO
4233 * PARSE THE DEVICES AND WORK OUT THE PROPER INTERFACES INVOLVED.
4234 * E.G. IF WE TRIED TO RUN A TUNNEL OVER A VLAN OR QINQ THIS WILL BREAK AS WE DON'T DISCOVER THAT HIERARCHY
4235 */
Murat Sezgin188b4a32015-06-03 10:58:59 -07004236 if (dest_dev && from_local_addr) {
4237 if (((ip_version == 4) && (protocol == IPPROTO_IPV6)) ||
4238 ((ip_version == 6) && (protocol == IPPROTO_IPIP))) {
4239 dev_put(dest_dev);
4240 dest_dev = given_dest_dev;
4241 if (dest_dev) {
4242 dev_hold(dest_dev);
Tushar Mathurbac03242015-09-15 18:41:59 +05304243 if (ip_version == 4) {
4244 DEBUG_TRACE("HACK: %s tunnel packet with dest_addr: " ECM_IP_ADDR_DOT_FMT " uses dev: %p(%s)\n", "IPV6", ECM_IP_ADDR_TO_DOT(dest_addr), dest_dev, dest_dev->name);
4245 } else {
4246 DEBUG_TRACE("HACK: %s tunnel packet with dest_addr: " ECM_IP_ADDR_OCTAL_FMT " uses dev: %p(%s)\n", "IPIP", ECM_IP_ADDR_TO_OCTAL(dest_addr), dest_dev, dest_dev->name);
4247 }
Murat Sezgin188b4a32015-06-03 10:58:59 -07004248 }
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05304249 }
Gareth Williams43fc0852014-05-26 19:10:00 +01004250 }
ratheesh kannotha32fdd12015-09-09 08:02:58 +05304251
4252#ifdef ECM_INTERFACE_L2TPV2_ENABLE
4253 /*
4254 * if the address is a local address and indev=l2tp.
4255 */
ratheesh kannothf4801a02016-12-09 22:46:39 +05304256 if ((given_src_dev->type == ARPHRD_PPP) && (given_src_dev->priv_flags & IFF_PPP_L2TPV2) && ppp_is_xmit_locked(given_src_dev)) {
ratheesh kannotha32fdd12015-09-09 08:02:58 +05304257 dev_put(dest_dev);
4258 dest_dev = given_dest_dev;
4259 if (dest_dev) {
4260 dev_hold(dest_dev);
4261 DEBUG_TRACE("l2tp packet tunnel packet with dest_addr: " ECM_IP_ADDR_OCTAL_FMT " uses dev: %p(%s)\n", ECM_IP_ADDR_TO_OCTAL(dest_addr), dest_dev, dest_dev->name);
4262 }
4263 }
4264#endif
4265
Shyam Sunder23f2e542015-09-28 14:56:49 +05304266#ifdef ECM_INTERFACE_PPTP_ENABLE
4267 /*
4268 * if the address is a local address and indev=PPTP.
4269 */
4270 if (protocol == IPPROTO_GRE && given_dest_dev && given_dest_dev->type == ARPHRD_PPP) {
4271 dev_put(dest_dev);
4272 dest_dev = given_dest_dev;
4273 if (dest_dev) {
4274 dev_hold(dest_dev);
4275 DEBUG_TRACE("PPTP packet tunnel packet with dest_addr: " ECM_IP_ADDR_OCTAL_FMT " uses dev: %p(%s)\n", ECM_IP_ADDR_TO_OCTAL(dest_addr), dest_dev, dest_dev->name);
4276 }
4277 }
4278#endif
4279
Gareth Williams46f4b5f2014-06-01 23:35:23 +01004280 if (!dest_dev) {
4281 DEBUG_WARN("dest_addr: " ECM_IP_ADDR_OCTAL_FMT " - cannot locate device\n", ECM_IP_ADDR_TO_OCTAL(dest_addr));
4282 return ECM_DB_IFACE_HEIRARCHY_MAX;
4283 }
Ben Menchaca84f36632014-02-28 20:57:38 +00004284 dest_dev_name = dest_dev->name;
4285 dest_dev_type = dest_dev->type;
4286
4287 /*
Gareth Williams46f4b5f2014-06-01 23:35:23 +01004288 * Get device to reach the given source address.
4289 * If the heirarchy is for a routed connection we must try route lookup first, falling back to any given_src_dev.
4290 * If the heirarchy is NOT for a routed connection we try the given_src_dev first, followed by routed lookup.
4291 */
4292 from_local_addr = false;
4293 if (is_routed) {
4294 src_dev = ecm_interface_dev_find_by_addr(src_addr, &from_local_addr);
4295 if (!src_dev && given_src_dev) {
4296 /*
4297 * Fall back to any given
4298 */
4299 src_dev = given_src_dev;
4300 dev_hold(src_dev);
4301 }
4302 } else if (given_src_dev) {
4303 src_dev = given_src_dev;
4304 dev_hold(src_dev);
4305 } else {
4306 /*
4307 * Fall back to routed look up
4308 */
4309 src_dev = ecm_interface_dev_find_by_addr(src_addr, &from_local_addr);
4310 }
4311
4312 /*
4313 * GGG ALERT: If the address is a local address and protocol is an IP tunnel
4314 * then this connection is a tunnel endpoint made to this device.
4315 * In which case we circumvent all proper procedure and just hack the devices to make stuff work.
4316 * GGG TODO THIS MUST BE FIXED - WE MUST USE THE INTERFACE HIERARCHY FOR ITS INTENDED PURPOSE TO
4317 * PARSE THE DEVICES AND WORK OUT THE PROPER INTERFACES INVOLVED.
4318 * E.G. IF WE TRIED TO RUN A TUNNEL OVER A VLAN OR QINQ THIS WILL BREAK AS WE DON'T DISCOVER THAT HIERARCHY
4319 */
Murat Sezgin188b4a32015-06-03 10:58:59 -07004320 if (src_dev && from_local_addr) {
4321 if (((ip_version == 4) && (protocol == IPPROTO_IPV6)) ||
4322 ((ip_version == 6) && (protocol == IPPROTO_IPIP))) {
4323 dev_put(src_dev);
4324 src_dev = given_src_dev;
4325 if (src_dev) {
4326 dev_hold(src_dev);
Tushar Mathurbac03242015-09-15 18:41:59 +05304327 if (ip_version == 4) {
4328 DEBUG_TRACE("HACK: %s tunnel packet with src_addr: " ECM_IP_ADDR_DOT_FMT " uses dev: %p(%s)\n", "IPV6", ECM_IP_ADDR_TO_DOT(src_addr), src_dev, src_dev->name);
4329 } else {
4330 DEBUG_TRACE("HACK: %s tunnel packet with src_addr: " ECM_IP_ADDR_OCTAL_FMT " uses dev: %p(%s)\n", "IPIP", ECM_IP_ADDR_TO_OCTAL(src_addr), src_dev, src_dev->name);
4331 }
Murat Sezgin188b4a32015-06-03 10:58:59 -07004332 }
Gareth Williams46f4b5f2014-06-01 23:35:23 +01004333 }
4334 }
Murat Sezgin188b4a32015-06-03 10:58:59 -07004335
ratheesh kannothed721852015-09-28 12:39:52 +05304336#ifdef ECM_INTERFACE_L2TPV2_ENABLE
4337 /*
4338 * if the address is a local address and indev=l2tp.
4339 */
4340 if (skb && skb->sk && (skb->sk->sk_protocol == IPPROTO_UDP) && (udp_sk(skb->sk)->encap_type == UDP_ENCAP_L2TPINUDP)) {
4341 if (dest_dev != given_src_dev) {
4342 dev_put(src_dev);
4343 src_dev = given_src_dev;
4344 if (src_dev) {
4345 dev_hold(src_dev);
4346 DEBUG_TRACE("l2tp tunnel packet with src_addr: " ECM_IP_ADDR_OCTAL_FMT " uses dev: %p(%s)\n", ECM_IP_ADDR_TO_OCTAL(src_addr), src_dev, src_dev->name);
4347 }
4348 }
4349 }
4350#endif
4351
Gareth Williams46f4b5f2014-06-01 23:35:23 +01004352 if (!src_dev) {
4353 DEBUG_WARN("src_addr: " ECM_IP_ADDR_OCTAL_FMT " - cannot locate device\n", ECM_IP_ADDR_TO_OCTAL(src_addr));
4354 dev_put(dest_dev);
4355 return ECM_DB_IFACE_HEIRARCHY_MAX;
4356 }
4357 src_dev_name = src_dev->name;
4358 src_dev_type = src_dev->type;
4359
4360 /*
4361 * Check if source and dest dev are same.
4362 * For the forwarded flows which involve tunnels this will happen when called from input hook.
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05304363 */
4364 if (src_dev == dest_dev) {
Gareth Williams46f4b5f2014-06-01 23:35:23 +01004365 DEBUG_TRACE("Protocol is :%d source dev and dest dev are same\n", protocol);
Murat Sezgin188b4a32015-06-03 10:58:59 -07004366 if (((ip_version == 4) && ((protocol == IPPROTO_IPV6) || (protocol == IPPROTO_ESP)))
4367 || ((ip_version == 6) && (protocol == IPPROTO_IPIP))) {
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05304368 /*
Gareth Williams46f4b5f2014-06-01 23:35:23 +01004369 * This happens from the input hook
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05304370 * We do not want to create a connection entry for this
Gareth Williams46f4b5f2014-06-01 23:35:23 +01004371 * GGG TODO YES WE DO.
4372 * GGG TODO THIS CONCERNS ME AS THIS SHOULD BE CAUGHT MUCH
4373 * EARLIER IN THE FRONT END IF POSSIBLE TO AVOID PERFORMANCE PENALTIES.
4374 * WE HAVE DONE A TREMENDOUS AMOUT OF WORK TO GET TO THIS POINT.
4375 * WE WILL ABORT HERE AND THIS WILL BE REPEATED FOR EVERY PACKET.
4376 * IN KEEPING WITH THE ECM DESIGN IT IS BETTER TO CREATE A CONNECTION AND RECORD IN THE HIERARCHY
4377 * ENOUGH INFORMATION TO ENSURE THAT ACCELERATION IS NOT BROKEN / DOES NOT OCCUR AT ALL.
4378 * THAT WAY WE DO A HEAVYWEIGHT ESTABLISHING OF A CONNECTION ONCE AND NEVER AGAIN...
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05304379 */
4380 dev_put(src_dev);
4381 dev_put(dest_dev);
4382 return ECM_DB_IFACE_HEIRARCHY_MAX;
4383 }
Murat Sezgin70c44cd2016-03-02 11:32:10 -08004384 }
Murat Sezgin3aea6c92015-11-13 13:14:12 -08004385
Murat Sezgin70c44cd2016-03-02 11:32:10 -08004386 bridge = ecm_interface_should_update_egress_device_bridged(
4387 given_dest_dev, dest_dev, is_routed);
Murat Sezgin3aea6c92015-11-13 13:14:12 -08004388
Murat Sezgin70c44cd2016-03-02 11:32:10 -08004389 if (bridge) {
Murat Sezgin70c44cd2016-03-02 11:32:10 -08004390 struct net_device *new_dest_dev;
Murat Sezginb9bd5e02016-08-05 14:55:07 -07004391 new_dest_dev = br_port_dev_get(bridge, dest_node_addr, skb, serial);
4392 if (new_dest_dev) {
4393 dev_put(dest_dev);
4394 if (new_dest_dev != given_dest_dev) {
4395 DEBUG_INFO("Adjusted port for %pM is %s (given was %s)\n",
4396 dest_node_addr, new_dest_dev->name,
4397 given_dest_dev->name);
Murat Sezgin3aea6c92015-11-13 13:14:12 -08004398
Murat Sezginb9bd5e02016-08-05 14:55:07 -07004399 dest_dev = new_dest_dev;
4400 dest_dev_name = dest_dev->name;
4401 dest_dev_type = dest_dev->type;
Murat Sezgin3aea6c92015-11-13 13:14:12 -08004402 }
Murat Sezgin3aea6c92015-11-13 13:14:12 -08004403 }
Murat Sezgin70c44cd2016-03-02 11:32:10 -08004404 dev_put(bridge);
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05304405 }
4406
Murat Sezgin7ef29962015-08-14 10:53:24 -07004407 next_dest_addr_valid = true;
Murat Sezgin5dae8832015-12-03 14:23:19 -08004408 next_dest_node_addr_valid = false;
Murat Sezgin7ef29962015-08-14 10:53:24 -07004409 ECM_IP_ADDR_COPY(next_dest_addr, dest_addr);
4410
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05304411 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00004412 * Iterate until we are done or get to the max number of interfaces we can record.
4413 * NOTE: current_interface_index tracks the position of the first interface position in interfaces[]
4414 * because we add from the end first_interface grows downwards.
4415 */
4416 current_interface_index = ECM_DB_IFACE_HEIRARCHY_MAX;
4417 while (current_interface_index > 0) {
4418 struct ecm_db_iface_instance *ii;
4419 struct net_device *next_dev;
Ben Menchaca84f36632014-02-28 20:57:38 +00004420 /*
4421 * Get the ecm db interface instance for the device at hand
4422 */
ratheesh kannotha32fdd12015-09-09 08:02:58 +05304423 ii = ecm_interface_establish_and_ref(feci, dest_dev, skb);
Ben Menchaca84f36632014-02-28 20:57:38 +00004424
4425 /*
4426 * If the interface could not be established then we abort
4427 */
4428 if (!ii) {
4429 DEBUG_WARN("Failed to establish interface: %p, name: %s\n", dest_dev, dest_dev_name);
4430 dev_put(src_dev);
4431 dev_put(dest_dev);
4432
4433 /*
4434 * Release the interfaces heirarchy we constructed to this point.
4435 */
4436 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
4437 return ECM_DB_IFACE_HEIRARCHY_MAX;
4438 }
4439
4440 /*
4441 * Record the interface instance into the interfaces[]
4442 */
4443 current_interface_index--;
4444 interfaces[current_interface_index] = ii;
4445
4446 /*
4447 * Now we have to figure out what the next device will be (in the transmission path) the skb
4448 * will use to emit to the destination address.
4449 */
4450 do {
Gareth Williamsdbb2bfd2014-11-20 16:42:09 -08004451#ifdef ECM_INTERFACE_PPP_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00004452 int channel_count;
4453 struct ppp_channel *ppp_chan[1];
Ben Menchaca84f36632014-02-28 20:57:38 +00004454 int channel_protocol;
ratheesh kannotha32fdd12015-09-09 08:02:58 +05304455#ifdef ECM_INTERFACE_PPPOE_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00004456 struct pppoe_opt addressing;
Gareth Williamsc5b9d712014-05-09 20:40:07 +01004457#endif
ratheesh kannotha32fdd12015-09-09 08:02:58 +05304458#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00004459
4460 DEBUG_TRACE("Net device: %p is type: %d, name: %s\n", dest_dev, dest_dev_type, dest_dev_name);
4461 next_dev = NULL;
4462
4463 if (dest_dev_type == ARPHRD_ETHER) {
4464 /*
4465 * Ethernet - but what sub type?
4466 */
4467
Gareth Williams141d2382014-11-25 11:35:19 -08004468#ifdef ECM_INTERFACE_VLAN_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00004469 /*
4470 * VLAN?
4471 */
4472 if (is_vlan_dev(dest_dev)) {
4473 /*
4474 * VLAN master
4475 * No locking needed here, ASSUMPTION is that real_dev is held for as long as we have dev.
4476 */
Shyam Sunder9db20852016-03-09 19:04:49 +05304477 next_dev = ecm_interface_vlan_real_dev(dest_dev);
Ben Menchaca84f36632014-02-28 20:57:38 +00004478 dev_hold(next_dev);
4479 DEBUG_TRACE("Net device: %p is VLAN, slave dev: %p (%s)\n",
4480 dest_dev, next_dev, next_dev->name);
4481 break;
4482 }
Gareth Williams141d2382014-11-25 11:35:19 -08004483#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00004484
4485 /*
4486 * BRIDGE?
4487 */
4488 if (ecm_front_end_is_bridge_device(dest_dev)) {
4489 /*
4490 * Bridge
4491 * Figure out which port device the skb will go to using the dest_addr.
4492 */
Ben Menchaca84f36632014-02-28 20:57:38 +00004493 uint8_t mac_addr[ETH_ALEN];
Murat Sezgin7ef29962015-08-14 10:53:24 -07004494
4495 if (next_dest_node_addr_valid) {
4496 memcpy(mac_addr, next_dest_node_addr, ETH_ALEN);
4497 } else if (!next_dest_addr_valid) {
Ben Menchaca84f36632014-02-28 20:57:38 +00004498 dev_put(src_dev);
4499 dev_put(dest_dev);
4500
4501 /*
4502 * Release the interfaces heirarchy we constructed to this point.
4503 */
4504 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
4505 return ECM_DB_IFACE_HEIRARCHY_MAX;
Murat Sezgin7ef29962015-08-14 10:53:24 -07004506 } else {
Murat Sezgin5dae8832015-12-03 14:23:19 -08004507 if (!ecm_interface_multicast_get_next_node_mac_address(next_dest_addr, dest_dev, ip_version, mac_addr)) {
Murat Sezgin7ef29962015-08-14 10:53:24 -07004508 dev_put(src_dev);
4509 dev_put(dest_dev);
4510
4511 /*
4512 * Release the interfaces heirarchy we constructed to this point.
4513 */
4514 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
4515 return ECM_DB_IFACE_HEIRARCHY_MAX;
4516 }
Ben Menchaca84f36632014-02-28 20:57:38 +00004517 }
Murat Sezgin545cf7d2016-03-04 09:48:21 -08004518 next_dev = br_port_dev_get(dest_dev,
4519 mac_addr, skb, serial);
Ben Menchaca84f36632014-02-28 20:57:38 +00004520 if (!next_dev) {
4521 DEBUG_WARN("Unable to obtain output port for: %pM\n", mac_addr);
4522 dev_put(src_dev);
4523 dev_put(dest_dev);
4524
4525 /*
4526 * Release the interfaces heirarchy we constructed to this point.
4527 */
4528 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
4529 return ECM_DB_IFACE_HEIRARCHY_MAX;
4530 }
4531 DEBUG_TRACE("Net device: %p is BRIDGE, next_dev: %p (%s)\n", dest_dev, next_dev, next_dev->name);
4532 break;
4533 }
Gareth Williams8ac34292015-03-17 14:06:58 +00004534
Murat Sezginb3731e82014-11-26 12:20:59 -08004535#ifdef ECM_INTERFACE_BOND_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00004536 /*
4537 * LAG?
4538 */
4539 if (ecm_front_end_is_lag_master(dest_dev)) {
4540 /*
4541 * Link aggregation
Murat Sezginb3731e82014-11-26 12:20:59 -08004542 * Figure out whiich slave device of the link aggregation will be used to reach the destination.
Ben Menchaca84f36632014-02-28 20:57:38 +00004543 */
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05304544 bool dest_on_link = false;
4545 ip_addr_t dest_gw_addr = ECM_IP_ADDR_NULL;
4546 uint32_t src_addr_32 = 0;
4547 uint32_t dest_addr_32 = 0;
Suman Ghoshf14d2172015-07-31 14:38:10 +05304548 struct in6_addr src_addr6;
4549 struct in6_addr dest_addr6;
Ben Menchaca84f36632014-02-28 20:57:38 +00004550 uint8_t src_mac_addr[ETH_ALEN];
4551 uint8_t dest_mac_addr[ETH_ALEN];
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05304552 struct net_device *master_dev = NULL;
Ben Menchaca84f36632014-02-28 20:57:38 +00004553
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05304554 memset(src_mac_addr, 0, ETH_ALEN);
4555 memset(dest_mac_addr, 0, ETH_ALEN);
Ben Menchaca84f36632014-02-28 20:57:38 +00004556
Gareth Williams341df382015-07-20 16:44:17 +01004557 if (ip_version == 4) {
4558 ECM_IP_ADDR_TO_NIN4_ADDR(src_addr_32, src_addr);
4559 ECM_IP_ADDR_TO_NIN4_ADDR(dest_addr_32, dest_addr);
4560 }
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05304561
4562 if (!is_routed) {
4563 memcpy(src_mac_addr, src_node_addr, ETH_ALEN);
4564 memcpy(dest_mac_addr, dest_node_addr, ETH_ALEN);
4565 } else {
Murat Sezginb3731e82014-11-26 12:20:59 -08004566 struct net_device *dest_dev_master;
4567
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05304568 /*
4569 * Use appropriate source MAC address for routed packets
4570 */
Murat Sezginb3731e82014-11-26 12:20:59 -08004571 dest_dev_master = ecm_interface_get_and_hold_dev_master(dest_dev);
4572 if (dest_dev_master) {
4573 memcpy(src_mac_addr, dest_dev_master->dev_addr, ETH_ALEN);
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05304574 } else {
4575 memcpy(src_mac_addr, dest_dev->dev_addr, ETH_ALEN);
4576 }
4577
4578 /*
4579 * Determine destination MAC address for this routed packet
4580 */
Tushar Mathur78b5f432015-09-18 20:13:31 +05304581 if (next_dest_node_addr_valid) {
4582 memcpy(dest_mac_addr, next_dest_node_addr, ETH_ALEN);
4583 } else if (!next_dest_addr_valid) {
4584 dev_put(src_dev);
4585 dev_put(dest_dev);
Murat Sezginb3731e82014-11-26 12:20:59 -08004586 if (dest_dev_master) {
4587 dev_put(dest_dev_master);
4588 }
4589
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05304590 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
4591 return ECM_DB_IFACE_HEIRARCHY_MAX;
Tushar Mathur78b5f432015-09-18 20:13:31 +05304592 } else {
4593 if (!ecm_interface_mac_addr_get(dest_addr, dest_mac_addr,
4594 &dest_on_link, dest_gw_addr)) {
4595
4596 /*
4597 * Find proper interfce from which to issue ARP
4598 * or neighbour solicitation packet.
4599 */
4600 if (dest_dev_master) {
4601 master_dev = dest_dev_master;
4602 } else {
4603 master_dev = dest_dev;
4604 }
4605
4606 dev_hold(master_dev);
4607
4608 if (dest_dev_master) {
4609 dev_put(dest_dev_master);
4610 }
4611
4612 if (ip_version == 4) {
4613 DEBUG_WARN("Unable to obtain MAC address for " ECM_IP_ADDR_DOT_FMT "\n", ECM_IP_ADDR_TO_DOT(dest_addr));
4614 ecm_interface_send_arp_request(dest_dev, dest_addr, dest_on_link, dest_gw_addr);
4615 }
4616#ifdef ECM_IPV6_ENABLE
4617 if (ip_version == 6) {
Murat Sezgin5dae8832015-12-03 14:23:19 -08004618 DEBUG_WARN("Unable to obtain MAC address for " ECM_IP_ADDR_OCTAL_FMT "\n", ECM_IP_ADDR_TO_OCTAL(dest_addr));
Tushar Mathur78b5f432015-09-18 20:13:31 +05304619 ecm_interface_send_neighbour_solicitation(master_dev, dest_addr);
4620 }
4621#endif
4622 dev_put(src_dev);
4623 dev_put(dest_dev);
4624 dev_put(master_dev);
4625 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
4626 return ECM_DB_IFACE_HEIRARCHY_MAX;
4627 }
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05304628 }
Murat Sezginb3731e82014-11-26 12:20:59 -08004629
4630 if (dest_dev_master) {
4631 dev_put(dest_dev_master);
4632 }
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05304633 }
4634
Murat Sezgin188b4a32015-06-03 10:58:59 -07004635 if (ip_version == 4) {
4636 next_dev = bond_get_tx_dev(NULL, src_mac_addr, dest_mac_addr,
4637 &src_addr_32, &dest_addr_32,
Suman Ghoshfb8e7702015-08-20 15:27:57 +05304638 htons((uint16_t)ETH_P_IP), dest_dev, layer4hdr);
Murat Sezgin188b4a32015-06-03 10:58:59 -07004639 } else if (ip_version == 6) {
Suman Ghoshf14d2172015-07-31 14:38:10 +05304640 ECM_IP_ADDR_TO_NIN6_ADDR(src_addr6, src_addr);
4641 ECM_IP_ADDR_TO_NIN6_ADDR(dest_addr6, dest_addr);
Murat Sezgin188b4a32015-06-03 10:58:59 -07004642 next_dev = bond_get_tx_dev(NULL, src_mac_addr, dest_mac_addr,
Suman Ghoshf14d2172015-07-31 14:38:10 +05304643 src_addr6.s6_addr, dest_addr6.s6_addr,
Shyam Sundere60540c2016-04-29 15:06:35 +05304644 htons((uint16_t)ETH_P_IPV6), dest_dev, layer4hdr);
Murat Sezgin188b4a32015-06-03 10:58:59 -07004645 }
4646
Tushar Mathur933907c2014-06-24 17:06:14 +05304647 if (next_dev && netif_carrier_ok(next_dev)) {
Ben Menchaca84f36632014-02-28 20:57:38 +00004648 dev_hold(next_dev);
4649 } else {
4650 DEBUG_WARN("Unable to obtain LAG output slave device\n");
4651 dev_put(src_dev);
4652 dev_put(dest_dev);
4653
4654 /*
4655 * Release the interfaces heirarchy we constructed to this point.
4656 */
4657 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
4658 return ECM_DB_IFACE_HEIRARCHY_MAX;
4659 }
4660
4661 DEBUG_TRACE("Net device: %p is LAG, slave dev: %p (%s)\n", dest_dev, next_dev, next_dev->name);
Ben Menchaca84f36632014-02-28 20:57:38 +00004662 break;
4663 }
Murat Sezginb3731e82014-11-26 12:20:59 -08004664#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00004665
4666 /*
4667 * ETHERNET!
4668 * Just plain ethernet it seems.
4669 */
4670 DEBUG_TRACE("Net device: %p is ETHERNET\n", dest_dev);
4671 break;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05304672 }
Ben Menchaca84f36632014-02-28 20:57:38 +00004673
4674 /*
4675 * LOOPBACK?
4676 */
4677 if (dest_dev_type == ARPHRD_LOOPBACK) {
4678 DEBUG_TRACE("Net device: %p is LOOPBACK type: %d\n", dest_dev, dest_dev_type);
4679 break;
4680 }
4681
4682 /*
4683 * IPSEC?
4684 */
4685 if (dest_dev_type == ECM_ARPHRD_IPSEC_TUNNEL_TYPE) {
4686 DEBUG_TRACE("Net device: %p is IPSec tunnel type: %d\n", dest_dev, dest_dev_type);
Murat Sezgin5dae8832015-12-03 14:23:19 -08004687 /* TODO Figure out the next device the tunnel is using... */
Ben Menchaca84f36632014-02-28 20:57:38 +00004688 break;
4689 }
4690
4691 /*
4692 * SIT (6-in-4)?
4693 */
4694 if (dest_dev_type == ARPHRD_SIT) {
4695 DEBUG_TRACE("Net device: %p is SIT (6-in-4) type: %d\n", dest_dev, dest_dev_type);
Murat Sezgin5dae8832015-12-03 14:23:19 -08004696 /* TODO Figure out the next device the tunnel is using... */
Ben Menchaca84f36632014-02-28 20:57:38 +00004697 break;
4698 }
4699
4700 /*
4701 * IPIP6 Tunnel?
4702 */
4703 if (dest_dev_type == ARPHRD_TUNNEL6) {
4704 DEBUG_TRACE("Net device: %p is TUNIPIP6 type: %d\n", dest_dev, dest_dev_type);
Murat Sezgin5dae8832015-12-03 14:23:19 -08004705 /* TODO Figure out the next device the tunnel is using... */
Ben Menchaca84f36632014-02-28 20:57:38 +00004706 break;
4707 }
4708
4709 /*
4710 * If this is NOT PPP then it is unknown to the ecm and we cannot figure out it's next device.
4711 */
4712 if (dest_dev_type != ARPHRD_PPP) {
4713 DEBUG_TRACE("Net device: %p is UNKNOWN type: %d\n", dest_dev, dest_dev_type);
4714 break;
4715 }
4716
Gareth Williamsdbb2bfd2014-11-20 16:42:09 -08004717#ifndef ECM_INTERFACE_PPP_ENABLE
Gareth Williamsc5b9d712014-05-09 20:40:07 +01004718 DEBUG_TRACE("Net device: %p is UNKNOWN (PPP Unsupported) type: %d\n", dest_dev, dest_dev_type);
4719#else
ratheesh kannotha32fdd12015-09-09 08:02:58 +05304720 DEBUG_TRACE("Net device: %p is PPP\n", dest_dev);
4721
4722#ifdef ECM_INTERFACE_L2TPV2_ENABLE
ratheesh kannothf4801a02016-12-09 22:46:39 +05304723 if ((given_src_dev->priv_flags & IFF_PPP_L2TPV2) && ppp_is_xmit_locked(given_src_dev)) {
ratheesh kannothed721852015-09-28 12:39:52 +05304724 if (skb->skb_iif == dest_dev->ifindex) {
4725 DEBUG_TRACE("Net device: %p PPP channel is PPPoL2TPV2\n", dest_dev);
4726 break;
4727 }
ratheesh kannotha32fdd12015-09-09 08:02:58 +05304728 }
4729#endif
Shyam Sunder23f2e542015-09-28 14:56:49 +05304730
4731#ifdef ECM_INTERFACE_PPTP_ENABLE
4732 if (protocol == IPPROTO_GRE && dest_dev && dest_dev->type == ARPHRD_PPP) {
4733 DEBUG_TRACE("Net device: %p PPP channel is PPTP\n", dest_dev);
4734 break;
4735 }
4736#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00004737 /*
4738 * PPP - but what is the channel type?
4739 * First: If this is multi-link then we do not support it
4740 */
4741 if (ppp_is_multilink(dest_dev) > 0) {
4742 DEBUG_TRACE("Net device: %p is MULTILINK PPP - Unknown to the ECM\n", dest_dev);
4743 break;
4744 }
4745
Ben Menchaca84f36632014-02-28 20:57:38 +00004746 /*
4747 * Get the PPP channel and then enquire what kind of channel it is
4748 * NOTE: Not multilink so only one channel to get.
4749 */
4750 channel_count = ppp_hold_channels(dest_dev, ppp_chan, 1);
4751 if (channel_count != 1) {
4752 DEBUG_TRACE("Net device: %p PPP has %d channels - Unknown to the ECM\n",
4753 dest_dev, channel_count);
4754 break;
4755 }
4756
4757 /*
4758 * Get channel protocol type
Gareth Williams6f96a4b2014-05-29 19:41:21 +01004759 * NOTE: Not all PPP channels support channel specific methods.
Ben Menchaca84f36632014-02-28 20:57:38 +00004760 */
Gareth Williams6f96a4b2014-05-29 19:41:21 +01004761 channel_protocol = ppp_channel_get_protocol(ppp_chan[0]);
ratheesh kannotha32fdd12015-09-09 08:02:58 +05304762
4763#ifdef ECM_INTERFACE_L2TPV2_ENABLE
4764 if (channel_protocol == PX_PROTO_OL2TP) {
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05304765
Ben Menchaca84f36632014-02-28 20:57:38 +00004766 /*
ratheesh kannotha32fdd12015-09-09 08:02:58 +05304767 * PPPoL2TPV2 channel
Ben Menchaca84f36632014-02-28 20:57:38 +00004768 */
4769 ppp_release_channels(ppp_chan, 1);
ratheesh kannotha32fdd12015-09-09 08:02:58 +05304770 DEBUG_TRACE("Net device: %p PPP channel is PPPoL2TPV2\n", dest_dev);
Ben Menchaca84f36632014-02-28 20:57:38 +00004771
ratheesh kannotha32fdd12015-09-09 08:02:58 +05304772 /*
4773 * Release the channel. Note that next_dev not held.
4774 */
Ben Menchaca84f36632014-02-28 20:57:38 +00004775 break;
4776 }
ratheesh kannotha32fdd12015-09-09 08:02:58 +05304777#endif
4778#ifdef ECM_INTERFACE_PPPOE_ENABLE
4779 if (channel_protocol == PX_PROTO_OE) {
4780 /*
4781 * PPPoE channel
4782 */
4783 DEBUG_TRACE("Net device: %p PPP channel is PPPoE\n", dest_dev);
4784
4785 /*
4786 * Get PPPoE session information and the underlying device it is using.
4787 */
4788 pppoe_channel_addressing_get(ppp_chan[0], &addressing);
4789
4790 /*
4791 * Copy the dev hold into this, we will release the hold later
4792 */
4793 next_dev = addressing.dev;
4794 next_dest_addr_valid = false;
4795 next_dest_node_addr_valid = true;
4796 memcpy(next_dest_node_addr, addressing.pa.remote, ETH_ALEN);
4797
4798 /*
4799 * Release the channel. Note that next_dev is still (correctly) held.
4800 */
4801 ppp_release_channels(ppp_chan, 1);
4802 break;
4803 }
4804#endif
4805
4806 DEBUG_TRACE("Net device: %p PPP channel protocol: %d - Unknown to the ECM\n",
4807 dest_dev, channel_protocol);
Ben Menchaca84f36632014-02-28 20:57:38 +00004808
4809 /*
ratheesh kannotha32fdd12015-09-09 08:02:58 +05304810 * Release the channel
Ben Menchaca84f36632014-02-28 20:57:38 +00004811 */
4812 ppp_release_channels(ppp_chan, 1);
ratheesh kannotha32fdd12015-09-09 08:02:58 +05304813
Gareth Williamsc5b9d712014-05-09 20:40:07 +01004814#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00004815 } while (false);
4816
4817 /*
Gareth Williamsa11d4352014-05-14 18:25:49 +01004818 * No longer need dest_dev as it may become next_dev
Ben Menchaca84f36632014-02-28 20:57:38 +00004819 */
Ben Menchaca84f36632014-02-28 20:57:38 +00004820 dev_put(dest_dev);
4821
4822 /*
4823 * Check out the next_dev, if any
4824 */
4825 if (!next_dev) {
4826 int32_t i __attribute__((unused));
4827 DEBUG_INFO("Completed interface heirarchy construct with first interface @: %d\n", current_interface_index);
4828#if DEBUG_LEVEL > 1
4829 for (i = current_interface_index; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
4830 DEBUG_TRACE("\tInterface @ %d: %p, type: %d, name: %s\n",
Murat Sezgin3d9a7642018-05-15 16:24:09 -07004831 i, interfaces[i], ecm_db_iface_type_get(interfaces[i]), ecm_db_interface_type_to_string(ecm_db_iface_type_get(interfaces[i])));
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05304832
Ben Menchaca84f36632014-02-28 20:57:38 +00004833 }
4834#endif
Gareth Williamsa11d4352014-05-14 18:25:49 +01004835
4836 /*
4837 * Release src_dev now
4838 */
4839 dev_put(src_dev);
Ben Menchaca84f36632014-02-28 20:57:38 +00004840 return current_interface_index;
4841 }
4842
Gareth Williamsa11d4352014-05-14 18:25:49 +01004843 /*
4844 * dest_dev becomes next_dev
4845 */
Ben Menchaca84f36632014-02-28 20:57:38 +00004846 dest_dev = next_dev;
4847 dest_dev_name = dest_dev->name;
4848 dest_dev_type = dest_dev->type;
4849 }
4850
4851 DEBUG_WARN("Too many interfaces: %d\n", current_interface_index);
4852 DEBUG_ASSERT(current_interface_index == 0, "Bad logic handling current_interface_index: %d\n", current_interface_index);
4853 dev_put(src_dev);
4854 dev_put(dest_dev);
4855
4856 /*
4857 * Release the interfaces heirarchy we constructed to this point.
4858 */
4859 ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
4860 return ECM_DB_IFACE_HEIRARCHY_MAX;
4861}
Murat Sezgin5dae8832015-12-03 14:23:19 -08004862EXPORT_SYMBOL(ecm_interface_multicast_from_heirarchy_construct);
4863#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00004864
4865/*
Gareth Williamsadf425f2014-05-26 19:29:02 +01004866 * ecm_interface_list_stats_update()
4867 * Given an interface list, walk the interfaces and update the stats for certain types.
4868 */
4869static void ecm_interface_list_stats_update(int iface_list_first, struct ecm_db_iface_instance *iface_list[], uint8_t *mac_addr,
Suman Ghosh812ad302018-05-09 21:07:50 +05304870 bool is_mcast_flow, uint32_t tx_packets, uint32_t tx_bytes, uint32_t rx_packets, uint32_t rx_bytes,
4871 bool is_ported)
Gareth Williamsadf425f2014-05-26 19:29:02 +01004872{
4873 int list_index;
4874
4875 for (list_index = iface_list_first; (list_index < ECM_DB_IFACE_HEIRARCHY_MAX); list_index++) {
4876 struct ecm_db_iface_instance *ii;
4877 ecm_db_iface_type_t ii_type;
4878 char *ii_name;
4879 struct net_device *dev;
4880
4881 ii = iface_list[list_index];
Murat Sezgin3d9a7642018-05-15 16:24:09 -07004882 ii_type = ecm_db_iface_type_get(ii);
Gareth Williamsadf425f2014-05-26 19:29:02 +01004883 ii_name = ecm_db_interface_type_to_string(ii_type);
4884 DEBUG_TRACE("list_index: %d, ii: %p, type: %d (%s)\n", list_index, ii, ii_type, ii_name);
4885
4886 /*
4887 * Locate real device in system
4888 */
4889 dev = dev_get_by_index(&init_net, ecm_db_iface_interface_identifier_get(ii));
4890 if (!dev) {
4891 DEBUG_WARN("Could not locate interface\n");
4892 continue;
4893 }
4894 DEBUG_TRACE("found dev: %p (%s)\n", dev, dev->name);
4895
Shyam Sunderbf40d0e2015-06-23 15:56:37 +05304896 if (likely(!is_mcast_flow)) {
4897 /*
4898 * Refresh the bridge forward table entry if the port is a bridge port
4899 * Note: A bridge port can be of different interface type, e.g VLAN, ethernet.
4900 * This check, therefore, should be performed for all interface types.
4901 */
Suman Ghosh812ad302018-05-09 21:07:50 +05304902 if (is_ported && is_valid_ether_addr(mac_addr) && ecm_front_end_is_bridge_port(dev) && rx_packets) {
Shyam Sunderbf40d0e2015-06-23 15:56:37 +05304903 DEBUG_TRACE("Update bridge fdb entry for mac: %pM\n", mac_addr);
4904 br_refresh_fdb_entry(dev, mac_addr);
4905 }
Selin Dag1af781a2014-06-10 10:37:54 -07004906 }
4907
Gareth Williamsadf425f2014-05-26 19:29:02 +01004908 switch (ii_type) {
4909 struct rtnl_link_stats64 stats;
4910
Gareth Williams141d2382014-11-25 11:35:19 -08004911#ifdef ECM_INTERFACE_VLAN_ENABLE
Gareth Williamsadf425f2014-05-26 19:29:02 +01004912 case ECM_DB_IFACE_TYPE_VLAN:
Radha krishna Simha Jigurue9d46fd2014-06-03 22:17:19 +05304913 DEBUG_INFO("VLAN\n");
Gareth Williamsadf425f2014-05-26 19:29:02 +01004914 stats.rx_packets = rx_packets;
4915 stats.rx_bytes = rx_bytes;
4916 stats.tx_packets = tx_packets;
4917 stats.tx_bytes = tx_bytes;
4918 __vlan_dev_update_accel_stats(dev, &stats);
4919 break;
Gareth Williams141d2382014-11-25 11:35:19 -08004920#endif
Gareth Williamsadf425f2014-05-26 19:29:02 +01004921 case ECM_DB_IFACE_TYPE_BRIDGE:
4922 DEBUG_INFO("BRIDGE\n");
4923 stats.rx_packets = rx_packets;
4924 stats.rx_bytes = rx_bytes;
4925 stats.tx_packets = tx_packets;
4926 stats.tx_bytes = tx_bytes;
4927 br_dev_update_stats(dev, &stats);
Gareth Williamsadf425f2014-05-26 19:29:02 +01004928 break;
Murat Sezgina683edd2015-01-20 10:48:30 -08004929
ratheesh kannotha32fdd12015-09-09 08:02:58 +05304930#ifdef ECM_INTERFACE_PPPOE_ENABLE
Murat Sezgina683edd2015-01-20 10:48:30 -08004931 case ECM_DB_IFACE_TYPE_PPPOE:
4932 DEBUG_INFO("PPPOE\n");
ratheesh kannothb1b753a2015-09-28 11:17:35 +05304933 ppp_update_stats(dev, rx_packets, rx_bytes, tx_packets, tx_bytes, 0, 0, 0, 0);
Murat Sezgina683edd2015-01-20 10:48:30 -08004934 break;
4935#endif
Gareth Williamsadf425f2014-05-26 19:29:02 +01004936 default:
4937 /*
4938 * TODO: Extend it accordingly
4939 */
4940 break;
4941 }
4942
4943 dev_put(dev);
4944 }
4945}
4946
4947/*
4948 * ecm_interface_stats_update()
4949 * Using the interface lists for the given connection, update the interface statistics for each.
4950 *
4951 * 'from' here is wrt the connection 'from' side. Likewise with 'to'.
4952 * TX is wrt what the interface has transmitted. RX is what the interface has received.
4953 */
4954void ecm_interface_stats_update(struct ecm_db_connection_instance *ci,
4955 uint32_t from_tx_packets, uint32_t from_tx_bytes, uint32_t from_rx_packets, uint32_t from_rx_bytes,
4956 uint32_t to_tx_packets, uint32_t to_tx_bytes, uint32_t to_rx_packets, uint32_t to_rx_bytes)
4957{
4958 struct ecm_db_iface_instance *from_ifaces[ECM_DB_IFACE_HEIRARCHY_MAX];
4959 struct ecm_db_iface_instance *to_ifaces[ECM_DB_IFACE_HEIRARCHY_MAX];
4960 int from_ifaces_first;
4961 int to_ifaces_first;
4962 uint8_t mac_addr[ETH_ALEN];
Suman Ghosh812ad302018-05-09 21:07:50 +05304963 bool is_ported = false;
4964 uint8_t protocol = ecm_db_connection_protocol_get(ci);
4965
4966 /*
4967 * Set is_ported flag based on protocol
4968 */
4969 if ((protocol == IPPROTO_UDP) || (protocol == IPPROTO_TCP)) {
4970 is_ported = true;
4971 }
Gareth Williamsadf425f2014-05-26 19:29:02 +01004972
4973 /*
4974 * Iterate the 'from' side interfaces and update statistics and state for the real HLOS interfaces
4975 * from_tx_packets / bytes: the amount transmitted by the 'from' interface
4976 * from_rx_packets / bytes: the amount received by the 'from' interface
4977 */
4978 DEBUG_INFO("%p: Update from interface stats\n", ci);
Murat Sezgin3d9a7642018-05-15 16:24:09 -07004979 from_ifaces_first = ecm_db_connection_interfaces_get_and_ref(ci, from_ifaces, ECM_DB_OBJ_DIR_FROM);
4980 ecm_db_connection_node_address_get(ci, ECM_DB_OBJ_DIR_FROM, mac_addr);
Suman Ghosh812ad302018-05-09 21:07:50 +05304981 ecm_interface_list_stats_update(from_ifaces_first, from_ifaces, mac_addr, false, from_tx_packets, from_tx_bytes, from_rx_packets, from_rx_bytes, is_ported);
Gareth Williamsadf425f2014-05-26 19:29:02 +01004982 ecm_db_connection_interfaces_deref(from_ifaces, from_ifaces_first);
4983
4984 /*
4985 * Iterate the 'to' side interfaces and update statistics and state for the real HLOS interfaces
4986 * to_tx_packets / bytes: the amount transmitted by the 'to' interface
4987 * to_rx_packets / bytes: the amount received by the 'to' interface
4988 */
4989 DEBUG_INFO("%p: Update to interface stats\n", ci);
Murat Sezgin3d9a7642018-05-15 16:24:09 -07004990 to_ifaces_first = ecm_db_connection_interfaces_get_and_ref(ci, to_ifaces, ECM_DB_OBJ_DIR_TO);
4991 ecm_db_connection_node_address_get(ci, ECM_DB_OBJ_DIR_TO, mac_addr);
Suman Ghosh812ad302018-05-09 21:07:50 +05304992 ecm_interface_list_stats_update(to_ifaces_first, to_ifaces, mac_addr, false, to_tx_packets, to_tx_bytes, to_rx_packets, to_rx_bytes, is_ported);
Gareth Williamsadf425f2014-05-26 19:29:02 +01004993 ecm_db_connection_interfaces_deref(to_ifaces, to_ifaces_first);
4994}
4995EXPORT_SYMBOL(ecm_interface_stats_update);
4996
Shyam Sunder6358b862015-05-04 15:06:24 +05304997#ifdef ECM_MULTICAST_ENABLE
4998/*
Shyam Sunder6358b862015-05-04 15:06:24 +05304999 * ecm_interface_multicast_stats_update()
5000 * Using the interface lists for the given connection, update the interface statistics for each.
5001 *
5002 * 'from interface' here is the connection 'from' side. Likewise with 'to interface'.
5003 * TX is wrt what the interface has transmitted. RX is what the interface has received.
5004 */
5005void ecm_interface_multicast_stats_update(struct ecm_db_connection_instance *ci, uint32_t from_tx_packets, uint32_t from_tx_bytes,
5006 uint32_t from_rx_packets, uint32_t from_rx_bytes, uint32_t to_tx_packets, uint32_t to_tx_bytes,
5007 uint32_t to_rx_packets, uint32_t to_rx_bytes)
5008{
5009 struct ecm_db_iface_instance *from_ifaces[ECM_DB_IFACE_HEIRARCHY_MAX];
Shyam Sunderbf40d0e2015-06-23 15:56:37 +05305010 struct ecm_db_iface_instance *to_list_single[ECM_DB_IFACE_HEIRARCHY_MAX];
Shyam Sunder6358b862015-05-04 15:06:24 +05305011 struct ecm_db_iface_instance *to_ifaces;
5012 struct ecm_db_iface_instance *ii_temp;
5013 int from_ifaces_first;
5014 int *to_ifaces_first;
5015 int if_index;
5016 int ret;
5017 uint8_t mac_addr[ETH_ALEN];
Suman Ghosh812ad302018-05-09 21:07:50 +05305018 bool is_ported = false;
5019 uint8_t protocol = ecm_db_connection_protocol_get(ci);
5020
5021 /*
5022 * Set is_ported flag based on protocol
5023 */
5024 if (protocol == IPPROTO_UDP) {
5025 is_ported = true;
5026 }
Shyam Sunder6358b862015-05-04 15:06:24 +05305027
5028 /*
5029 * Iterate the 'from' side interfaces and update statistics and state for the real HLOS interfaces
5030 * from_tx_packets / bytes: the amount transmitted by the 'from' interface
5031 * from_rx_packets / bytes: the amount received by the 'from' interface
5032 */
5033 DEBUG_INFO("%p: Update from interface stats\n", ci);
Murat Sezgin3d9a7642018-05-15 16:24:09 -07005034 from_ifaces_first = ecm_db_connection_interfaces_get_and_ref(ci, from_ifaces, ECM_DB_OBJ_DIR_FROM);
5035 ecm_db_connection_node_address_get(ci, ECM_DB_OBJ_DIR_FROM, mac_addr);
Suman Ghosh812ad302018-05-09 21:07:50 +05305036 ecm_interface_list_stats_update(from_ifaces_first, from_ifaces, mac_addr, false, from_tx_packets, from_tx_bytes, from_rx_packets, from_rx_bytes, is_ported);
Shyam Sunder6358b862015-05-04 15:06:24 +05305037 ecm_db_connection_interfaces_deref(from_ifaces, from_ifaces_first);
5038
5039 /*
5040 * Iterate the 'to' side interfaces and update statistics and state for the real HLOS interfaces
5041 * to_tx_packets / bytes: the amount transmitted by the 'to' interface
5042 * to_rx_packets / bytes: the amount received by the 'to' interface
5043 */
5044 DEBUG_INFO("%p: Update to interface stats\n", ci);
5045
5046 /*
5047 * This function allocates the memory for temporary destination interface heirarchies.
5048 * This memory needs to be free at the end.
5049 */
5050 ret = ecm_db_multicast_connection_to_interfaces_get_and_ref_all(ci, &to_ifaces, &to_ifaces_first);
5051 if (ret == 0) {
5052 DEBUG_WARN("%p: Get and ref to all multicast detination interface heirarchies failed\n", ci);
5053 return;
5054 }
5055
5056 for (if_index = 0; if_index < ECM_DB_MULTICAST_IF_MAX; if_index++) {
5057 if (to_ifaces_first[if_index] < ECM_DB_IFACE_HEIRARCHY_MAX) {
5058 ii_temp = ecm_db_multicast_if_heirarchy_get(to_ifaces, if_index);
Shyam Sunderbf40d0e2015-06-23 15:56:37 +05305059 ecm_db_multicast_copy_if_heirarchy(to_list_single, ii_temp);
Suman Ghosh812ad302018-05-09 21:07:50 +05305060 ecm_interface_list_stats_update(to_ifaces_first[if_index], to_list_single, mac_addr, true, to_tx_packets, to_tx_bytes, to_rx_packets, to_rx_bytes, is_ported);
Shyam Sunder6358b862015-05-04 15:06:24 +05305061 }
5062 }
5063
5064 ecm_db_multicast_connection_to_interfaces_deref_all(to_ifaces, to_ifaces_first);
5065}
5066EXPORT_SYMBOL(ecm_interface_multicast_stats_update);
5067#endif
5068
Gareth Williamsadf425f2014-05-26 19:29:02 +01005069/*
Ben Menchaca84f36632014-02-28 20:57:38 +00005070 * ecm_interface_regenerate_connections()
5071 * Cause regeneration of all connections that are using the specified interface.
5072 */
5073static void ecm_interface_regenerate_connections(struct ecm_db_iface_instance *ii)
5074{
Gareth Williamsb5903892015-03-20 15:13:07 +00005075#ifdef ECM_DB_XREF_ENABLE
Murat Sezgin3d9a7642018-05-15 16:24:09 -07005076 int dir;
5077 struct ecm_db_connection_instance *ci[ECM_DB_OBJ_DIR_MAX];
Gareth Williamsa4390962015-08-26 12:51:31 +01005078 struct ecm_db_connection_instance *ci_mcast __attribute__ ((unused));
Gareth Williamsb5903892015-03-20 15:13:07 +00005079#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00005080
5081 DEBUG_TRACE("Regenerate connections using interface: %p\n", ii);
5082
Gareth Williamsb5903892015-03-20 15:13:07 +00005083#ifndef ECM_DB_XREF_ENABLE
5084 /*
5085 * An interface has changed, re-generate the connections to ensure all state is updated.
5086 */
Tushar Mathurd38cacd2015-07-28 12:19:10 +05305087 ecm_db_regeneration_needed();
Gareth Williamsb5903892015-03-20 15:13:07 +00005088#else
Murat Sezgin3d9a7642018-05-15 16:24:09 -07005089 for (dir = 0; dir < ECM_DB_OBJ_DIR_MAX; dir++) {
5090 ci[dir] = ecm_db_iface_connections_get_and_ref_first(ii, dir);
5091 }
5092
Ben Menchaca84f36632014-02-28 20:57:38 +00005093 /*
Gareth Williamsa4390962015-08-26 12:51:31 +01005094 * If the interface has NO connections then we re-generate all.
5095 */
Murat Sezgin3d9a7642018-05-15 16:24:09 -07005096 if (!ci[ECM_DB_OBJ_DIR_FROM] && !ci[ECM_DB_OBJ_DIR_TO] && !ci[ECM_DB_OBJ_DIR_FROM_NAT] && !ci[ECM_DB_OBJ_DIR_TO_NAT]) {
Gareth Williamsa4390962015-08-26 12:51:31 +01005097 ecm_db_regeneration_needed();
5098 DEBUG_TRACE("%p: Regenerate (ALL) COMPLETE\n", ii);
5099 return;
5100 }
5101
Murat Sezgin3d9a7642018-05-15 16:24:09 -07005102 for (dir = 0; dir < ECM_DB_OBJ_DIR_MAX; dir++) {
5103 /*
5104 * Re-generate all connections associated with this interface
5105 */
5106 DEBUG_TRACE("%p: Regenerate %s direction connections\n", ii, ecm_db_obj_dir_strings[dir]);
5107 while (ci[dir]) {
5108 struct ecm_db_connection_instance *cin;
5109 cin = ecm_db_connection_iface_get_and_ref_next(ci[dir], dir);
Ben Menchaca84f36632014-02-28 20:57:38 +00005110
Murat Sezgin3d9a7642018-05-15 16:24:09 -07005111 DEBUG_TRACE("%p: Regenerate: %p", ii, ci[dir]);
5112 ecm_db_connection_regenerate(ci[dir]);
5113 ecm_db_connection_deref(ci[dir]);
5114 ci[dir] = cin;
5115 }
Gareth Williamsa4390962015-08-26 12:51:31 +01005116 }
5117
5118#ifdef ECM_MULTICAST_ENABLE
5119 /*
5120 * Multicasts would not have recorded in the lists above.
5121 * Our only way to re-gen those is to iterate all multicasts.
5122 * GGG TODO This will be optimised in a future release.
5123 */
5124 ci_mcast = ecm_db_connections_get_and_ref_first();
5125 while (ci_mcast) {
5126 struct ecm_db_connection_instance *cin;
5127
5128 /*
5129 * Multicast and NOT flagged for re-gen?
5130 */
5131 if (ecm_db_multicast_connection_to_interfaces_set_check(ci_mcast)
5132 && ecm_db_connection_regeneration_required_peek(ci_mcast)) {
Xiaoping Faned6d37e2015-09-17 14:13:47 -07005133 ecm_db_connection_regenerate(ci_mcast);
Gareth Williamsa4390962015-08-26 12:51:31 +01005134 }
5135
5136 cin = ecm_db_connection_get_and_ref_next(ci_mcast);
5137 ecm_db_connection_deref(ci_mcast);
5138 ci_mcast = cin;
Ben Menchaca84f36632014-02-28 20:57:38 +00005139 }
Gareth Williamsb5903892015-03-20 15:13:07 +00005140#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00005141
Gareth Williamsa4390962015-08-26 12:51:31 +01005142#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00005143 DEBUG_TRACE("%p: Regenerate COMPLETE\n", ii);
5144}
5145
5146/*
5147 * ecm_interface_dev_regenerate_connections()
5148 * Cause regeneration of all connections that are using the specified interface.
5149 */
Tushar Mathurcccbf282015-01-13 01:22:44 +05305150void ecm_interface_dev_regenerate_connections(struct net_device *dev)
Ben Menchaca84f36632014-02-28 20:57:38 +00005151{
5152 struct ecm_db_iface_instance *ii;
5153
5154 DEBUG_INFO("Regenerate connections for: %p (%s)\n", dev, dev->name);
5155
5156 /*
Murat Sezgin91c5d712015-06-12 15:16:22 -07005157 * If the interface is known to us then we will get it returned by this
5158 * function and process it accordingly.
Ben Menchaca84f36632014-02-28 20:57:38 +00005159 */
Murat Sezgin91c5d712015-06-12 15:16:22 -07005160 ii = ecm_db_iface_find_and_ref_by_interface_identifier(dev->ifindex);
Ben Menchaca84f36632014-02-28 20:57:38 +00005161 if (!ii) {
5162 DEBUG_WARN("%p: No interface instance could be established for this dev\n", dev);
5163 return;
5164 }
5165 ecm_interface_regenerate_connections(ii);
5166 DEBUG_TRACE("%p: Regenerate for %p: COMPLETE\n", dev, ii);
5167 ecm_db_iface_deref(ii);
5168}
5169
5170/*
Suman Ghosh7a261712016-01-12 21:42:55 +05305171 * ecm_interface_defunct_connections()
5172 * Cause defunct of all connections that are using the specified interface.
5173 */
5174static void ecm_interface_defunct_connections(struct ecm_db_iface_instance *ii)
5175{
5176#ifndef ECM_DB_XREF_ENABLE
5177 ecm_db_connection_defunct_all();
5178#else
Murat Sezgin3d9a7642018-05-15 16:24:09 -07005179 int dir;
5180 struct ecm_db_connection_instance *ci[ECM_DB_OBJ_DIR_MAX];
Suman Ghosh7a261712016-01-12 21:42:55 +05305181 struct ecm_db_connection_instance *ci_mcast __attribute__ ((unused));
5182
5183 DEBUG_TRACE("defunct connections using interface: %p\n", ii);
5184
Murat Sezgin3d9a7642018-05-15 16:24:09 -07005185 for (dir = 0; dir < ECM_DB_OBJ_DIR_MAX; dir++) {
5186 ci[dir] = ecm_db_iface_connections_get_and_ref_first(ii, dir);
5187 }
Suman Ghosh7a261712016-01-12 21:42:55 +05305188
5189 /*
Bhaskar Valaboju35d2a8b2018-01-16 18:35:10 +05305190 * Defunct ALL if all the four connection instances are NULL
5191 */
Murat Sezgin3d9a7642018-05-15 16:24:09 -07005192 if (!ci[ECM_DB_OBJ_DIR_FROM] && !ci[ECM_DB_OBJ_DIR_TO] && !ci[ECM_DB_OBJ_DIR_FROM_NAT] && !ci[ECM_DB_OBJ_DIR_TO_NAT]) {
5193 ecm_db_regeneration_needed();
5194 DEBUG_TRACE("%p: Regenerate (ALL) COMPLETE\n", ii);
Bhaskar Valaboju35d2a8b2018-01-16 18:35:10 +05305195 return;
5196 }
5197
5198 /*
Suman Ghosh7a261712016-01-12 21:42:55 +05305199 * Defunct all connections associated with this interface
5200 */
Murat Sezgin3d9a7642018-05-15 16:24:09 -07005201 for (dir = 0; dir < ECM_DB_OBJ_DIR_MAX; dir++) {
5202 DEBUG_TRACE("%p: Defunct %s direction connections\n", ii, ecm_db_obj_dir_strings[dir]);
5203 while (ci[dir]) {
5204 struct ecm_db_connection_instance *cin;
5205 cin = ecm_db_connection_iface_get_and_ref_next(ci[dir], dir);
Suman Ghosh7a261712016-01-12 21:42:55 +05305206
Murat Sezgin3d9a7642018-05-15 16:24:09 -07005207 DEBUG_TRACE("%p: Defunct: %p", ii, ci[dir]);
5208 ecm_db_connection_make_defunct(ci[dir]);
5209 ecm_db_connection_deref(ci[dir]);
5210 ci[dir] = cin;
5211 }
Suman Ghosh7a261712016-01-12 21:42:55 +05305212 }
5213#endif
5214 DEBUG_TRACE("%p: Defunct COMPLETE\n", ii);
5215}
5216
5217/*
5218 * ecm_interface_dev_defunct_connections()
5219 * Cause defunct of all connections that are using the specified interface.
5220 */
5221void ecm_interface_dev_defunct_connections(struct net_device *dev)
5222{
5223 struct ecm_db_iface_instance *ii;
5224
5225 DEBUG_INFO("defunct connections for: %p (%s)\n", dev, dev->name);
5226
5227 /*
5228 * If the interface is known to us then we will get it returned by this
5229 * function and process it accordingly.
5230 */
5231 ii = ecm_db_iface_find_and_ref_by_interface_identifier(dev->ifindex);
5232 if (!ii) {
5233 DEBUG_WARN("%p: No interface instance could be established for this dev\n", dev);
5234 return;
5235 }
5236 ecm_interface_defunct_connections(ii);
5237 DEBUG_TRACE("%p: defunct for %p: COMPLETE\n", dev, ii);
5238 ecm_db_iface_deref(ii);
5239}
5240
5241/*
Ben Menchaca84f36632014-02-28 20:57:38 +00005242 * ecm_interface_mtu_change()
5243 * MTU of interface has changed
5244 */
5245static void ecm_interface_mtu_change(struct net_device *dev)
5246{
5247 int mtu;
5248 struct ecm_db_iface_instance *ii;
5249
5250 mtu = dev->mtu;
5251 DEBUG_INFO("%p (%s): MTU Change to: %d\n", dev, dev->name, mtu);
5252
5253 /*
Murat Sezgin91c5d712015-06-12 15:16:22 -07005254 * Find the interface for the given device.
Ben Menchaca84f36632014-02-28 20:57:38 +00005255 */
Murat Sezgin91c5d712015-06-12 15:16:22 -07005256 ii = ecm_db_iface_find_and_ref_by_interface_identifier(dev->ifindex);
Ben Menchaca84f36632014-02-28 20:57:38 +00005257 if (!ii) {
5258 DEBUG_WARN("%p: No interface instance could be established for this dev\n", dev);
5259 return;
5260 }
5261
5262 /*
5263 * Change the mtu
5264 */
5265 ecm_db_iface_mtu_reset(ii, mtu);
5266 DEBUG_TRACE("%p (%s): MTU Changed to: %d\n", dev, dev->name, mtu);
Tushar Mathurad534d62015-06-10 18:37:52 +05305267 if (netif_is_bond_slave(dev)) {
5268 struct net_device *master = NULL;
5269 master = ecm_interface_get_and_hold_dev_master(dev);
5270 DEBUG_ASSERT(master, "Expected a master\n");
5271 ecm_interface_dev_regenerate_connections(master);
5272 dev_put(master);
5273 } else {
5274 ecm_interface_regenerate_connections(ii);
5275 }
5276
Ben Menchaca84f36632014-02-28 20:57:38 +00005277 DEBUG_TRACE("%p: Regenerate for %p: COMPLETE\n", dev, ii);
5278 ecm_db_iface_deref(ii);
5279}
5280
5281/*
5282 * ecm_interface_netdev_notifier_callback()
5283 * Netdevice notifier callback to inform us of change of state of a netdevice
5284 */
5285static int ecm_interface_netdev_notifier_callback(struct notifier_block *this, unsigned long event, void *ptr)
5286{
Stephen Wang69379c32015-02-04 18:37:13 -08005287#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 10, 0))
Ben Menchaca84f36632014-02-28 20:57:38 +00005288 struct net_device *dev __attribute__ ((unused)) = (struct net_device *)ptr;
Stephen Wang69379c32015-02-04 18:37:13 -08005289#else
5290 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
5291#endif
Tushar Mathurad534d62015-06-10 18:37:52 +05305292 struct net_device *master = NULL;
Ben Menchaca84f36632014-02-28 20:57:38 +00005293
5294 DEBUG_INFO("Net device notifier for: %p, name: %s, event: %lx\n", dev, dev->name, event);
5295
5296 switch (event) {
5297 case NETDEV_DOWN:
5298 DEBUG_INFO("Net device: %p, DOWN\n", dev);
Tushar Mathurad534d62015-06-10 18:37:52 +05305299 if (netif_is_bond_slave(dev)) {
5300 master = ecm_interface_get_and_hold_dev_master(dev);
5301 DEBUG_ASSERT(master, "Expected a master\n");
Murat Sezgina52ce612017-11-14 17:08:08 -08005302 ecm_interface_dev_defunct_connections(master);
Tushar Mathurad534d62015-06-10 18:37:52 +05305303 dev_put(master);
5304 } else {
Murat Sezgina52ce612017-11-14 17:08:08 -08005305 ecm_interface_dev_defunct_connections(dev);
Tushar Mathurad534d62015-06-10 18:37:52 +05305306 }
Ben Menchaca84f36632014-02-28 20:57:38 +00005307 break;
5308
5309 case NETDEV_CHANGE:
5310 DEBUG_INFO("Net device: %p, CHANGE\n", dev);
5311 if (!netif_carrier_ok(dev)) {
5312 DEBUG_INFO("Net device: %p, CARRIER BAD\n", dev);
Tushar Mathur933907c2014-06-24 17:06:14 +05305313 if (netif_is_bond_slave(dev)) {
Murat Sezginb3731e82014-11-26 12:20:59 -08005314 master = ecm_interface_get_and_hold_dev_master(dev);
Bhaskar Valaboju5cbdf812018-02-21 09:59:24 +05305315 DEBUG_ASSERT(master, "Expected a master.\n");
5316 ecm_interface_dev_defunct_connections(master);
Murat Sezginb3731e82014-11-26 12:20:59 -08005317 dev_put(master);
Tushar Mathur933907c2014-06-24 17:06:14 +05305318 } else {
Bhaskar Valaboju5cbdf812018-02-21 09:59:24 +05305319 ecm_interface_dev_defunct_connections(dev);
Tushar Mathur933907c2014-06-24 17:06:14 +05305320 }
Ben Menchaca84f36632014-02-28 20:57:38 +00005321 }
5322 break;
5323
5324 case NETDEV_CHANGEMTU:
5325 DEBUG_INFO("Net device: %p, MTU CHANGE\n", dev);
5326 ecm_interface_mtu_change(dev);
5327 break;
5328
5329 default:
5330 DEBUG_TRACE("Net device: %p, UNHANDLED: %lx\n", dev, event);
5331 break;
5332 }
5333
5334 return NOTIFY_DONE;
5335}
5336
5337/*
Murat Sezgin9304d472017-04-14 10:16:52 -07005338 * ecm_interface_node_connections_defunct()
5339 * Defunct the connections on this node.
Murat Sezgina205b042016-07-19 14:18:14 -07005340 */
Murat Sezgin9304d472017-04-14 10:16:52 -07005341void ecm_interface_node_connections_defunct(uint8_t *mac)
Murat Sezgina205b042016-07-19 14:18:14 -07005342{
Murat Sezgina5f3de12016-08-02 17:29:30 -07005343 struct ecm_db_node_instance *ni = NULL;
Murat Sezgina205b042016-07-19 14:18:14 -07005344
5345 if (unlikely(!mac)) {
5346 DEBUG_WARN("mac address is null\n");
5347 return;
5348 }
5349
Murat Sezgina5f3de12016-08-02 17:29:30 -07005350 ni = ecm_db_node_chain_get_and_ref_first(mac);
5351 while (ni) {
5352 struct ecm_db_node_instance *nin;
Murat Sezgina205b042016-07-19 14:18:14 -07005353
Murat Sezgina5f3de12016-08-02 17:29:30 -07005354 if (ecm_db_node_is_mac_addr_equal(ni, mac)) {
Murat Sezgin3d9a7642018-05-15 16:24:09 -07005355 int dir;
5356 for (dir = 0; dir < ECM_DB_OBJ_DIR_MAX; dir++) {
5357 ecm_db_traverse_node_connection_list_and_defunct(ni, dir);
5358 }
Murat Sezgina5f3de12016-08-02 17:29:30 -07005359 }
5360
5361 /*
5362 * Get next node in the chain
5363 */
5364 nin = ecm_db_node_chain_get_and_ref_next(ni);
5365 ecm_db_node_deref(ni);
5366 ni = nin;
Murat Sezgina205b042016-07-19 14:18:14 -07005367 }
Murat Sezgina205b042016-07-19 14:18:14 -07005368}
Murat Sezgin9304d472017-04-14 10:16:52 -07005369EXPORT_SYMBOL(ecm_interface_node_connections_defunct);
Murat Sezgina205b042016-07-19 14:18:14 -07005370
5371/*
Ben Menchaca84f36632014-02-28 20:57:38 +00005372 * struct notifier_block ecm_interface_netdev_notifier
5373 * Registration for net device changes of state.
5374 */
5375static struct notifier_block ecm_interface_netdev_notifier __read_mostly = {
5376 .notifier_call = ecm_interface_netdev_notifier_callback,
5377};
Murat Sezgina205b042016-07-19 14:18:14 -07005378
Murat Sezgin8c345822015-05-27 15:35:38 -07005379#if defined(ECM_DB_XREF_ENABLE) && defined(ECM_BAND_STEERING_ENABLE)
Ben Menchaca84f36632014-02-28 20:57:38 +00005380/*
ratheesh kannoth37e35b02015-03-26 11:25:02 +05305381 * ecm_interfae_node_br_fdb_notify_event()
5382 * This is a call back for "bridge fdb update event/ageing timer expire
5383 * event".
5384 */
5385static int ecm_interface_node_br_fdb_notify_event(struct notifier_block *nb,
5386 unsigned long val,
5387 void *data)
5388{
5389 uint8_t *mac = (uint8_t *)data;
ratheesh kannoth37e35b02015-03-26 11:25:02 +05305390
Murat Sezgin04470032017-07-07 14:53:32 -07005391 if (ECM_FRONT_END_TYPE_NSS == ecm_front_end_type_get()) {
5392 DEBUG_INFO("FDB updated for node %pM\n", mac);
5393 ecm_interface_node_connections_defunct(mac);
5394 }
ratheesh kannoth37e35b02015-03-26 11:25:02 +05305395
5396 return NOTIFY_DONE;
5397}
5398
5399static struct notifier_block ecm_interface_node_br_fdb_update_nb = {
5400 .notifier_call = ecm_interface_node_br_fdb_notify_event,
5401};
Xiaoping Fan8fe3edd2016-06-22 16:03:17 -07005402
5403static int ecm_interface_node_br_fdb_delete_event(struct notifier_block *nb,
5404 unsigned long event,
5405 void *ctx)
5406{
5407 struct br_fdb_event *fe = (struct br_fdb_event *)ctx;
5408
5409 if ((event != BR_FDB_EVENT_DEL) || fe->is_local) {
5410 DEBUG_WARN("local fdb or not deleting event, ignore\n");
5411 return NOTIFY_DONE;
5412 }
5413
5414 return ecm_interface_node_br_fdb_notify_event(nb, event, fe->addr);
5415}
5416
5417static struct notifier_block ecm_interface_node_br_fdb_delete_nb = {
5418 .notifier_call = ecm_interface_node_br_fdb_delete_event,
5419};
Murat Sezgin8c345822015-05-27 15:35:38 -07005420#endif
Shyam Sunder6358b862015-05-04 15:06:24 +05305421
5422#ifdef ECM_MULTICAST_ENABLE
5423/*
5424 * ecm_interface_multicast_find_outdated_iface_instances()
5425 *
5426 * Called in the case of Routing/Bridging Multicast update events.
5427 *
5428 * This function takes a list of ifindex for the connection which was received
5429 * from MFC or bridge snooper, compares it against the existing list of interfaces
5430 * in the DB connection, and extracts the list of those interfaces that have left
5431 * the multicast group.
5432 *
5433 * ci A DB connection instance.
5434 * mc_updates Part of return Information. The function will mark the index of those
5435 * interfaces in the DB connection 'to_mcast_interfaces' array that have
5436 * left the group, in the mc_updates->if_leave_idx array. The caller uses this
5437 * information to delete those outdated interface heirarchies from the
5438 * connection.
5439 * is_bridged True if the function called due to bridge multicast snooper update event.
5440 * dst_dev Holds the netdevice ifindex number of the new list of interfaces as reported
5441 * by the update from MFC or Bridge snooper.
5442 * max_to_dev Size of the array 'dst_dev'
5443 *
5444 * Return true if outdated interfaces found
5445 */
5446static bool ecm_interface_multicast_find_outdated_iface_instances(struct ecm_db_connection_instance *ci, struct ecm_multicast_if_update *mc_updates,
5447 uint32_t flags, bool is_br_snooper, uint32_t *mc_dst_if_index, uint32_t max_to_dev)
5448{
5449 struct ecm_db_iface_instance *mc_ifaces;
5450 struct ecm_db_iface_instance *ii_temp;
5451 struct ecm_db_iface_instance *ii_single;
5452 struct ecm_db_iface_instance **ifaces;
5453 struct ecm_db_iface_instance *to_iface;
5454 int32_t *to_iface_first;
5455 int32_t *mc_ifaces_first;
5456 uint32_t *dst_if_index;
5457 ecm_db_iface_type_t ii_type;
5458 int32_t heirarchy_index;
5459 int32_t if_index;
5460 int32_t if_cnt = 0;
5461 int found = 0;
5462 int ii;
5463 int ret;
5464 int32_t ifaces_identifier;
5465
5466 ret = ecm_db_multicast_connection_to_interfaces_get_and_ref_all(ci, &mc_ifaces, &mc_ifaces_first);
5467 if (ret == 0) {
5468 DEBUG_WARN("%p: multicast interfaces ref fail!\n", ci);
5469 return false;
5470 }
5471
5472 /*
5473 * Loop through the current interface list in the DB
5474 * connection 'to_mcast_interfaces' array
5475 */
5476 for (heirarchy_index = 0; heirarchy_index < ECM_DB_MULTICAST_IF_MAX; heirarchy_index++) {
5477 found = 0;
5478 to_iface_first = ecm_db_multicast_if_first_get_at_index(mc_ifaces_first, heirarchy_index);
5479
5480 /*
5481 * Invalid interface entry, skip
5482 */
5483 if (*to_iface_first == ECM_DB_IFACE_HEIRARCHY_MAX) {
5484 continue;
5485 }
5486
5487 ii_temp = ecm_db_multicast_if_heirarchy_get(mc_ifaces, heirarchy_index);
5488 ii_single = ecm_db_multicast_if_instance_get_at_index(ii_temp, ECM_DB_IFACE_HEIRARCHY_MAX - 1);
5489 ifaces = (struct ecm_db_iface_instance **)ii_single;
5490 to_iface = *ifaces;
Murat Sezgin3d9a7642018-05-15 16:24:09 -07005491 ii_type = ecm_db_iface_type_get(to_iface);
Shyam Sunder6358b862015-05-04 15:06:24 +05305492
5493 /*
5494 * If the update was received from bridge snooper, do not consider entries in the
5495 * interface list that are not part of a bridge.
5496 */
5497 if (is_br_snooper && (ii_type != ECM_DB_IFACE_TYPE_BRIDGE)) {
5498 continue;
5499 }
5500
5501 /*
5502 * If the update was received from MFC, do not consider entries in the
5503 * interface list that are part of a bridge. The bridge entries will be
5504 * taken care by the Bridge Snooper Callback
5505 */
5506 if (ii_type == ECM_DB_IFACE_TYPE_BRIDGE) {
5507 if (!is_br_snooper && !(flags & ECM_DB_MULTICAST_CONNECTION_BRIDGE_DEV_SET_FLAG)) {
5508 continue;
5509 }
5510 }
5511
5512 /*
5513 * Try to find a match in the newly received interface list, for any of
5514 * the interface instance in the heirarchy. If found, it means that this
5515 * interface has not left the group. If not found, it means that this
5516 * interface has left the group.
5517 */
5518 for (ii = ECM_DB_IFACE_HEIRARCHY_MAX - 1; ii >= *to_iface_first; ii--) {
5519 ii_single = ecm_db_multicast_if_instance_get_at_index(ii_temp, ii);
5520 ifaces = (struct ecm_db_iface_instance **)ii_single;
5521 to_iface = *ifaces;
5522
Murat Sezgin3d9a7642018-05-15 16:24:09 -07005523 ii_type = ecm_db_iface_type_get(to_iface);
Shyam Sunder6358b862015-05-04 15:06:24 +05305524 ifaces_identifier = ecm_db_iface_interface_identifier_get(to_iface);
5525 for (if_index = 0; if_index < max_to_dev; if_index++) {
5526 dst_if_index = ecm_db_multicast_if_num_get_at_index(mc_dst_if_index, if_index);
5527 if (*dst_if_index == ifaces_identifier) {
5528 found = 1;
5529 break;
5530 }
5531 }
5532 if (found) {
5533 break;
5534 }
5535 }
5536
5537 /*
5538 * We did not find a match for the interface in the present list. So mark
5539 * if as one that has left the group.
5540 */
5541 if (!found) {
5542 if_cnt++;
5543 mc_updates->if_leave_idx[heirarchy_index] = 1;
5544 }
5545 }
5546
5547 ecm_db_multicast_connection_to_interfaces_deref_all(mc_ifaces, mc_ifaces_first);
5548 mc_updates->if_leave_cnt = if_cnt;
5549 return (if_cnt > 0);
5550}
5551
5552/*
5553 * ecm_interface_multicast_find_new_iface_instances()
5554 *
5555 * Called in the case of Routing/Bridging Multicast update events.
5556 *
5557 * This function takes a list of ifindex for the connection which was received
5558 * from MFC or bridge snooper, compares it against the existing list of interfaces
5559 * in the DB connection, and extracts the list of the new joinees for the multicast
5560 * group.
5561 *
5562 * ci A DB connection instance.
5563 * mc_updates Part of return Information. The function will mark the index of those
5564 * interfaces in the 'dst_dev' array that have joined the group, in the
5565 * mc_updates->if_join_idx array. The caller uses this information to add the new
5566 * interface heirarchies into the connection.
5567 * dst_dev Holds the netdevice ifindex number of the new list of interfaces as reported
5568 * by the update from MFC or Bridge snooper.
5569 * max_to_dev Size of the array 'dst_dev'
5570 *
5571 * Return true if new joinees found
5572 */
5573static bool ecm_interface_multicast_find_new_iface_instances(struct ecm_db_connection_instance *ci,
5574 struct ecm_multicast_if_update *mc_updates, uint32_t *mc_dst_if_index, uint32_t max_to_dev)
5575{
5576 struct ecm_db_iface_instance *mc_ifaces;
5577 struct ecm_db_iface_instance *ii_temp;
5578 struct ecm_db_iface_instance *ii_single;
5579 struct ecm_db_iface_instance **ifaces;
5580 int32_t *mc_ifaces_first;
5581 int32_t *to_list_first;
5582 int32_t heirarchy_index;
5583 int32_t if_index;
5584 int32_t if_cnt = 0;
5585 int found = 0;
5586 int ii;
5587 int ret;
5588 uint32_t *dst_if_index;
5589 int32_t ifaces_identifier;
5590 struct ecm_db_iface_instance *to_list;
5591
5592 ret = ecm_db_multicast_connection_to_interfaces_get_and_ref_all(ci, &mc_ifaces, &mc_ifaces_first);
5593 if (ret == 0) {
5594 DEBUG_WARN("%p: multicast interfaces ref fail!\n", ci);
5595 return false;
5596 }
5597
5598 /*
5599 * Loop through the new interface list 'dst_dev'
5600 */
5601 for (if_index = 0; if_index < max_to_dev; if_index++) {
5602 found = 0;
5603 dst_if_index = ecm_db_multicast_if_num_get_at_index(mc_dst_if_index, if_index);
5604 if (*dst_if_index == 0) {
5605 continue;
5606 }
5607
5608 for (heirarchy_index = 0; heirarchy_index < ECM_DB_MULTICAST_IF_MAX ; heirarchy_index++) {
5609 to_list_first = ecm_db_multicast_if_first_get_at_index(mc_ifaces_first, heirarchy_index);
5610
5611 /*
5612 * Invalid interface entry, skip
5613 */
5614 if (*to_list_first == ECM_DB_IFACE_HEIRARCHY_MAX) {
5615 continue;
5616 }
5617
5618 ii_temp = ecm_db_multicast_if_heirarchy_get(mc_ifaces, heirarchy_index);
5619
5620 /*
5621 * Try to find a match for this ifindex (dst_dev[if_index]), in any of the
5622 * interface instance in the heirarchy. If not found, it means that this
5623 * ifindex has joined the group. If found, it means that this ifindex was
5624 * already part of the list of destination interfaces.
5625 */
5626 for (ii = ECM_DB_IFACE_HEIRARCHY_MAX - 1; ii >= *to_list_first; ii--) {
5627 ii_single = ecm_db_multicast_if_instance_get_at_index(ii_temp, ii);
5628 ifaces = (struct ecm_db_iface_instance **)ii_single;
5629 to_list = *ifaces;
5630 ifaces_identifier = ecm_db_iface_interface_identifier_get(to_list);
5631 if (*dst_if_index == ifaces_identifier) {
5632 found = 1;
5633 break;
5634 }
5635 }
5636
5637 if (found) {
5638 break;
5639 }
5640 }
5641
5642 /*
5643 * We did not find a match for the interface in the present list. So mark
5644 * it as one that has joined the group.
5645 */
5646 if (!found) {
5647
5648 /*
5649 * Store the if index of the new joinee
5650 */
5651 mc_updates->join_dev[if_cnt] = *dst_if_index;
5652
5653 /*
5654 * Identify a new vacant slot in the 'to_mcast_interfaces' to place
5655 * the new interface
5656 */
5657 for (heirarchy_index = 0; heirarchy_index < ECM_DB_MULTICAST_IF_MAX ; heirarchy_index++) {
5658 to_list_first = ecm_db_multicast_if_first_get_at_index(mc_ifaces_first, heirarchy_index);
5659 if (*to_list_first == ECM_DB_IFACE_HEIRARCHY_MAX) {
5660 mc_updates->if_join_idx[heirarchy_index] = 1;
5661 break;
5662 }
5663 }
5664
5665 if_cnt++;
5666 }
5667 }
5668
5669 ecm_db_multicast_connection_to_interfaces_deref_all(mc_ifaces, mc_ifaces_first);
5670 mc_updates->if_join_cnt = if_cnt;
5671
5672 return (if_cnt > 0);
5673}
5674
5675/*
5676 * ecm_interface_multicast_find_updates_to_iface_list()
5677 * Process IGMP/MLD updates either from MFC or bridge snooper. Identity the interfaces
5678 * that have left the group and new interfaces that have joined the group.
5679 *
5680 * The function returns true if there was any update necessary to the current destination
5681 * interface list
5682 */
5683bool ecm_interface_multicast_find_updates_to_iface_list(struct ecm_db_connection_instance *ci, struct ecm_multicast_if_update *mc_updates,
5684 uint32_t flags, bool is_br_snooper, uint32_t *mc_dst_if_index, uint32_t max_to_dev)
5685{
5686 bool join;
5687 bool leave;
5688 /*
5689 * Find destination interfaces that have left the group
5690 */
5691 leave = ecm_interface_multicast_find_outdated_iface_instances(ci, mc_updates, flags, is_br_snooper, mc_dst_if_index, max_to_dev);
5692 /*
5693 * Find new destination interfaces that have joined the group
5694 */
5695 join = ecm_interface_multicast_find_new_iface_instances(ci, mc_updates, mc_dst_if_index, max_to_dev);
5696
5697 return (leave || join);
5698}
5699EXPORT_SYMBOL(ecm_interface_multicast_find_updates_to_iface_list);
5700#endif
5701
Murat Sezgin42a44c22016-05-05 14:06:39 -07005702#ifdef ECM_DB_XREF_ENABLE
5703/*
5704 * ecm_interface_neigh_mac_update_notify_event()
5705 * Neighbour mac address change handler.
5706 */
5707static int ecm_interface_neigh_mac_update_notify_event(struct notifier_block *nb,
5708 unsigned long val,
5709 void *data)
5710{
Murat Sezgin42a44c22016-05-05 14:06:39 -07005711 struct neigh_mac_update *nmu = (struct neigh_mac_update *)data;
5712
5713 /*
5714 * If the old and new mac addresses are equal, do nothing.
5715 * This case shouldn't happen.
5716 */
5717 if (!ecm_mac_addr_equal(nmu->old_mac, nmu->update_mac)) {
5718 DEBUG_TRACE("old and new mac addresses are equal: %pM\n", nmu->old_mac);
5719 return NOTIFY_DONE;
5720 }
5721
5722 /*
5723 * If the old mac is zero, do nothing. When a host joins the arp table first
5724 * time, its old mac comes as zero. We shouldn't handle this case, because
5725 * there is not any connection in ECM db with zero mac.
5726 */
5727 if (is_zero_ether_addr(nmu->old_mac)) {
5728 DEBUG_WARN("old mac is zero\n");
5729 return NOTIFY_DONE;
5730 }
5731
5732 DEBUG_TRACE("old mac: %pM new mac: %pM\n", nmu->old_mac, nmu->update_mac);
5733
Murat Sezgina205b042016-07-19 14:18:14 -07005734 DEBUG_INFO("neigh mac update notify for node %pM\n", nmu->old_mac);
Murat Sezgin9304d472017-04-14 10:16:52 -07005735 ecm_interface_node_connections_defunct((uint8_t *)nmu->old_mac);
Murat Sezgin42a44c22016-05-05 14:06:39 -07005736
5737 return NOTIFY_DONE;
5738}
5739
5740/*
5741 * struct notifier_block ecm_interface_neigh_mac_update_nb
5742 * Registration for neighbour mac address update.
5743 */
5744static struct notifier_block ecm_interface_neigh_mac_update_nb = {
5745 .notifier_call = ecm_interface_neigh_mac_update_notify_event,
5746};
5747#endif
5748
Murat Sezgin1f381852014-11-20 09:51:07 -08005749/*
Murat Sezgina205b042016-07-19 14:18:14 -07005750 * ecm_interface_wifi_event_iwevent
5751 * wireless event handler
5752 */
5753static int ecm_interface_wifi_event_iwevent(int ifindex, unsigned char *buf, size_t len)
5754{
5755 struct iw_event iwe_buf, *iwe = &iwe_buf;
5756 char *pos, *end;
5757
5758 pos = buf;
5759 end = buf + len;
5760 while (pos + IW_EV_LCP_LEN <= end) {
5761
5762 /*
5763 * Copy the base data structure to get iwe->len
5764 */
5765 memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
5766
5767 /*
5768 * Check that len is valid and that we have that much in the buffer.
5769 *
5770 */
5771 if (iwe->len < IW_EV_LCP_LEN) {
5772 return -1;
5773 }
5774
5775 if ((iwe->len > sizeof (struct iw_event)) || (iwe->len + pos) > end) {
5776 return -1;
5777 }
5778
5779 /*
5780 * Do the copy again with the full length.
5781 */
5782 memcpy(&iwe_buf, pos, iwe->len);
5783
5784 if (iwe->cmd == IWEVREGISTERED) {
5785 DEBUG_INFO("STA %pM joining\n", (uint8_t *)iwe->u.addr.sa_data);
5786 } else if (iwe->cmd == IWEVEXPIRED) {
5787 DEBUG_INFO("STA %pM leaving\n", (uint8_t *)iwe->u.addr.sa_data);
Murat Sezgin9304d472017-04-14 10:16:52 -07005788 ecm_interface_node_connections_defunct((uint8_t *)iwe->u.addr.sa_data);
Murat Sezgina205b042016-07-19 14:18:14 -07005789 } else {
5790 DEBUG_INFO("iwe->cmd is %d for STA %pM\n", iwe->cmd, (unsigned char *) iwe->u.addr.sa_data);
5791 }
5792
5793 pos += iwe->len;
5794 }
5795
5796 return 0;
5797}
5798
5799/*
5800 * ecm_interface_wifi_event_newlink
5801 * Link event handler
5802 */
5803static int ecm_interface_wifi_event_newlink(struct ifinfomsg *ifi, unsigned char *buf, size_t len)
5804{
5805 struct rtattr *attr;
5806 int attrlen, rta_len;
5807
5808 DEBUG_TRACE("Event from interface %d\n", ifi->ifi_index);
5809
5810 attrlen = len;
5811 attr = (struct rtattr *) buf;
5812 rta_len = RTA_ALIGN(sizeof(struct rtattr));
5813
5814 while (RTA_OK(attr, attrlen)) {
5815 if (attr->rta_type == IFLA_WIRELESS) {
5816 ecm_interface_wifi_event_iwevent(ifi->ifi_index, ((char *) attr) + rta_len, attr->rta_len - rta_len);
5817 }
5818 attr = RTA_NEXT(attr, attrlen);
5819 }
5820
5821 return 0;
5822}
5823
5824/*
5825 * ecm_interface_wifi_event_handler
5826 * Netlink event handler
5827 */
5828static int ecm_interface_wifi_event_handler(unsigned char *buf, int len)
5829{
5830 struct nlmsghdr *nlh;
5831 struct ifinfomsg *ifi;
5832 int left;
5833
5834 nlh = (struct nlmsghdr *) buf;
5835 left = len;
5836
5837 while (NLMSG_OK(nlh, left)) {
5838 switch (nlh->nlmsg_type) {
5839 case RTM_NEWLINK:
5840 case RTM_DELLINK:
5841 if (NLMSG_PAYLOAD(nlh, 0) < sizeof(struct ifinfomsg)) {
5842 DEBUG_INFO("invalid netlink message\n");
5843 break;
5844 }
5845
5846 ifi = NLMSG_DATA(nlh);
5847 DEBUG_INFO("ifi->ifi_family: %d\n", ifi->ifi_family);
5848 if (ifi->ifi_family != AF_BRIDGE) {
5849 ecm_interface_wifi_event_newlink(ifi, (u8 *)ifi + NLMSG_ALIGN(sizeof(struct ifinfomsg)),
5850 NLMSG_PAYLOAD(nlh, sizeof(struct ifinfomsg)));
5851 }
5852 break;
5853 }
5854
5855 nlh = NLMSG_NEXT(nlh, left);
5856 }
5857
5858 return 0;
5859}
5860
5861/*
5862 * ecm_interface_wifi_event_rx
5863 * Receive netlink message from socket
5864 */
5865static int ecm_interface_wifi_event_rx(struct socket *sock, struct sockaddr_nl *addr, unsigned char *buf, int len)
5866{
5867 struct msghdr msg;
5868 struct iovec iov;
5869 mm_segment_t oldfs;
5870 int size;
5871
5872 iov.iov_base = buf;
5873 iov.iov_len = len;
5874
5875 msg.msg_flags = 0;
5876 msg.msg_name = addr;
5877 msg.msg_namelen = sizeof(struct sockaddr_nl);
5878 msg.msg_control = NULL;
5879 msg.msg_controllen = 0;
5880#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0))
5881 msg.msg_iov = &iov;
5882 msg.msg_iovlen = 1;
5883#else
5884 iov_iter_init(&msg.msg_iter, READ, &iov, 1, 1);
5885#endif
5886 oldfs = get_fs();
5887 set_fs(KERNEL_DS);
5888 size = sock_recvmsg(sock, &msg, len, msg.msg_flags);
5889 set_fs(oldfs);
5890
5891 return size;
5892}
5893
5894/*
5895 * ecm_interface_wifi_event_thread
5896 */
5897static void ecm_interface_wifi_event_thread(void)
5898{
5899 int err;
5900 int size;
5901 struct sockaddr_nl saddr;
5902 unsigned char buf[512];
5903 int len = sizeof(buf);
5904
5905 allow_signal(SIGKILL|SIGSTOP);
5906 err = sock_create(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE, &__ewn.sock);
5907 if (err < 0) {
5908 DEBUG_ERROR("failed to create sock\n");
5909 goto exit1;
5910 }
5911
Murat Sezginac267642016-11-02 15:55:11 -07005912 memset(&saddr, 0, sizeof(saddr));
Murat Sezgina205b042016-07-19 14:18:14 -07005913 saddr.nl_family = AF_NETLINK;
5914 saddr.nl_groups = RTNLGRP_LINK;
5915 saddr.nl_pid = current->pid;
5916
5917 err = __ewn.sock->ops->bind(__ewn.sock, (struct sockaddr *)&saddr, sizeof(struct sockaddr));
5918 if (err < 0) {
5919 DEBUG_ERROR("failed to bind sock\n");
5920 goto exit2;
5921 }
5922
5923 DEBUG_INFO("ecm_interface_wifi_event thread started\n");
5924 while (!kthread_should_stop()) {
5925 size = ecm_interface_wifi_event_rx(__ewn.sock, &saddr, buf, len);
5926 DEBUG_TRACE("got a netlink msg with len %d\n", size);
5927
5928 if (signal_pending(current))
5929 break;
5930
5931 if (size < 0) {
5932 DEBUG_WARN("netlink rx error\n");
5933 } else {
5934 ecm_interface_wifi_event_handler(buf, size);
5935 }
5936 }
5937
5938 DEBUG_INFO("ecm_interface_wifi_event thread stopped\n");
5939exit2:
5940 sock_release(__ewn.sock);
5941exit1:
5942 __ewn.sock = NULL;
5943
5944 return;
5945}
5946
5947/*
5948 * ecm_interface_wifi_event_start()
5949 */
5950int ecm_interface_wifi_event_start(void)
5951{
5952 if (__ewn.thread) {
5953 return 0;
5954 }
5955
5956 __ewn.thread = kthread_run((void *)ecm_interface_wifi_event_thread, NULL, "ECM_wifi_event");
5957 if (IS_ERR(__ewn.thread)) {
5958 DEBUG_ERROR("Unable to start kernel thread\n");
5959 return -ENOMEM;
5960 }
5961
5962 return 0;
5963}
5964
5965/*
5966 * ecm_interface_wifi_event_stop()
5967 */
5968int ecm_interface_wifi_event_stop(void)
5969{
5970 int err;
5971
5972 if (__ewn.thread == NULL) {
5973 return 0;
5974 }
5975
5976 DEBUG_INFO("kill ecm_interface_wifi_event thread\n");
5977 force_sig(SIGKILL, __ewn.thread);
5978 err = kthread_stop(__ewn.thread);
5979 __ewn.thread = NULL;
5980
5981 return err;
5982}
5983
5984/*
Murat Sezgineebedb92017-11-17 17:14:32 -08005985 * ecm_interface_src_check_handler()
5986 * Source interface check sysctl node handler.
5987 */
5988static int ecm_interface_src_check_handler(struct ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
5989{
5990 int ret;
5991 int current_value;
5992
5993 /*
5994 * Take the current value
5995 */
5996 current_value = ecm_interface_src_check;
5997
5998 /*
5999 * Write the variable with user input
6000 */
6001 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
6002 if (ret || (!write)) {
6003 return ret;
6004 }
6005
6006 if (ECM_FRONT_END_TYPE_NSS != ecm_front_end_type_get()) {
6007 DEBUG_WARN("Source interface check is for NSS only.\n");
6008 return -EINVAL;
6009 }
6010
6011 if ((ecm_interface_src_check != 1) && (ecm_interface_src_check != 0)) {
6012 DEBUG_WARN("Invalid input. Valid values 0/1\n");
6013 ecm_interface_src_check = current_value;
6014 return -EINVAL;
6015 }
6016
6017 return ret;
6018}
6019
6020static struct ctl_table ecm_interface_table[] = {
6021 {
6022 .procname = "src_interface_check",
6023 .data = &ecm_interface_src_check,
6024 .maxlen = sizeof(int),
6025 .mode = 0644,
6026 .proc_handler = &ecm_interface_src_check_handler,
6027 },
6028 { }
6029};
6030
6031static struct ctl_table ecm_interface_root_dir[] = {
6032 {
6033 .procname = "ecm",
6034 .mode = 0555,
6035 .child = ecm_interface_table,
6036 },
6037 { }
6038};
6039
6040static struct ctl_table ecm_interface_root[] = {
6041 {
6042 .procname = "net",
6043 .mode = 0555,
6044 .child = ecm_interface_root_dir,
6045 },
6046 { }
6047};
6048
6049/*
Nicolas Costaf46c33b2014-05-15 10:02:00 -05006050 * ecm_interface_init()
Ben Menchaca84f36632014-02-28 20:57:38 +00006051 */
Nicolas Costaf46c33b2014-05-15 10:02:00 -05006052int ecm_interface_init(void)
Ben Menchaca84f36632014-02-28 20:57:38 +00006053{
6054 int result;
Nicolas Costaf46c33b2014-05-15 10:02:00 -05006055 DEBUG_INFO("ECM Interface init\n");
Ben Menchaca84f36632014-02-28 20:57:38 +00006056
Murat Sezgineebedb92017-11-17 17:14:32 -08006057 /*
6058 * Register sysctl table.
6059 */
6060 ecm_interface_ctl_table_header = register_sysctl_table(ecm_interface_root);
6061
Ben Menchaca84f36632014-02-28 20:57:38 +00006062 result = register_netdevice_notifier(&ecm_interface_netdev_notifier);
6063 if (result != 0) {
6064 DEBUG_ERROR("Failed to register netdevice notifier %d\n", result);
Murat Sezgineebedb92017-11-17 17:14:32 -08006065 unregister_sysctl_table(ecm_interface_ctl_table_header);
Murat Sezgin908ecb32015-05-10 20:54:36 -07006066 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00006067 }
Murat Sezgin8c345822015-05-27 15:35:38 -07006068#if defined(ECM_DB_XREF_ENABLE) && defined(ECM_BAND_STEERING_ENABLE)
ratheesh kannoth37e35b02015-03-26 11:25:02 +05306069 /*
6070 * register for bridge fdb database modificationevents
6071 */
ratheesh kannotha32fdd12015-09-09 08:02:58 +05306072 br_fdb_update_register_notify(&ecm_interface_node_br_fdb_update_nb);
Xiaoping Fan8fe3edd2016-06-22 16:03:17 -07006073 br_fdb_register_notify(&ecm_interface_node_br_fdb_delete_nb);
Murat Sezgin8c345822015-05-27 15:35:38 -07006074#endif
Murat Sezgin42a44c22016-05-05 14:06:39 -07006075#ifdef ECM_DB_XREF_ENABLE
6076 neigh_mac_update_register_notify(&ecm_interface_neigh_mac_update_nb);
6077#endif
Murat Sezgina205b042016-07-19 14:18:14 -07006078 ecm_interface_wifi_event_start();
6079
Nicolas Costaf46c33b2014-05-15 10:02:00 -05006080 return 0;
Ben Menchaca84f36632014-02-28 20:57:38 +00006081}
Nicolas Costaf46c33b2014-05-15 10:02:00 -05006082EXPORT_SYMBOL(ecm_interface_init);
Ben Menchaca84f36632014-02-28 20:57:38 +00006083
6084/*
6085 * ecm_interface_exit()
6086 */
Nicolas Costaf46c33b2014-05-15 10:02:00 -05006087void ecm_interface_exit(void)
Ben Menchaca84f36632014-02-28 20:57:38 +00006088{
6089 DEBUG_INFO("ECM Interface exit\n");
Nicolas Costaf46c33b2014-05-15 10:02:00 -05006090
6091 spin_lock_bh(&ecm_interface_lock);
6092 ecm_interface_terminate_pending = true;
6093 spin_unlock_bh(&ecm_interface_lock);
6094
6095 unregister_netdevice_notifier(&ecm_interface_netdev_notifier);
Murat Sezgin42a44c22016-05-05 14:06:39 -07006096#ifdef ECM_DB_XREF_ENABLE
6097 neigh_mac_update_unregister_notify(&ecm_interface_neigh_mac_update_nb);
6098#endif
6099
Murat Sezgin8c345822015-05-27 15:35:38 -07006100#if defined(ECM_DB_XREF_ENABLE) && defined(ECM_BAND_STEERING_ENABLE)
ratheesh kannoth37e35b02015-03-26 11:25:02 +05306101 /*
6102 * unregister for bridge fdb update events
6103 */
6104 br_fdb_update_unregister_notify(&ecm_interface_node_br_fdb_update_nb);
Xiaoping Fan8fe3edd2016-06-22 16:03:17 -07006105 br_fdb_unregister_notify(&ecm_interface_node_br_fdb_delete_nb);
Murat Sezgin8c345822015-05-27 15:35:38 -07006106#endif
Murat Sezgina205b042016-07-19 14:18:14 -07006107 ecm_interface_wifi_event_stop();
Murat Sezgineebedb92017-11-17 17:14:32 -08006108
6109 /*
6110 * Unregister sysctl table.
6111 */
6112 if (ecm_interface_ctl_table_header) {
6113 unregister_sysctl_table(ecm_interface_ctl_table_header);
6114 }
Ben Menchaca84f36632014-02-28 20:57:38 +00006115}
Nicolas Costaf46c33b2014-05-15 10:02:00 -05006116EXPORT_SYMBOL(ecm_interface_exit);