blob: e98bcbc5de479d2ca78afe4644713d2b8958224f [file] [log] [blame]
/*
* Copyright (c) 2012, 2015, 2017-2018, The Linux Foundation. All rights reserved.
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all copies.
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef KVER32
#include <linux/kconfig.h>
#include <linux/version.h>
#include <generated/autoconf.h>
#else
#include <linux/autoconf.h>
#endif
#include <linux/if_arp.h>
#include <linux/netdevice.h>
#include <linux/netfilter_arp.h>
#include <linux/inetdevice.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <linux/tcp.h>
#include <linux/icmp.h>
#ifdef KVER32
#include <linux/export.h>
#endif
#include <net/netfilter/nf_conntrack.h>
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
#include <linux/if_vlan.h>
#endif
#if defined (CONFIG_BRIDGE)
#include <../net/bridge/br_private.h>
#endif
#include <linux/ppp_defs.h>
#include <linux/filter.h>
#include <linux/if_pppox.h>
#include <linux/if_ppp.h>
#include <linux/ppp_channel.h>
#include <linux/ppp-comp.h>
#include <net/sock.h>
#include <net/route.h>
#include <net/netevent.h>
#include <net/ipv6.h>
#include <net/ip_fib.h>
#include "hsl_api.h"
#include "fal_nat.h"
#include "fal_ip.h"
#include "fal_fdb.h"
#include "hsl.h"
#include "nat_helper.h"
#include "napt_acl.h"
#include "lib/nat_helper_hsl.h"
#include "lib/nat_helper_dt.h"
#include "hsl_shared_api.h"
#include <net/addrconf.h>
#undef CONFIG_IPV6_HWACCEL
#ifdef CONFIG_IPV6_HWACCEL
#include <net/ndisc.h>
#include <net/neighbour.h>
#include <net/netevent.h>
#include <net/ipv6.h>
#include <net/ip6_route.h>
#include <linux/ipv6.h>
#include <linux/netfilter_ipv6.h>
#endif
//#define AP136_QCA_HEADER_EN 1
#define MAC_LEN 6
#define IP_LEN 4
#define ARP_HEADER_LEN 8
#define ARP_ENTRY_MAX 128
#define DESS_CHIP_VER 0x14
#define HOST_PREFIX_MAX 31
/* P6 is used by loop dev. */
#define S17_P6PAD_MODE_REG_VALUE 0x01000000
#define MULTIROUTE_WR
extern struct net init_net;
//char *nat_lan_dev_list = "eth0.1";
char nat_lan_dev_list[IFNAMSIZ*4] = "br-lan eth0.1";
char nat_wan_dev_list[IFNAMSIZ*5] = "eth0.2";
char nat_wan_port = 0x20;
int setup_wan_if = 0;
int setup_lan_if=0;
#define NAT_LAN_DEV_VID 1
#define NAT_WAN_DEV_VID 2
uint32_t nat_lan_vid = NAT_LAN_DEV_VID;
uint32_t nat_wan_vid = NAT_WAN_DEV_VID;
static int wan_fid = 0xffff;
static fal_pppoe_session_t pppoetbl = {0};
static uint32_t pppoe_gwid = 0;
static char nat_bridge_dev[IFNAMSIZ*4] = "br-lan";
static uint8_t lanip[4] = {0}, lanipmask[4] = {0}, wanip[4] = {0};
#ifdef CONFIG_IPV6_HWACCEL
static struct in6_addr wan6ip = IN6ADDR_ANY_INIT;
static struct in6_addr lan6ip = IN6ADDR_ANY_INIT;
#endif
extern int nat_chip_ver;
#ifdef ISISC
struct ipv6_default_route_binding
{
struct in6_addr next_hop;
uint32_t nh_entry_id;
};
#endif
#ifdef MULTIROUTE_WR
#define MAX_HOST 8
struct wan_next_hop
{
u_int32_t host_ip;
u_int32_t entry_id;
u_int32_t in_acl;
u_int32_t in_use;
u_int8_t host_mac[6];
};
static struct net_device *multi_route_indev = NULL;
static struct wan_next_hop wan_nh_ent[MAX_HOST] = {{0}};
#define NAT_BACKGROUND_TASK
#ifdef NAT_BACKGROUND_TASK
#define NAT_HELPER_MSG_MAX 512
struct bg_ring_buf_cb {
unsigned int read_idx;
unsigned int write_idx;
unsigned int num;
unsigned int full_flag;
struct nat_helper_bg_msg *buf;
};
struct bg_task_cb {
/*struct semaphore bg_sem; */ /*trigger thread work*/
spinlock_t bg_lock; /*ring buf access protect*/
/*struct task_struct *bg_task;*/
struct workqueue_struct *nat_wq;
struct bg_ring_buf_cb ring;
};
enum{
NAT_HELPER_ARP_ADD_MSG = 0,
NAT_HELPER_ARP_DEL_MSG,
NAT_HELPER_IPV6_MSG
};
struct arp_in_msg {
uint8_t mac[ETH_ALEN];
char name[IFNAMSIZ]; /* device name */
uint32_t ip;
struct net_device *in;
};
struct ipv6_msg {
struct sk_buff *skb;
struct net_device *in;
};
struct nat_helper_bg_msg {
struct work_struct work;
uint32_t msg_type;
uint16_t sub_type;
uint16_t reservd;
union {
struct arp_in_msg arp_in;
struct ipv6_msg ipv6;
};
};
struct bg_task_cb task_cb;
int bg_ring_buf_write(struct nat_helper_bg_msg msg)
{
unsigned int idx = 0;
spin_lock_bh(&task_cb.bg_lock);
if((task_cb.ring).full_flag &&
((task_cb.ring).read_idx == (task_cb.ring).write_idx)) {
HNAT_PRINTK("ring buf is full!\n");
spin_unlock_bh(&task_cb.bg_lock);
return -1;
}
msg.work = (task_cb.ring).buf[(task_cb.ring).write_idx].work;
(task_cb.ring).buf[(task_cb.ring).write_idx] = msg;
idx = (task_cb.ring).write_idx;
(task_cb.ring).write_idx = ((task_cb.ring).write_idx+1)%NAT_HELPER_MSG_MAX;
if(task_cb.ring.read_idx == task_cb.ring.write_idx)
task_cb.ring.full_flag = 1;
spin_unlock_bh(&task_cb.bg_lock);
queue_work(task_cb.nat_wq, &(task_cb.ring).buf[idx].work);
return 0;
}
int bg_ring_buf_read(struct nat_helper_bg_msg *msg)
{
spin_lock_bh(&task_cb.bg_lock);
task_cb.ring.read_idx = (task_cb.ring.read_idx+1)%NAT_HELPER_MSG_MAX;
task_cb.ring.full_flag = 0;
spin_unlock_bh(&task_cb.bg_lock);
return 0;
}
#endif
a_uint32_t nat_helper_wan_port_get(void)
{
a_uint32_t i = 0;
for (i = 0; i < 6; i ++) {
if ((nat_wan_port >> i) & 1)
break;
}
return i;
}
static int wan_nh_get(u_int32_t host_ip)
{
int i;
host_ip = htonl(host_ip);
for (i=0; i<MAX_HOST; i++)
{
if ((wan_nh_ent[i].host_ip != 0) && !memcmp(&wan_nh_ent[i].host_ip, &host_ip, 4))
{
// printk("%s %d\n", __FUNCTION__, __LINE__);
// if ((wan_nh_ent[i].entry_id != 0) && (wan_nh_ent[i].in_acl != 1))
if (wan_nh_ent[i].in_acl != 1)
{
wan_nh_ent[i].in_acl = 1;
return i;
}
// printk("%s %d\n", __FUNCTION__, __LINE__);
}
printk("%s %d wan_nh_ent 0x%08x host_ip 0x%08x\n", __FUNCTION__, __LINE__, wan_nh_ent[i].host_ip, host_ip);
}
return -1;
}
static void wan_nh_add(u_int8_t *host_ip , u_int8_t *host_mac, u_int32_t id)
{
int i;
for( i = 0 ; i < MAX_HOST ; i++ )
{
if((wan_nh_ent[i].host_ip != 0) && !memcmp(&wan_nh_ent[i].host_ip, host_ip, 4))
{
if (host_mac == NULL) break;
if(!memcmp(&wan_nh_ent[i].host_mac, host_mac,6))
return;
else
break ;
}
if(wan_nh_ent[i].host_ip == 0)
break;
}
if (i < MAX_HOST)
{
if ((wan_nh_ent[i].in_use) && (wan_nh_ent[i].in_acl)) return;
memcpy(&wan_nh_ent[i].host_ip, host_ip, 4);
if (host_mac != NULL)
{
memcpy(wan_nh_ent[i].host_mac, host_mac, 6);
wan_nh_ent[i].entry_id = id;
if ((wan_nh_ent[i].in_use) && !(wan_nh_ent[i].in_acl))
{
droute_add_acl_rules(*(uint32_t *)&lanip, *(uint32_t *)&lanipmask, id);
/* set the in_acl flag */
wan_nh_ent[i].in_acl = 1;
}
}
else
{
/* set the in_use flag */
wan_nh_ent[i].in_use = 1;
}
HNAT_PRINTK("%s: ip %08x (%d)\n" ,__func__, wan_nh_ent[i].host_ip, i);
}
}
uint32_t get_next_hop(uint32_t daddr, uint32_t saddr)
{
struct fib_result res;
#ifdef KVER32
struct flowi4 fl =
{
.flowi4_iif = multi_route_indev->ifindex,
.flowi4_mark = 0,
.flowi4_tos = 0,
.flowi4_scope = RT_SCOPE_UNIVERSE,
.daddr = htonl(daddr),
.saddr = htonl(saddr),
};
#else
struct flowi fl = { .nl_u = { .ip4_u =
{
.daddr = daddr,
.saddr = saddr,
.tos = 0,
.scope = RT_SCOPE_UNIVERSE,
}
},
.mark = 0,
.iif = multi_route_indev->ifindex
};
#endif
struct net * net = dev_net(multi_route_indev);
struct fib_nh *mrnh = NULL;
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,4,0))
if (fib_lookup(net, &fl, &res) != 0)
#else
if (fib_lookup(net, &fl, &res,0) != 0)
#endif
{
return 0;
}
else
{
mrnh = res.fi->fib_nh;
if (NULL == mrnh)
{
return 0;
}
}
return ntohl(mrnh->nh_gw);
}
uint32_t napt_set_default_route(fal_ip4_addr_t dst_addr, fal_ip4_addr_t src_addr)
{
sw_error_t rv;
/* search for the next hop (s) */
if (!(get_aclrulemask() & (1 << S17_ACL_LIST_DROUTE)))
{
if (multi_route_indev && \
(nf_athrs17_hnat_wan_type != NF_S17_WAN_TYPE_PPPOE) &&
(nf_athrs17_hnat_wan_type != NF_S17_WAN_TYPE_PPPOES0))
{
uint32_t next_hop = get_next_hop(dst_addr, src_addr);
HNAT_PRINTK("Next hop: %08x\n", next_hop);
if (next_hop != 0)
{
fal_host_entry_t arp_entry;
memset(&arp_entry, 0, sizeof(arp_entry));
arp_entry.ip4_addr = next_hop;
arp_entry.flags = FAL_IP_IP4_ADDR;
rv = IP_HOST_GET(0, FAL_IP_ENTRY_IPADDR_EN, &arp_entry);
if (rv != SW_OK)
{
printk("%s: IP_HOST_GET error... (non-existed host: %08x?) \n", __func__, next_hop);
/* add into the nh_ent */
wan_nh_add((u_int8_t *)&next_hop, (u_int8_t *)NULL, 0);
}
else
{
if (wan_nh_get(next_hop) != -1)
droute_add_acl_rules(*(uint32_t *)&lanip, *(uint32_t *)&lanipmask, arp_entry.entry_id);
else
printk("%s %d\n", __FUNCTION__, __LINE__);
}
}
else
{
HNAT_PRINTK("no need to set the default route... \n");
// set_aclrulemask (S17_ACL_LIST_DROUTE);
}
}
else
{
printk("multi_route_indev %pK nf_athrs17_hnat_wan_type %d\n", multi_route_indev, nf_athrs17_hnat_wan_type);
}
}
/* end next hop (s) */
return SW_OK;
}
#endif /* MULTIROUTE_WR */
void qcaswitch_hostentry_flush(void)
{
fal_host_entry_t hostentry;
sw_error_t ret;
do
{
memset(&hostentry, 0, sizeof(fal_host_entry_t));
hostentry.entry_id = FAL_NEXT_ENTRY_FIRST_ID;
ret = IP_HOST_NEXT (0, FAL_IP_ENTRY_ID_EN, &hostentry);
if (SW_OK == ret)
{
IP_HOST_DEL(0, FAL_IP_ENTRY_IPADDR_EN, &hostentry);
}
}while (SW_OK == ret);
return;
}
#ifdef CONFIG_IPV6_HWACCEL /* only for S17c */
static struct in6_addr* get_ipv6_default_gateway(void)
{
/* ip_route_output_key can't return correct default nexhop
* routes are less than 4 and it only searches in route
* hash, not in fib, so use fib_lookup.
*/
struct in6_addr *ip6addr = NULL;
struct in6_addr des_addr = IN6ADDR_ANY_INIT;
struct rt6_info *rt = rt6_lookup(&init_net, &des_addr, NULL, 0, 0);
if (rt)
{
ip6addr = &rt->rt6i_gateway;
}
return ip6addr;
}
static int add_pppoev6_host_entry(void)
{
struct in6_addr local_lan6ip = IN6ADDR_ANY_INIT;
unsigned long flags;
int ppp_sid, ppp_sid2;
unsigned char ppp_peer_mac[ETH_ALEN];
unsigned char ppp_peer_mac2[ETH_ALEN];
a_uint32_t ppp_peer_ip = 0;
int wvid;
fal_host_entry_t nh_arp_entry;
sw_error_t rv;
a_uint32_t droute_entry_id = 0;
a_bool_t ena;
static fal_pppoe_session_t pppoev6_sid_table = {0};
struct in6_addr *next_hop;
local_irq_save(flags);
memcpy(&local_lan6ip, &lan6ip, sizeof(struct in6_addr));
ppp_sid2 = nf_athrs17_hnat_ppp_id2;
ppp_sid = nf_athrs17_hnat_ppp_id;
ppp_peer_ip = nf_athrs17_hnat_ppp_peer_ip;
memcpy(ppp_peer_mac, nf_athrs17_hnat_ppp_peer_mac, ETH_ALEN);
memcpy(ppp_peer_mac2, nf_athrs17_hnat_ppp_peer_mac2, ETH_ALEN);
wvid = wan_fid;
local_irq_restore(flags);
if (NF_S17_WAN_TYPE_PPPOE != nf_athrs17_hnat_wan_type)
{
return SW_BAD_STATE;
}
if (__ipv6_addr_type(&local_lan6ip) == IPV6_ADDR_ANY)
{
/* Cannot get lanip6 successfully. */
return SW_BAD_STATE;
}
if (0xffff == wvid)
{
printk("%s: Cannot get WAN vid!\n", __FUNCTION__);
return SW_FAIL;
}
if (0 == nf_athrs17_hnat_ppp_peer_ip)
{
return SW_FAIL;
}
next_hop = get_ipv6_default_gateway();
if (NULL == next_hop)
{
printk("No IPv6 Gateway!\n");
return SW_BAD_STATE;
}
if (0 != ppp_sid)
{
if ((ppp_sid == ppp_sid2)||(0 == ppp_sid2)) /* v4 and v6 have the same session id */
{
memset(&nh_arp_entry, 0, sizeof(nh_arp_entry));
nh_arp_entry.ip4_addr = ppp_peer_ip;
nh_arp_entry.flags = FAL_IP_IP4_ADDR;
rv = IP_HOST_GET(0, FAL_IP_ENTRY_IPADDR_EN, &nh_arp_entry);
if (rv != SW_OK)
{
printk("%s: IP_HOST_GET error (0x%08x)\n", __func__, ppp_peer_ip);
if (PPPOE_STATUS_GET(0, &ena) != SW_OK)
{
if (!ena)
{
if (PPPOE_STATUS_SET(0, A_TRUE) != SW_OK)
{
aos_printk("Cannot enable the PPPoE mode\n");
return SW_FAIL;
}
}
}
pppoev6_sid_table.session_id = ppp_sid;
pppoev6_sid_table.multi_session = 1;
pppoev6_sid_table.uni_session = 1;
pppoev6_sid_table.entry_id = 0;
/* set the PPPoE edit reg (0x2200), and PPPoE session reg (0x5f000) */
rv = PPPOE_SESSION_TABLE_ADD(0, &pppoev6_sid_table);
if (rv == SW_OK)
{
a_int32_t a_entry_id = -1;
PPPOE_SESSION_ID_SET(0, pppoev6_sid_table.entry_id, pppoev6_sid_table.session_id);
aos_printk("pppoe session: %d, entry_id: %d\n",
pppoev6_sid_table.session_id, pppoev6_sid_table.entry_id);
/* create the peer host ARP entry */
a_entry_id = arp_hw_add(S17_WAN_PORT, wan_fid, (void *)&ppp_peer_ip, (void *)ppp_peer_mac, 0);
if (a_entry_id >= 0) /* hostentry creation okay */
{
rv = IP_HOST_PPPOE_BIND(0, a_entry_id, pppoev6_sid_table.entry_id, A_TRUE);
if ( rv != SW_OK)
{
aos_printk("IP_HOST_PPPOE_BIND failed (entry: %d, rv: %d)... \n",
a_entry_id, rv);
PPPOE_SESSION_TABLE_DEL(0, &pppoev6_sid_table);
return SW_FAIL;
}
droute_entry_id = a_entry_id;
}
else
{
PPPOE_SESSION_TABLE_DEL(0, &pppoev6_sid_table);
return SW_FAIL;
}
}
else
{
aos_printk("PPPoE session add failed.. (id: %d)\n",
pppoev6_sid_table.session_id);
aos_printk("rv: %d\n", rv);
return SW_FAIL;
}
}
else
{
droute_entry_id = nh_arp_entry.entry_id;
}
ipv6_droute_add_acl_rules(&local_lan6ip, droute_entry_id);
}
else /* Not the same session id */
{
if (PPPOE_STATUS_GET(0, &ena) != SW_OK)
{
if (!ena)
{
if (PPPOE_STATUS_SET(0, A_TRUE) != SW_OK)
{
aos_printk("Cannot enable the PPPoE mode\n");
return SW_FAIL;
}
}
}
memset(&nh_arp_entry, 0, sizeof(nh_arp_entry));
memcpy((void *)&nh_arp_entry.ip6_addr, (void *)next_hop, sizeof(nh_arp_entry.ip6_addr));
nh_arp_entry.flags = FAL_IP_IP6_ADDR;
rv = IP_HOST_GET(0, FAL_IP_ENTRY_IPADDR_EN, &nh_arp_entry);
if (rv != SW_OK)
{
/* ARP alread setup. */
return SW_OK;
}
pppoev6_sid_table.session_id = ppp_sid2;
pppoev6_sid_table.multi_session = 1;
pppoev6_sid_table.uni_session = 1;
pppoev6_sid_table.entry_id = 0;
/* set the PPPoE edit reg (0x2200), and PPPoE session reg (0x5f000) */
rv = PPPOE_SESSION_TABLE_ADD(0, &pppoev6_sid_table);
if (rv == SW_OK)
{
a_int32_t a_entry_id = -1;
PPPOE_SESSION_ID_SET(0, pppoev6_sid_table.entry_id, pppoev6_sid_table.session_id);
aos_printk("pppoe session: %d, entry_id: %d\n",
pppoev6_sid_table.session_id, pppoev6_sid_table.entry_id);
/* create the peer host ARP entry */
a_entry_id = arp_hw_add(S17_WAN_PORT, wan_fid, (void *)next_hop, ppp_peer_mac2, 1);
if (a_entry_id >= 0) /* hostentry creation okay */
{
rv = IP_HOST_PPPOE_BIND(0, a_entry_id, pppoev6_sid_table.entry_id, A_TRUE);
if ( rv != SW_OK)
{
aos_printk("IP_HOST_PPPOE_BIND failed (entry: %d, rv: %d)... \n",
a_entry_id, rv);
PPPOE_SESSION_TABLE_DEL(0, &pppoev6_sid_table);
return SW_FAIL;
}
droute_entry_id = a_entry_id;
}
else
{
PPPOE_SESSION_TABLE_DEL(0, &pppoev6_sid_table);
return SW_FAIL;
}
}
else
{
aos_printk("PPPoE session add failed.. (id: %d)\n",
pppoev6_sid_table.session_id);
aos_printk("rv: %d\n", rv);
return SW_FAIL;
}
ipv6_droute_add_acl_rules(&local_lan6ip, droute_entry_id);
}
}
return SW_OK;
}
uint32_t napt_set_ipv6_default_route(void)
{
sw_error_t rv;
static a_bool_t ipv6_droute_setup = A_FALSE;
static struct ipv6_default_route_binding ipv6_droute_bind = {IN6ADDR_ANY_INIT,0};
struct in6_addr local_lan6ip = IN6ADDR_ANY_INIT;
unsigned long flags;
if (((nat_chip_ver&0xffff)>>8) == DESS_CHIP_VER)
return SW_OK;
/* search for the next hop (s)*/
if (NF_S17_WAN_TYPE_IP == nf_athrs17_hnat_wan_type)
{
struct in6_addr *next_hop = get_ipv6_default_gateway();
// printk("IPv6 next hop: %pI6\n", next_hop);
if (next_hop != NULL)
{
fal_host_entry_t ipv6_neigh_entry;
if (__ipv6_addr_type(next_hop) == IPV6_ADDR_LINKLOCAL)
return SW_OK;
local_irq_save(flags);
memcpy(&local_lan6ip, &lan6ip, sizeof(struct in6_addr));
local_irq_restore(flags);
memset(&ipv6_neigh_entry, 0, sizeof(ipv6_neigh_entry));
memcpy(&ipv6_neigh_entry.ip6_addr, next_hop, 16);
ipv6_neigh_entry.flags = FAL_IP_IP6_ADDR;
rv = IP_HOST_GET(0, FAL_IP_ENTRY_IPADDR_EN, &ipv6_neigh_entry);
if ((rv != SW_OK)||(__ipv6_addr_type(&local_lan6ip) == IPV6_ADDR_ANY))
{
if (ipv6_droute_setup)
{
ipv6_droute_del_acl_rules();
memset(&ipv6_droute_bind, 0, sizeof(ipv6_droute_bind));
ipv6_droute_setup = A_FALSE;
}
}
else
{
if (ipv6_droute_setup)
{
if (!ipv6_addr_equal(&ipv6_droute_bind.next_hop, next_hop) ||
ipv6_droute_bind.nh_entry_id != ipv6_neigh_entry.entry_id)
{
ipv6_droute_del_acl_rules();
}
}
ipv6_droute_bind.next_hop = *next_hop;
ipv6_droute_bind.nh_entry_id = ipv6_neigh_entry.entry_id;
ipv6_droute_add_acl_rules(&local_lan6ip, ipv6_neigh_entry.entry_id);
ipv6_droute_setup = A_TRUE;
}
}
else
{
if (ipv6_droute_setup)
{
ipv6_droute_del_acl_rules();
memset(&ipv6_droute_bind, 0, sizeof(ipv6_droute_bind));
ipv6_droute_setup = A_FALSE;
}
}
}
else if (NF_S17_WAN_TYPE_IP == nf_athrs17_hnat_wan_type)
{
add_pppoev6_host_entry();
}
return SW_OK;
}
#endif /* ifdef CONFIG_IPV6_HWACCEL */
static sw_error_t hnat_add_host_route(
fal_ip4_addr_t ip_addr,
uint32_t prefix_len)
{
fal_host_route_t host_route;
memset(&host_route, 0, sizeof(fal_host_route_t));
IP_HOST_ROUTE_GET(0, 0, &host_route);
if ((host_route.route_addr.ip4_addr == ip_addr) &&
(host_route.prefix_length == prefix_len) &&
host_route.valid)
return SW_OK;
host_route.valid = A_TRUE;
host_route.vrf_id = 0;
host_route.ip_version = 0;
host_route.route_addr.ip4_addr = ip_addr;
host_route.prefix_length = prefix_len;
return IP_HOST_ROUTE_ADD(0, 0, &host_route);
}
static sw_error_t setup_interface_entry(char *list_if, int is_wan)
{
char temp[IFNAMSIZ*4]; /* Max 4 interface entries right now. */
char *dev_name, *list_all;
struct net_device *nat_dev;
struct in_device *in_device_lan = NULL, *in_device_wan = NULL;
uint8_t *devmac, if_mac_addr[MAC_LEN];
char *br_name;
uint32_t vid = 0;
sw_error_t setup_error;
uint32_t ipv6 = 0;
memcpy(temp, list_if, strlen(list_if)+1);
list_all = temp;
setup_error = SW_FAIL;
rcu_read_lock();
while ((dev_name = strsep(&list_all, " ")) != NULL)
{
nat_dev = dev_get_by_name(&init_net, dev_name);
if (NULL == nat_dev)
{
// printk("%s: Cannot get device %s by name!\n", __FUNCTION__, dev_name);
setup_error = SW_FAIL;
continue;
}
#if defined (CONFIG_BRIDGE)
#ifdef KVER32
if (NULL != br_port_get_rcu(nat_dev)) /* under bridge interface. */
{
/* Get bridge interface name */
br_name = (char *)(br_port_get_rcu(nat_dev)->br->dev->name);
if (!is_wan) {
strlcat (nat_lan_dev_list, " ", sizeof(nat_lan_dev_list));
strlcat (nat_lan_dev_list, br_name, sizeof(nat_lan_dev_list));
}
/* Get dmac */
devmac = (uint8_t *)(br_port_get_rcu(nat_dev)->br->dev->dev_addr);
}
#else
if (NULL != nat_dev->br_port) /* under bridge interface. */
{
/* Get bridge interface name */
br_name = (char *)nat_dev->br_port->br->dev->name;
//memcpy (nat_bridge_dev, br_name, sizeof(br_name));
strcat (nat_lan_dev_list, " ");
strcat (nat_lan_dev_list, br_name);
/* Get dmac */
devmac = (uint8_t *)nat_dev->br_port->br->dev->dev_addr;
}
#endif
else
#endif /* CONFIG_BRIDGE */
{
devmac = (uint8_t *)nat_dev->dev_addr;
}
/* get vid */
#if 0
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
vid = vlan_dev_vlan_id(nat_dev);
#else
vid = 0;
#endif
#endif
if(is_wan)
vid = nat_wan_vid;
else
vid = nat_lan_vid;
#ifdef CONFIG_IPV6_HWACCEL
ipv6 = 1;
if (is_wan)
{
wan_fid = vid;
}
#else
ipv6 = 0;
if (is_wan)
{
if (NF_S17_WAN_TYPE_PPPOEV6 == nf_athrs17_hnat_wan_type)
ipv6 = 1;
wan_fid = vid;
}
#endif
#ifdef ISISC
if (0 == is_wan) /* Not WAN -> LAN */
{
/* Setup private and netmask as soon as possible */
if (br_port_get_rcu(nat_dev)) /* under bridge interface. */
{
in_device_lan = (struct in_device *) (br_port_get_rcu(nat_dev)->br->dev->ip_ptr);
}
else
{
in_device_lan = (struct in_device *) nat_dev->ip_ptr;
}
if ((in_device_lan) && (in_device_lan->ifa_list))
{
nat_hw_prv_mask_set((a_uint32_t)(in_device_lan->ifa_list->ifa_mask));
nat_hw_prv_base_set((a_uint32_t)(in_device_lan->ifa_list->ifa_address));
#ifndef KVER32
printk("Set private base 0x%08x for %s\n", (a_uint32_t)(in_device_lan->ifa_list->ifa_address), nat_dev->br_port->br->dev->name);
#endif
memcpy(&lanip, (void *)&(in_device_lan->ifa_list->ifa_address), 4); /* copy Lan port IP. */
memcpy(&lanipmask, (void *)&(in_device_lan->ifa_list->ifa_mask), 4);
#ifndef ISISC
redirect_internal_ip_packets_to_cpu_on_wan_add_acl_rules((a_uint32_t)(in_device_lan->ifa_list->ifa_address),
(a_uint32_t)(in_device_lan->ifa_list->ifa_mask));
#endif
}
if(setup_lan_if) {
dev_put(nat_dev);
rcu_read_unlock();
return SW_OK;
} else {
setup_lan_if = 1;
}
}
#endif
if (1 == is_wan) {
if (br_port_get_rcu(nat_dev)) {
in_device_wan = (struct in_device *) (br_port_get_rcu(nat_dev)->br->dev->ip_ptr);
} else {
in_device_wan = (struct in_device *) nat_dev->ip_ptr;
}
if((nf_athrs17_hnat_wan_type == NF_S17_WAN_TYPE_IP) &&
(in_device_wan) && (in_device_wan->ifa_list))
{
a_uint32_t index;
if (((nat_chip_ver&0xffff) >> 8) == DESS_CHIP_VER) {
a_uint32_t ip, len;
ip = in_device_wan->ifa_list->ifa_address & in_device_wan->ifa_list->ifa_mask;
ip = ntohl(ip);
len = 32 - ffs(ntohl(in_device_wan->ifa_list->ifa_mask));
hnat_add_host_route(ip, len);
}
nat_hw_pub_ip_add(ntohl((a_uint32_t)(in_device_wan->ifa_list->ifa_address)),
&index);
HNAT_PRINTK("pubip add 0x%x\n", (a_uint32_t)(in_device_wan->ifa_list->ifa_address));
}
}
memcpy(if_mac_addr, devmac, MAC_LEN);
devmac = if_mac_addr;
dev_put(nat_dev);
if(if_mac_add(devmac, vid, ipv6) != 0)
{
setup_error = SW_FAIL;
continue;
}
else
{
setup_error = SW_OK;
break;
}
}
rcu_read_unlock();
return setup_error;
}
static void setup_dev_list(void)
{
fal_vlan_t entry;
uint32_t tmp_vid = 0xffffffff;
/*get the vlan entry*/
while(1) {
if(SW_OK != VLAN_NEXT(0, tmp_vid, &entry))
break;
tmp_vid = entry.vid;
if(tmp_vid != 0) {
if(entry.mem_ports & nat_wan_port) {
/*wan port*/
HNAT_PRINTK("wan port vid:%d\n", tmp_vid);
nat_wan_vid = tmp_vid;
snprintf(nat_wan_dev_list, IFNAMSIZ*5,
"eth0.%d eth1.%d eth0 pppoe-wan erouter0 br-wan",
tmp_vid, tmp_vid);
} else {
/*lan port*/
HNAT_PRINTK("lan port vid:%d\n", tmp_vid);
nat_lan_vid = tmp_vid;
snprintf(nat_lan_dev_list, IFNAMSIZ*4, "eth0.%d eth1.%d eth1 br-lan",
tmp_vid, tmp_vid);
}
}
}
}
static int setup_all_interface_entry(void)
{
//static int setup_lan_if=0;
static int setup_default_vid = 0;
int i = 0;
setup_dev_list();
if (0 == setup_default_vid)
{
for (i=0; i<7; i++) /* For AR8327/AR8337, only 7 port */
{
#ifdef NAT_TODO /* need to implement here */
PORTVLAN_ROUTE_DEFV_SET(0, i);
#endif
}
setup_default_vid = 1;
}
//if (0 == setup_lan_if)
{
#ifdef ISISC
//MISC_ARP_CMD_SET(0, FAL_MAC_FRWRD); /* Should be put in init function. */
#if 0
MISC_ARP_SP_NOT_FOUND_SET(0, FAL_MAC_RDT_TO_CPU);
#endif
#endif
if (SW_OK == setup_interface_entry(nat_lan_dev_list, 0))
{
//setup_lan_if = 1; /* setup LAN interface entry success */
//printk("Setup LAN interface entry done!\n");
}
}
if (0 == setup_wan_if)
{
if (SW_OK == setup_interface_entry(nat_wan_dev_list, 1))
{
setup_wan_if = 1; /* setup WAN interface entry success */
}
}
if (((nat_chip_ver&0xffff)>>8) == NAT_CHIP_VER_8327) {
if ((nf_athrs17_hnat_wan_type == NF_S17_WAN_TYPE_PPPOE) ||
(nf_athrs17_hnat_wan_type == NF_S17_WAN_TYPE_PPPOEV6))
{
uint8_t buf[6];
memcpy(buf, nf_athrs17_hnat_ppp_peer_mac, ETH_ALEN);
HNAT_PRINTK("Peer MAC: %s ", buf);
/* add the peer interface with VID */
if_mac_add(buf, wan_fid, 0);
HNAT_PRINTK(" --> (%.2x-%.2x-%.2x-%.2x-%.2x-%.2x)\n", \
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
memcpy(&wanip, (void *)&nf_athrs17_hnat_wan_ip, 4);
}
}
return 1;
}
/* check for pppoe session change */
static void isis_pppoe_check_for_redial(void)
{
if (nf_athrs17_hnat_wan_type == NF_S17_WAN_TYPE_IP)
return;
if(((nf_athrs17_hnat_wan_type == NF_S17_WAN_TYPE_PPPOE) \
|| (nf_athrs17_hnat_wan_type == NF_S17_WAN_TYPE_PPPOEV6)) \
&& (pppoetbl.session_id != 0))
{
if(pppoetbl.session_id != nf_athrs17_hnat_ppp_id)
{
aos_printk("%s: PPPoE session ID changed... \n", __func__);
if (nf_athrs17_hnat_wan_type != NF_S17_WAN_TYPE_PPPOEV6)
{
if (PPPOE_SESSION_TABLE_DEL(0, &pppoetbl) != SW_OK)
{
aos_printk("delete old pppoe session %d entry_id %d failed.. \n", pppoetbl.session_id, pppoetbl.entry_id);
return;
}
/* force PPPoE parser for multi- and uni-cast packets; for v1.0.7+ */
pppoetbl.session_id = nf_athrs17_hnat_ppp_id;
pppoetbl.multi_session = 1;
if (((nat_chip_ver & 0xffff)>>8) == NAT_CHIP_VER_8327)
pppoetbl.uni_session = 1;
else
pppoetbl.uni_session = 0;
pppoetbl.entry_id = 0;
/* set the PPPoE edit reg (0x2200), and PPPoE session reg (0x5f000) */
if (PPPOE_SESSION_TABLE_ADD(0, &pppoetbl) == SW_OK)
{
PPPOE_SESSION_ID_SET(0, pppoetbl.entry_id, pppoetbl.session_id);
printk("%s: new pppoe session id: %x, entry_id: %x\n", __func__, pppoetbl.session_id, pppoetbl.entry_id);
}
}
else /* nf_athrs17_hnat_wan_type == NF_S17_WAN_TYPE_PPPOEV6 */
{
/* reset the session Id only */
aos_printk("IPV6 PPPOE mode... \n");
pppoetbl.session_id = nf_athrs17_hnat_ppp_id;
PPPOE_SESSION_ID_SET(0, pppoetbl.entry_id, pppoetbl.session_id);
printk("%s: new pppoe session id: %x, entry_id: %x\n", __func__, pppoetbl.session_id, pppoetbl.entry_id);
}
/* read back the WAN IP */
memcpy(&wanip, (void *)&nf_athrs17_hnat_wan_ip, 4);
aos_printk("Read the WAN IP back... %.8x\n", *(uint32_t *)&wanip);
/* change the PPPoE ACL to ensure the packet is correctly forwarded by the HNAT engine */
pppoe_add_acl_rules(*(uint32_t *)&wanip, *(uint32_t *)&lanip,
*(uint32_t *)&lanipmask, pppoe_gwid);
}
}
}
#ifdef ISIS /* only for S17 */
static void pppoev6_mac6_loop_dev(void)
{
#define PPPOEV6_SESSION_ID 0xfffe
fal_pppoe_session_t ptbl;
sw_error_t rv;
a_uint32_t entry;
memset(&ptbl, 0, sizeof(fal_pppoe_session_t));
aos_printk("%s: set MAC6 as loopback device\n", __func__);
ptbl.session_id = PPPOEV6_SESSION_ID;
ptbl.multi_session = 1;
ptbl.uni_session = 1;
ptbl.entry_id = 0xe;
/* set the PPPoE edit reg (0x2200), and PPPoE session reg (0x5f000) */
if (PPPOE_SESSION_TABLE_ADD(0, &ptbl) == SW_OK)
{
PPPOE_SESSION_ID_SET(0, ptbl.entry_id, ptbl.session_id);
aos_printk("%s: pppoe session id: %d added into entry: %d \n", __func__, ptbl.session_id, ptbl.entry_id);
}
else
{
aos_printk("%s: failed on adding pppoe session id: %d\n", __func__, ptbl.session_id);
}
/* PPPoE entry 0 */
entry = PPPOEV6_SESSION_ID;
REG_ENTRY_SET(rv, 0, PPPOE_EDIT, 0, (a_uint8_t *) (&entry), sizeof (a_uint32_t));
aos_printk("%s: end of function... \n", __func__);
}
static void pppoev6_remove_parser(uint32_t entry_id)
{
sw_error_t rv;
a_uint32_t entry;
aos_printk("%s: clear entry id: %d\n", __func__, entry_id);
/* clear the session id in the PPPoE parser engine */
entry = 0;
REG_ENTRY_SET(rv, 0, PPPOE_SESSION,
entry_id, (a_uint8_t *) (&entry), sizeof (a_uint32_t));
}
#if 0
static void pppoev6_mac6_stop_learning(void)
{
/* do not disable this port if some other registers are already filled in
to prevent setting conflict */
int val = S17_P6PAD_MODE_REG_VALUE;
sw_error_t rv;
a_uint32_t entry;
if ( val != (1<<24))
{
aos_printk("%s: MAC 6 already being used!\n", __FUNCTION__);
return;
}
/* clear the MAC6 learning bit */
REG_ENTRY_GET(rv, 0, PORT_LOOKUP_CTL, 6, (a_uint8_t *) (&entry), sizeof (a_uint32_t));
entry = entry & ~(1<<20);
REG_ENTRY_SET(rv, 0, PORT_LOOKUP_CTL, 6, (a_uint8_t *) (&entry), sizeof (a_uint32_t));
/* force loopback mode */
entry = 0x7e;
REG_ENTRY_SET(rv, 0, PORT_STATUS, 6, (a_uint8_t *) (&entry), sizeof (a_uint32_t));
entry = 0x10;
REG_ENTRY_SET(rv, 0, PORT_HDR_CTL, 6, (a_uint8_t *) (&entry), sizeof (a_uint32_t));
}
#endif
#endif // ifdef ISIS
static int add_pppoe_host_entry(uint32_t sport, a_int32_t arp_entry_id)
{
a_bool_t ena;
int rv = SW_OK;
fal_host_entry_t nh_arp_entry;
if (0xffff == wan_fid)
{
printk("%s: Cannot get WAN vid!\n", __FUNCTION__);
return SW_FAIL;
}
if (PPPOE_STATUS_GET(0, &ena) != SW_OK)
{
aos_printk("Cannot get the PPPoE mode\n");
ena = 0;
}
memset(&nh_arp_entry, 0, sizeof(nh_arp_entry));
nh_arp_entry.ip4_addr = ntohl(nf_athrs17_hnat_ppp_peer_ip);
nh_arp_entry.flags = FAL_IP_IP4_ADDR;
rv = IP_HOST_GET(0, FAL_IP_ENTRY_IPADDR_EN, &nh_arp_entry);
if (SW_OK != rv || pppoetbl.session_id != nf_athrs17_hnat_ppp_id)
{
if ((!ena) && (PPPOE_STATUS_SET(0, A_TRUE) != SW_OK))
aos_printk("Cannot enable the PPPoE mode\n");
aos_printk("PPPoE enable mode: %d\n", ena);
pppoetbl.session_id = nf_athrs17_hnat_ppp_id;
pppoetbl.multi_session = 1;
if (((nat_chip_ver & 0xffff)>>8) == NAT_CHIP_VER_8327)
pppoetbl.uni_session = 1;
else
pppoetbl.uni_session = 0;
pppoetbl.entry_id = 0;
/* set the PPPoE edit reg (0x2200), and PPPoE session reg (0x5f000) */
rv = PPPOE_SESSION_TABLE_ADD(0, &pppoetbl);
if (rv == SW_OK)
{
uint8_t mbuf[6], ibuf[4];
a_int32_t a_entry_id = -1;
a_uint32_t index;
PPPOE_SESSION_ID_SET(0, pppoetbl.entry_id, pppoetbl.session_id);
aos_printk("pppoe session: %d, entry_id: %d\n", pppoetbl.session_id, pppoetbl.entry_id);
if (((nat_chip_ver&0xffff)>>8) == DESS_CHIP_VER) {
hnat_add_host_route(ntohl(nf_athrs17_hnat_wan_ip),
HOST_PREFIX_MAX);
}
/* create the peer host ARP entry */
memcpy(ibuf, (void *)&nf_athrs17_hnat_ppp_peer_ip, 4);
memcpy(mbuf, nf_athrs17_hnat_ppp_peer_mac, ETH_ALEN);
a_entry_id = arp_hw_add(S17_WAN_PORT, wan_fid, ibuf, mbuf, 0);
if (a_entry_id >= 0) /* hostentry creation okay */
{
aos_printk("(1)Bind PPPoE session ID: %d, entry_id: %d to host entry: %d\n", \
pppoetbl.session_id, pppoetbl.entry_id, a_entry_id);
rv = IP_HOST_PPPOE_BIND(0, a_entry_id, pppoetbl.entry_id, A_TRUE);
if ( rv != SW_OK)
{
aos_printk("IP_HOST_PPPOE_BIND failed (entry: %d, rv: %d)... \n", a_entry_id, rv);
}
aos_printk("adding ACLs \n");
pppoe_gwid = a_entry_id;
pppoe_add_acl_rules(nf_athrs17_hnat_wan_ip, *(uint32_t *)&lanip,
*(uint32_t *)&lanipmask, a_entry_id);
nat_hw_pub_ip_add(ntohl(nf_athrs17_hnat_wan_ip), &index);
aos_printk("ACL creation okay... \n");
} else {
HNAT_PRINTK("pppoe arp add fail!\n");
}
}
else
{
aos_printk("PPPoE session add failed.. (id: %d)\n", pppoetbl.session_id);
aos_printk("rv: %d\n", rv);
}
#ifdef ISIS
if (nf_athrs17_hnat_wan_type == NF_S17_WAN_TYPE_PPPOEV6)
{
aos_printk("IPV6 PPPOE mode... (share the same ID with IPV4's)\n");
pppoev6_mac6_loop_dev();
pppoev6_remove_parser(pppoetbl.entry_id);
/* bind the first LAN host to the pseudo PPPoE ID */
rv = IP_HOST_PPPOE_BIND(0, arp_entry_id, 0, A_TRUE);
if ( rv != SW_OK)
{
aos_printk("IP_HOST_PPPOE_BIND failed (entry: %d, rv: %d)... \n", arp_entry_id, rv);
}
}
#endif // ifdef ISIS
}
#ifdef ISIS
else /* ena */
{
if ((nf_athrs17_hnat_wan_type == NF_S17_WAN_TYPE_PPPOEV6) &&
(sport != S17_WAN_PORT)&& (arp_entry_id != 0))
{
aos_printk("IPV6 PPPoE mode\n");
/* bind LAN hosts to the pseudo PPPoE ID */
rv = IP_HOST_PPPOE_BIND(0, arp_entry_id, 0, A_TRUE);
if ( rv != SW_OK)
{
aos_printk("IP_HOST_PPPOE_BIND failed (entry: %d, rv: %d)... \n", arp_entry_id, rv);
}
}
}
#endif // ifdef ISIS
return SW_OK;
}
static int
dev_check(char *in_dev, char *dev_list)
{
char *list_dev;
char temp[100] = {0};
char *list;
if(!in_dev || !dev_list)
{
return 0;
}
strlcpy(temp, dev_list, sizeof(temp));
list = temp;
while ((list_dev = strsep(&list, " ")) != NULL)
{
HNAT_PRINTK("%s: strlen:%d list_dev:%s in_dev:%s\n",
__func__, strlen(list_dev), list_dev, in_dev);
if (!strncmp(list_dev, in_dev, strlen(list_dev)))
{
HNAT_PRINTK("%s: %s\n", __FUNCTION__, list_dev);
return 1;
}
}
return 0;
}
#ifndef ISISC
static uint32_t get_netmask_from_netdevice(const struct net_device *in_net_dev)
{
struct in_device *my_in_device = NULL;
uint32_t result = 0xffffff00;
if((in_net_dev) && (in_net_dev->ip_ptr != NULL))
{
my_in_device = (struct in_device *)(in_net_dev->ip_ptr);
if(my_in_device->ifa_list != NULL)
{
result = my_in_device->ifa_list->ifa_mask;
}
}
return result;
}
#endif
static void hnat_add_neigh(struct neighbour *neigh)
{
struct nat_helper_bg_msg msg;
struct net_device *dev = NULL;
memset(&msg, 0, sizeof(msg));
msg.arp_in.ip = *((uint32_t *)neigh->primary_key);
memcpy(msg.arp_in.mac, neigh->ha, ETH_ALEN);
strlcpy(msg.arp_in.name, neigh->dev->name, IFNAMSIZ);
msg.arp_in.in = neigh->dev;
if (neigh->dev->priv_flags & IFF_EBRIDGE) {
if (!(dev = br_port_dev_get(neigh->dev, neigh->ha, NULL, 0))) {
HNAT_ERR_PRINTK("Failed to find bridge port by [%pM]\n",
neigh->ha);
return ;
}
} else {
dev = neigh->dev;
dev_hold(dev);
}
if (strncmp(dev->name, "eth", strlen("eth")) &&
strncmp(dev->name, "erouter", strlen("erouter"))) {
dev_put(dev);
return ;
}
dev_put(dev);
msg.msg_type = NAT_HELPER_ARP_ADD_MSG;
bg_ring_buf_write(msg);
}
static void hnat_del_neigh(struct neighbour *neigh)
{
struct nat_helper_bg_msg msg;
memset(&msg, 0, sizeof(msg));
msg.arp_in.ip = ntohl(*((uint32_t *)neigh->primary_key));
msg.msg_type = NAT_HELPER_ARP_DEL_MSG;
bg_ring_buf_write(msg);
}
static int hnat_netevent_event(struct notifier_block *unused, unsigned long event, void *ptr)
{
struct neigh_table *tbl;
struct neighbour *neigh;
if (event != NETEVENT_NEIGH_UPDATE)
return NOTIFY_DONE;
neigh = ptr;
tbl = neigh->tbl;
if (tbl->family != AF_INET)
return NOTIFY_DONE;
HNAT_PRINTK("netevent state %d for ip[%pI4]\n",
neigh->nud_state, (uint32_t *)neigh->primary_key);
if (neigh->nud_state & NUD_VALID) {
if (neigh->nud_state & NUD_NOARP) {
return NOTIFY_DONE;
}
HNAT_PRINTK("New ARP entry ip[%pI4] mac[%pM]\n",
(uint32_t *)neigh->primary_key, neigh->ha);
hnat_add_neigh(neigh);
} else {
HNAT_PRINTK("Del ARP entry ip[%pI4] mac[%pM] with status[%d]\n",
(uint32_t *)neigh->primary_key, neigh->ha, neigh->nud_state);
hnat_del_neigh(neigh);
}
return NOTIFY_DONE;
}
#ifdef NAT_BACKGROUND_TASK
static unsigned int
arp_del(struct nat_helper_bg_msg *msg)
{
fal_host_entry_t host;
memset(&host, 0, sizeof(host));
if (!nat_hw_prv_base_is_match(msg->arp_in.ip))
return 0;
if (napt_hw_get_by_sip(msg->arp_in.ip)) {
host.flags |= FAL_IP_IP4_ADDR;
host.ip4_addr = msg->arp_in.ip;
IP_HOST_DEL(0, FAL_IP_ENTRY_IPADDR_EN, &host);
}
return 0;
}
static unsigned int
arp_add(struct nat_helper_bg_msg *msg)
{
uint8_t *smac;
uint8_t dev_is_lan = 0;
uint32_t sport = 0, vid = 0;
a_bool_t prvbasemode = 1;
sw_error_t rv = SW_OK;
struct arp_in_msg *arp_info = &msg->arp_in;
a_int32_t arp_entry_id = -1;
fal_fdb_entry_t entry;
/* check for PPPoE redial here, to reduce overheads */
isis_pppoe_check_for_redial();
/* do not write out host table if HNAT is disabled */
if (!nf_athrs17_hnat)
return 0;
setup_all_interface_entry();
if(dev_check((char *)arp_info->name, (char *)nat_wan_dev_list))
{
}
else if (dev_check((char *)arp_info->name, (char *)nat_lan_dev_list))
{
dev_is_lan = 1;
}
else
{
HNAT_INFO_PRINTK("Not Support device: %s\n", (char *)arp_info->name);
return 0;
}
if(dev_is_lan) {
vid = nat_lan_vid;
} else {
vid = nat_wan_vid;
}
memset(&entry, 0, sizeof(entry));
entry.fid = vid;
smac = arp_info->mac;
aos_mem_copy(&(entry.addr), smac, sizeof(fal_mac_addr_t));
if(FDB_ENTRY_SEARCH(0, &entry) == SW_OK) {
vid = entry.fid;
sport = 0;
while (sport < 32) {
if(entry.port.map & (1 << sport)) {
break;
}
sport++;
}
} else {
HNAT_PRINTK("not find the FDB entry\n");
}
if (sport == 0) {
HNAT_PRINTK("Not the expected arp, ignore it!\n");
return 0;
}
arp_entry_id = arp_hw_add(sport, vid, (a_uint8_t *)&arp_info->ip, smac, 0);
if(arp_entry_id < 0)
{
HNAT_ERR_PRINTK("ARP entry error!!\n");
return 0;
}
if (0 == dev_is_lan)
{
struct in_device *in_dev;
in_dev = __in_dev_get_rtnl(arp_info->in);
if (in_dev) {
if (in_dev->ifa_list) {
*(uint32_t *)&wanip = ntohl(in_dev->ifa_list->ifa_local);
}
}
#ifdef MULTIROUTE_WR
wan_nh_add((u_int8_t *)&arp_info->ip, smac, arp_entry_id);
#endif
}
if(dev_is_lan && nat_hw_prv_base_can_update())
{
nat_hw_flush();
nat_hw_prv_base_update_disable();
#ifdef MULTIROUTE_WR
//multi_route_indev = in;
#endif
}
multi_route_indev = arp_info->in;
if ((nf_athrs17_hnat_wan_type == NF_S17_WAN_TYPE_PPPOE) ||
(nf_athrs17_hnat_wan_type == NF_S17_WAN_TYPE_PPPOEV6))
{
add_pppoe_host_entry(sport, arp_entry_id);
}
if (((nat_chip_ver & 0xffff)>>8) != NAT_CHIP_VER_8327)
return 1;
/* check for SIP and DIP range */
if ((lanip[0] != 0) && (wanip[0] != 0))
{
rv = NAT_PRV_ADDR_MODE_GET(0, &prvbasemode);
if (rv == SW_NOT_SUPPORTED || rv == SW_NOT_INITIALIZED) {
return 1;
}
else if (rv != SW_OK) {
aos_printk("Private IP base mode check failed: %d\n", prvbasemode);
}
if (!prvbasemode) /* mode 0 */
{
if ((lanip[0] == wanip[0]) && (lanip[1] == wanip[1]))
{
if ((lanip[2] & 0xf0) == (wanip[2] & 0xf0))
{
if (get_aclrulemask()& (1 << S17_ACL_LIST_IPCONF))
return 0;
aos_printk("LAN IP and WAN IP conflict... \n");
/* set h/w acl to filter out this case */
#ifdef MULTIROUTE_WR
// if ( (wan_nh_ent[0].host_ip != 0) && (wan_nh_ent[0].entry_id != 0))
if ( (wan_nh_ent[0].host_ip != 0))
ip_conflict_add_acl_rules(*(uint32_t *)&wanip, *(uint32_t *)&lanip, wan_nh_ent[0].entry_id);
#endif
return 0;
}
}
}
else /* mode 1*/
{
;; /* do nothing */
}
}
return 1;
}
#endif
static struct notifier_block hnat_netevent_notifier = {
.notifier_call = hnat_netevent_event,
};
#ifdef AUTO_UPDATE_PPPOE_INFO
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0))
struct prv_ppp_file {
int k;
struct sk_buff_head xmitq;
struct sk_buff_head recvq;
wait_queue_head_t wait;
atomic_t cnt;
int hlen;
int idx;
int d;
};
struct prv_ppp {
struct prv_ppp_file file;
char *o;
struct list_head channels;
int n_channels;
spinlock_t rlock;
spinlock_t wlock;
int m;
unsigned int flags;
unsigned int xmitstate;
unsigned int recvstate;
int d;
char *vj;
int mode[6];
struct sk_buff *xpending;
char *xcmp;
void *xstate;
char *rcmp;
void *rstate;
unsigned long l_xmit;
unsigned long l_recv;
struct net_device *dev;
int resv1;
#ifdef CONFIG_PPP_MULTILINK
int resv2;
u32 resv3;
int resv4;
u32 resv5;
u32 resv6;
struct sk_buff_head rq;
#endif /* CONFIG_PPP_MULTILINK */
#ifdef CONFIG_PPP_FILTER
char *p_filter;
char *a_filter;
unsigned p_len, a_len;
#endif /* CONFIG_PPP_FILTER */
char *pnet;
};
struct prv_channel {
struct prv_ppp_file file;
struct list_head list;
struct ppp_channel *chan;
struct rw_semaphore sem;
spinlock_t downlock;
struct prv_ppp *ppp;
char *cnet;
struct list_head clist;
rwlock_t uplock;
#ifdef CONFIG_PPP_MULTILINK
u8 resv1;
u8 resv2;
u32 resv3;
int resv4;
#endif
};
#endif
static int qcaswitch_pppoe_ip_event(struct notifier_block *this,
unsigned long event, void *ptr)
{
struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
struct net_device *dev = (struct net_device *)ifa->ifa_dev->dev;
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0))
struct list_head *list;
struct prv_channel *pch;
struct prv_ppp *ppp = netdev_priv(dev);
#endif
struct sock *sk;
struct pppox_sock *po;
static int connection_count = 0;
fal_pppoe_session_t del_pppoetbl;
int channel_count;
struct ppp_channel *ppp_chan[1];
int channel_protocol;
if (!((dev->type == ARPHRD_PPP) && (dev->flags & IFF_POINTOPOINT)))
return NOTIFY_DONE;
if (dev_net(dev) != &init_net)
return NOTIFY_DONE;
setup_all_interface_entry();
switch (event)
{
case NETDEV_UP:
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0))
if (ppp_is_multilink(dev) == 0) {
/* not doing multilink: send it down the first channel */
channel_count = ppp_hold_channels(dev, ppp_chan, 1);
if (channel_count != 1)
return NOTIFY_DONE;
channel_protocol = ppp_channel_get_protocol(ppp_chan[0]);
if (channel_protocol == PX_PROTO_OE)
{
if (ppp_chan[0]->private)
{
/* the NETDEV_UP event will be sent many times
* because of ifa operation ifa->ifa_local != ifa->ifa_address
* means that remote ip is really added.
*/
if (ifa->ifa_local == ifa->ifa_address)
{
ppp_release_channels(ppp_chan, 1);
return NOTIFY_DONE;
}
sk = (struct sock *)(ppp_chan[0]->private);
po = (struct pppox_sock*)sk;
connection_count++;
if (((NF_S17_WAN_TYPE_PPPOE == nf_athrs17_hnat_wan_type) &&
(0 != nf_athrs17_hnat_ppp_id))) /* another session for IPv6 */
{
nf_athrs17_hnat_ppp_id2 = ntohs(po->proto.pppoe.pa.sid);
memcpy(nf_athrs17_hnat_ppp_peer_mac2,
po->proto.pppoe.pa.remote, ETH_ALEN);
} else {
nf_athrs17_hnat_wan_type = NF_S17_WAN_TYPE_PPPOE;
nf_athrs17_hnat_wan_ip = ifa->ifa_local;
nf_athrs17_hnat_ppp_peer_ip = ifa->ifa_address;
memcpy(nf_athrs17_hnat_ppp_peer_mac,
po->pppoe_pa.remote, ETH_ALEN);
nf_athrs17_hnat_ppp_id = ntohs(po->pppoe_pa.sid);
}
ppp_release_channels(ppp_chan, 1);
} else {
ppp_release_channels(ppp_chan, 1);
/* channel got unregistered */
return NOTIFY_DONE;
}
} else {
ppp_release_channels(ppp_chan, 1);
/* channel got unregistered */
return NOTIFY_DONE;
}
}
#else
//struct prv_ppp *ppp = netdev_priv(dev);
//struct prv_channel *pch;
list = &ppp->channels;
if (list_empty(list))
return NOTIFY_DONE;
if ((ppp->flags & SC_MULTILINK) == 0) {
list = list->next;
pch = list_entry(list, struct prv_channel, clist);
if (pch->chan)
{
if (pch->chan->private) {
if (ifa->ifa_local == ifa->ifa_address)
return NOTIFY_DONE;
sk = (struct sock *)pch->chan->private;
po = (struct pppox_sock*)sk;
connection_count++;
if (((NF_S17_WAN_TYPE_PPPOE == nf_athrs17_hnat_wan_type) &&
(0 != nf_athrs17_hnat_ppp_id)))
{
nf_athrs17_hnat_ppp_id2 = po->num;
memcpy(nf_athrs17_hnat_ppp_peer_mac2, po->pppoe_pa.remote, ETH_ALEN);
}
else
{
nf_athrs17_hnat_wan_type = NF_S17_WAN_TYPE_PPPOE;
nf_athrs17_hnat_wan_ip = ifa->ifa_local;
nf_athrs17_hnat_ppp_peer_ip = ifa->ifa_address;
memcpy(nf_athrs17_hnat_ppp_peer_mac, po->pppoe_pa.remote, ETH_ALEN);
nf_athrs17_hnat_ppp_id = ntohs(po->pppoe_pa.sid);
}
}
}
else
{
return NOTIFY_DONE;
}
}
#endif
break;
case NETDEV_DOWN:
if (NF_S17_WAN_TYPE_PPPOE != nf_athrs17_hnat_wan_type)
{
return NOTIFY_DONE;
}
connection_count--;
if (ifa->ifa_local == nf_athrs17_hnat_wan_ip)
{
/* PPPoE Interface really down */
ipv6_droute_del_acl_rules();
del_pppoetbl.session_id = nf_athrs17_hnat_ppp_id;
del_pppoetbl.multi_session = 1;
if (((nat_chip_ver & 0xffff)>>8) == NAT_CHIP_VER_8327)
del_pppoetbl.uni_session = 1;
else
del_pppoetbl.uni_session = 0;
del_pppoetbl.entry_id = 0;
PPPOE_SESSION_TABLE_DEL(0, &del_pppoetbl);
memset(&pppoetbl, 0, sizeof(pppoetbl));
nf_athrs17_hnat_wan_type = NF_S17_WAN_TYPE_IP;
nf_athrs17_hnat_wan_ip = 0;
nf_athrs17_hnat_ppp_peer_ip = 0;
nf_athrs17_hnat_ppp_id = 0;
memset(&nf_athrs17_hnat_ppp_peer_mac, 0, ETH_ALEN);
}
else
{
if (0 != nf_athrs17_hnat_ppp_id2)
{
del_pppoetbl.session_id = nf_athrs17_hnat_ppp_id2;
del_pppoetbl.multi_session = 1;
if (((nat_chip_ver & 0xffff)>>8) == NAT_CHIP_VER_8327)
del_pppoetbl.uni_session = 1;
else
del_pppoetbl.uni_session = 0;
del_pppoetbl.entry_id = 0;
PPPOE_SESSION_TABLE_DEL(0, &del_pppoetbl);
memset(&pppoetbl, 0, sizeof(pppoetbl));
}
nf_athrs17_hnat_ppp_id2 = 0;
memset(&nf_athrs17_hnat_ppp_peer_mac2, 0, ETH_ALEN);
}
qcaswitch_hostentry_flush();
break;
default:
break;
}
return NOTIFY_DONE;
}
/* a linux interface is configured with ipaddr, then
* it becomes a L3 routing interface
* add the router mac of this interface to the table
*/
/* FIXME: only hande pppoe event right now. */
static int qcaswitch_ip_event(struct notifier_block *this,
unsigned long event, void *ptr)
{
struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
struct net_device *dev = (struct net_device *)ifa->ifa_dev->dev;
if ((dev->type == ARPHRD_PPP) && (dev->flags & IFF_POINTOPOINT))
{
return qcaswitch_pppoe_ip_event(this, event, ptr);
}
return NOTIFY_DONE;
}
static struct notifier_block qcaswitch_ip_notifier =
{
.notifier_call = qcaswitch_ip_event,
.priority = 100,
};
#endif // ifdef AUTO_UPDATE_PPPOE_INFO
#define HOST_AGEOUT_STATUS 1
void host_check_aging(void)
{
fal_host_entry_t *host_entry_p, host_entry= {0};
sw_error_t rv;
int cnt = 0;
unsigned long flags;
fal_napt_entry_t src_napt = {0}, pub_napt = {0};
host_entry_p = &host_entry;
host_entry_p->entry_id = FAL_NEXT_ENTRY_FIRST_ID;
/*check host is not neccessary, check napt is enough*/
return;
local_irq_save(flags);
while (1)
{
host_entry_p->status = HOST_AGEOUT_STATUS;
/* FIXME: now device id is set to 0. */
rv = IP_HOST_NEXT (0, FAL_IP_ENTRY_STATUS_EN, host_entry_p);
// rv = IP_HOST_NEXT (0, 0, host_entry_p);
if (SW_OK != rv)
break;
if (cnt >= ARP_ENTRY_MAX) // arp entry number
break;
if (ARP_AGE_NEVER == host_entry_p->status)
continue;
if ((S17_WAN_PORT == host_entry_p->port_id) &&
(host_entry_p->counter_en))
{
if (0 != host_entry_p->packet)
{
// arp entry is using, update it.
host_entry.status = ARP_AGE;
printk("Update WAN port hostentry!\n");
IP_HOST_ADD(0, host_entry_p);
}
else
{
printk("Del WAN port hostentry!\n");
IP_HOST_DEL(0, FAL_IP_ENTRY_IPADDR_EN, host_entry_p);
}
continue;
}
src_napt.entry_id = FAL_NEXT_ENTRY_FIRST_ID;
memcpy(&src_napt.src_addr, &host_entry_p->ip4_addr, sizeof(fal_ip4_addr_t));
pub_napt.entry_id = FAL_NEXT_ENTRY_FIRST_ID;
memcpy(&pub_napt.trans_addr, &host_entry_p->ip4_addr, sizeof(fal_ip4_addr_t));
if((NAPT_NEXT(0, FAL_NAT_ENTRY_SOURCE_IP_EN ,&src_napt) !=0) && \
(NAPT_NEXT(0, FAL_NAT_ENTRY_PUBLIC_IP_EN ,&pub_napt) != 0))
{
/* Cannot find naptentry */
printk("ARP id 0x%x: Cannot find NAPT entry!\n", host_entry_p->entry_id);
IP_HOST_DEL(0, FAL_IP_ENTRY_IPADDR_EN, host_entry_p);
continue;
}
// arp entry is using, update it.
host_entry_p->status = ARP_AGE;
IP_HOST_ADD(0, host_entry_p);
printk("update entry 0x%x port %d\n", host_entry_p->entry_id, host_entry_p->port_id);
cnt++;
}
local_irq_restore(flags);
}
#ifdef CONFIG_IPV6_HWACCEL
#define IPV6_LEN 16
#define MAC_LEN 6
#define PROTO_ICMPV6 0x3a
#define NEIGHBOUR_SOL 135
#define NEIGHBOUR_AD 136
struct icmpv6_option
{
__u8 type;
__u8 len;
__u8 mac[MAC_LEN];
};
#if 0
static unsigned int ipv6_handle(unsigned int hooknum,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
struct sk_buff *new_skb = NULL;
struct nat_helper_bg_msg msg;
/*unsigned long flags = 0;*/
if (!nf_athrs17_hnat)
return NF_ACCEPT;
new_skb = skb_clone(skb, GFP_ATOMIC);
if(new_skb) {
memset(&msg, 0, sizeof(msg));
msg.msg_type = NAT_HELPER_IPV6_MSG;
msg.ipv6.skb = new_skb;
msg.ipv6.in = (struct net_device *)in;
/*send msgto background task*/
/*spin_lock_irqsave(&task_cb.bg_lock, flags);*/
if(bg_ring_buf_write(msg))
kfree_skb(new_skb);
/*spin_unlock_irqrestore(&task_cb.bg_lock, flags);*/
}
return NF_ACCEPT;
}
#endif
#ifdef NAT_BACKGROUND_TASK
static unsigned int ipv6_bg_handle(struct nat_helper_bg_msg *msg)
{
struct net_device *in = msg->arp_in.in;
struct sk_buff *skb = msg->arp_in.skb;
struct ipv6hdr *iph6 = ipv6_hdr(skb);
struct icmp6hdr *icmp6 = icmp6_hdr(skb);
__u8 *sip = ((__u8 *)icmp6)+sizeof(struct icmp6hdr);
struct icmpv6_option *icmpv6_opt = (struct icmpv6_option *)(sip+IPV6_LEN);
__u8 *sa = icmpv6_opt->mac;
uint32_t sport = 0, vid = 0;
struct inet6_ifaddr *in_device_addr = NULL;
uint8_t dev_is_lan = 0;
uint8_t *smac;
/* do not write out host table if HNAT is disabled */
if (!nf_athrs17_hnat)
return 0;
setup_all_interface_entry();
if(dev_check((char *)in->name, (char *)nat_wan_dev_list))
{
dev_is_lan = 0;
}
else if (dev_check((char *)in->name, (char *)nat_lan_dev_list))
{
dev_is_lan = 1;
}
else
{
HNAT_PRINTK("Not Support device: %s\n", (char *)in->name);
return 0;
}
if(PROTO_ICMPV6 == iph6->nexthdr)
{
if(NEIGHBOUR_AD == icmp6->icmp6_type)
{
fal_fdb_entry_t entry;
if (__ipv6_addr_type((struct in6_addr*)sip) & IPV6_ADDR_LINKLOCAL)
return 0;
#ifdef AP136_QCA_HEADER_EN
if(arp_if_info_get((void *)(skb->head), &sport, &vid) != 0)
{
return 0;
}
if ((0 == vid)||(0 == sport))
{
printk("Error: Null sport or vid!!\n");
return 0;
}
#else
if(dev_is_lan) {
vid = NAT_LAN_DEV_VID;
} else {
vid = NAT_WAN_DEV_VID;
}
memset(&entry, 0, sizeof(entry));
entry.fid = vid;
smac = skb_mac_header(skb) + MAC_LEN;
aos_mem_copy(&(entry.addr), smac, sizeof(fal_mac_addr_t));
if(FDB_ENTRY_SEARCH(0, &entry) == SW_OK) {
vid = entry.fid;
sport = 0;
while (sport < 32) {
if(entry.port.map & (1 << sport)) {
break;
}
sport++;
}
} else {
printk("not find the FDB entry\n");
}
#endif
if ((0 == dev_is_lan) && (S17_WAN_PORT != sport))
{
printk("Error: WAN port %d\n", sport);
return 0;
}
HNAT_PRINTK("ND Reply %x %x\n",icmpv6_opt->type,icmpv6_opt->len);
HNAT_PRINTK("isis_v6: incoming packet, sip = %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\n"
,sip[0],sip[1],sip[2],sip[3],sip[4],sip[5],sip[6],sip[7]
,sip[8],sip[9],sip[10],sip[11],sip[12],sip[13],sip[14],sip[15]
);
HNAT_PRINTK("isis_v6: incoming packet, sa = %.2x-%.2x-%.2x-%.2x-%.2x-%.2x\n", sa[0], sa[1], sa[2], sa[3], sa[4], sa[5]);
HNAT_PRINTK("isis_v6: vid = %d sport = %d\n", vid, sport);
//add nd entry
if((2 == icmpv6_opt->type) && (1 == icmpv6_opt->len))
{
arp_hw_add(sport, vid, sip, sa, 1);
}
else /* ND AD packets without option filed? Fix Me!! */
{
sa = skb_mac_header(skb) + MAC_LEN;
HNAT_PRINTK("isis_v6 Changed sa = %.2x-%.2x-%.2x-%.2x-%.2x-%.2x\n", sa[0], sa[1], sa[2], sa[3], sa[4], sa[5]);
arp_hw_add(sport, vid, sip, sa, 1);
}
#ifdef NAT_TODO /* should be ok */
if ((NULL != in->ip6_ptr) && (NULL != ((struct inet6_dev *)in->ip6_ptr)->addr_list))
#else
if (NULL != in->ip6_ptr)
#endif
{
//list_for_each_entry(in_device_addr, &(in->ip6_ptr)->addr_list, if_list);
struct inet6_dev *idev = __in6_dev_get(in);
list_for_each_entry(in_device_addr, &idev->addr_list, if_list) {
if (in_device_addr->scope == 0 &&
!(in_device_addr->flags & IFA_F_TENTATIVE)) {
break;
}
}
if (0 == dev_is_lan)
{
/* WAN ipv6 address*/
memcpy(&wan6ip, (__u8 *)&in_device_addr->addr, sizeof(struct in6_addr));
HNAT_PRINTK("%s: ipv6 wanip %pI6\n", in->name, &wan6ip);
}
else
{
/* LAN ipv6 address*/
memcpy(&lan6ip, (__u8 *)&in_device_addr->addr, sizeof(struct in6_addr));
HNAT_PRINTK("%s: ipv6 lanip %pI6\n", in->name, &lan6ip);
}
}
}
}
return 1;
}
#endif
#if 0
static struct nf_hook_ops ipv6_inhook =
{
.hook = ipv6_handle,
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,4,0))
.owner = THIS_MODULE,
#endif
.pf = PF_INET6,
.hooknum = NF_INET_PRE_ROUTING,
.priority = NF_IP6_PRI_CONNTRACK,
};
#endif
#endif /* CONFIG_IPV6_HWACCEL */
#ifdef NAT_BACKGROUND_TASK
static void nat_task_entry(struct work_struct *wq)
{
struct nat_helper_bg_msg msg;
/*unsigned long flags = 0;*/
unsigned int result = 0;
msg = *(struct nat_helper_bg_msg *)wq;
/*spin_lock_irqsave(&task_cb.bg_lock, flags);*/
bg_ring_buf_read(NULL);
/*spin_unlock_irqrestore(&task_cb.bg_lock, flags);*/
if(msg.msg_type == NAT_HELPER_ARP_ADD_MSG) {
result = arp_add(&msg);
} else if (msg.msg_type == NAT_HELPER_ARP_DEL_MSG) {
result = arp_del(&msg);
}
#ifdef CONFIG_IPV6_HWACCEL
else if(msg.msg_type == NAT_HELPER_IPV6_MSG) {
result = ipv6_bg_handle(&msg);
}
#endif
HNAT_PRINTK("handle msg: %d, result: %d\n", msg.msg_type, result);
}
void nat_helper_bg_task_init()
{
unsigned int i = 0;
struct nat_helper_bg_msg *msg;
/*create the thread and alloc ring buffer*/
memset(&task_cb, 0, sizeof(task_cb));
task_cb.nat_wq = create_singlethread_workqueue("nat_wq");
if(!task_cb.nat_wq)
{
aos_printk("create nat workqueuefail\n");
return;
}
/*init lock and alloc the ring buffer*/
/*sema_init(&task_cb.bg_sem, 0);*/
spin_lock_init(&task_cb.bg_lock);
task_cb.ring.num = NAT_HELPER_MSG_MAX;
task_cb.ring.buf = kzalloc(NAT_HELPER_MSG_MAX * sizeof(struct nat_helper_bg_msg), GFP_ATOMIC);
if(!task_cb.ring.buf) {
aos_printk("ring buf alloc fail!\n");
return;
}
msg = (struct nat_helper_bg_msg*)task_cb.ring.buf;
for(i = 0; i < task_cb.ring.num; i++)
{
INIT_WORK(&msg[i].work, nat_task_entry);
}
aos_printk("bg task init successfull!\n");
}
void nat_helper_bg_task_exit()
{
/*stop the workqueue and release the ring buffer*/
if(task_cb.nat_wq)
destroy_workqueue(task_cb.nat_wq);
if(task_cb.ring.buf)
kfree(task_cb.ring.buf);
}
#endif
extern int napt_procfs_init(void);
extern void napt_procfs_exit(void);
void host_helper_init(a_uint32_t portbmp)
{
REG_GET(0, 0, (a_uint8_t *)&nat_chip_ver, 4);
/* header len 4 with type 0xaaaa */
HEADER_TYPE_SET(0, A_TRUE, 0xaaaa);
if (((nat_chip_ver & 0xffff)>>8) == NAT_CHIP_VER_8337 ||
((nat_chip_ver & 0xffff)>>8) == NAT_CHIP_VER_DESS) {
/* For S17c (ISISC), it is not necessary to make all frame with header */
printk("host_helper_init start\n");
//PORT_TXHDR_MODE_SET(0, 0, FAL_ONLY_MANAGE_FRAME_EN);
/* Fix tag disappear problem, set TO_CPU_VID_CHG_EN, 0xc00 bit1 */
CPU_VID_EN_SET(0, A_TRUE);
/* set RM_RTD_PPPOE_EN, 0xc00 bit0 */
RTD_PPPOE_EN_SET(0, A_TRUE);
/* Avoid ARP response storm for HUB, now this fix only apply on PORT5 */
#if 0
MISC_ARP_SP_NOT_FOUND_SET(0, FAL_MAC_RDT_TO_CPU);
MISC_ARP_GUARD_SET(0, S17_WAN_PORT, FAL_MAC_IP_PORT_GUARD);
#endif
/* set VLAN_TRANS_TEST register bit, to block packets from WAN port has private dip */
NETISOLATE_SET(0, A_TRUE);
} else {
PORT_TXHDR_MODE_SET(0, 0, FAL_ALL_TYPE_FRAME_EN);
}
CPU_PORT_STATUS_SET(0, A_TRUE);
IP_ROUTE_STATUS_SET(0, A_TRUE);
napt_procfs_init();
memcpy(nat_bridge_dev, nat_lan_dev_list, strlen(nat_lan_dev_list)+1);
register_netevent_notifier(&hnat_netevent_notifier);
/*hnat not upport ipv6*/
#if 0
#ifdef CONFIG_IPV6_HWACCEL
aos_printk("Registering IPv6 hooks... \n");
nf_register_hook(&ipv6_inhook);
#endif
#endif
#ifdef AUTO_UPDATE_PPPOE_INFO
register_inetaddr_notifier(&qcaswitch_ip_notifier);
#endif // ifdef AUTO_UPDATE_PPPOE_INFO
nat_wan_port = portbmp;
/* Enable ACLs to handle MLD packets */
upnp_ssdp_add_acl_rules();
ipv6_snooping_solicted_node_add_acl_rules();
ipv6_snooping_sextuple0_group_add_acl_rules();
ipv6_snooping_quintruple0_1_group_add_acl_rules();
napt_helper_hsl_init();
}
void host_helper_exit(void)
{
napt_procfs_exit();
unregister_netevent_notifier(&hnat_netevent_notifier);
#if 0
#ifdef CONFIG_IPV6_HWACCEL
nf_unregister_hook(&ipv6_inhook);
#endif
#endif
#ifdef AUTO_UPDATE_PPPOE_INFO
unregister_inetaddr_notifier(&qcaswitch_ip_notifier);
#endif
}