diff options
author | Ludovic Pouzenc <ludovic@pouzenc.fr> | 2018-09-14 23:55:51 +0200 |
---|---|---|
committer | Ludovic Pouzenc <ludovic@pouzenc.fr> | 2018-09-14 23:55:51 +0200 |
commit | ec7f575de8a5e23b2e53dd4099d54e719e0319a6 (patch) | |
tree | 0810f2af1827b88334f366acd85a2c0c878d59ad /target | |
parent | b1de0730aebffb68c8fc6283860ad6cb5c2b3e30 (diff) | |
download | mtk-20170518-ec7f575de8a5e23b2e53dd4099d54e719e0319a6.zip mtk-20170518-ec7f575de8a5e23b2e53dd4099d54e719e0319a6.tar.gz mtk-20170518-ec7f575de8a5e23b2e53dd4099d54e719e0319a6.tar.bz2 |
target/linux/mediatek: add dirty Mediatek module wifi_fwd IPv4 port 53 (dns) and 67 (dhcp), IPv6 port 53
Diffstat (limited to 'target')
-rw-r--r-- | target/linux/mediatek/patches/1018-wifi-forward.patch | 5715 |
1 files changed, 5715 insertions, 0 deletions
diff --git a/target/linux/mediatek/patches/1018-wifi-forward.patch b/target/linux/mediatek/patches/1018-wifi-forward.patch new file mode 100644 index 0000000..e40773b --- /dev/null +++ b/target/linux/mediatek/patches/1018-wifi-forward.patch @@ -0,0 +1,5715 @@ +Index: linux-3.10.20/drivers/net/wireless/wifi_forward/wifi_fwd/Kconfig +=================================================================== +--- /dev/null ++++ linux-3.10.20/drivers/net/wireless/wifi_forward/wifi_fwd/Kconfig +@@ -0,0 +1 @@ ++ +Index: linux-3.10.20/drivers/net/wireless/wifi_forward/wifi_fwd/Makefile +=================================================================== +--- /dev/null ++++ linux-3.10.20/drivers/net/wireless/wifi_forward/wifi_fwd/Makefile +@@ -0,0 +1 @@ ++obj-$(CONFIG_WIFI_PKT_FWD) += wifi_fwd.o +Index: linux-3.10.20/drivers/net/wireless/wifi_forward/wifi_fwd/wifi_fwd.c +=================================================================== +--- /dev/null ++++ linux-3.10.20/drivers/net/wireless/wifi_forward/wifi_fwd/wifi_fwd.c +@@ -0,0 +1,2726 @@ ++/**************************************************************************** ++ * Mediatek Inc. ++ * 5F., No.5, Taiyuan 1st St., Zhubei City, ++ * Hsinchu County 302, Taiwan, R.O.C. ++ * (c) Copyright 2014, Mediatek, Inc. ++ * ++ * All rights reserved. Ralink's source code is an unpublished work and the ++ * use of a copyright notice does not imply otherwise. This source code ++ * contains confidential trade secret material of Ralink Tech. Any attemp ++ * or participation in deciphering, decoding, reverse engineering or in any ++ * way altering the source code is stricitly prohibited, unless the prior ++ * written consent of Ralink Technology, Inc. is obtained. ++ **************************************************************************** ++ ++ Module Name: ++ wifi_fwd.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Annie Lu 2014-06-30 Initial version ++ */ ++ ++#include "wifi_fwd.h" ++ ++struct net_device *ap_2g = NULL, *apcli_2g = NULL, *ap_5g = NULL, *apcli_5g = NULL, *br_lan = NULL; ++struct net_device *ap1_2g = NULL, *apcli1_2g = NULL, *ap1_5g = NULL, *apcli1_5g = NULL; ++struct FwdPair *WiFiFwdBase = NULL; ++struct DevInfo *FwdDevice = NULL; ++struct PacketSource *pkt_src = NULL; ++struct TxSourceEntry *tx_src_tbl = NULL; ++unsigned int tx_src_count = 0; /* count the value of tx_src_tbl */ ++ ++/* currently supports up to 3 */ ++void * adapter_tmp_1 = NULL; ++void * adapter_tmp_2 = NULL; ++void * adapter_tmp_3 = NULL; ++ ++unsigned char wf_debug_level; ++static unsigned long wifi_fwd_op_flag; ++static unsigned char rep_net_dev; ++ ++static unsigned char next_2g_band; ++static unsigned char fwd_counter; ++static signed char main_5g_h_link_cnt; ++static signed char main_5g_link_cnt; ++static signed char main_2g_link_cnt; ++ ++static unsigned int eth_rep5g_h_wrg_uni_cnt; ++static unsigned int eth_rep5g_h_wrg_bct_cnt; ++static unsigned int eth_rep5g_wrg_uni_cnt; ++static unsigned int eth_rep5g_wrg_bct_cnt; ++static unsigned int eth_rep2g_wrg_uni_cnt; ++static unsigned int eth_rep2g_wrg_bct_cnt; ++ ++static unsigned int band_cb_offset; ++static unsigned int recv_from_cb_offset; ++ ++REPEATER_ADAPTER_DATA_TABLE global_map_tbl_1, global_map_tbl_2, global_map_tbl_3; ++ ++struct APCLI_BRIDGE_LEARNING_MAPPING_MAP global_map_tbl; ++spinlock_t global_map_tbl_lock; ++unsigned long global_map_tbl_irq_flags; ++spinlock_t global_band_tbl_lock; ++unsigned long global_band_tbl_irq_flags; ++spinlock_t priority_tbl_lock; ++unsigned long priority_tbl_irq_flags; ++ ++ ++#define ARP_ETH_TYPE 0x0806 ++#define LLTD_ETH_TYPE 0x88D9 ++ ++#ifndef TCP ++#define TCP 0x06 ++#endif /* !TCP */ ++ ++#ifndef UDP ++#define UDP 0x11 ++#endif /* !UDP */ ++ ++#ifndef ETH_P_IPV6 ++#define ETH_P_IPV6 0x86DD ++#endif /* !ETH_P_IPV6 */ ++ ++#ifndef ETH_P_IP ++#define ETH_P_IP 0x0800 /* Internet Protocol packet */ ++#endif /* ETH_P_IP */ ++ ++#ifndef LENGTH_802_3 ++#define LENGTH_802_3 14 ++#endif /* !LENGTH_802_3 */ ++ ++#define IPV6_NEXT_HEADER_UDP 0x11 ++#define IPV6_HDR_LEN 40 ++ ++static const REPEATER_ADAPTER_DATA_TABLE *rep_table[] = ++{ ++ &global_map_tbl_1, ++ &global_map_tbl_2, ++ &global_map_tbl_3, ++}; ++ ++static const void **adapter_table[] = ++{ ++ &adapter_tmp_1, ++ &adapter_tmp_2, ++ &adapter_tmp_3, ++}; ++ ++unsigned char num_rep_tbl = (sizeof(rep_table) / sizeof(REPEATER_ADAPTER_DATA_TABLE *)); ++unsigned char num_adapter_tbl = (sizeof(adapter_table) / sizeof(void **)); ++ ++struct net_device *ra_dev_get_by_name(const char *name) ++{ ++ struct net_device *dev; ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) ++ dev = dev_get_by_name(&init_net, name); ++#else ++ dev = dev_get_by_name(name); ++#endif ++ ++ if (dev) ++ dev_put(dev); ++ ++ return dev; ++} ++ ++static unsigned char is_fastlane_mode(struct net_device *dev) ++{ ++ int link_cnt = 0; ++ ++ if (main_2g_link_cnt != 0) ++ link_cnt++; ++ if (main_5g_link_cnt != 0) ++ link_cnt++; ++ if (main_5g_h_link_cnt != 0) ++ link_cnt++; ++ ++ if (link_cnt == 1) ++ return 1; ++ else ++ return 0; ++} ++ ++static unsigned char is_concurrent_mode(struct net_device *dev) ++{ ++ int link_cnt = 0; ++ ++ if (main_2g_link_cnt != 0) ++ link_cnt++; ++ if (main_5g_link_cnt != 0) ++ link_cnt++; ++ if (main_5g_h_link_cnt != 0) ++ link_cnt++; ++ ++ if (link_cnt > 1) ++ return 1; ++ else ++ return 0; ++} ++ ++static unsigned char is_mbss_mode(unsigned int band_from) ++{ ++ if (((main_2g_link_cnt >= 2) && IS_PACKET_FROM_2G(band_from)) ++ || ((main_5g_link_cnt >= 2) && IS_PACKET_FROM_5G(band_from)) ++ || ((main_5g_h_link_cnt >= 2) && IS_PACKET_FROM_5G_H(band_from))) ++ return 1; ++ else ++ return 0; ++} ++ ++/* ++ return value: ++ >=0: array index of FwdDevice ++ -1: search failed ++*/ ++static int wifi_fwd_find_device(struct net_device *dev) ++{ ++ int idx = 0; ++ ++ for (idx=0; idx<WIFI_FWD_DEVICE_SIZE; idx++) ++ { ++ if ((FwdDevice != NULL) && ++ (FwdDevice[idx].valid == TRUE) && ++ (FwdDevice[idx].dev== dev)) ++ return idx; ++ } ++ ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s] no entry found\n", __FUNCTION__)); ++ return -1; ++} ++ ++/* ++ return value: ++ >=0: array index of FwdDevice ++ -1: search failed ++*/ ++static int wifi_fwd_find_device_by_info(BAND_INDEX band, unsigned int type) ++{ ++ int idx = 0; ++ ++ for (idx=0; idx<WIFI_FWD_DEVICE_SIZE; idx++) ++ { ++ if ((FwdDevice != NULL) && ++ (FwdDevice[idx].valid == TRUE) && ++ (FwdDevice[idx].band == band) && ++ (FwdDevice[idx].type == type)) ++ return idx; ++ } ++ ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s] no entry found\n", __FUNCTION__)); ++ return -1; ++} ++ ++static void cal_link_cnt_by_idx(unsigned char index, unsigned char policy) ++{ ++ struct DevInfo *dev_info = NULL; ++ ++ if (index > WIFI_FWD_DEVICE_SIZE) ++ return; ++ ++ dev_info = FwdDevice + index; ++ ++ if (dev_info == NULL) ++ return; ++ ++ if (IS_APCLI_DEV(dev_info->type) && IS_VALID(dev_info->valid)) ++ { ++ switch(dev_info->band) ++ { ++ case band_2g: ++ if (policy > 0) ++ main_2g_link_cnt++; ++ else ++ main_2g_link_cnt--; ++ ++ if (main_2g_link_cnt < 0) ++ main_2g_link_cnt = 0; ++ ++ break; ++ ++ case band_5g: ++ if (policy > 0) ++ main_5g_link_cnt++; ++ else ++ main_5g_link_cnt--; ++ ++ if (main_5g_link_cnt < 0) ++ main_5g_link_cnt = 0; ++ ++ break; ++ ++ case band_5g_h: ++ if (policy > 0) ++ main_5g_h_link_cnt++; ++ else ++ main_5g_h_link_cnt--; ++ ++ if (main_5g_h_link_cnt < 0) ++ main_5g_h_link_cnt = 0; ++ ++ break; ++ ++ default: ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("[%s][%d] unknown band(%x)\n", ++ __FUNCTION__, __LINE__, dev_info->band)); ++ break; ++ } ++ } ++ ++ if (policy > 0) ++ fwd_counter++; ++ else ++ fwd_counter--; ++} ++ ++static void cal_link_count_by_net_dev(struct net_device *dev, unsigned char policy) ++{ ++ int link_idx = 0; ++ ++ if (dev == NULL) ++ return; ++ ++ link_idx = wifi_fwd_find_device(dev); ++ ++ if (link_idx >=0) ++ cal_link_cnt_by_idx(link_idx, policy); ++} ++ ++static void dump_bridge_by_name(void) ++{ ++ br_lan = ra_dev_get_by_name("br-lan"); ++} ++ ++static void wifi_fwd_reset_link_count(void) ++{ ++ fwd_counter = 0; ++ main_5g_h_link_cnt = 0; ++ main_5g_link_cnt = 0; ++ main_2g_link_cnt = 0; ++} ++ ++static bool wifi_fwd_needed(void) ++{ ++ if (!WIFI_FWD_TEST_FLAG(fOP_WIFI_FWD_ACTIVE) ++ || !WIFI_FWD_TEST_FLAG(fOP_WIFI_FWD_ENABLED) ++ || (fwd_counter == 0)) ++ return FALSE; ++ else ++ return TRUE; ++} ++ ++static void wifi_fwd_show_entry(void) ++{ ++ int idx = 0; ++ ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("\n[%s]fwd_link=%d,[5g_h main]=%d [5g main]=%d, [2g main]=%d\n", ++ __FUNCTION__, fwd_counter, main_5g_h_link_cnt, main_5g_link_cnt, main_2g_link_cnt)); ++ ++ for (idx=0; idx<WIFI_FWD_TBL_SIZE; idx++) ++ { ++ if (WiFiFwdBase[idx].valid) ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("[%s]index=%d, valid=%d, src_dev=0x%08x, dest_dev=0x%08x\n", ++ __FUNCTION__, idx, WiFiFwdBase[idx].valid, (int)WiFiFwdBase[idx].src, (int)WiFiFwdBase[idx].dest)); ++ } ++ ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("---------------------------------------------------------------------------------------------\n")); ++ ++ for (idx=0; idx<WIFI_FWD_DEVICE_SIZE; idx++) ++ { ++ if (FwdDevice[idx].valid) ++ { ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("[%s]index=%d, valid=%d, ", ++ __FUNCTION__, idx, FwdDevice[idx].valid)); ++ ++ if (FwdDevice[idx].type == INT_MAIN) ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("type=MAIN, ")); ++ else if (FwdDevice[idx].type == INT_MBSSID) ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("type=MBSSID, ")); ++ else if (FwdDevice[idx].type == INT_APCLI) ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("type=APCLI, ")); ++ ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("mbss=0x%02x, ", FwdDevice[idx].mbss_idx)); ++ ++ if (FwdDevice[idx].band == band_2g) ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("band=2G, src_dev=0x%08x, ", (int)FwdDevice[idx].dev)); ++ else if (FwdDevice[idx].band == band_5g) ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("band=5G, src_dev=0x%08x, ", (int)FwdDevice[idx].dev)); ++ else if (FwdDevice[idx].band == band_5g_h) ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("band=5G-h, src_dev=0x%08x, ", (int)FwdDevice[idx].dev)); ++ ++ if (FwdDevice[idx].partner != NULL) ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("dest_dev=0x%08x\n", (int)FwdDevice[idx].partner->dev)); ++ else ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("\n")); ++ } ++ else ++ continue; ++ } ++ ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("[%s]eth_rep5g_h_wrg_uni_cnt=%u, eth_rep5g_wrg_uni_cnt=%u, eth_rep2g_wrg_uni_cnt=%u\n", ++ __FUNCTION__, eth_rep5g_h_wrg_uni_cnt, eth_rep5g_wrg_uni_cnt, eth_rep2g_wrg_uni_cnt)); ++ ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("[%s]eth_rep5g_h_wrg_bct_cnt=%u, eth_rep5g_wrg_bct_cnt=%u, eth_rep2g_wrg_bct_cnt=%u\n", ++ __FUNCTION__, eth_rep5g_h_wrg_bct_cnt, eth_rep5g_wrg_bct_cnt, eth_rep2g_wrg_bct_cnt)); ++ ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("[%s]rep=%d\n", __FUNCTION__, rep_net_dev)); ++} ++ ++static void wifi_fwd_delete_entry_by_idx(unsigned char idx) ++{ ++ int i = 0; ++ ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("\n[%s]--------------------------------------------\n", __FUNCTION__)); ++ ++ if (idx < WIFI_FWD_TBL_SIZE) ++ { ++ if (WiFiFwdBase[idx].valid) ++ { ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s]index=%d, valid=%d, src dev=0x%08X, dest dev=0x%08X\n", ++ __FUNCTION__, idx, WiFiFwdBase[idx].valid, (int)WiFiFwdBase[idx].src, (int)WiFiFwdBase[idx].dest)); ++ ++ cal_link_count_by_net_dev(WiFiFwdBase[idx].src, 0); ++ memset(&WiFiFwdBase[idx], 0, sizeof(struct FwdPair)); ++ ++ } else ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s]index=%d is void originally\n", __FUNCTION__, idx)); ++ } ++ else ++ { ++ for (i=0; i<WIFI_FWD_TBL_SIZE; i++) ++ memset(&WiFiFwdBase[i], 0, sizeof(struct FwdPair)); ++ ++ wifi_fwd_reset_link_count(); ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s] flush all entries\n", __FUNCTION__)); ++ } ++} ++ ++static void packet_source_show_entry(void) ++{ ++ int idx = 0; ++ ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("\n[%s]--------------------------------------------\n", __FUNCTION__)); ++ ++ for (idx=0; idx<WIFI_FWD_TBL_SIZE; idx++) ++ { ++ if (pkt_src[idx].valid) ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("[%s]index=%d, valid=%d, src=0x%08X, peer=0x%08X, " ++ "h_source=%02X:%02X:%02X:%02X:%02X:%02X, h_dest=%02X:%02X:%02X:%02X:%02X:%02X\n", ++ __FUNCTION__, idx, pkt_src[idx].valid, (int)pkt_src[idx].src, (int)pkt_src[idx].peer, ++ pkt_src[idx].h_source[0], pkt_src[idx].h_source[1], pkt_src[idx].h_source[2], ++ pkt_src[idx].h_source[3], pkt_src[idx].h_source[4], pkt_src[idx].h_source[5], ++ pkt_src[idx].h_dest[0], pkt_src[idx].h_dest[1], pkt_src[idx].h_dest[2], ++ pkt_src[idx].h_dest[3], pkt_src[idx].h_dest[4], pkt_src[idx].h_dest[5])); ++ } ++} ++ ++static void packet_source_delete_entry(unsigned char idx) ++{ ++ int i = 0; ++ ++ if (!WIFI_FWD_TEST_FLAG(fOP_WIFI_FWD_ENABLED)) ++ return; ++ ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("\n[%s]--------------------------------------------\n", __FUNCTION__)); ++ ++ if (idx < WIFI_FWD_TBL_SIZE) ++ { ++ if (pkt_src[idx].valid) ++ { ++ memset(&pkt_src[idx], 0, sizeof(struct PacketSource)); ++ ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s]index=%d, valid=%d, src=0x%08X, peer=0x%08X, " ++ "h_source=%02X:%02X:%02X:%02X:%02X:%02X, h_dest=%02X:%02X:%02X:%02X:%02X:%02X\n", ++ __FUNCTION__, idx, pkt_src[idx].valid, (int)pkt_src[idx].src, (int)pkt_src[idx].peer, ++ pkt_src[idx].h_source[0], pkt_src[idx].h_source[1], pkt_src[idx].h_source[2], ++ pkt_src[idx].h_source[3], pkt_src[idx].h_source[4], pkt_src[idx].h_source[5], ++ pkt_src[idx].h_dest[0], pkt_src[idx].h_dest[1], pkt_src[idx].h_dest[2], ++ pkt_src[idx].h_dest[3], pkt_src[idx].h_dest[4], pkt_src[idx].h_dest[5])); ++ } else ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s]index=%d is void originally\n", __FUNCTION__, idx)); ++ } ++ else if (idx == WIFI_FWD_TBL_SIZE) ++ { ++ eth_rep5g_h_wrg_uni_cnt = 0; ++ eth_rep5g_h_wrg_bct_cnt = 0; ++ eth_rep5g_wrg_uni_cnt = 0; ++ eth_rep5g_wrg_bct_cnt = 0; ++ eth_rep2g_wrg_uni_cnt = 0; ++ eth_rep2g_wrg_bct_cnt = 0; ++ ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s] reset counters\n", __FUNCTION__)); ++ } ++ else ++ { ++ for (i=0; i<WIFI_FWD_TBL_SIZE; i++) ++ memset(&pkt_src[i], 0, sizeof(struct PacketSource)); ++ ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s] flush all entries\n", __FUNCTION__)); ++ } ++} ++ ++/* ++ return value: ++ >=0: array index of WiFiFwdBase ++ -1: search failed ++*/ ++static int wifi_fwd_find_empty_entry(void) ++{ ++ int idx = 0; ++ ++ for (idx=0; idx<WIFI_FWD_TBL_SIZE; idx++) ++ { ++ if (WiFiFwdBase[idx].valid == FALSE) ++ return idx; ++ } ++ ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s] table full\n", __FUNCTION__)); ++ return -1; ++} ++ ++/* ++ return value: ++ >=0: array index of WiFiFwdBase ++ -1: search failed ++*/ ++static int wifi_fwd_find_entry(struct net_device *src, struct net_device *dest) ++{ ++ int idx = 0; ++ ++ for (idx=0; idx<WIFI_FWD_TBL_SIZE; idx++) ++ { ++ if ((WiFiFwdBase[idx].valid == TRUE) && ++ (WiFiFwdBase[idx].src == src) && ++ (WiFiFwdBase[idx].dest == dest)) ++ return idx; ++ } ++ ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s] no entry found\n", __FUNCTION__)); ++ return -1; ++} ++ ++static unsigned char wifi_fwd_establish_entry(struct net_device *src, struct net_device *dest) ++{ ++ struct FwdPair *entry = NULL; ++ int idx = 0; ++ ++ if (!src || !dest) ++ return 0; ++ ++ /* check if it is an existed entry */ ++ idx = wifi_fwd_find_entry(src, dest); ++ if (idx >= 0) ++ return 0; ++ ++ /* to establish the path between src and dest */ ++ idx = wifi_fwd_find_empty_entry(); ++ if (idx == -1) ++ return 0; ++ ++ entry = WiFiFwdBase + idx; ++ entry->valid = TRUE; ++ entry->src = src; ++ entry->dest = dest; ++ cal_link_count_by_net_dev(entry->src, 1); ++ ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s %d] valid=%d, src=0x%08X, dest=0x%08X\n", ++ __FUNCTION__, idx, entry->valid, (unsigned int)entry->src, (unsigned int)entry->dest)); ++ ++ return 1; ++} ++ ++/* ++ return value: ++ 1: clear OK ++ 0: clear failed (wrong input index) ++*/ ++static int wifi_fwd_clear_entry(int index) ++{ ++ struct FwdPair *entry = NULL; ++ entry = WiFiFwdBase + index; ++ ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[wifi_fwd_clear_entry] original: index=%d, valid=%d, src_dev=0x%08X, dest_dev=0x%08X\n", ++ index, entry->valid, (int)entry->src, (int)entry->dest)); ++ ++ if (entry->valid) { ++ memset(entry, 0, sizeof(struct FwdPair)); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++/* ++ return value: ++ 1: clear OK ++ 0: clear failed (wrong input index) ++*/ ++static int wifi_fwd_clear_device(int index) ++{ ++ struct DevInfo *entry = NULL; ++ entry = FwdDevice+ index; ++ ++ if (entry->valid) { ++ memset(entry, 0, sizeof(struct DevInfo)); ++ return 1; ++ } ++ return 0; ++} ++ ++static void wifi_fwd_set_cb_num(unsigned int band_cb_num, unsigned int receive_cb_num) ++{ ++ band_cb_offset = band_cb_num; ++ recv_from_cb_offset = receive_cb_num; ++ ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("[%s] band_cb_offset=%d, recv_from_cb_offset=%d\n", ++ __FUNCTION__, band_cb_offset, recv_from_cb_offset)); ++} ++ ++static bool wifi_fwd_check_active(void) ++{ ++ if (WIFI_FWD_TEST_FLAG(fOP_WIFI_FWD_ACTIVE) ++ && WIFI_FWD_TEST_FLAG(fOP_WIFI_FWD_ENABLED)) ++ return TRUE; ++ else ++ return FALSE; ++} ++ ++static unsigned char wifi_fwd_check_rep(unsigned char rep) ++{ ++ switch(rep) ++ { ++ case eth_traffic_band_2g: ++ if (main_2g_link_cnt == 0) ++ { ++ if (next_2g_band == band_5g) ++ { ++ if (main_5g_link_cnt != 0) ++ return eth_traffic_band_5g; ++ else if (main_5g_h_link_cnt != 0) ++ return eth_traffic_band_5g_H; ++ } ++ else ++ { ++ if (main_5g_h_link_cnt != 0) ++ return eth_traffic_band_5g_H; ++ else if (main_5g_link_cnt != 0) ++ return eth_traffic_band_5g; ++ } ++ } ++ else ++ break; ++ ++ case eth_traffic_band_5g: ++ if (main_5g_link_cnt == 0) ++ { ++ if (main_5g_h_link_cnt != 0) ++ return eth_traffic_band_5g_H; ++ else if (main_2g_link_cnt != 0) ++ return eth_traffic_band_2g; ++ } ++ else ++ break; ++ ++ case eth_traffic_band_5g_H: ++ if (main_5g_h_link_cnt == 0) ++ { ++ if (main_5g_link_cnt != 0) ++ return eth_traffic_band_5g; ++ else if (main_2g_link_cnt != 0) ++ return eth_traffic_band_2g; ++ } ++ else ++ break; ++ ++ default: ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("[%s] rep=%d by default\n", __FUNCTION__, eth_traffic_band_5g)); ++ return eth_traffic_band_5g; ++ } ++ ++ return rep; ++} ++ ++static void wifi_fwd_get_rep(unsigned char rep) ++{ ++ if (!WIFI_FWD_TEST_FLAG(fOP_WIFI_FWD_ENABLED)) ++ return; ++ ++ if (rep == 0) ++ rep_net_dev = eth_traffic_band_2g; ++ else if (rep == eth_traffic_band_5g_H) ++ rep_net_dev = eth_traffic_band_5g_H; ++ else ++ rep_net_dev = eth_traffic_band_5g; ++ ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("[%s] rep = %d\n", __FUNCTION__, rep_net_dev)); ++} ++ ++static void wifi_fwd_set_debug_level(unsigned char level) ++{ ++ if (level == 0) ++ wf_debug_level = WF_DEBUG_OFF; ++ else ++ wf_debug_level = WF_DEBUG_ON; ++ ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("[%s] level=%d\n", __FUNCTION__, wf_debug_level)); ++} ++ ++static void wifi_fwd_pro_active(void) ++{ ++ WIFI_FWD_SET_FLAG(fOP_WIFI_FWD_ACTIVE); ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("[%s]\n", __FUNCTION__)); ++} ++ ++static void wifi_fwd_pro_halt(void) ++{ ++ WIFI_FWD_CLEAR_FLAG(fOP_WIFI_FWD_ACTIVE); ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("[%s]\n", __FUNCTION__)); ++} ++ ++static void wifi_fwd_pro_enabled(void) ++{ ++ WIFI_FWD_SET_FLAG(fOP_WIFI_FWD_ENABLED); ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("[%s]\n", __FUNCTION__)); ++} ++ ++static void wifi_fwd_pro_disabled(void) ++{ ++ WIFI_FWD_CLEAR_FLAG(fOP_WIFI_FWD_ENABLED); ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("[%s]\n", __FUNCTION__)); ++} ++ ++static void wifi_fwd_access_schedule_active(void) ++{ ++ WIFI_FWD_SET_FLAG(fOP_WIFI_FWD_ACCESS_SCHED_ACTIVE); ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("[%s]\n", __FUNCTION__)); ++} ++ ++static void wifi_fwd_access_schedule_halt(void) ++{ ++ WIFI_FWD_CLEAR_FLAG(fOP_WIFI_FWD_ACCESS_SCHED_ACTIVE); ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("[%s]\n", __FUNCTION__)); ++} ++ ++static void wifi_fwd_hijack_active(void) ++{ ++ WIFI_FWD_SET_FLAG(fOP_WIFI_FWD_HIJACK_ACTIVE); ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("[%s]\n", __FUNCTION__)); ++} ++ ++static void wifi_fwd_hijack_halt(void) ++{ ++ WIFI_FWD_CLEAR_FLAG(fOP_WIFI_FWD_HIJACK_ACTIVE); ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("[%s]\n", __FUNCTION__)); ++} ++ ++static void packet_tx_source_flush_all(void) ++{ ++ struct TxSourceEntry *entry = NULL; ++ int i = 0; ++ ++ if (!tx_src_tbl || (tx_src_count == 0)) ++ return; ++ ++ for (i=0; i<WIFI_FWD_TBL_SIZE; i++) ++ { ++ entry = tx_src_tbl + i; ++ ++ /* keep the records of wireless stations */ ++ if ((entry->valid == 1) && (entry->bfrom_wireless == 0)) ++ { ++ tx_src_count--; ++ entry->valid = 0; ++ } ++ ++ if (tx_src_count == 0) ++ break; ++ } ++} ++ ++/* delete the records of wireless stations */ ++static void wf_fwd_delete_entry_inform(unsigned char *addr) ++{ ++ struct TxSourceEntry *entry = NULL; ++ int i = 0, count = 0; ++ ++ if (!WIFI_FWD_TEST_FLAG(fOP_WIFI_FWD_ENABLED)) ++ return; ++ ++ if (!addr || (tx_src_count == 0)) ++ return; ++ ++ for (i=0; i<WIFI_FWD_TBL_SIZE; i++) ++ { ++ entry = tx_src_tbl + i; ++ ++ if (entry->valid == TRUE) ++ { ++ count++; ++ if(MAC_ADDR_EQUAL(addr, entry->h_source)) ++ { ++ entry->valid = FALSE; ++ entry->bfrom_wireless = 0; ++ tx_src_count--; ++ ++ if (tx_src_count < 0) ++ tx_src_count = 0; ++ ++ return; ++ } ++ ++ if (count >= tx_src_count) ++ return; ++ } ++ } ++} ++ ++/* add the records of wireless stations */ ++static void wf_fwd_add_entry_inform(unsigned char *addr) ++{ ++ struct TxSourceEntry *entry = NULL; ++ int i = 0; ++ ++ if (!addr) ++ return; ++ ++ for (i=0; i<WIFI_FWD_TBL_SIZE; i++) ++ { ++ entry = tx_src_tbl + i; ++ ++ if (entry->valid == FALSE) ++ { ++ tx_src_count++; ++ entry->valid = TRUE; ++ entry->bfrom_wireless = 1; ++ COPY_MAC_ADDR(entry->h_source, addr); ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s %d] valid=%d, src_mac=%02X:%02X:%02X:%02X:%02X:%02X\n", ++ __FUNCTION__,i, entry->valid, ++ entry->h_source[0], entry->h_source[1], entry->h_source[2], ++ entry->h_source[3], entry->h_source[4], entry->h_source[5])); ++ break; ++ } ++ } ++} ++ ++/* ++ return value: ++ 0: insert failed ++ 1: insert success ++ 2: do nothing ++*/ ++static int wifi_fwd_insert_tx_source_entry(struct sk_buff *skb,struct DevInfo *tx_dev_info) ++{ ++ struct ethhdr *mh = eth_hdr(skb); ++ //unsigned int recv_from = WIFI_FWD_GET_PACKET_RECV_FROM(skb, recv_from_cb_offset); ++ struct TxSourceEntry *entry = NULL; ++ int i = 0; ++ unsigned char bInsert = 0; ++ ++ if((IS_VALID(tx_dev_info->valid) && !is_concurrent_mode(tx_dev_info->dev)) || !mh) ++ return 2; ++ ++ if(IS_VALID(tx_dev_info->valid) && IS_APCLI_DEV(tx_dev_info->type)) ++ { ++ for (i=0; i<WIFI_FWD_TBL_SIZE; i++) ++ { ++ entry = tx_src_tbl + i; ++ if ((entry->valid == 1) && ++ MAC_ADDR_EQUAL(mh->h_source, entry->h_source)) ++ return 2; ++ } ++ bInsert = 1; ++ } ++ ++ if(!bInsert) ++ return 2; ++ ++ for (i=0; i<WIFI_FWD_TBL_SIZE; i++) ++ { ++ entry = tx_src_tbl + i; ++ if (entry->valid == 0) ++ { ++ tx_src_count++; ++ entry->valid = 1; ++ entry->bfrom_wireless = 0; ++ COPY_MAC_ADDR(entry->h_source, mh->h_source); ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s %d] valid=%d, src_mac=%02X:%02X:%02X:%02X:%02X:%02X\n", ++ __FUNCTION__,i, entry->valid, ++ entry->h_source[0], entry->h_source[1], entry->h_source[2], ++ entry->h_source[3], entry->h_source[4], entry->h_source[5])); ++ return 1; ++ } ++ } ++ ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s] No free space for insert tx source entry.\n",__FUNCTION__)); ++ return 0; ++} ++ ++/* ++ return value: ++ 0: no looping ++ 1: looping found ++ 2: forward to bridge ++*/ ++static unsigned char wifi_fwd_check_looping( ++ struct sk_buff *skb, ++ struct DevInfo *dev_info) ++{ ++ struct ethhdr *mh = eth_hdr(skb); ++ struct TxSourceEntry *entry = NULL; ++ unsigned int recv_from = WIFI_FWD_GET_PACKET_RECV_FROM(skb, recv_from_cb_offset); ++ int i = 0, count = 0; ++ unsigned char bMulticast = 0; ++ ++ /* ++ no need to check while: ++ 1. this skb has no ethernet header ++ 2. this packet is not received from ap-client ++ 3. tx_src_count is 0 -> tx_src_tbl has no entries ++ 4. dev_info is valid and not in concurrent mode ++ */ ++ if ((IS_VALID(dev_info->valid) && !is_concurrent_mode(dev_info->dev)) || ++ !IS_PACKET_FROM_APCLI(recv_from) || ++ (tx_src_count == 0) || ++ !mh) ++ return 0; ++ ++ if (IS_VALID(dev_info->valid) && IS_APCLI_DEV(dev_info->type)) ++ { ++ if ((mh->h_dest[0] & 0x1) == 0x1) ++ bMulticast = 1; ++ ++ for (i=0; i<WIFI_FWD_TBL_SIZE; i++) ++ { ++ entry = tx_src_tbl + i; ++ if (entry->valid == 1) ++ { ++ count++; ++ if (MAC_ADDR_EQUAL(mh->h_source, entry->h_source)) ++ { ++ /* means the source has changed to other side no matter it comes from wireless or ethernet */ ++ if (!bMulticast) ++ { ++ wf_fwd_delete_entry_inform(entry->h_source); ++ return 0; ++ } ++ ++ return 1; ++ } ++ ++ if (count >= tx_src_count) ++ break; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++/* ++ return value: ++ 0: do nothing ++ 1: forward to bridge ++*/ ++static unsigned char wifi_fwd_pkt_to_bridge_by_dest_addr( ++ struct sk_buff *skb, ++ struct net_device *dev) ++{ ++ struct ethhdr *mh = eth_hdr(skb); ++ struct TxSourceEntry *tx_src_entry = NULL; ++ unsigned int recv_from; ++ int i = 0, count = 0; ++ ++ recv_from = WIFI_FWD_GET_PACKET_RECV_FROM(skb, recv_from_cb_offset); ++ ++ if ((tx_src_count > 0) && IS_PACKET_FROM_APCLI(recv_from) && mh) ++ { ++ for (i=0; i<WIFI_FWD_TBL_SIZE; i++) ++ { ++ tx_src_entry = tx_src_tbl + i; ++ if (tx_src_entry->valid) ++ { ++ count++; ++ if ((tx_src_entry->bfrom_wireless == 0) && ++ MAC_ADDR_EQUAL(tx_src_entry->h_source, mh->h_dest)) ++ return 1; ++ ++ if (count >= tx_src_count) ++ break; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++void wifi_fwd_check_device(struct net_device *net_dev, signed int type, signed int mbss_idx, unsigned char channel, unsigned char link) ++{ ++ struct DevInfo *DeviceEntry = NULL; ++ struct DevInfo *DeviceEntryTmp = NULL; ++ struct DevInfo *DeviceTmp = NULL; ++ struct DevInfo *DevicePartnerCheck = NULL; ++ unsigned char idx = 0, i = 0, j = 0, valid_index = 0; ++ bool get_idx = FALSE; ++ ++ if (!WIFI_FWD_TEST_FLAG(fOP_WIFI_FWD_ENABLED)) ++ return; ++ ++ if (!net_dev || !type) ++ return; ++ ++ FWD_IRQ_LOCK(&priority_tbl_lock, priority_tbl_irq_flags); ++ ++ for (idx=0; idx<WIFI_FWD_DEVICE_SIZE; idx++) ++ { ++ DeviceEntry = FwdDevice + idx; ++ ++ if (IS_VALID(DeviceEntry->valid) && (DeviceEntry->dev == net_dev)) ++ { ++ if (link == 0) ++ { ++ DevicePartnerCheck = DeviceEntry->partner; ++ ++ /* to avoid there is one more partner point to this device */ ++ if (DevicePartnerCheck != NULL) ++ { ++ for (j=0; j<WIFI_FWD_DEVICE_SIZE; j++) ++ { ++ DeviceTmp = FwdDevice + j; ++ ++ if (idx == j) ++ continue; ++ ++ if ((DeviceTmp->band == DevicePartnerCheck->band) && ++ (DeviceTmp->type != DevicePartnerCheck->type)) ++ { ++ DevicePartnerCheck->partner = DeviceTmp; ++ DeviceTmp->partner = DevicePartnerCheck; ++ } ++ } ++ } ++ ++ wifi_fwd_clear_device(idx); ++ } ++ ++ FWD_IRQ_UNLOCK(&priority_tbl_lock, priority_tbl_irq_flags); ++ return; ++ } ++ ++ if ((DeviceEntry->valid == FALSE) && (get_idx != TRUE)) ++ { ++ valid_index = idx; ++ get_idx = TRUE; ++ } ++ } ++ ++ if (link == 0) ++ { ++ FWD_IRQ_UNLOCK(&priority_tbl_lock, priority_tbl_irq_flags); ++ return; ++ } ++ ++ if (get_idx != TRUE) ++ { ++ FWD_IRQ_UNLOCK(&priority_tbl_lock, priority_tbl_irq_flags); ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("[%s] No free space for inserting device info.\n", __FUNCTION__)); ++ return; ++ } ++ ++ DeviceEntry = FwdDevice + valid_index; ++ DeviceEntry->dev = net_dev; ++ DeviceEntry->index = valid_index; ++ DeviceEntry->type = type; ++ DeviceEntry->mbss_idx = mbss_idx; ++ ++ if (IS_5G_HIGH(channel)) ++ { ++ DeviceEntry->band = band_5g_h; ++ DeviceEntry->second_band = band_5g; ++ DeviceEntry->third_band = band_2g; ++ } ++ else if (channel > 14) ++ { ++ DeviceEntry->band = band_5g; ++ DeviceEntry->second_band = band_5g_h; ++ DeviceEntry->third_band = band_2g; ++ } ++ else ++ { ++ DeviceEntry->band = band_2g; ++ DeviceEntry->second_band = band_5g; ++ DeviceEntry->third_band = band_5g_h; ++ } ++ ++ DeviceEntry->partner = NULL; ++ ++ for (i=0; i<WIFI_FWD_DEVICE_SIZE; i++) ++ { ++ DeviceEntryTmp = FwdDevice + i; ++ ++ if (i == DeviceEntry->index) ++ continue; ++ ++ if ((DeviceEntryTmp->band == DeviceEntry->band) && ++ (DeviceEntryTmp->type != DeviceEntry->type)) ++ { ++ DeviceEntry->partner = DeviceEntryTmp; ++ DeviceEntryTmp->partner = DeviceEntry; ++ } ++ } ++ ++ DeviceEntry->valid = TRUE; ++ ++ FWD_IRQ_UNLOCK(&priority_tbl_lock, priority_tbl_irq_flags); ++ return; ++} ++ ++static char wifi_fwd_find_fastlane(struct DevInfo *src, struct DevInfo *dest) ++{ ++ struct DevInfo *DeviceOthSrc = NULL; ++ int idx = 0, i = 0; ++ ++ if (dest == NULL) ++ return -1; ++ ++ for (i=0; i<WIFI_FWD_DEVICE_SIZE; i++) ++ { ++ DeviceOthSrc = FwdDevice+i; ++ ++ if ((DeviceOthSrc == NULL) || (DeviceOthSrc == src)) ++ continue; ++ ++ if ((DeviceOthSrc->valid == TRUE) && ++ IS_APCLI_DEV(DeviceOthSrc->type)) ++ { ++ idx = wifi_fwd_find_entry(DeviceOthSrc->dev, dest->dev); ++ ++ if (idx >= 0) ++ return idx; ++ } ++ } ++ ++ return -1; ++ ++} ++ ++ ++/* ++ return value: ++ 1: delete success ++ 0: delete failed ++*/ ++static unsigned char wifi_fwd_delete_entry(struct net_device *src, struct net_device *dest, unsigned char link_down) ++{ ++ int i, j; ++ int src_index, tmp_index, second_src_index, third_src_index; ++ bool need_flush = FALSE; ++ struct DevInfo *DeviceTmp = NULL, *DeviceSecondSrc = NULL, *DeviceThirdSrc = NULL; ++ ++ if (!WIFI_FWD_TEST_FLAG(fOP_WIFI_FWD_ENABLED)) ++ return 0; ++ ++ if (!src) ++ return 0; ++ ++ FWD_IRQ_LOCK(&priority_tbl_lock, priority_tbl_irq_flags); ++ ++ /* if AP interface is down */ ++ if (link_down == 0) ++ { ++ for (i = 0; i < WIFI_FWD_DEVICE_SIZE; i++) ++ { ++ DeviceTmp = FwdDevice+i; ++ ++ if (DeviceTmp->valid != TRUE) ++ continue; ++ ++ if (!IS_APCLI_DEV(DeviceTmp->type)) ++ continue; ++ ++ tmp_index = wifi_fwd_find_entry(DeviceTmp->dev, dest); ++ ++ if (tmp_index>=0) ++ { ++ if (wifi_fwd_clear_entry(tmp_index)!=0) ++ { ++ cal_link_cnt_by_idx(i, 0); ++ need_flush = TRUE; ++ } ++ } ++ } ++ FWD_IRQ_UNLOCK(&priority_tbl_lock, priority_tbl_irq_flags); ++ goto done; ++ } ++ ++ src_index = wifi_fwd_find_device(src); ++ ++ if (src_index < 0) ++ { ++ FWD_IRQ_UNLOCK(&priority_tbl_lock, priority_tbl_irq_flags); ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s][%d]Error!!!!!!!!!!!!src_index(%d) src(%d)\n", __FUNCTION__, __LINE__, src_index, (int)src)); ++ return 0; ++ } ++ /* ++ Delete the src path ++ */ ++ for (j = 0; j < WIFI_FWD_DEVICE_SIZE; j++) ++ { ++ DeviceTmp = FwdDevice+j; ++ ++ if (DeviceTmp->valid != TRUE) ++ continue; ++ ++ if (!IS_AP_DEV(DeviceTmp->type)) ++ continue; ++ ++ tmp_index = wifi_fwd_find_entry(src, DeviceTmp->dev); ++ ++ if (tmp_index>=0) ++ { ++ if (wifi_fwd_clear_entry(tmp_index)!=0) ++ { ++ cal_link_cnt_by_idx(src_index, 0); ++ need_flush = TRUE; ++ ++ second_src_index = wifi_fwd_find_device_by_info(DeviceTmp->second_band,INT_APCLI); ++ DeviceSecondSrc = FwdDevice+second_src_index; ++ ++ if ((second_src_index>=0) && (second_src_index!=src_index)) ++ wifi_fwd_establish_entry(DeviceSecondSrc->dev, DeviceTmp->dev); ++ else ++ { ++ third_src_index = wifi_fwd_find_device_by_info(DeviceTmp->third_band,INT_APCLI); ++ ++ DeviceThirdSrc = FwdDevice+third_src_index; ++ ++ if ((third_src_index>=0) && (third_src_index!=src_index)) ++ wifi_fwd_establish_entry(DeviceThirdSrc->dev, DeviceTmp->dev); ++ ++ } ++ } ++ } ++ } ++ ++ ++ FWD_IRQ_UNLOCK(&priority_tbl_lock, priority_tbl_irq_flags); ++ ++done: ++ ++ if (need_flush) ++ { ++ /* flush packet source table */ ++ packet_source_delete_entry(WIFI_FWD_TBL_SIZE+1); ++ ++ /* flush tx packet source table */ ++ packet_tx_source_flush_all(); ++ } ++ ++ WIFI_FWD_CLEAR_FLAG(fOP_GET_NET_DEVICE_STATUS_DONE); ++ return 1; ++} ++ ++ ++/* ++ return value: ++ 1: insert success ++ 0: insert failed ++*/ ++static unsigned char wifi_fwd_insert_entry(struct net_device *src, struct net_device *dest, void *adapter) ++{ ++ struct DevInfo *DeviceEntrySrc = NULL, *DeviceEntryDest = NULL, *DeviceEntryOthDest = NULL, *DeviceEntryOthSrc = NULL; ++ int idx = 0, k = 0, index = 0, src_index = 0; ++ ++ if (!WIFI_FWD_TEST_FLAG(fOP_WIFI_FWD_ENABLED)) ++ return 0; ++ ++ if (!src || !dest) ++ return 0; ++ ++ if (!WIFI_FWD_TEST_FLAG(fOP_GET_NET_DEVICE_STATUS_DONE)) { ++ dump_bridge_by_name(); ++ WIFI_FWD_SET_FLAG(fOP_GET_NET_DEVICE_STATUS_DONE); ++ } ++ ++ FWD_IRQ_LOCK(&priority_tbl_lock, priority_tbl_irq_flags); ++ ++ /* ++ src is the net device of ap client trying to insert the entry into WiFi forwarding table ++ ++ according to forwarding device table, find the partner of src ++ */ ++ for (src_index=0; src_index<WIFI_FWD_DEVICE_SIZE; src_index++) ++ { ++ DeviceEntrySrc = FwdDevice + src_index; ++ ++ if ((DeviceEntrySrc != NULL) && ++ (DeviceEntrySrc->valid == TRUE) && ++ (DeviceEntrySrc->dev == src) && ++ IS_APCLI_DEV(DeviceEntrySrc->type)) ++ { ++ DeviceEntryDest = DeviceEntrySrc->partner; ++ break; ++ } ++ } ++ ++ if (src_index >= WIFI_FWD_DEVICE_SIZE) ++ { ++ FWD_IRQ_UNLOCK(&priority_tbl_lock, priority_tbl_irq_flags); ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s][%d]cannot find DevSrc(%x) in FwdDevice\n", __FUNCTION__, __LINE__, (int)src)); ++ return 0; ++ } ++ ++ /* ++ check if there exists fastlane path by searching forwarding device table ++ if yes, delete the cross path of fastlane ++ */ ++ ++ idx = wifi_fwd_find_fastlane(DeviceEntrySrc, DeviceEntryDest); ++ ++ if (idx >= 0) ++ wifi_fwd_delete_entry_by_idx(idx); ++ ++ if (DeviceEntryDest != NULL) ++ { ++ /* try to establish the path between src and dest */ ++ if (wifi_fwd_establish_entry(DeviceEntrySrc->dev, DeviceEntryDest->dev) == 0) ++ { ++ FWD_IRQ_UNLOCK(&priority_tbl_lock, priority_tbl_irq_flags); ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s][%d]forwarding path establishing failed\n", __FUNCTION__, __LINE__)); ++ return 0; ++ } ++ } ++ ++ /* ++ check if there exists higher priority forwarding path for other dest from ap view ++ if yes, change the link from original src to new one ++ */ ++ for (k=0; k<WIFI_FWD_DEVICE_SIZE; k++) ++ { ++ DeviceEntryOthDest = FwdDevice + k; ++ ++ if (DeviceEntryOthDest->valid != TRUE) ++ continue; ++ ++ if (!IS_AP_DEV(DeviceEntryOthDest->type)) ++ continue; ++ ++ if (DeviceEntryOthDest != DeviceEntryDest) ++ { ++ index = -1; ++ DeviceEntryOthSrc = NULL; ++ ++ if ((DeviceEntryOthDest->partner != NULL) && ++ (DeviceEntryOthDest->partner->valid == TRUE)) ++ DeviceEntryOthSrc = DeviceEntryOthDest->partner; ++ ++ if ((DeviceEntryOthSrc != NULL) && IS_VALID(DeviceEntryOthSrc->valid)) ++ index = wifi_fwd_find_entry(DeviceEntryOthSrc->dev,DeviceEntryOthDest->dev); ++ ++ if (index >= 0) ++ continue; ++ ++ index = wifi_fwd_find_fastlane(DeviceEntryOthSrc, DeviceEntryOthDest); ++ ++ if (index < 0) ++ { ++ if (DeviceEntrySrc != NULL) ++ wifi_fwd_establish_entry(DeviceEntrySrc->dev, DeviceEntryOthDest->dev); ++ ++ continue; ++ } ++ ++ wifi_fwd_delete_entry_by_idx(index); ++ if (DeviceEntrySrc != NULL) ++ wifi_fwd_establish_entry(DeviceEntrySrc->dev, DeviceEntryOthDest->dev); ++ ++#if 0 ++ /*Increase 2G apcli link cannot change 5G's link*/ ++ if (DeviceEntrySrc->band == band_5g) ++ { ++ if (((DeviceEntryOthDest->band == band_2g) && (next_2g_band == band_5g)) || ++ (DeviceEntryOthDest->band == band_5g_h)) ++ { ++ wifi_fwd_delete_entry_by_idx(index); ++ ++ if (DeviceEntrySrc!=NULL) ++ wifi_fwd_establish_entry(DeviceEntrySrc->dev, DeviceEntryOthDest->dev); ++ } ++ } ++ else if (DeviceEntrySrc->band == band_5g_h) ++ { ++ if (((DeviceEntryOthDest->band == band_2g) && (next_2g_band == band_5g_h)) || ++ (DeviceEntryOthDest->band == band_5g)) ++ { ++ ++ wifi_fwd_delete_entry_by_idx(index); ++ ++ if (DeviceEntrySrc!=NULL) ++ wifi_fwd_establish_entry(DeviceEntrySrc->dev, DeviceEntryOthDest->dev); ++ } ++ } ++ else if (DeviceEntrySrc->band == band_2g) ++ { ++ if (DeviceEntryOthDest->band == band_2g) ++ { ++ wifi_fwd_delete_entry_by_idx(index); ++ ++ if (DeviceEntrySrc != NULL) ++ wifi_fwd_establish_entry(DeviceEntrySrc->dev, DeviceEntryOthDest->dev); ++ } ++ } ++#endif ++ } ++ ++ } ++ ++ FWD_IRQ_UNLOCK(&priority_tbl_lock, priority_tbl_irq_flags); ++ ++ /* flush packet source table */ ++ packet_source_delete_entry(WIFI_FWD_TBL_SIZE+1); ++ return 1; ++} ++ ++ ++/* ++ return value: ++ 0: Success, skb is handled by wifi_fwd module. ++ 1: FAIL, do nothing ++*/ ++static struct net_device * wifi_fwd_insert_packet_source(struct sk_buff *skb, struct net_device *dev, struct net_device *peer) ++{ ++ struct ethhdr *mh = eth_hdr(skb); ++ struct PacketSource *entry = NULL; ++ bool need_flush = false; ++ int i = 0; ++ ++ for (i=0; i<WIFI_FWD_TBL_SIZE; i++) ++ { ++ entry = pkt_src + i; ++ ++ if (entry->valid == 1) { ++ if (peer == entry->peer) { ++ if (MAC_ADDR_EQUAL(mh->h_source, entry->h_source)) { ++ if (dev == entry->src) { ++ return peer; ++ } else { ++ need_flush = true; ++ break; ++ } ++ } ++ } ++ } ++ } ++ ++ if (need_flush == true) ++ packet_source_delete_entry(WIFI_FWD_TBL_SIZE+1); ++ else ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s] packet source cannot be found\n", __FUNCTION__)); ++ ++ for (i=0; i<WIFI_FWD_TBL_SIZE; i++) ++ { ++ entry = pkt_src + i; ++ ++ if (entry->valid == 0) { ++ COPY_MAC_ADDR(entry->h_source, mh->h_source); ++ COPY_MAC_ADDR(entry->h_dest, mh->h_dest); ++ entry->valid = 1; ++ entry->peer = peer; ++ entry->src = dev; ++ ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s %d] valid=%d, from=0x%08X, will send to=0x%08X, " ++ "src_mac=%02X:%02X:%02X:%02X:%02X:%02X, dest_mac=%02X:%02X:%02X:%02X:%02X:%02X\n", ++ __FUNCTION__, i, entry->valid, (int)entry->src, (int)entry->peer, ++ entry->h_source[0], entry->h_source[1], entry->h_source[2], ++ entry->h_source[3], entry->h_source[4], entry->h_source[5], ++ entry->h_dest[0], entry->h_dest[1], entry->h_dest[2], ++ entry->h_dest[3], entry->h_dest[4],entry->h_dest[5])); ++ ++ return entry->peer; ++ } ++ } ++ return NULL; ++} ++ ++static void wifi_fwd_tx_count_by_source_addr( ++ struct sk_buff *skb, ++ struct net_device *tx_dev, ++ unsigned char *found_path, ++ unsigned char *entry_cnt) ++{ ++ struct PacketSource *ppkt_src = NULL; ++ struct FwdPair *entry = NULL; ++ int i = 0; ++ ++ for (i=0; i<WIFI_FWD_TBL_SIZE; i++) ++ { ++ ppkt_src = pkt_src + i; ++ ++ if (ppkt_src->valid == 1) ++ { ++ if (MAC_ADDR_EQUAL(&skb->data[6], ppkt_src->h_source)) ++ { ++ *entry_cnt = *entry_cnt + 1; ++ ++ if ((ppkt_src->src == tx_dev) || (ppkt_src->peer == tx_dev)) ++ { ++ for (i=0; i<WIFI_FWD_TBL_SIZE; i++) ++ { ++ entry = WiFiFwdBase + i; ++ ++ if (entry->valid == 1) ++ { ++ if (((entry->src == ppkt_src->src) && (entry->dest == ppkt_src->peer)) || ++ ((entry->src == ppkt_src->peer) && (entry->dest == ppkt_src->src))) ++ *found_path = *found_path + 1; ++ } ++ } ++ } ++ } ++ } ++ else ++ break; ++ } ++} ++ ++ ++/* ++ return value: ++ 1: find entry ++ 0: find nothing ++*/ ++static unsigned char wifi_fwd_find_sa_entry_by_sa_and_nd( ++ struct sk_buff *skb, ++ struct net_device *sender_dev, ++ unsigned char idx) ++{ ++ struct PacketSource *entry = NULL; ++ struct ethhdr *mh = eth_hdr(skb); ++ int i = 0; ++ ++ for (i=0; i<WIFI_FWD_TBL_SIZE; i++) ++ { ++ entry = pkt_src + i; ++ ++ if (entry->valid == 1) ++ { ++ if (MAC_ADDR_EQUAL(mh->h_source, entry->h_source)) ++ { ++ if (idx == 0) ++ { ++ if (entry->src == sender_dev) ++ return 1; ++ } ++ else ++ { ++ if (entry->peer== sender_dev) ++ return 1; ++ } ++ } ++ } ++ else ++ break; ++ } ++ ++ return 0; ++} ++ ++#if 0 ++/* ++ return value: # of found entries ++*/ ++static unsigned char wifi_fwd_sa_count_by_source_addr( ++ struct sk_buff *skb, ++ struct net_device *receive_dev) ++{ ++ struct PacketSource *entry = NULL; ++ struct ethhdr *mh = eth_hdr(skb); ++ int i = 0, sa_cnt = 0; ++ ++ for (i=0; i<WIFI_FWD_TBL_SIZE; i++) ++ { ++ entry = pkt_src + i; ++ ++ if (entry->valid == 1) ++ { ++ if ((mh->h_source[0] & 0x2) == 0x2) ++ { ++ if (memcmp(&mh->h_source[3], &entry->h_source[3], 3) == 0) ++ sa_cnt++; ++ } ++ else ++ { ++ if (MAC_ADDR_EQUAL(mh->h_source, entry->h_source)) ++ sa_cnt++; ++ } ++ } ++ else ++ break; ++ } ++ ++ return sa_cnt; ++} ++#endif ++ ++/* ++ return value: ++ 0: suppose it is forwarded from bridge ++ 1: not forwarded from bridge ++ 2: should be forwarded to bridge ++*/ ++static unsigned char wifi_fwd_check_from_bridge_by_dest_addr( ++ struct sk_buff *skb, ++ struct DevInfo *sender_dev_info) ++{ ++ struct PacketSource *entry = NULL; ++ struct ethhdr *mh = eth_hdr(skb); ++ struct DevInfo *entry_dev_info = NULL; ++ int i = 0, idx = 0; ++ ++ for (i=0; i<WIFI_FWD_TBL_SIZE; i++) ++ { ++ entry = pkt_src + i; ++ ++ if (entry->valid == 1) ++ { ++ idx = wifi_fwd_find_device(entry->src); ++ ++ if (idx<0) ++ { ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s] idx(%d)\n", __FUNCTION__, idx)); ++ return 0; ++ } ++ ++ entry_dev_info = FwdDevice+idx; ++ ++ if ((sender_dev_info->valid == TRUE) && (entry_dev_info->valid == TRUE)) ++ { ++ if ((IS_AP_DEV(sender_dev_info->type) && IS_AP_DEV(entry_dev_info->type)) && ++ (sender_dev_info->index != entry_dev_info->index)) ++ { ++ if (MAC_ADDR_EQUAL(mh->h_dest, entry->h_source)) ++ return 2; ++ } ++ else ++ { ++ if (MAC_ADDR_EQUAL(mh->h_dest, entry->h_source)) ++ return 1; ++ } ++ } ++ } ++ else ++ break; ++ } ++ ++ return 0; ++} ++ ++/* ++ return value: ++ 0: error ++ > 0: the band that the packet comes from ++*/ ++static unsigned int band_pkt_from(struct sk_buff *skb) ++{ ++ unsigned int band_from = WIFI_FWD_GET_PACKET_BAND(skb, band_cb_offset); ++ ++ if (IS_PACKET_FROM_2G(band_from)) ++ return band_2g; ++ else if (IS_PACKET_FROM_5G(band_from)) ++ return band_5g; ++ else if (IS_PACKET_FROM_5G_H(band_from)) ++ return band_5g_h; ++} ++ ++static void wifi_fwd_clone_and_redirect_pkt(struct sk_buff *skb, BAND_INDEX band) ++{ ++ struct sk_buff *clone_pkt = NULL; ++ struct DevInfo *rdt_dev = NULL; ++ int rdt_dev_idx = 0; ++ ++ clone_pkt = skb_clone(skb, GFP_ATOMIC); ++ rdt_dev_idx = wifi_fwd_find_device_by_info(band, INT_APCLI); ++ ++ if (rdt_dev_idx < 0) ++ goto error; ++ ++ rdt_dev = FwdDevice + rdt_dev_idx; ++ ++ if (rdt_dev == NULL) ++ goto error; ++ ++ clone_pkt->dev = rdt_dev->dev; ++ dev_queue_xmit(clone_pkt); ++ return; ++ ++ ++error: ++ ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("[%s] cannnot find redirect device(%d)\n", __FUNCTION__, rdt_dev_idx)); ++ return; ++} ++ ++ ++/* ++ return value: ++ 0: no need to drop this packet ++ 1: drop this packet ++*/ ++static unsigned char wifi_fwd_tx_lookup_entry(struct net_device *tx_dev, struct sk_buff *skb) ++{ ++ struct DevInfo *device_tx = NULL; ++ unsigned char found = 0, entry_cnt = 0, rep = 0; ++ unsigned int recv_from = 0, band_from = 0; ++ int idx = 0, need_redirect = 0; ++ ++ band_from = WIFI_FWD_GET_PACKET_BAND(skb, band_cb_offset); ++ recv_from = WIFI_FWD_GET_PACKET_RECV_FROM(skb, recv_from_cb_offset); ++ ++ /* drop the packet due to there's no forwarding links between ap-client and ap */ ++ if (IS_PACKET_FROM_APCLI(recv_from) && !MAIN_SSID_OP(tx_dev)) ++ return 1; ++ ++ /* ++ in FastLane topology: ++ 1. forward the packet to driver and handle without any drop ++ 2. only for unicast ++ */ ++ if (IS_UNICAST_PACKET(skb) && is_fastlane_mode(tx_dev)) ++ return 0; ++ ++ idx = wifi_fwd_find_device(tx_dev); ++ if (idx < 0) ++ return 1; ++ ++ device_tx = FwdDevice + idx; ++ ++ /* ++ drop the packet from other band if ++ 1. @ concurrent mode ++ 2. the tx device is valid ++ 3. the tx device is ap-client, not ap ++ */ ++ if (is_concurrent_mode(tx_dev) ++ && IS_VALID(device_tx->valid) ++ && IS_APCLI_DEV(device_tx->type)) ++ { ++ /* double check the rep setting due to tri-band topology */ ++ rep = wifi_fwd_check_rep(rep_net_dev); ++ ++ if (device_tx->band == band_5g_h) ++ { ++ if (IS_PACKET_FROM_2G(band_from) && (main_2g_link_cnt != 0)) ++ { ++ if (IS_TAG_PACKET(band_from)) ++ need_redirect = band_2g; ++ else ++ return 1; ++ } ++ ++ if ((IS_PACKET_FROM_5G(band_from) && (main_5g_link_cnt != 0)) || ++ ((IS_PACKET_FROM_2G(band_from) && (main_2g_link_cnt == 0)) && (next_2g_band == band_5g))) ++ { ++ if (IS_TAG_PACKET(band_from)) ++ need_redirect = band_5g; ++ else ++ return 1; ++ } ++ ++ if (IS_PACKET_FROM_ETHER(band_from)) ++ { ++ if (IS_UNICAST_PACKET(skb)) ++ { ++ if (rep == eth_traffic_band_2g) ++ { ++ eth_rep2g_wrg_uni_cnt++; ++ need_redirect = band_2g; ++ } ++ else if (rep == eth_traffic_band_5g) ++ { ++ eth_rep5g_wrg_uni_cnt++; ++ need_redirect = band_5g; ++ } ++ } ++ else ++ { ++ if (rep == eth_traffic_band_2g) ++ eth_rep2g_wrg_bct_cnt++; ++ else if (rep == eth_traffic_band_5g) ++ eth_rep5g_wrg_bct_cnt++; ++ } ++ } ++ } ++ else if (device_tx->band == band_5g) ++ { ++ if (IS_PACKET_FROM_2G(band_from) && (main_2g_link_cnt != 0)) ++ { ++ if (IS_TAG_PACKET(band_from)) ++ need_redirect = band_2g; ++ else ++ return 1; ++ } ++ ++ if ((IS_PACKET_FROM_5G_H(band_from) && (main_5g_h_link_cnt != 0)) || ++ ((IS_PACKET_FROM_2G(band_from) && (main_2g_link_cnt == 0)) && (next_2g_band == band_5g_h))) ++ { ++ if (IS_TAG_PACKET(band_from)) ++ need_redirect = band_5g_h; ++ else ++ return 1; ++ } ++ if (IS_PACKET_FROM_ETHER(band_from)) ++ { ++ if (IS_UNICAST_PACKET(skb)) ++ { ++ if (rep == eth_traffic_band_2g) ++ { ++ eth_rep2g_wrg_uni_cnt++; ++ need_redirect = band_2g; ++ } ++ else if (rep == eth_traffic_band_5g_H) ++ { ++ eth_rep5g_h_wrg_uni_cnt++; ++ need_redirect = band_5g_h; ++ } ++ } ++ else ++ { ++ if (rep == eth_traffic_band_2g) ++ eth_rep2g_wrg_bct_cnt++; ++ else if (rep == eth_traffic_band_5g_H) ++ eth_rep5g_h_wrg_bct_cnt++; ++ } ++ } ++ } ++ else if (device_tx->band == band_2g) ++ { ++ if (IS_PACKET_FROM_5G(band_from) && (main_5g_link_cnt != 0)) ++ { ++ if (IS_TAG_PACKET(band_from)) ++ need_redirect = band_5g; ++ else ++ return 1; ++ } ++ ++ if (IS_PACKET_FROM_5G_H(band_from) && (main_5g_h_link_cnt != 0)) ++ { ++ if (IS_TAG_PACKET(band_from)) ++ need_redirect = band_5g_h; ++ else ++ return 1; ++ } ++ ++ if (IS_PACKET_FROM_ETHER(band_from)) ++ { ++ if (IS_UNICAST_PACKET(skb)) ++ { ++ if (rep == eth_traffic_band_5g) ++ { ++ eth_rep5g_wrg_uni_cnt++; ++ need_redirect = band_5g; ++ } ++ else if (rep == eth_traffic_band_5g_H) ++ { ++ eth_rep5g_h_wrg_uni_cnt++; ++ need_redirect = band_5g_h; ++ } ++ } ++ else ++ { ++ if (rep == eth_traffic_band_5g) ++ eth_rep5g_wrg_bct_cnt++; ++ else if (rep == eth_traffic_band_5g_H) ++ eth_rep5g_h_wrg_bct_cnt++; ++ } ++ } ++ } ++ ++ if (need_redirect != 0) ++ { ++ wifi_fwd_clone_and_redirect_pkt(skb, need_redirect); ++ return 1; ++ } ++ } ++ ++ wifi_fwd_tx_count_by_source_addr(skb, tx_dev, &found, &entry_cnt); ++ ++ if (IS_BROADCAST_PACKET(skb)) ++ { ++ if(wifi_fwd_insert_tx_source_entry(skb,device_tx) == 0) ++ return 0; ++ ++ if (found == 0) ++ { ++ if (entry_cnt == 0) ++ { ++ if (is_concurrent_mode(tx_dev) && ++ IS_PACKET_FROM_ETHER(band_from)) ++ { ++ rep = wifi_fwd_check_rep(rep_net_dev); ++ ++ if (IS_VALID(device_tx->valid) && IS_APCLI_DEV(device_tx->type)) ++ { ++ if (device_tx->band == band_5g_h) ++ { ++ if (rep == eth_traffic_band_5g_H) ++ return 0; ++ else ++ return 1; ++ } ++ else if (device_tx->band == band_5g) ++ { ++ if (rep == eth_traffic_band_5g) ++ return 0; ++ else ++ return 1; ++ } ++ else if (device_tx->band == band_2g) ++ { ++ if (rep == eth_traffic_band_2g) ++ return 0; ++ else ++ return 1; ++ } ++ } ++ } ++ } ++ ++ return 0; ++ } ++ else ++ { ++ if (entry_cnt >= 2) ++ return 0; ++ else ++ { ++ if (wifi_fwd_find_sa_entry_by_sa_and_nd(skb, tx_dev, 1) == 0) ++ return 1; ++ else ++ return 0; ++ } ++ } ++ } ++ else ++ { ++ if (found == 0) ++ { ++ if (entry_cnt == 0) ++ { ++ if (is_concurrent_mode(tx_dev) && ++ IS_PACKET_FROM_ETHER(band_from)) ++ { ++ rep = wifi_fwd_check_rep(rep_net_dev); ++ ++ if (rep == eth_traffic_band_5g_H) ++ { ++ if (IS_VALID(device_tx->valid) && REP_IS_5G_H(device_tx->band)) ++ return 0; ++ } ++ else if (rep == eth_traffic_band_5g) ++ { ++ if (IS_VALID(device_tx->valid) && REP_IS_5G(device_tx->band)) ++ return 0; ++ } ++ else if (rep == eth_traffic_band_2g) ++ { ++ if (IS_VALID(device_tx->valid) && REP_IS_2G(device_tx->band)) ++ return 0; ++ } ++ } ++ } ++ } ++ ++ return 0; ++ } ++} ++ ++/* ++ return value of struct net_device: ++ NULL: search failed ++ other: partner net_device ++*/ ++static struct net_device * wifi_fwd_lookup_entry(struct net_device *dev, unsigned char *type, struct sk_buff *skb) ++{ ++ struct FwdPair *entry = NULL; ++ struct net_device *src = NULL; ++ int i = 0; ++ ++ for (i=0; i<WIFI_FWD_TBL_SIZE; i++) ++ { ++ entry = WiFiFwdBase + i; ++ ++ if (entry->valid == 1) ++ { ++ if (entry->src == dev) ++ { ++ *type = ENTRY_TYPE_SRC; ++ src = wifi_fwd_insert_packet_source(skb, dev, entry->dest); ++ ++ if (src != NULL) ++ return src; ++ } ++ else if (entry->dest == dev) ++ { ++ *type = ENTRY_TYPE_DEST; ++ src = wifi_fwd_insert_packet_source(skb, dev, entry->src); ++ ++ if (src != NULL) ++ return src; ++ } ++ } ++ } ++ ++ *type = ENTRY_TYPE_INVALID; ++ return NULL; ++} ++ ++void wifi_fwd_probe_adapter(void *adapter) ++{ ++ if (!WIFI_FWD_TEST_FLAG(fOP_WIFI_FWD_ENABLED)) ++ return; ++ ++ if ((adapter != NULL) && (adapter_tmp_1 == NULL)) { ++ adapter_tmp_1 = adapter; ++ } else if ((adapter != NULL) && (adapter_tmp_2 == NULL)) { ++ if (adapter != adapter_tmp_1) ++ adapter_tmp_2 = adapter; ++ } else if ((adapter != NULL) && (adapter_tmp_3 == NULL)) { ++ if ((adapter != adapter_tmp_1) && (adapter != adapter_tmp_2)) ++ adapter_tmp_3 = adapter; ++ ++ } ++} ++ ++void wifi_fwd_feedback_map_table(void *adapter, void **peer, void **opp_peer, void **oth_peer) ++{ ++ unsigned char index; ++ ++ if (!WIFI_FWD_TEST_FLAG(fOP_WIFI_FWD_ENABLED)) ++ return; ++ ++ if(!adapter) ++ return; ++ ++ FWD_IRQ_LOCK(&global_band_tbl_lock, global_band_tbl_irq_flags); ++ ++ for (index=0; index<num_rep_tbl; index++) ++ { ++ if (adapter == *adapter_table[index]) ++ { ++ if (rep_table[index]->Enabled == TRUE) ++ *peer = rep_table[index]; ++ else ++ *peer = NULL; ++ ++ } ++ else ++ { ++ if (*opp_peer == NULL) ++ { ++ if (rep_table[index] && rep_table[index]->Enabled == TRUE) ++ *opp_peer = rep_table[index]; ++ else ++ *opp_peer = NULL; ++ } ++ else ++ { ++ if (rep_table[index] && rep_table[index]->Enabled == TRUE) ++ *oth_peer = rep_table[index]; ++ else ++ *oth_peer = NULL; ++ ++ } ++ } ++ } ++ FWD_IRQ_UNLOCK(&global_band_tbl_lock, global_band_tbl_irq_flags); ++ ++} ++ ++void wifi_fwd_insert_repeater_mapping(void *adapter, void *lock, void *cli_mapping, void *map_mapping, void *ifAddr_mapping) ++{ ++ if (!WIFI_FWD_TEST_FLAG(fOP_WIFI_FWD_ENABLED)) ++ return; ++ ++ FWD_IRQ_LOCK(&global_band_tbl_lock, global_band_tbl_irq_flags); ++ ++ if ((adapter == adapter_tmp_1)) { ++ global_map_tbl_1.EntryLock = lock; ++ global_map_tbl_1.CliHash = cli_mapping; ++ global_map_tbl_1.MapHash = map_mapping; ++ if ((global_map_tbl_1.Wdev_ifAddr ==NULL) || ++ (global_map_tbl_1.Wdev_ifAddr == ifAddr_mapping)) ++ global_map_tbl_1.Wdev_ifAddr = ifAddr_mapping; ++ else ++ global_map_tbl_1.Wdev_ifAddr_DBDC = ifAddr_mapping; ++ global_map_tbl_1.Enabled = TRUE; ++ ++ } else if ((adapter == adapter_tmp_2)) { ++ global_map_tbl_2.EntryLock = lock; ++ global_map_tbl_2.CliHash = cli_mapping; ++ global_map_tbl_2.MapHash = map_mapping; ++ if ((global_map_tbl_2.Wdev_ifAddr ==NULL) || ++ (global_map_tbl_2.Wdev_ifAddr == ifAddr_mapping)) ++ global_map_tbl_2.Wdev_ifAddr = ifAddr_mapping; ++ else ++ global_map_tbl_2.Wdev_ifAddr_DBDC = ifAddr_mapping; ++ global_map_tbl_2.Enabled = TRUE; ++ ++ } else if ((adapter == adapter_tmp_3)) { ++ global_map_tbl_3.EntryLock = lock; ++ global_map_tbl_3.CliHash = cli_mapping; ++ global_map_tbl_3.MapHash = map_mapping; ++ if ((global_map_tbl_3.Wdev_ifAddr ==NULL) || ++ (global_map_tbl_3.Wdev_ifAddr == ifAddr_mapping)) ++ global_map_tbl_3.Wdev_ifAddr = ifAddr_mapping; ++ else ++ global_map_tbl_3.Wdev_ifAddr_DBDC = ifAddr_mapping; ++ ++ global_map_tbl_3.Enabled = TRUE; ++ } ++ ++ FWD_IRQ_UNLOCK(&global_band_tbl_lock, global_band_tbl_irq_flags); ++} ++ ++void wifi_fwd_insert_bridge_mapping(struct sk_buff *skb) ++{ ++ struct net_device *net_dev = NULL; ++ struct APCLI_BRIDGE_LEARNING_MAPPING_STRUCT *map_tbl_entry = NULL; ++ unsigned char pkt_from, tbl_size = 0; ++ ++ net_dev = skb->dev; ++ ++ if (!WIFI_FWD_TEST_FLAG(fOP_WIFI_FWD_ENABLED)) ++ return; ++ ++ if ((net_dev == ap_5g) || (net_dev == apcli_5g)) ++ pkt_from = WIFI_FWD_PACKET_SPECIFIC_5G; ++ else ++ pkt_from = WIFI_FWD_PACKET_SPECIFIC_2G; ++ ++ FWD_IRQ_LOCK(&global_map_tbl_lock, global_map_tbl_irq_flags); ++ ++ if (global_map_tbl.entry_num < 0) { ++ FWD_IRQ_UNLOCK(&global_map_tbl_lock, global_map_tbl_irq_flags); ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s] no entry found in the list\n", __FUNCTION__)); ++ return; ++ } ++ ++ tbl_size = sizeof(struct APCLI_BRIDGE_LEARNING_MAPPING_STRUCT); ++ map_tbl_entry = (struct APCLI_BRIDGE_LEARNING_MAPPING_STRUCT *) kmalloc(tbl_size, GFP_ATOMIC); ++ ++ if (map_tbl_entry) { ++ memset(map_tbl_entry, 0, tbl_size); ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s] size of map_tbl_entry = %dbytes\n", __FUNCTION__, tbl_size)); ++ } else ++ return; ++ ++ map_tbl_entry->rcvd_net_dev = net_dev; ++ map_tbl_entry->entry_from = pkt_from; ++ memcpy(map_tbl_entry->src_addr, ((unsigned char *)skb->data)[6], ETH_ALEN); ++ ++ if (global_map_tbl.entry_num == 0) { ++ global_map_tbl.pHead = map_tbl_entry; ++ global_map_tbl.pTail = map_tbl_entry; ++ map_tbl_entry->pBefore = NULL; ++ map_tbl_entry->pNext = NULL; ++ } ++ else if (global_map_tbl.entry_num > 0) { ++ global_map_tbl.pTail->pNext = map_tbl_entry; ++ map_tbl_entry->pBefore = global_map_tbl.pTail; ++ global_map_tbl.pTail = map_tbl_entry; ++ } ++ ++ global_map_tbl.entry_num++; ++ FWD_IRQ_UNLOCK(&global_map_tbl_lock, global_map_tbl_irq_flags); ++ ++ if (0) { ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s] %s\n", __FUNCTION__, (pkt_from == WIFI_FWD_PACKET_SPECIFIC_5G ? "5G" : "2.4G"))); ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s] inserting mac addr = %02X:%02X:%02X:%02X:%02X:%02X\n", ++ __FUNCTION__, PRINT_MAC(map_tbl_entry->src_addr))); ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s] rcvd from %s\n", __FUNCTION__, WIFI_FWD_NETDEV_GET_DEVNAME(map_tbl_entry->rcvd_net_dev))); ++ } ++ ++ return; ++} ++ ++ ++/* ++ return value: ++ 1: success ++ 0: fail ++*/ ++static int wifi_fwd_search_mapping_table(struct sk_buff *skb, struct APCLI_BRIDGE_LEARNING_MAPPING_STRUCT **tbl_entry) ++{ ++ struct net_device *net_dev = NULL; ++ struct APCLI_BRIDGE_LEARNING_MAPPING_STRUCT *map_tbl_entry = NULL; ++ unsigned char pkt_from, idx = 0; ++ ++ net_dev = skb->dev; ++ ++ if (!WIFI_FWD_TEST_FLAG(fOP_WIFI_FWD_ENABLED)) ++ return 0; ++ ++ if ((net_dev == ap_5g) || (net_dev == apcli_5g)) ++ pkt_from = WIFI_FWD_PACKET_SPECIFIC_5G; ++ else ++ pkt_from = WIFI_FWD_PACKET_SPECIFIC_2G; ++ ++ FWD_IRQ_LOCK(&global_map_tbl_lock, global_map_tbl_irq_flags); ++ ++ if (global_map_tbl.entry_num <= 0) { ++ FWD_IRQ_UNLOCK(&global_map_tbl_lock, global_map_tbl_irq_flags); ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s] no entry found in the list\n", __FUNCTION__)); ++ return 0; ++ } ++ else ++ { ++ if (global_map_tbl.pHead != NULL) { ++ map_tbl_entry = global_map_tbl.pHead; ++ } ++ else ++ { ++ FWD_IRQ_UNLOCK(&global_map_tbl_lock, global_map_tbl_irq_flags); ++ return 0; ++ } ++ ++ for (idx=0; idx<global_map_tbl.entry_num; idx++) ++ { ++ if (MAC_ADDR_EQUAL(map_tbl_entry->src_addr, ((unsigned char *)skb->data)[6]) && ++ (net_dev != map_tbl_entry->rcvd_net_dev)) ++ { ++ if (map_tbl_entry->entry_from == WIFI_FWD_PACKET_SPECIFIC_5G) { ++ /* indicate this entry exist in dual band. packets sending to this entry need to be monitored */ ++ map_tbl_entry->entry_from |= pkt_from; ++ map_tbl_entry->rcvd_net_dev = net_dev; ++ } ++ else ++ { ++ /* make sure the net device reported in the packet is up */ ++ if (dev_get_flags(map_tbl_entry->rcvd_net_dev) & IFF_UP) { ++ map_tbl_entry->entry_from |= pkt_from; /* indicate this entry exist in dual band. packet need to send to this */ ++ SET_OS_PKT_NETDEV(RTPKT_TO_OSPKT(skb), map_tbl_entry->rcvd_net_dev); /* change net_device of packet to 2G */ ++ } ++ } ++ ++ *tbl_entry = map_tbl_entry; ++ FWD_IRQ_UNLOCK(&global_map_tbl_lock, global_map_tbl_irq_flags); ++ return 1; ++ } ++ else if (MAC_ADDR_EQUAL(map_tbl_entry->src_addr, ((unsigned char *)skb->data)[6]) && ++ (net_dev == map_tbl_entry->rcvd_net_dev)) ++ { ++ *tbl_entry = map_tbl_entry; ++ FWD_IRQ_UNLOCK(&global_map_tbl_lock, global_map_tbl_irq_flags); ++ return 1; ++ } ++ ++ map_tbl_entry = map_tbl_entry->pNext; ++ } ++ ++ FWD_IRQ_UNLOCK(&global_map_tbl_lock, global_map_tbl_irq_flags); ++ } ++ ++ return 0; ++} ++ ++ ++/* ++ return value: ++ 1: Allocate Success ++ 0: Allocate FAIL ++*/ ++static int wifi_fwd_alloc_tbl(unsigned int NumOfEntry) ++{ ++ unsigned int TblSize = 0; ++ ++ TblSize = NumOfEntry * sizeof(struct FwdPair); ++ WiFiFwdBase = (struct FwdPair *) kmalloc(TblSize, GFP_ATOMIC); ++ if (WiFiFwdBase) { ++ memset(WiFiFwdBase, 0, TblSize); ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s] size of WiFiFwdBase = %dbytes\n", __FUNCTION__, TblSize)); ++ } ++ else ++ return 0; ++ ++ TblSize = NumOfEntry * sizeof(struct PacketSource); ++ pkt_src = (struct PacketSource *) kmalloc(TblSize, GFP_ATOMIC); ++ if (pkt_src) { ++ memset(pkt_src, 0, TblSize); ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s] size of pkt_src = %dbytes\n", __FUNCTION__, TblSize)); ++ } ++ else ++ return 0; ++ ++ TblSize = NumOfEntry * sizeof(struct TxSourceEntry); ++ tx_src_tbl = (struct TxSourceEntry *) kmalloc(TblSize, GFP_ATOMIC); ++ if (tx_src_tbl) { ++ memset(tx_src_tbl, 0, TblSize); ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s] size of tx_src_tbl = %dbytes\n", __FUNCTION__, TblSize)); ++ } ++ else ++ return 0; ++ ++ TblSize = sizeof(struct APCLI_BRIDGE_LEARNING_MAPPING_MAP); ++ memset(&global_map_tbl, 0, TblSize); ++ ++ TblSize = sizeof(struct _REPEATER_ADAPTER_DATA_TABLE); ++ memset(&global_map_tbl_1, 0, TblSize); ++ memset(&global_map_tbl_2, 0, TblSize); ++ memset(&global_map_tbl_3, 0, TblSize); ++ ++ return 1; ++} ++ ++static int wifi_fwd_alloc_device_info(unsigned int NumOfDevice) ++{ ++ unsigned int DeviceSize = 0; ++ ++ DeviceSize = NumOfDevice * sizeof(struct DevInfo); ++ FwdDevice = (struct DevInfo *) kmalloc(DeviceSize, GFP_ATOMIC); ++ if (FwdDevice) { ++ memset(FwdDevice, 0, DeviceSize); ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s] size of FwdDevice = %dbytes\n", __FUNCTION__, DeviceSize)); ++ } ++ else ++ return 0; ++ ++ return 1; ++} ++ ++ ++ ++static unsigned char wifi_fwd_check_and_forward(struct sk_buff *skb) ++{ ++ struct ethhdr *mh = NULL; ++ struct iphdr *iph = NULL; ++ struct udphdr *uh = NULL; ++ struct tcphdr *th = NULL; ++ struct ipv6hdr *ipv6h = NULL; ++ void *ptr = NULL; ++ unsigned short type = 0; ++ ++ mh = eth_hdr(skb); ++ if (mh) ++ { ++ type = ntohs(mh->h_proto); ++ switch(type) ++ { ++ /* ++ Forward LLTD EthType: 0x88D9 ++ */ ++ case LLTD_ETH_TYPE: ++#if 0 ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("Forward - LLTD_ETH_TYPE: 0x%02x\n", type)); ++#endif ++ if (!WIFI_FWD_TEST_FLAG(fOP_WIFI_FWD_ACCESS_SCHED_ACTIVE)) ++ return TRUE; ++ break; ++ ++ /* ++ Forward ARP EthType: 0x0806 ++ */ ++ case ARP_ETH_TYPE: ++#if 0 ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("Forward - ARP_ETH_TYPE: 0x%02x\n", type)); ++#endif ++ if (WIFI_FWD_TEST_FLAG(fOP_WIFI_FWD_ACCESS_SCHED_ACTIVE)) ++ return TRUE; ++ break; ++ ++ case ETH_P_IP: ++ iph = (struct iphdr *)(skb->data); ++#if 0 ++ hex_dump_("Data", skb->data, (iph->ihl<<2)); ++#endif ++ if (iph) ++ { ++ ptr = (void *)(skb->data+(iph->ihl<<2)); ++ if (ptr) ++ { ++#if 0 ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("wifi_fwd_check_and_forward - iph->protocol: 0x%02x\n", iph->protocol)); ++#endif ++ switch(iph->protocol) ++ { ++ case UDP: ++ /* ++ Forward UDP port 53 and 67 ++ */ ++ uh = (struct udphdr*)(ptr); ++ if ((ntohs(uh->source) == 53) || (ntohs(uh->dest) == 53) || ++ (ntohs(uh->source) == 67) || (ntohs(uh->dest) == 67)) ++ { ++#if 0 ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("Forward - udp source port: %d, dest port: %d\n", ntohs(uh->source), ntohs(uh->dest))); ++#endif ++ return TRUE; ++ } ++ break; ++ ++ case TCP: ++ /* ++ Forward TCP port 80 and 5000 ++ */ ++ th = (struct tcphdr *)(ptr); ++ if ((ntohs(th->source) == 80) || ++ (ntohs(th->dest) == 80) || ++ (ntohs(th->source) == 5000) || ++ (ntohs(th->dest) == 5000)) ++ { ++#if 0 ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("Forward - tcp source port: %d, dest port: %d\n", ntohs(th->source), ntohs(th->dest))); ++#endif ++ if (!WIFI_FWD_TEST_FLAG(fOP_WIFI_FWD_ACCESS_SCHED_ACTIVE)) ++ return TRUE; ++ } ++ break; ++ ++ default: ++ break; ++ } ++ } ++ } ++ break; ++ ++ case ETH_P_IPV6: ++#if 0 ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("IPv6: IPV6_HDR_LEN = %d\n", IPV6_HDR_LEN)); ++ hex_dump_("Data", skb->data, LENGTH_802_3+IPV6_HDR_LEN); ++#endif ++ ipv6h = (struct ipv6hdr *)(skb->data); ++ if (ipv6h) ++ { ++#if 0 ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("ipv6h->version = 0x%x\n", ipv6h->version)); ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("ipv6h->nexthdr = 0x%x\n", ipv6h->nexthdr)); ++#endif ++ ptr = (void *)(skb->data+IPV6_HDR_LEN); ++ if (ptr) ++ { ++ switch(ipv6h->nexthdr) ++ { ++ /* ++ Forward IPv6 UDP port 53 ++ */ ++ case IPV6_NEXT_HEADER_UDP: ++ uh = (struct udphdr*)(ptr); ++#if 0 ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("udp source port: %d, dest port: %d\n", ntohs(uh->source), ntohs(uh->dest))); ++#endif ++ if ((ntohs(uh->source) == 53) || (ntohs(uh->dest) == 53)) ++ { ++ return TRUE; ++ } ++ break; ++ ++ default: ++ break; ++ } ++ } ++ } ++ break; ++ ++ default: ++ break; ++ } ++ } ++ ++ return FALSE; ++} ++ ++/* ++ return value: ++ 0: return to driver and handle ++ 1: return to driver and release ++*/ ++static int wifi_fwd_tx_handler(struct sk_buff *skb) ++{ ++ struct net_device *net_dev = NULL; ++ unsigned char ret = 0; ++ net_dev = skb->dev; ++ ++ /* ++ return this skb to driver and handle while: ++ 1. path of WiFi forwarding is inactive ++ 2. the skb does not exist ++ 3. no forwarding connection is established ++ */ ++ if (!WIFI_FWD_TEST_FLAG(fOP_WIFI_FWD_ACTIVE) ++ || !WIFI_FWD_TEST_FLAG(fOP_WIFI_FWD_ENABLED) ++ || !skb ++ || (fwd_counter == 0)) ++ return 0; ++ ++ ret = wifi_fwd_tx_lookup_entry(net_dev, skb); ++ return ret; ++} ++ ++/* ++ return value: ++ 0: skb is handled by wifi_fwd module ++ 1: return to driver and handle ++ 2: return to driver and release ++*/ ++static int wifi_fwd_rx_handler(struct sk_buff *skb) ++{ ++ struct net_device *net_dev = NULL; ++ struct net_device *target = NULL; ++ struct ethhdr *mh = eth_hdr(skb); ++ struct DevInfo *device_info = NULL; ++ unsigned char rep = 0, type = ENTRY_TYPE_INVALID; ++ unsigned int recv_from = 0, band_from = 0, ret = 0; ++ int idx = 0; ++ ++ net_dev = skb->dev; ++ recv_from = WIFI_FWD_GET_PACKET_RECV_FROM(skb, recv_from_cb_offset); ++ band_from = WIFI_FWD_GET_PACKET_BAND(skb, band_cb_offset); ++ ++ /* ++ return this skb to driver and bridge while: ++ 1. path of WiFi forwarding is inactive ++ 2. the skb does not exist ++ 3. no forwarding connection is established ++ 4. the destination is to bridge or ethernet ++ 5. in FastLane topology ++ 6. handling multicast/broadcast Rx ++ 7. hit hijack ++ */ ++ if (!WIFI_FWD_TEST_FLAG(fOP_WIFI_FWD_ACTIVE) ++ || !WIFI_FWD_TEST_FLAG(fOP_WIFI_FWD_ENABLED) ++ || !skb ++ || (fwd_counter == 0)) ++ return 1; ++ ++ /* drop the packet due to there's no forwarding links between ap-client and ap */ ++ if (IS_PACKET_FROM_APCLI(recv_from) && !MAIN_SSID_OP(net_dev)) ++ return 2; ++ ++ /* handle access schedule */ ++ if (WIFI_FWD_TEST_FLAG(fOP_WIFI_FWD_ACCESS_SCHED_ACTIVE)) ++ { ++ if (IS_PACKET_FROM_APCLI(recv_from)) ++ { ++ if (wifi_fwd_check_and_forward(skb) == FALSE) ++ return 2; ++ } ++ } ++ ++ /* forward the packet to bridge no matter unicast or broadcast */ ++ if (MAC_ADDR_EQUAL(mh->h_dest, br_lan->dev_addr)) ++ return 1; ++ ++ /* ++ in FastLane topology: ++ 1. forward Rx packets to bridge and let flooding work done by bridge ++ 2. no matter unicast or multicast/broadcast ++ or in MBSS support ++ */ ++ if (is_fastlane_mode(net_dev) || is_mbss_mode(band_from)) ++ return 1; ++ ++ idx = wifi_fwd_find_device(net_dev); ++ if (idx < 0) ++ { ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s][%d] cannot find device information\n", __FUNCTION__, __LINE__)); ++ return 1; ++ } ++ ++ device_info = FwdDevice + idx; ++ ++ /* ++ prevent from looping ++ 0: no looping ++ 1: looping found and need to drop the packet ++ 2: forward to bridge and handle ++ */ ++ ret = wifi_fwd_check_looping(skb, device_info); ++ if (ret == 1) ++ return 2; ++ else if (ret == 2) ++ return 1; ++ ++ /* after checking looping, handle multicast/broadcast Rx */ ++ if ((mh->h_dest[0] & 0x1) == 0x1) ++ return 1; ++ ++ /* handle hijack */ ++ if (WIFI_FWD_TEST_FLAG(fOP_WIFI_FWD_HIJACK_ACTIVE)) ++ { ++ if (wifi_fwd_check_and_forward(skb) == TRUE) ++ { ++ WIFI_FWD_SET_PACKET_BAND(skb,WIFI_FWD_PACKET_SPECIFIC_TAG, band_cb_offset); ++ return 1; ++ } ++ } ++ ++ /* forward the packet to bridge by comparing destination address @ concurrent mode */ ++ if (wifi_fwd_pkt_to_bridge_by_dest_addr(skb, net_dev)) ++ return 1; ++ ++ target = wifi_fwd_lookup_entry(net_dev, &type, skb); ++ ++ /* handle unicast Rx for non-FastLane cases */ ++ if (target != NULL) ++ { ++ /* prevent from looping */ ++ if (wifi_fwd_find_sa_entry_by_sa_and_nd(skb, net_dev, 0) != 0) ++ { ++ unsigned char hit = 0; ++ ++ /* forward to bridge if it is not a WiFi net device back-end packet */ ++ hit = wifi_fwd_check_from_bridge_by_dest_addr(skb, device_info); ++ ++ if (hit == 0) ++ { ++ /* this packet should be forwarded to bridge due to the destination is addessing to bridge or ethernet */ ++ if (is_concurrent_mode(net_dev) && IS_PACKET_FROM_ETHER(band_from)) ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("[%s][%d] this case is not reasonable\n", __FUNCTION__, __LINE__)); ++ ++ return 1; ++ } ++ else if (hit == 2) ++ { ++ /* match inner communication case */ ++ return 1; ++ } ++ else ++ { ++ /* this packet should be delivered to WiFi interface and transmitted directly */ ++ skb_push(skb, ETH_HLEN); ++ skb->dev = target; ++ dev_queue_xmit(skb); ++ return 0; ++ } ++ ++ return 1; ++ } ++ else ++ return 2; ++ } ++ else ++ return 1; ++} ++ ++ ++static int wifi_fwd_init_mod(void) ++{ ++ if (!wifi_fwd_alloc_tbl(WIFI_FWD_TBL_SIZE)) { ++ return -ENOMEM; /* memory allocation failed */ ++ } ++ ++ if (!wifi_fwd_alloc_device_info(WIFI_FWD_DEVICE_SIZE)) { ++ return -ENOMEM; /* memory allocation failed */ ++ } ++ ++ WIFI_FWD_CLEAR_FLAG(fOP_GET_NET_DEVICE_STATUS_DONE); ++ WIFI_FWD_CLEAR_FLAG(fOP_WIFI_FWD_ACCESS_SCHED_ACTIVE); ++ WIFI_FWD_SET_FLAG(fOP_WIFI_FWD_ENABLED); ++ WIFI_FWD_SET_FLAG(fOP_WIFI_FWD_ACTIVE); ++ WIFI_FWD_CLEAR_FLAG(fOP_WIFI_FWD_HIJACK_ACTIVE); ++ ++ wifi_fwd_reset_link_count(); ++ ++ eth_rep5g_wrg_uni_cnt = 0; ++ eth_rep5g_wrg_bct_cnt = 0; ++ eth_rep2g_wrg_uni_cnt = 0; ++ eth_rep2g_wrg_bct_cnt = 0; ++ rep_net_dev = eth_traffic_band_5g; ++ next_2g_band = band_5g; ++ band_cb_offset = DEFAULT_BAND_CB_OFFSET; ++ recv_from_cb_offset = DEFAULT_RECV_FROM_CB_OFFSET; ++ wf_debug_level = WF_DEBUG_OFF; ++ ++ wf_fwd_tx_hook = wifi_fwd_tx_handler; ++ wf_fwd_rx_hook = wifi_fwd_rx_handler; ++ wf_fwd_entry_insert_hook = wifi_fwd_insert_entry; ++ wf_fwd_entry_delete_hook = wifi_fwd_delete_entry; ++ wf_fwd_set_cb_num = wifi_fwd_set_cb_num; ++ wf_fwd_check_active_hook = wifi_fwd_check_active; ++ wf_fwd_get_rep_hook = wifi_fwd_get_rep; ++ wf_fwd_pro_active_hook = wifi_fwd_pro_active; ++ wf_fwd_pro_halt_hook = wifi_fwd_pro_halt; ++ wf_fwd_pro_enabled_hook = wifi_fwd_pro_enabled; ++ wf_fwd_pro_disabled_hook = wifi_fwd_pro_disabled; ++ wf_fwd_access_schedule_active_hook = wifi_fwd_access_schedule_active; ++ wf_fwd_access_schedule_halt_hook = wifi_fwd_access_schedule_halt; ++ wf_fwd_hijack_active_hook = wifi_fwd_hijack_active; ++ wf_fwd_hijack_halt_hook = wifi_fwd_hijack_halt; ++ wf_fwd_show_entry_hook = wifi_fwd_show_entry; ++ wf_fwd_needed_hook = wifi_fwd_needed; ++ wf_fwd_delete_entry_hook = wifi_fwd_delete_entry_by_idx; ++ packet_source_show_entry_hook = packet_source_show_entry; ++ packet_source_delete_entry_hook = packet_source_delete_entry; ++ wf_fwd_feedback_map_table = wifi_fwd_feedback_map_table; ++ wf_fwd_probe_adapter = wifi_fwd_probe_adapter; ++ wf_fwd_insert_bridge_mapping_hook = wifi_fwd_insert_bridge_mapping; ++ wf_fwd_insert_repeater_mapping_hook = wifi_fwd_insert_repeater_mapping; ++ wf_fwd_search_mapping_table_hook = wifi_fwd_search_mapping_table; ++ wf_fwd_delete_entry_inform_hook = wf_fwd_delete_entry_inform; ++ wf_fwd_check_device_hook = wifi_fwd_check_device; ++ wf_fwd_add_entry_inform_hook = wf_fwd_add_entry_inform; ++ ++ return 0; ++} ++ ++ ++static void wifi_fwd_cleanup_mod(void) ++{ ++ if (WiFiFwdBase) ++ kfree(WiFiFwdBase); ++ WiFiFwdBase = NULL; ++ ++ if (FwdDevice) ++ kfree(FwdDevice); ++ FwdDevice = NULL; ++ ++ if (pkt_src) ++ kfree(pkt_src); ++ pkt_src = NULL; ++ ++ if(tx_src_tbl) ++ kfree(tx_src_tbl); ++ tx_src_tbl = NULL; ++ ++ wf_fwd_tx_hook = NULL; ++ wf_fwd_rx_hook = NULL; ++ wf_fwd_entry_insert_hook = NULL; ++ wf_fwd_entry_delete_hook = NULL; ++ wf_fwd_set_cb_num = NULL; ++ wf_fwd_check_active_hook = NULL; ++ wf_fwd_get_rep_hook = NULL; ++ wf_fwd_pro_active_hook = NULL; ++ wf_fwd_pro_halt_hook = NULL; ++ wf_fwd_pro_enabled_hook = NULL; ++ wf_fwd_pro_disabled_hook = NULL; ++ wf_fwd_access_schedule_active_hook = NULL; ++ wf_fwd_access_schedule_halt_hook = NULL; ++ wf_fwd_hijack_active_hook = NULL; ++ wf_fwd_hijack_halt_hook = NULL; ++ wf_fwd_show_entry_hook = NULL; ++ wf_fwd_needed_hook = NULL; ++ wf_fwd_delete_entry_hook = NULL; ++ packet_source_show_entry_hook = NULL; ++ packet_source_delete_entry_hook = NULL; ++ wf_fwd_feedback_map_table = NULL; ++ wf_fwd_probe_adapter = NULL; ++ wf_fwd_insert_bridge_mapping_hook = NULL; ++ wf_fwd_insert_repeater_mapping_hook = NULL; ++ wf_fwd_search_mapping_table_hook = NULL; ++ wf_fwd_delete_entry_inform_hook = NULL; ++ wf_fwd_check_device_hook = NULL; ++ wf_fwd_add_entry_inform_hook = NULL; ++ wf_fwd_debug_level_hook = NULL; ++ ++ return; ++} ++ ++ ++module_init(wifi_fwd_init_mod); ++module_exit(wifi_fwd_cleanup_mod); ++ ++MODULE_AUTHOR("MediaTek Inc"); ++MODULE_LICENSE("Proprietary"); ++MODULE_DESCRIPTION("MediaTek WiFi Packet Forwarding Module\n"); ++ +Index: linux-3.10.20/drivers/net/wireless/wifi_forward/wifi_fwd/wifi_fwd.h +=================================================================== +--- /dev/null ++++ linux-3.10.20/drivers/net/wireless/wifi_forward/wifi_fwd/wifi_fwd.h +@@ -0,0 +1,319 @@ ++/**************************************************************************** ++ * Mediatek Inc. ++ * 5F., No.5, Taiyuan 1st St., Zhubei City, ++ * Hsinchu County 302, Taiwan, R.O.C. ++ * (c) Copyright 2014, Mediatek, Inc. ++ * ++ * All rights reserved. Ralink's source code is an unpublished work and the ++ * use of a copyright notice does not imply otherwise. This source code ++ * contains confidential trade secret material of Ralink Tech. Any attemp ++ * or participation in deciphering, decoding, reverse engineering or in any ++ * way altering the source code is stricitly prohibited, unless the prior ++ * written consent of Ralink Technology, Inc. is obtained. ++ **************************************************************************** ++ ++ Module Name: ++ wifi_fwd.h ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Annie Lu 2014-06-30 Initial version ++*/ ++ ++#ifndef __WF_FWD_H__ ++#define __WF_FWD_H__ ++ ++#include <linux/version.h> ++#include <linux/module.h> ++#include <linux/skbuff.h> ++#include <linux/kernel.h> ++#include <linux/net.h> ++#include <linux/netdevice.h> ++#include <linux/ip.h> ++#include <linux/ipv6.h> ++#include <linux/udp.h> ++#include <linux/tcp.h> ++ ++#ifndef TRUE ++#define TRUE 1 ++#endif ++ ++#ifndef FALSE ++#define FALSE 0 ++#endif ++ ++/* enternal symbol */ ++extern int (*wf_fwd_rx_hook) (struct sk_buff *skb); ++extern int (*wf_fwd_tx_hook) (struct sk_buff *skb); ++ ++extern unsigned char (*wf_fwd_entry_insert_hook) (struct net_device *src, struct net_device *dest, void *adapter); ++extern unsigned char (*wf_fwd_entry_delete_hook) (struct net_device *src, struct net_device *dest, unsigned char link_down); ++extern void (*wf_fwd_set_cb_num) (unsigned int band_cb_num, unsigned int receive_cb_num); ++extern bool (*wf_fwd_check_active_hook) (void); ++extern void (*wf_fwd_get_rep_hook) (unsigned char idx); ++extern void (*wf_fwd_pro_active_hook) (void); ++extern void (*wf_fwd_pro_halt_hook) (void); ++extern void (*wf_fwd_pro_enabled_hook) (void); ++extern void (*wf_fwd_pro_disabled_hook) (void); ++extern void (*wf_fwd_access_schedule_active_hook) (void); ++extern void (*wf_fwd_access_schedule_halt_hook) (void); ++extern void (*wf_fwd_hijack_active_hook) (void); ++extern void (*wf_fwd_hijack_halt_hook) (void); ++extern void (*wf_fwd_show_entry_hook) (void); ++extern bool (*wf_fwd_needed_hook) (void); ++extern void (*wf_fwd_delete_entry_hook) (unsigned char idx); ++extern void (*packet_source_show_entry_hook) (void); ++extern void (*packet_source_delete_entry_hook) (unsigned char idx); ++extern void (*wf_fwd_feedback_map_table) (void *adapter, void *peer, void *opp_peer, void *oth_peer); ++extern void (*wf_fwd_probe_adapter) (void *adapter); ++extern void (*wf_fwd_insert_repeater_mapping_hook)(void *adapter, void *lock, void *cli_mapping, void *map_mapping, void *ifAddr_mapping); ++extern void (*wf_fwd_insert_bridge_mapping_hook) (struct sk_buff *skb); ++extern int (*wf_fwd_search_mapping_table_hook) (struct sk_buff *skb, struct APCLI_BRIDGE_LEARNING_MAPPING_STRUCT **tbl_entry); ++extern void (*wf_fwd_delete_entry_inform_hook) (unsigned char *addr); ++extern void (*wf_fwd_check_device_hook) ( struct net_device *net_dev, signed int type, signed int mbss_idx, unsigned char channel, unsigned char link); ++extern void (*wf_fwd_add_entry_inform_hook) (unsigned char *addr); ++extern void (*wf_fwd_debug_level_hook) (unsigned char level); ++ ++#ifndef ETH_ALEN ++#define ETH_ALEN 6 ++#endif ++#define MAC_ADDR_LEN 6 ++ ++#define H_CHANNEL_BIGGER_THAN 144 ++#define fOP_GET_NET_DEVICE_STATUS_DONE 0x00000001 ++#define fOP_WIFI_FWD_ENABLED 0x00000002 ++#define fOP_WIFI_FWD_ACTIVE 0x00000010 ++#define fOP_WIFI_FWD_ACCESS_SCHED_ACTIVE 0x00000100 ++#define fOP_WIFI_FWD_HIJACK_ACTIVE 0x00001000 ++ ++#define WIFI_FWD_SET_FLAG(_F) (wifi_fwd_op_flag |= (_F)) ++#define WIFI_FWD_CLEAR_FLAG(_F) (wifi_fwd_op_flag &= ~(_F)) ++#define WIFI_FWD_CLEAR_FLAGS (wifi_fwd_op_flag = 0) ++#define WIFI_FWD_TEST_FLAG(_F) ((wifi_fwd_op_flag & (_F)) != 0) ++#define WIFI_FWD_TEST_FLAGS(_F) ((wifi_fwd_op_flag & (_F)) == (_F)) ++ ++#define CMP_TO_REP(_p, _x) (REP_IS_##_x##G(_p)) ++ ++/* sanity check for apidx */ ++#define REP_IS_5G_H(_p) ((_p) == band_5g_h) ++#define REP_IS_5G(_p) ((_p) == band_5g) ++#define REP_IS_2G(_p) ((_p) == band_2g) ++ ++#define IS_UNICAST_PACKET(_p) ((((unsigned char *)(_p)->data)[0] & 0x1) == 0x0) ++#define IS_BROADCAST_PACKET(_p) ((((unsigned char *)(_p)->data)[0] & 0x1) == 0x1) ++ ++#define IS_AP_DEV(_p) ((_p) & (INT_MAIN | INT_MBSSID)) ++#define IS_APCLI_DEV(_p) ((_p) & INT_APCLI) ++#define IS_5G_HIGH(_p) ((_p) > H_CHANNEL_BIGGER_THAN) ++#define IS_VALID(_p) ((_p) == TRUE) ++ ++#define MAIN_SSID_OP(_p) ((main_2g_link_cnt != 0) || (main_5g_link_cnt != 0) || (main_5g_h_link_cnt != 0)) ++ ++#define WIFI_FWD_TBL_SIZE 50 ++#define WIFI_FWD_DEVICE_SIZE 34 /* currently max number of MBSS support */ ++ ++#define ENTRY_TYPE_INVALID 0 ++#define ENTRY_TYPE_SRC 1 ++#define ENTRY_TYPE_DEST 2 ++ ++/* debug macro */ ++#define dbg_print printk ++#define WF_DEBUG_OFF 0 ++#define WF_DEBUG_TRACE 1 ++#define WF_DEBUG_ON 2 ++ ++extern unsigned char wf_debug_level; ++ ++/* sync from WiFi driver */ ++#define INT_MAIN 0x0100 ++#define INT_MBSSID 0x0200 ++#define INT_APCLI 0x0400 ++ ++#define WF_FWD_PRINT(Level, Fmt) \ ++ do{ \ ++ unsigned char __gLevel = (Level); \ ++ if (__gLevel <= wf_debug_level) \ ++ { \ ++ printk Fmt; \ ++ } \ ++ }while(0) ++ ++/* CB related */ ++#define CB_OFF 10 ++#define RTPKT_TO_OSPKT(_p) ((struct sk_buff *)(_p)) ++#define GET_OS_PKT_CB(_p) (RTPKT_TO_OSPKT(_p)->cb) ++#define PACKET_CB(_p, _offset) ((RTPKT_TO_OSPKT(_p)->cb[CB_OFF + (_offset)])) ++ ++/* [CB_OFF + 34]: tag the packet is sent by which band */ ++#define DEFAULT_BAND_CB_OFFSET 34 ++#define WIFI_FWD_PACKET_SPECIFIC_2G 0x1 ++#define WIFI_FWD_PACKET_SPECIFIC_5G 0x2 ++#define WIFI_FWD_PACKET_SPECIFIC_ETHER 0x4 ++#define WIFI_FWD_PACKET_SPECIFIC_TAG 0x8 ++#define WIFI_FWD_PACKET_SPECIFIC_5G_H 0x10 ++ ++#define WIFI_FWD_SET_PACKET_BAND(_p, _offset, _flg) \ ++ do{ \ ++ if (_flg) \ ++ PACKET_CB(_p, _offset) |= (_flg); \ ++ else \ ++ PACKET_CB(_p, _offset) &= (~_flg); \ ++ }while(0) ++ ++#define WIFI_FWD_GET_PACKET_BAND(_p, _offset) (PACKET_CB(_p, _offset)) ++ ++/* [CB_OFF + 35]: tag the packet received from which net device */ ++#define DEFAULT_RECV_FROM_CB_OFFSET 35 ++#define WIFI_FWD_PACKET_RECV_FROM_2G_CLIENT 0x01 ++#define WIFI_FWD_PACKET_RECV_FROM_5G_CLIENT 0x02 ++#define WIFI_FWD_PACKET_RECV_FROM_2G_AP 0x04 ++#define WIFI_FWD_PACKET_RECV_FROM_5G_AP 0x08 ++#define WIFI_FWD_PACKET_RECV_FROM_5G_H_CLIENT 0x10 ++#define WIFI_FWD_PACKET_RECV_FROM_5G_H_AP 0x20 ++ ++#if 0 ++#define WIFI_FWD_PACKET_RECV_FROM_2G_GUEST_CLIENT 0x10 ++#define WIFI_FWD_PACKET_RECV_FROM_5G_GUEST_CLIENT 0x20 ++#define WIFI_FWD_PACKET_RECV_FROM_2G_GUEST_AP 0x40 ++#define WIFI_FWD_PACKET_RECV_FROM_5G_GUEST_AP 0x80 ++#endif ++ ++#define WIFI_FWD_SET_PACKET_RECV_FROM(_p, _offset, _flg) \ ++ do{ \ ++ if (_flg) \ ++ PACKET_CB(_p, _offset) |= (_flg); \ ++ else \ ++ PACKET_CB(_p, _offset) &= (~_flg); \ ++ }while(0) ++ ++#define WIFI_FWD_GET_PACKET_RECV_FROM(_p, _offset) (PACKET_CB(_p, _offset)) ++ ++#define IS_PACKET_FROM_APCLI(_x) \ ++ ((((_x) & WIFI_FWD_PACKET_RECV_FROM_2G_CLIENT) == WIFI_FWD_PACKET_RECV_FROM_2G_CLIENT) ||\ ++ (((_x) & WIFI_FWD_PACKET_RECV_FROM_5G_CLIENT) == WIFI_FWD_PACKET_RECV_FROM_5G_CLIENT) ||\ ++ (((_x) & WIFI_FWD_PACKET_RECV_FROM_5G_H_CLIENT) == WIFI_FWD_PACKET_RECV_FROM_5G_H_CLIENT)) ++ ++#define IS_PACKET_FROM_2G(_x) \ ++ (((_x) & WIFI_FWD_PACKET_SPECIFIC_2G) == WIFI_FWD_PACKET_SPECIFIC_2G) ++ ++#define IS_PACKET_FROM_5G(_x) \ ++ (((_x) & WIFI_FWD_PACKET_SPECIFIC_5G) == WIFI_FWD_PACKET_SPECIFIC_5G) ++ ++#define IS_PACKET_FROM_5G_H(_x) \ ++ (((_x) & WIFI_FWD_PACKET_SPECIFIC_5G_H) == WIFI_FWD_PACKET_SPECIFIC_5G_H) ++ ++#define IS_TAG_PACKET(_x) \ ++ (((_x) & WIFI_FWD_PACKET_SPECIFIC_TAG) == WIFI_FWD_PACKET_SPECIFIC_TAG) ++ ++#define IS_PACKET_FROM_ETHER(_x) \ ++ ((((_x) & WIFI_FWD_PACKET_SPECIFIC_2G) != WIFI_FWD_PACKET_SPECIFIC_2G) &&\ ++ (((_x) & WIFI_FWD_PACKET_SPECIFIC_5G) != WIFI_FWD_PACKET_SPECIFIC_5G) &&\ ++ (((_x) & WIFI_FWD_PACKET_SPECIFIC_5G_H) != WIFI_FWD_PACKET_SPECIFIC_5G_H)) ++ ++#define IS_PACKET_FROM_MAIN_SSID(_x) \ ++ (((_x) & 0x0F) != 0x0) ++ ++#define IS_PACKET_FROM_GUEST_SSID(_x) \ ++ (((_x) & 0x0F) == 0x0) ++ ++ ++typedef enum _ETHER_BAND_BINDDING { ++ eth_traffic_band_2g = 2, ++ eth_traffic_band_5g = 5, ++ eth_traffic_band_5g_H = 6, ++} ETHER_BAND_BINDDING, *PETHER_BAND_BINDDING; ++ ++typedef enum _BAND_INDEX { ++ band_2g = 2, ++ band_5g = 5, ++ band_5g_h = 6, ++} BAND_INDEX; ++ ++/* data structure */ ++struct FwdPair { ++ unsigned char valid; /* 1: valid, 0: invalid */ ++ struct net_device *src; ++ struct net_device *dest; ++}; ++ ++struct PacketSource { ++ unsigned char valid; /* 1: valid, 0: invalid */ ++ struct net_device *peer; ++ struct net_device *src; ++ unsigned char h_source[ETH_ALEN]; ++ unsigned char h_dest[ETH_ALEN]; ++}; ++ ++/* ++ mainly to avoid looping caused by lan stations ++ 1. insert entries while (1) mac table insert entry @ WiFi driver (2) wifi_fwd_tx_handler @ forwarding module ++ 2. check while receiving packets ++*/ ++struct TxSourceEntry { ++ unsigned char valid; /* 1: valid, 0: invalid */ ++ unsigned char bfrom_wireless; /* 1: from wireless, 0: from ethernet */ ++ unsigned char h_source[ETH_ALEN]; ++}; ++ ++struct DevInfo { ++ unsigned char valid; /* 1: valid, 0: invalid */ ++ unsigned char index; ++ unsigned int type; /* ap or ap-client */ ++ int mbss_idx; /* for ap mode */ ++ BAND_INDEX band; ++ BAND_INDEX second_band; ++ BAND_INDEX third_band; ++ struct net_device *dev; ++ struct DevInfo *partner; ++}; ++ ++struct APCLI_BRIDGE_LEARNING_MAPPING_STRUCT { ++ struct net_device *rcvd_net_dev; ++ unsigned char src_addr[ETH_ALEN]; ++ unsigned char entry_from; ++ struct APCLI_BRIDGE_LEARNING_MAPPING_STRUCT *pBefore; ++ struct APCLI_BRIDGE_LEARNING_MAPPING_STRUCT *pNext; ++}; ++ ++struct APCLI_BRIDGE_LEARNING_MAPPING_MAP { ++ struct APCLI_BRIDGE_LEARNING_MAPPING_STRUCT *pHead; ++ struct APCLI_BRIDGE_LEARNING_MAPPING_STRUCT *pTail; ++ unsigned int entry_num; ++}; ++ ++typedef struct _REPEATER_ADAPTER_DATA_TABLE { ++ bool Enabled; ++ void *EntryLock; ++ void **CliHash; ++ void **MapHash; ++ void *Wdev_ifAddr; ++ void *Wdev_ifAddr_DBDC; ++} REPEATER_ADAPTER_DATA_TABLE; ++ ++ ++#define FWD_IRQ_LOCK(__lock, __irqflags) \ ++{ \ ++ __irqflags = 0; \ ++ spin_lock_irqsave((spinlock_t *)(__lock), __irqflags); \ ++} ++ ++#define FWD_IRQ_UNLOCK(__lock, __irqflag) \ ++{ \ ++ spin_unlock_irqrestore((spinlock_t *)(__lock), __irqflag); \ ++} ++ ++#define PRINT_MAC(addr) \ ++ addr[0], addr[1], addr[2], addr[3], addr[4], addr[5] ++ ++#define MAC_ADDR_EQUAL(addr1,addr2) (!memcmp((void *)(addr1), (void *)(addr2), ETH_ALEN)) ++#define COPY_MAC_ADDR(addr1, addr2) (memcpy((addr1), (addr2), ETH_ALEN)) ++ ++#define WIFI_FWD_NETDEV_GET_DEVNAME(_pNetDev) ((_pNetDev)->name) ++#define WIFI_FWD_NETDEV_GET_PHYADDR(_pNetDev) ((_pNetDev)->dev_addr) ++ ++#define SET_OS_PKT_NETDEV(_pkt, _pNetDev) \ ++ (RTPKT_TO_OSPKT(_pkt)->dev) = (_pNetDev) ++#endif +Index: linux-3.10.20/drivers/net/wireless/wifi_forward/wifi_fwd_v1/Kconfig +=================================================================== +--- /dev/null ++++ linux-3.10.20/drivers/net/wireless/wifi_forward/wifi_fwd_v1/Kconfig +@@ -0,0 +1 @@ ++ +Index: linux-3.10.20/drivers/net/wireless/wifi_forward/wifi_fwd_v1/Makefile +=================================================================== +--- /dev/null ++++ linux-3.10.20/drivers/net/wireless/wifi_forward/wifi_fwd_v1/Makefile +@@ -0,0 +1 @@ ++obj-$(CONFIG_WIFI_PKT_FWD) += wifi_fwd.o +Index: linux-3.10.20/drivers/net/wireless/wifi_forward/wifi_fwd_v1/wifi_fwd.c +=================================================================== +--- /dev/null ++++ linux-3.10.20/drivers/net/wireless/wifi_forward/wifi_fwd_v1/wifi_fwd.c +@@ -0,0 +1,2174 @@ ++/**************************************************************************** ++ * Mediatek Inc. ++ * 5F., No.5, Taiyuan 1st St., Zhubei City, ++ * Hsinchu County 302, Taiwan, R.O.C. ++ * (c) Copyright 2014, Mediatek, Inc. ++ * ++ * All rights reserved. Ralink's source code is an unpublished work and the ++ * use of a copyright notice does not imply otherwise. This source code ++ * contains confidential trade secret material of Ralink Tech. Any attemp ++ * or participation in deciphering, decoding, reverse engineering or in any ++ * way altering the source code is stricitly prohibited, unless the prior ++ * written consent of Ralink Technology, Inc. is obtained. ++ **************************************************************************** ++ ++ Module Name: ++ wifi_fwd.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Annie Lu 2014-06-30 Initial version ++ */ ++ ++#include "wifi_fwd.h" ++ ++struct net_device *ap_2g = NULL, *apcli_2g = NULL, *ap_5g = NULL, *apcli_5g = NULL, *br_lan = NULL; ++struct net_device *ap1_2g = NULL, *apcli1_2g = NULL, *ap1_5g = NULL, *apcli1_5g = NULL; ++struct FwdPair *WiFiFwdBase = NULL; ++struct PacketSource *pkt_src = NULL; ++struct TxSourceEntry *tx_src_tbl = NULL; ++unsigned int tx_src_count = 0; ++ ++void * adapter_2g = NULL; ++void * adapter_5g = NULL; ++void * adapter_tmp_1 = NULL; ++void * adapter_tmp_2 = NULL; ++ ++unsigned char wf_debug_level; ++static unsigned long wifi_fwd_op_flag; ++static unsigned char rep_net_dev; ++static unsigned char fwd_counter; ++static signed char main_5g_link_cnt; ++static signed char main_2g_link_cnt; ++static signed char guest_5g_link_cnt; ++static signed char guest_2g_link_cnt; ++ ++static unsigned int eth_rep5g_wrg_uni_cnt; ++static unsigned int eth_rep5g_wrg_bct_cnt; ++static unsigned int eth_rep2g_wrg_uni_cnt; ++static unsigned int eth_rep2g_wrg_bct_cnt; ++ ++static unsigned int band_cb_offset; ++static unsigned int recv_from_cb_offset; ++ ++REPEATER_ADAPTER_DATA_TABLE global_map_2g_tbl , global_map_5g_tbl; ++ ++struct APCLI_BRIDGE_LEARNING_MAPPING_MAP global_map_tbl; ++spinlock_t global_map_tbl_lock; ++unsigned long global_map_tbl_irq_flags; ++spinlock_t global_band_tbl_lock; ++unsigned long global_band_tbl_irq_flags; ++ ++ ++#define ARP_ETH_TYPE 0x0806 ++#define LLTD_ETH_TYPE 0x88D9 ++ ++#ifndef TCP ++#define TCP 0x06 ++#endif /* !TCP */ ++ ++#ifndef UDP ++#define UDP 0x11 ++#endif /* !UDP */ ++ ++#ifndef ETH_P_IPV6 ++#define ETH_P_IPV6 0x86DD ++#endif /* !ETH_P_IPV6 */ ++ ++#ifndef ETH_P_IP ++#define ETH_P_IP 0x0800 /* Internet Protocol packet */ ++#endif /* ETH_P_IP */ ++ ++#ifndef LENGTH_802_3 ++#define LENGTH_802_3 14 ++#endif /* !LENGTH_802_3 */ ++ ++#define IPV6_NEXT_HEADER_UDP 0x11 ++#define IPV6_HDR_LEN 40 ++ ++struct net_device *ra_dev_get_by_name(const char *name) ++{ ++ struct net_device *dev; ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) ++ dev = dev_get_by_name(&init_net, name); ++#else ++ dev = dev_get_by_name(name); ++#endif ++ ++ if (dev) ++ dev_put(dev); ++ ++ return dev; ++} ++ ++ ++static unsigned char is_wifi_fastlane_mode(struct net_device *dev) ++{ ++ if (IS_MAIN_SSID_DEV(dev)) { ++ if (((main_2g_link_cnt >= 2) && (main_5g_link_cnt == 0)) || ++ ((main_5g_link_cnt >= 2) && (main_2g_link_cnt == 0))) ++ return 1; ++ else ++ return 0; ++ } else if (IS_GUEST_SSID_DEV(dev)) { ++ if ((guest_2g_link_cnt >= 2) || (guest_5g_link_cnt >= 2)) ++ return 1; ++ else ++ return 0; ++ } ++} ++ ++ ++static unsigned char is_wifi_concurrent_mode(struct net_device *dev) ++{ ++ if (IS_MAIN_SSID_DEV(dev)) { ++ if (((main_2g_link_cnt == 1) && (main_5g_link_cnt == 1)) || ++ ((main_2g_link_cnt == 2) && (main_5g_link_cnt == 2))) ++ return 1; ++ else ++ return 0; ++ } else if (IS_GUEST_SSID_DEV(dev)) { ++ if ((guest_2g_link_cnt == 1) && (guest_5g_link_cnt == 1)) ++ return 1; ++ else ++ return 0; ++ } ++} ++ ++ ++static void cal_link_count_by_net_device(struct net_device *dev, unsigned char policy) ++{ ++ if (dev == apcli_2g) ++ { ++ if (policy > 0) ++ main_2g_link_cnt++; ++ else ++ main_2g_link_cnt--; ++ ++ if (main_2g_link_cnt < 0) ++ main_2g_link_cnt = 0; ++ } ++ else if (dev == apcli_5g) ++ { ++ if (policy > 0) ++ main_5g_link_cnt++; ++ else ++ main_5g_link_cnt--; ++ ++ if (main_5g_link_cnt < 0) ++ main_5g_link_cnt = 0; ++ } ++ else if (dev == apcli1_2g) ++ { ++ if (policy > 0) ++ guest_2g_link_cnt++; ++ else ++ guest_2g_link_cnt--; ++ ++ if (guest_2g_link_cnt < 0) ++ guest_2g_link_cnt = 0; ++ } ++ else if (dev == apcli1_5g) ++ { ++ if (policy > 0) ++ guest_5g_link_cnt++; ++ else ++ guest_5g_link_cnt--; ++ ++ if (guest_5g_link_cnt < 0) ++ guest_5g_link_cnt = 0; ++ } ++ ++ if (policy > 0) ++ fwd_counter++; ++ else ++ fwd_counter--; ++} ++ ++ ++static void dump_net_device_by_name(void) ++{ ++ ap_2g = ra_dev_get_by_name("ra0"); ++ apcli_2g = ra_dev_get_by_name("apcli0"); ++ ap_5g = ra_dev_get_by_name("rai0"); ++ apcli_5g = ra_dev_get_by_name("apclii0"); ++ ++ /* for Guest SSID */ ++ ap1_2g = ra_dev_get_by_name("ra1"); ++ apcli1_2g = ra_dev_get_by_name("apcli1"); ++ ap1_5g = ra_dev_get_by_name("rai1"); ++ apcli1_5g = ra_dev_get_by_name("apclii1"); ++ ++ br_lan = ra_dev_get_by_name("br-lan"); ++ ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[dump]ap_2g=0x%08X, apcli_2g=0x%08X, ap_5g=0x%08X, apcli_5g=0x%08X, br_lan=0x%08X\n", ++ (int)ap_2g, (int)apcli_2g, (int)ap_5g, (int)apcli_5g, (int)br_lan)); ++ ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[dump]ap1_2g=0x%08X, apcli1_2g=0x%08X, ap1_5g=0x%08X, apcli1_5g=0x%08X\n", ++ (int)ap1_2g, (int)apcli1_2g, (int)ap1_5g, (int)apcli1_5g)); ++ ++ ++} ++ ++ ++static void hex_dump_(char *str, unsigned char *pSrcBufVA, unsigned int SrcBufLen) ++{ ++ unsigned char *pt; ++ unsigned int x; ++ ++ pt = pSrcBufVA; ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("%s: %p, len = %d\n", str, pSrcBufVA, SrcBufLen)); ++ for (x=0; x<SrcBufLen; x++) { ++ if (x % 16 == 0) ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("0x%04x : ", x)); ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("%02x ", ((unsigned char)pt[x]))); ++ if (x % 16 == 15) ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("\n")); ++ } ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("\n")); ++} ++ ++ ++static void wifi_fwd_reset_link_count(void) ++{ ++ fwd_counter = 0; ++ main_5g_link_cnt = 0; ++ main_2g_link_cnt = 0; ++ guest_5g_link_cnt = 0; ++ guest_2g_link_cnt = 0; ++} ++ ++static bool wifi_fwd_needed(void) ++{ ++ if (!WIFI_FWD_TEST_FLAG(fOP_WIFI_FWD_ACTIVE) || !WIFI_FWD_TEST_FLAG(fOP_WIFI_FWD_ENABLED) || (fwd_counter == 0)) ++ return FALSE; ++ ++ return TRUE; ++} ++ ++ ++static void wifi_fwd_show_entry(void) ++{ ++ int idx = 0; ++ ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("\n[%s]fwd_link=%d, [5g main]=%d, [2g main]=%d, [5g guest]=%d, [2g guest]=%d\n", ++ __FUNCTION__, fwd_counter, main_5g_link_cnt, main_2g_link_cnt, ++ guest_5g_link_cnt, guest_2g_link_cnt)); ++ ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("[%s][5g main: 0x%08X <--> 0x%08X] : %d\n", ++ __FUNCTION__, (int)apcli_5g, (int)ap_5g, main_5g_link_cnt)); ++ ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("[%s][2g main: 0x%08X <--> 0x%08X] : %d\n", ++ __FUNCTION__, (int)apcli_2g, (int)ap_2g, main_2g_link_cnt)); ++ ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("[%s][5g guest: 0x%08X <--> 0x%08X] : %d\n", ++ __FUNCTION__, (int)apcli1_5g, (int)ap1_5g, guest_5g_link_cnt)); ++ ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("[%s][2g guest: 0x%08X <--> 0x%08X] : %d\n", ++ __FUNCTION__, (int)apcli1_2g, (int)ap1_2g, guest_2g_link_cnt)); ++ ++ for (idx=0; idx<WIFI_FWD_TBL_SIZE; idx++) ++ { ++ if (WiFiFwdBase[idx].valid) ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("[%s]index=%d, valid=%d, src_dev=0x%08X, dest_dev=0x%08X\n", ++ __FUNCTION__, idx, WiFiFwdBase[idx].valid, (int)WiFiFwdBase[idx].src, (int)WiFiFwdBase[idx].dest)); ++ } ++ ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("[%s]eth_rep5g_wrg_uni_cnt=%d, eth_rep5g_wrg_bct_cnt=%d\n", ++ __FUNCTION__, eth_rep5g_wrg_uni_cnt, eth_rep5g_wrg_bct_cnt)); ++ ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("[%s]eth_rep2g_wrg_uni_cnt=%d, eth_rep2g_wrg_bct_cnt=%d\n", ++ __FUNCTION__, eth_rep2g_wrg_uni_cnt, eth_rep2g_wrg_bct_cnt)); ++ ++} ++ ++ ++static void wifi_fwd_delete_entry_by_idx(unsigned char idx) ++{ ++ int i = 0; ++ ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("\n[%s]--------------------------------------------\n", __FUNCTION__)); ++ ++ if (idx < WIFI_FWD_TBL_SIZE) ++ { ++ if (WiFiFwdBase[idx].valid) ++ { ++ memset(&WiFiFwdBase[idx], 0, sizeof(struct FwdPair)); ++ cal_link_count_by_net_device(WiFiFwdBase[idx].src, 0); ++ ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("[%s]index=%d, valid=%d, src dev=0x%08X, dest dev=0x%08X\n", ++ __FUNCTION__, idx, WiFiFwdBase[idx].valid, (int)WiFiFwdBase[idx].src, (int)WiFiFwdBase[idx].dest)); ++ } else ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("[%s]index=%d is void originally\n", __FUNCTION__, idx)); ++ } ++ else ++ { ++ for (i=0; i<WIFI_FWD_TBL_SIZE; i++) ++ memset(&WiFiFwdBase[i], 0, sizeof(struct FwdPair)); ++ ++ wifi_fwd_reset_link_count(); ++ ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("[%s] flush all entries\n", __FUNCTION__)); ++ } ++} ++ ++ ++static void packet_source_show_entry(void) ++{ ++ int idx = 0; ++ ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("\n[%s]--------------------------------------------\n", __FUNCTION__)); ++ ++ for (idx=0; idx<WIFI_FWD_TBL_SIZE; idx++) ++ { ++ if (pkt_src[idx].valid) ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("[%s]index=%d, valid=%d, src=0x%08X, peer=0x%08X, " ++ "h_source=%02X:%02X:%02X:%02X:%02X:%02X, h_dest=%02X:%02X:%02X:%02X:%02X:%02X\n", ++ __FUNCTION__, idx, pkt_src[idx].valid, (int)pkt_src[idx].src, (int)pkt_src[idx].peer, ++ pkt_src[idx].h_source[0], pkt_src[idx].h_source[1], pkt_src[idx].h_source[2], ++ pkt_src[idx].h_source[3], pkt_src[idx].h_source[4], pkt_src[idx].h_source[5], ++ pkt_src[idx].h_dest[0], pkt_src[idx].h_dest[1], pkt_src[idx].h_dest[2], ++ pkt_src[idx].h_dest[3], pkt_src[idx].h_dest[4], pkt_src[idx].h_dest[5])); ++ } ++} ++ ++ ++static void packet_source_delete_entry(unsigned char idx) ++{ ++ int i = 0; ++ ++ if (!WIFI_FWD_TEST_FLAG(fOP_WIFI_FWD_ENABLED)) ++ return; ++ ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("\n[%s]--------------------------------------------\n", __FUNCTION__)); ++ ++ if (idx < WIFI_FWD_TBL_SIZE) ++ { ++ if (pkt_src[idx].valid) ++ { ++ memset(&pkt_src[idx], 0, sizeof(struct PacketSource)); ++ ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s]index=%d, valid=%d, src=0x%08X, peer=0x%08X, " ++ "h_source=%02X:%02X:%02X:%02X:%02X:%02X, h_dest=%02X:%02X:%02X:%02X:%02X:%02X\n", ++ __FUNCTION__, idx, pkt_src[idx].valid, (int)pkt_src[idx].src, (int)pkt_src[idx].peer, ++ pkt_src[idx].h_source[0], pkt_src[idx].h_source[1], pkt_src[idx].h_source[2], ++ pkt_src[idx].h_source[3], pkt_src[idx].h_source[4], pkt_src[idx].h_source[5], ++ pkt_src[idx].h_dest[0], pkt_src[idx].h_dest[1], pkt_src[idx].h_dest[2], ++ pkt_src[idx].h_dest[3], pkt_src[idx].h_dest[4], pkt_src[idx].h_dest[5])); ++ } else ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s]index=%d is void originally\n", __FUNCTION__, idx)); ++ } ++ else if (idx == WIFI_FWD_TBL_SIZE) ++ { ++ eth_rep5g_wrg_uni_cnt = 0; ++ eth_rep5g_wrg_bct_cnt = 0; ++ eth_rep2g_wrg_uni_cnt = 0; ++ eth_rep2g_wrg_bct_cnt = 0; ++ ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s] reset counters\n", __FUNCTION__)); ++ } ++ else ++ { ++ for (i=0; i<WIFI_FWD_TBL_SIZE; i++) ++ memset(&pkt_src[i], 0, sizeof(struct PacketSource)); ++ ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s] flush all entries\n", __FUNCTION__)); ++ } ++} ++ ++ ++/* ++ return value: ++ >=0: array index of WiFiFwdBase ++ -1: search failed ++*/ ++static int wifi_fwd_find_empty_entry(void) ++{ ++ int idx = 0; ++ ++ for (idx=0; idx<WIFI_FWD_TBL_SIZE; idx++) ++ { ++ if (WiFiFwdBase[idx].valid == 0) ++ return idx; ++ } ++ ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s] table full\n", __FUNCTION__)); ++ return -1; ++} ++ ++ ++/* ++ return value: ++ >=0: array index of WiFiFwdBase ++ -1: search failed ++*/ ++static int wifi_fwd_find_entry(struct net_device *src, struct net_device *dest) ++{ ++ int idx = 0; ++ ++ for (idx=0; idx<WIFI_FWD_TBL_SIZE; idx++) ++ { ++ if ((WiFiFwdBase[idx].valid) && ++ (WiFiFwdBase[idx].src == src) && ++ (WiFiFwdBase[idx].dest == dest)) ++ return idx; ++ } ++ ++ //WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s] no entry found\n", __FUNCTION__)); ++ return -1; ++} ++ ++ ++/* ++ return value: ++ 1: clear OK ++ 0: clear failed (wrong input index) ++*/ ++static int wifi_fwd_clear_entry(int index) ++{ ++ struct FwdPair *entry = NULL; ++ entry = WiFiFwdBase + index; ++ ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[wifi_fwd_clear_entry] original: index=%d, valid=%d, src_dev=0x%08X, dest_dev=0x%08X\n", ++ index, entry->valid, (int)entry->src, (int)entry->dest)); ++ ++ if (entry->valid) { ++ memset(entry, 0, sizeof(struct FwdPair)); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static void wifi_fwd_set_cb_num(unsigned int band_cb_num, unsigned int receive_cb_num) ++{ ++ band_cb_offset = band_cb_num; ++ recv_from_cb_offset = receive_cb_num; ++ ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s] band_cb_offset=%d, recv_from_cb_offset=%d\n", __FUNCTION__, band_cb_offset, recv_from_cb_offset)); ++} ++ ++static void wifi_fwd_get_rep(unsigned char rep) ++{ ++ if (!WIFI_FWD_TEST_FLAG(fOP_WIFI_FWD_ENABLED)) ++ return; ++ ++ if (rep == 0) ++ rep_net_dev = eth_traffic_band_2g; ++ else ++ rep_net_dev = eth_traffic_band_5g; ++ ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("[%s] rep=%d\n", __FUNCTION__, rep_net_dev)); ++} ++ ++static void wifi_fwd_set_debug_level(unsigned char level) ++{ ++ ++ if (level == 0) ++ wf_debug_level = WF_DEBUG_OFF; ++ else ++ wf_debug_level = WF_DEBUG_ON; ++ ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("[%s] level=%d\n", __FUNCTION__, wf_debug_level)); ++} ++ ++ ++ ++static void wifi_fwd_pro_active(void) ++{ ++ WIFI_FWD_SET_FLAG(fOP_WIFI_FWD_ACTIVE); ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("[%s]\n", __FUNCTION__)); ++} ++ ++ ++static void wifi_fwd_pro_halt(void) ++{ ++ WIFI_FWD_CLEAR_FLAG(fOP_WIFI_FWD_ACTIVE); ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("[%s]\n", __FUNCTION__)); ++} ++ ++static void wifi_fwd_pro_enabled(void) ++{ ++ WIFI_FWD_SET_FLAG(fOP_WIFI_FWD_ENABLED); ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("[%s]\n", __FUNCTION__)); ++} ++ ++ ++static void wifi_fwd_pro_disabled(void) ++{ ++ WIFI_FWD_CLEAR_FLAG(fOP_WIFI_FWD_ENABLED); ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("[%s]\n", __FUNCTION__)); ++} ++ ++static void wifi_fwd_access_schedule_active(void) ++{ ++ WIFI_FWD_SET_FLAG(fOP_WIFI_FWD_ACCESS_SCHED_ACTIVE); ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("[%s]\n", __FUNCTION__)); ++} ++ ++ ++static void wifi_fwd_access_schedule_halt(void) ++{ ++ WIFI_FWD_CLEAR_FLAG(fOP_WIFI_FWD_ACCESS_SCHED_ACTIVE); ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("[%s]\n", __FUNCTION__)); ++} ++ ++ ++static void wifi_fwd_hijack_active(void) ++{ ++ WIFI_FWD_SET_FLAG(fOP_WIFI_FWD_HIJACK_ACTIVE); ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("[%s]\n", __FUNCTION__)); ++} ++ ++ ++static void wifi_fwd_hijack_halt(void) ++{ ++ WIFI_FWD_CLEAR_FLAG(fOP_WIFI_FWD_HIJACK_ACTIVE); ++ WF_FWD_PRINT(WF_DEBUG_OFF, ("[%s]\n", __FUNCTION__)); ++} ++ ++ ++static void packet_tx_source_flush_all() ++{ ++ if(!tx_src_tbl) ++ return; ++ ++ memset(tx_src_tbl, 0, sizeof(struct TxSourceEntry)*WIFI_FWD_TBL_SIZE); ++ tx_src_count = 0; ++} ++ ++ ++static void wf_fwd_delete_entry_inform(unsigned char *addr) ++{ ++ int i = 0,count = 0; ++ struct TxSourceEntry *entry = NULL; ++ ++ if (!WIFI_FWD_TEST_FLAG(fOP_WIFI_FWD_ENABLED)) ++ return; ++ ++ if(!addr || (tx_src_count == 0)) ++ return; ++ ++ for (i=0; i<WIFI_FWD_TBL_SIZE; i++) ++ { ++ entry = tx_src_tbl + i; ++ if (entry->valid == 1) ++ { ++ count++; ++ if(MAC_ADDR_EQUAL(addr, entry->h_source)) ++ { ++ entry->valid = 0; ++ tx_src_count--; ++ if(tx_src_count < 0) ++ tx_src_count = 0; ++ ++ return; ++ } ++ ++ if(count >= tx_src_count) ++ return; ++ } ++ } ++} ++ ++ ++/* ++ return value: ++ 0: insert failed ++ 1: insert success ++ 2: do nothing ++*/ ++static int wifi_fwd_insert_tx_source_entry(struct sk_buff *skb,struct net_device *tx_dev) ++{ ++ struct ethhdr *mh = eth_hdr(skb); ++ unsigned int recv_from = WIFI_FWD_GET_PACKET_RECV_FROM(skb, recv_from_cb_offset); ++ struct TxSourceEntry *entry = NULL; ++ int i = 0, count = 0; ++ unsigned char bInsert = 0; ++ ++ if(!is_wifi_concurrent_mode(tx_dev) || !mh) ++ return 2; ++ ++ if(tx_dev == apcli_2g || tx_dev == apcli_5g) ++ { ++ for (i=0; i<WIFI_FWD_TBL_SIZE; i++) ++ { ++ entry = tx_src_tbl + i; ++ if ((entry->valid == 1) && ++ MAC_ADDR_EQUAL(mh->h_source, entry->h_source)) ++ return 2; ++ } ++ bInsert = 1; ++ } ++ ++ if(!bInsert) ++ return 2; ++ ++ for (i=0; i<WIFI_FWD_TBL_SIZE; i++) ++ { ++ entry = tx_src_tbl + i; ++ if (entry->valid == 0) ++ { ++ tx_src_count++; ++ entry->valid = 1; ++ COPY_MAC_ADDR(entry->h_source, mh->h_source); ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s %d] valid=%d, src_mac=%02X:%02X:%02X:%02X:%02X:%02X\n", ++ __FUNCTION__,i, entry->valid, ++ entry->h_source[0], entry->h_source[1], entry->h_source[2], ++ entry->h_source[3], entry->h_source[4], entry->h_source[5])); ++ return 1; ++ } ++ } ++ ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s] No free space for insert tx source entry.\n",__FUNCTION__)); ++ return 0; ++} ++ ++/* ++ return value: ++ 0: no looping ++ 1: looping found ++ 2: forward to bridge ++*/ ++static unsigned char wifi_fwd_check_looping( ++ struct sk_buff *skb, ++ struct net_device *dev) ++{ ++ struct ethhdr *mh = eth_hdr(skb); ++ unsigned int recv_from = WIFI_FWD_GET_PACKET_RECV_FROM(skb, recv_from_cb_offset); ++ struct TxSourceEntry *entry = NULL; ++ int i = 0,count = 0; ++ unsigned char bMulticast = 0; ++ ++ if (!is_wifi_concurrent_mode(dev) || ++ !IS_PACKET_FROM_APCLI(recv_from) || ++ (tx_src_count == 0) || ++ !mh) ++ return 0; ++ ++ if (dev == apcli_2g || dev == apcli_5g || dev == apcli1_2g || dev == apcli1_5g) ++ { ++ if ((mh->h_dest[0] & 0x1) == 0x1) ++ bMulticast = 1; ++ ++ for (i=0; i<WIFI_FWD_TBL_SIZE; i++) ++ { ++ entry = tx_src_tbl + i; ++ if ((entry->valid == 1)) ++ { ++ count++; ++ if(MAC_ADDR_EQUAL(mh->h_source, entry->h_source)) ++ { ++ // Mean the souce has changed to other side. ++ if(!bMulticast) ++ { ++ wf_fwd_delete_entry_inform(entry->h_source); ++ return 0; ++ } ++ ++ return 1; ++ } ++ ++ if(count >= tx_src_count) ++ break;; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++ ++/* ++ return value: ++ 1: insert success ++ 0: insert failed ++*/ ++static unsigned char wifi_fwd_establish_entry(struct net_device *src, struct net_device *dest) ++{ ++ struct FwdPair *entry = NULL; ++ int idx = 0; ++ ++ if (!src || !dest) ++ return 0; ++ ++ /* check if it is an existed entry */ ++ idx = wifi_fwd_find_entry(src, dest); ++ if (idx >= 0) ++ return 0; ++ ++ /* to establish the path between src and dest */ ++ idx = wifi_fwd_find_empty_entry(); ++ if (idx == -1) ++ return 0; ++ ++ entry = WiFiFwdBase + idx; ++ entry->valid = 1; ++ entry->src = src; ++ entry->dest = dest; ++ cal_link_count_by_net_device(entry->src, 1); ++ ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s %d] valid=%d, src=0x%08X, dest=0x%08X\n", ++ __FUNCTION__, idx, entry->valid, (unsigned int)entry->src, (unsigned int)entry->dest)); ++} ++ ++ ++static void main_ssid_cover_guest_ssid(struct net_device *src) ++{ ++ struct net_device *second_src = NULL, *second_dest = NULL, *first_src = NULL, *first_dest = NULL; ++ int idx = 0; ++ ++ idx = wifi_fwd_find_entry(apcli_2g, ap1_2g); ++ if (idx >= 0) { ++ wifi_fwd_clear_entry(idx); ++ cal_link_count_by_net_device(apcli_2g, 0); ++ } ++ ++ idx = wifi_fwd_find_entry(apcli_2g, ap1_5g); ++ if (idx >= 0) { ++ wifi_fwd_clear_entry(idx); ++ cal_link_count_by_net_device(apcli_2g, 0); ++ } ++ ++ idx = wifi_fwd_find_entry(apcli_5g, ap1_2g); ++ if (idx >= 0) { ++ wifi_fwd_clear_entry(idx); ++ cal_link_count_by_net_device(apcli_5g, 0); ++ } ++ ++ idx = wifi_fwd_find_entry(apcli_5g, ap1_5g); ++ if (idx >= 0) { ++ wifi_fwd_clear_entry(idx); ++ cal_link_count_by_net_device(apcli_5g, 0); ++ } ++ ++ if (GUEST_SSID_OP(src)) { ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s]no need to cover guest ssid\n", __FUNCTION__)); ++ return; ++ } ++ ++ if (is_wifi_concurrent_mode(apcli_2g)) ++ { ++ idx = wifi_fwd_find_entry(apcli_2g, ap1_2g); ++ if (idx < 0) ++ wifi_fwd_establish_entry(apcli_2g, ap1_2g); ++ ++ idx = wifi_fwd_find_entry(apcli_5g, ap1_5g); ++ if (idx < 0) ++ wifi_fwd_establish_entry(apcli_5g, ap1_5g); ++ ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s]need to cover guest ssid under concurrent mode\n", __FUNCTION__)); ++ } ++ else if (is_wifi_fastlane_mode(apcli_2g)) ++ { ++ idx = wifi_fwd_find_entry(apcli_2g, ap_2g); ++ if (idx >= 0) { ++ src = apcli_2g; ++ first_dest = ap1_2g; ++ second_dest = ap1_5g; ++ } else { ++ src = apcli_5g; ++ first_dest = ap1_5g; ++ second_dest = ap1_2g; ++ } ++ ++ idx = wifi_fwd_find_entry(src, first_dest); ++ if (idx < 0) ++ wifi_fwd_establish_entry(src, first_dest); ++ ++ idx = wifi_fwd_find_entry(src, second_dest); ++ if (idx < 0) ++ wifi_fwd_establish_entry(src, second_dest); ++ ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s]need to cover guest ssid under fastLane mode\n", __FUNCTION__)); ++ } ++ else ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s]no need to cover guest ssid under AP mode\n", __FUNCTION__)); ++} ++ ++ ++/* ++ return value: ++ 1: delete success ++ 0: delete failed ++*/ ++static unsigned char wifi_fwd_delete_entry(struct net_device *src, struct net_device *dest, unsigned char link_down) ++{ ++ struct net_device *second_src = NULL, *second_dest = NULL, *first_dest = NULL; ++ int idx = 0; ++ ++ if (!WIFI_FWD_TEST_FLAG(fOP_WIFI_FWD_ENABLED)) ++ return 1; ++ ++ if (src == apcli_2g) { ++ first_dest = ap_2g; ++ second_src = apcli_5g; ++ second_dest = ap_5g; ++ } else if (src == apcli_5g) { ++ first_dest = ap_5g; ++ second_src = apcli_2g; ++ second_dest = ap_2g; ++ } else if (src == apcli1_2g) { ++ first_dest = ap1_2g; ++ second_src = apcli1_5g; ++ second_dest = ap1_5g; ++ } else if (src == apcli1_5g) { ++ first_dest = ap1_5g; ++ second_src = apcli1_2g; ++ second_dest = ap1_2g; ++ } ++ ++ if (link_down == 0) ++ first_dest = dest; ++ ++ idx = wifi_fwd_find_entry(src, first_dest); ++ if (idx == -1) ++ return 0; ++ ++ if (wifi_fwd_clear_entry(idx) == 0) ++ return 0; ++ ++ cal_link_count_by_net_device(src, 0); ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s] index=%d, src=0x%08X, dest=0x%08X\n", ++ __FUNCTION__, idx, (int)src, (int)first_dest)); ++ ++ /* ++ check if there exists FastLane case ++ if yes, delete the cross path of FastLane as well ++ */ ++ idx = wifi_fwd_find_entry(src, second_dest); ++ if (idx >= 0) { ++ wifi_fwd_clear_entry(idx); ++ cal_link_count_by_net_device(src, 0); ++ } ++ ++ /* ++ check if there exists the connection of the other band ++ if yes, need to do FastLane case ++ */ ++ idx = wifi_fwd_find_entry(second_src, second_dest); ++ if (idx == -1) ++ goto done; ++ ++ /* try to establish the FastLane path between second_src and dest */ ++ if (wifi_fwd_establish_entry(second_src, first_dest) == 0) ++ return 0; ++ ++done: ++ main_ssid_cover_guest_ssid(src); ++ ++ /* flush packet source table */ ++ packet_source_delete_entry(WIFI_FWD_TBL_SIZE+1); ++ ++ /* flush tx packet source table */ ++ packet_tx_source_flush_all(); ++ ++ WIFI_FWD_CLEAR_FLAG(fOP_GET_NET_DEVICE_STATUS_DONE); ++ return 1; ++} ++ ++ ++/* ++ return value: ++ 1: insert success ++ 0: insert failed ++*/ ++static unsigned char wifi_fwd_insert_entry(struct net_device *src, struct net_device *dest, void *adapter) ++{ ++ struct net_device *second_src = NULL, *second_dest = NULL, *first_dest = NULL; ++ struct FwdPair *entry = NULL; ++ int idx = 0; ++ ++ if (!WIFI_FWD_TEST_FLAG(fOP_WIFI_FWD_ENABLED)) ++ return 0; ++ ++ if (!src || !dest) ++ return 0; ++ ++ if (!WIFI_FWD_TEST_FLAG(fOP_GET_NET_DEVICE_STATUS_DONE)) { ++ dump_net_device_by_name(); ++ WIFI_FWD_SET_FLAG(fOP_GET_NET_DEVICE_STATUS_DONE); ++ } ++ ++ if (src == apcli_2g) { ++ first_dest = ap_2g; ++ second_src = apcli_5g; ++ second_dest = ap_5g; ++ adapter_2g = adapter; ++ ++ if ((adapter_tmp_1 == adapter_2g) && (adapter_tmp_2 != NULL)) ++ adapter_5g = adapter_tmp_2; ++ else if ((adapter_tmp_2 == adapter_2g) && (adapter_tmp_1 != NULL)) ++ adapter_5g = adapter_tmp_1; ++ ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s] input adapter=0x%08X, adapter_2g=0x%08X, adapter_5g=0x%08X\n", ++ __FUNCTION__, (int)adapter, (int)adapter_2g, (int)adapter_5g)); ++ ++ } else if (src == apcli_5g) { ++ first_dest = ap_5g; ++ second_src = apcli_2g; ++ second_dest = ap_2g; ++ adapter_5g = adapter; ++ ++ if ((adapter_tmp_1 == adapter_5g) && (adapter_tmp_2 != NULL)) ++ adapter_2g = adapter_tmp_2; ++ else if ((adapter_tmp_2 == adapter_5g) && (adapter_tmp_1 != NULL)) ++ adapter_2g = adapter_tmp_1; ++ ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s] input adapter=0x%08X, adapter_5g=0x%08X, adapter_2g=0x%08X\n", ++ __FUNCTION__, (int)adapter, (int)adapter_5g, (int)adapter_2g)); ++ ++ } else if (src == apcli1_2g) { ++ first_dest = ap1_2g; ++ second_src = apcli1_5g; ++ second_dest = ap1_5g; ++ ++ if (adapter_2g == NULL) { ++ adapter_2g = adapter; ++ ++ if ((adapter_tmp_1 == adapter_2g) && (adapter_tmp_2 != NULL)) ++ adapter_5g = adapter_tmp_2; ++ else if ((adapter_tmp_2 == adapter_2g) && (adapter_tmp_1 != NULL)) ++ adapter_5g = adapter_tmp_1; ++ ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s] input adapter=0x%08X, adapter_2g=0x%08X, adapter_5g=0x%08X\n", ++ __FUNCTION__, (int)adapter, (int)adapter_2g, (int)adapter_5g)); ++ ++ } ++ } else if (src == apcli1_5g) { ++ first_dest = ap1_5g; ++ second_src = apcli1_2g; ++ second_dest = ap1_2g; ++ ++ if (adapter_5g == NULL) { ++ adapter_5g = adapter; ++ ++ if ((adapter_tmp_1 == adapter_5g) && (adapter_tmp_2 != NULL)) ++ adapter_2g = adapter_tmp_2; ++ else if ((adapter_tmp_2 == adapter_5g) && (adapter_tmp_1 != NULL)) ++ adapter_2g = adapter_tmp_1; ++ ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s] input adapter=0x%08X, adapter_5g=0x%08X, adapter_2g=0x%08X\n", ++ __FUNCTION__, (int)adapter, (int)adapter_5g, (int)adapter_2g)); ++ ++ } ++ } ++ ++ /* ++ check if there exists FastLane case ++ if yes, delete the cross path of FastLane ++ */ ++ idx = wifi_fwd_find_entry(second_src, first_dest); ++ if (idx >= 0) ++ wifi_fwd_delete_entry(second_src, first_dest, 0); ++ ++ /* try to establish the path between src and dest */ ++ if (wifi_fwd_establish_entry(src, first_dest) == 0) ++ return 0; ++ ++ /* ++ check if there exists the connection of the other band ++ if yes, no need to do FastLane case ++ */ ++ idx = wifi_fwd_find_entry(second_src, second_dest); ++ if (idx >= 0) ++ goto done; ++ ++ /* try to establish the FastLane path between src and second_dest */ ++ if (wifi_fwd_establish_entry(src, second_dest) == 0) ++ goto done; ++ ++done: ++ main_ssid_cover_guest_ssid(src); ++ ++ /* flush packet source table */ ++ packet_source_delete_entry(WIFI_FWD_TBL_SIZE+1); ++ ++ return 1; ++} ++ ++ ++/* ++ return value: ++ 0: Success, skb is handled by wifi_fwd module. ++ 1: FAIL, do nothing ++*/ ++static struct net_device * wifi_fwd_insert_packet_source(struct sk_buff *skb, struct net_device *dev, struct net_device *peer) ++{ ++ struct ethhdr *mh = eth_hdr(skb); ++ struct PacketSource *entry = NULL; ++ bool need_flush = false; ++ int i = 0; ++ ++ for (i=0; i<WIFI_FWD_TBL_SIZE; i++) ++ { ++ entry = pkt_src + i; ++ ++ if (entry->valid == 1) { ++ if (peer == entry->peer) { ++ if (MAC_ADDR_EQUAL(mh->h_source, entry->h_source)) { ++ if (dev == entry->src) { ++ return peer; ++ } else { ++ need_flush = true; ++ break; ++ } ++ } ++ } ++ } ++ } ++ ++ if (need_flush == true) ++ packet_source_delete_entry(WIFI_FWD_TBL_SIZE+1); ++ else ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s] packet source cannot be found\n", __FUNCTION__)); ++ ++ for (i=0; i<WIFI_FWD_TBL_SIZE; i++) ++ { ++ entry = pkt_src + i; ++ ++ if (entry->valid == 0) { ++ COPY_MAC_ADDR(entry->h_source, mh->h_source); ++ COPY_MAC_ADDR(entry->h_dest, mh->h_dest); ++ entry->valid = 1; ++ entry->peer = peer; ++ entry->src = dev; ++ ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s %d] valid=%d, from=0x%08X, will send to=0x%08X, " ++ "src_mac=%02X:%02X:%02X:%02X:%02X:%02X, dest_mac=%02X:%02X:%02X:%02X:%02X:%02X\n", ++ __FUNCTION__, i, entry->valid, entry->src, entry->peer, ++ entry->h_source[0], entry->h_source[1], entry->h_source[2], ++ entry->h_source[3], entry->h_source[4], entry->h_source[5], ++ entry->h_dest[0], entry->h_dest[1], entry->h_dest[2], ++ entry->h_dest[3], entry->h_dest[4],entry->h_dest[5])); ++ ++ return entry->peer; ++ } ++ } ++} ++ ++static void wifi_fwd_tx_count_by_source_addr( ++ struct sk_buff *skb, ++ struct net_device *tx_dev, ++ unsigned char *found_path, ++ unsigned char *entry_cnt) ++{ ++ struct PacketSource *ppkt_src = NULL; ++ struct FwdPair *entry = NULL; ++ int i = 0; ++ ++ for (i=0; i<WIFI_FWD_TBL_SIZE; i++) ++ { ++ ppkt_src = pkt_src + i; ++ ++ if (ppkt_src->valid == 1) ++ { ++ if (MAC_ADDR_EQUAL(&skb->data[6], ppkt_src->h_source)) ++ { ++ *entry_cnt = *entry_cnt + 1; ++ ++ if ((ppkt_src->src == tx_dev) || (ppkt_src->peer == tx_dev)) ++ { ++ for (i=0; i<WIFI_FWD_TBL_SIZE; i++) ++ { ++ entry = WiFiFwdBase + i; ++ ++ if (entry->valid == 1) ++ { ++ if (((entry->src == ppkt_src->src) && (entry->dest == ppkt_src->peer)) || ++ ((entry->src == ppkt_src->peer) && (entry->dest == ppkt_src->src))) ++ *found_path = *found_path + 1; ++ } ++ } ++ } ++ } ++ } ++ else ++ break; ++ } ++} ++ ++ ++/* ++ return value: ++ 1: find entry ++ 0: find nothing ++*/ ++static unsigned char wifi_fwd_find_sa_entry_by_sa_and_nd( ++ struct sk_buff *skb, ++ struct net_device *sender_dev, ++ unsigned char idx) ++{ ++ struct PacketSource *entry = NULL; ++ struct ethhdr *mh = eth_hdr(skb); ++ int i = 0; ++ ++ for (i=0; i<WIFI_FWD_TBL_SIZE; i++) ++ { ++ entry = pkt_src + i; ++ ++ if (entry->valid == 1) ++ { ++ if (MAC_ADDR_EQUAL(mh->h_source, entry->h_source)) ++ { ++ if (idx == 0) ++ { ++ if (entry->src == sender_dev) ++ return 1; ++ } ++ else ++ { ++ if (entry->peer== sender_dev) ++ return 1; ++ } ++ } ++ } ++ else ++ break; ++ } ++ ++ return 0; ++} ++ ++ ++/* ++ return value: # of found entries ++*/ ++static unsigned char wifi_fwd_sa_count_by_source_addr( ++ struct sk_buff *skb, ++ struct net_device *receive_dev) ++{ ++ struct PacketSource *entry = NULL; ++ struct ethhdr *mh = eth_hdr(skb); ++ int i = 0, sa_cnt = 0; ++ ++ for (i=0; i<WIFI_FWD_TBL_SIZE; i++) ++ { ++ entry = pkt_src + i; ++ ++ if (entry->valid == 1) ++ { ++ if ((mh->h_source[0] & 0x2) == 0x2) ++ { ++ if (memcmp(&mh->h_source[3], &entry->h_source[3], 3) == 0) ++ sa_cnt++; ++ } ++ else ++ { ++ if (MAC_ADDR_EQUAL(mh->h_source, entry->h_source)) ++ sa_cnt++; ++ } ++ } ++ else ++ break; ++ } ++ ++ return sa_cnt; ++} ++ ++ ++/* ++ return value: ++ 2: should be forwarded to bridge ++ 1: not forwarded from bridge ++ 0: suppose it is forwarded from bridge ++*/ ++static unsigned char wifi_fwd_check_from_bridge_by_dest_addr( ++ struct sk_buff *skb, ++ struct net_device *sender_dev) ++{ ++ struct PacketSource *entry = NULL; ++ struct ethhdr *mh = eth_hdr(skb); ++ int i = 0; ++ ++ for (i=0; i<WIFI_FWD_TBL_SIZE; i++) ++ { ++ entry = pkt_src + i; ++ ++ if (entry->valid == 1) ++ { ++ if (((sender_dev == ap_2g) && (entry->src== ap_5g)) || ++ ((sender_dev == ap_5g) && (entry->src == ap_2g)) || ++ ((sender_dev == ap1_5g) && (entry->src == ap1_2g)) || ++ ((sender_dev == ap1_5g) && (entry->src == ap1_2g))) ++ { ++ if (MAC_ADDR_EQUAL(mh->h_dest, entry->h_source)) ++ return 2; ++ } ++ else ++ { ++ if (MAC_ADDR_EQUAL(mh->h_dest, entry->h_source)) ++ return 1; ++ } ++ } ++ else ++ break; ++ } ++ ++ return 0; ++} ++ ++/* ++ return value: ++ 0: no need to drop this packet ++ 1: drop this packet ++*/ ++static unsigned char wifi_fwd_tx_lookup_entry(struct net_device *tx_dev, struct sk_buff *skb) ++{ ++ unsigned char found = 0, entry_cnt = 0; ++ unsigned int recv_from = 0, band_from = 0; ++ struct sk_buff *clone_pkt = NULL; ++ bool need_redirect = false; ++ ++ band_from = WIFI_FWD_GET_PACKET_BAND(skb, band_cb_offset); ++ recv_from = WIFI_FWD_GET_PACKET_RECV_FROM(skb, recv_from_cb_offset); ++ ++ if (IS_PACKET_FROM_APCLI(recv_from) && !MAIN_SSID_OP(tx_dev)) ++ return 1; ++ ++ /* drop the packet from guest ssid to main ssid, and vice versa */ ++ if (!IS_PACKET_FROM_ETHER(band_from) && ++ ((guest_2g_link_cnt != 0) || (guest_5g_link_cnt != 0))) ++ { ++ if (IS_MAIN_SSID_DEV(tx_dev)) { ++ if (IS_PACKET_FROM_GUEST_SSID(recv_from)) ++ return 1; ++ } else if (IS_GUEST_SSID_DEV(tx_dev)) { ++ if (IS_PACKET_FROM_MAIN_SSID(recv_from)) ++ return 1; ++ } ++ } ++ ++ /* drop the packet from the other band */ ++ if (is_wifi_concurrent_mode(tx_dev)) ++ { ++ if ((tx_dev == apcli_5g) || (tx_dev == apcli1_5g)) ++ { ++ if (IS_PACKET_FROM_2G(band_from)) { ++ if(IS_TAG_PACKET(band_from)) ++ need_redirect = true; ++ else ++ return 1; ++ } ++ ++ if ((rep_net_dev == eth_traffic_band_2g) && IS_PACKET_FROM_ETHER(band_from)) { ++ if ((((unsigned char *)skb->data)[0] & 0x1) == 0x0) { ++ eth_rep2g_wrg_uni_cnt++; ++ need_redirect = true; ++ } else ++ eth_rep2g_wrg_bct_cnt++; ++ } ++ ++ if (need_redirect == true) { ++ clone_pkt = skb_clone(skb, GFP_ATOMIC); ++ if (tx_dev == apcli_5g) ++ clone_pkt->dev = apcli_2g; ++ else ++ clone_pkt->dev = apcli1_2g; ++ dev_queue_xmit(clone_pkt); ++ return 1; ++ } ++ } ++ else if ((tx_dev == apcli_2g) || (tx_dev == apcli1_2g)) ++ { ++ if (IS_PACKET_FROM_5G(band_from)) { ++ if(IS_TAG_PACKET(band_from)) ++ need_redirect = true; ++ else ++ return 1; ++ } ++ ++ if ((rep_net_dev == eth_traffic_band_5g) && IS_PACKET_FROM_ETHER(band_from)) { ++ if ((((unsigned char *)skb->data)[0] & 0x1) == 0x0) { ++ eth_rep5g_wrg_uni_cnt++; ++ need_redirect = true; ++ } else ++ eth_rep5g_wrg_bct_cnt++; ++ } ++ ++ if (need_redirect == true) { ++ clone_pkt = skb_clone(skb, GFP_ATOMIC); ++ if (tx_dev == apcli_2g) ++ clone_pkt->dev = apcli_5g; ++ else ++ clone_pkt->dev = apcli1_5g; ++ dev_queue_xmit(clone_pkt); ++ return 1; ++ } ++ } ++ } ++ ++ /* ++ in FastLane topology: ++ 1. forward Tx packets to driver and handle without any drop ++ 2. only for unicast ++ */ ++ if (((((unsigned char *)skb->data)[0] & 0x1) == 0x0) && (is_wifi_fastlane_mode(tx_dev) && !GUEST_SSID_OP(tx_dev))) ++ return 0; ++ ++ wifi_fwd_tx_count_by_source_addr(skb, tx_dev, &found, &entry_cnt); ++ ++ if ((((unsigned char *)skb->data)[0] & 0x1) == 0x1) ++ { ++ if(wifi_fwd_insert_tx_source_entry(skb,tx_dev) == 0) ++ return 0; ++ ++ if (found == 0) ++ { ++ if (entry_cnt == 0) ++ { ++ if (is_wifi_concurrent_mode(tx_dev) && ++ IS_PACKET_FROM_ETHER(band_from)) ++ { ++ if ((tx_dev == apcli_5g) || (tx_dev == apcli1_5g)) ++ { ++ if (rep_net_dev == eth_traffic_band_5g) ++ return 0; ++ else ++ return 1; ++ } ++ else if ((tx_dev == apcli_2g) || (tx_dev == apcli1_2g)) ++ { ++ if (rep_net_dev == eth_traffic_band_2g) ++ return 0; ++ else ++ return 1; ++ } ++ } ++ } ++ ++ return 0; ++ } ++ else ++ { ++ if (entry_cnt >= 2) ++ return 0; ++ else ++ { ++ if (wifi_fwd_find_sa_entry_by_sa_and_nd(skb, tx_dev, 1) == 0) ++ return 1; ++ else ++ return 0; ++ } ++ } ++ } ++ else ++ { ++#if 0 /* move to earlier and handle it */ ++ /* in FastLane case, forward Rx packets to bridge and let flooding work done by bridge */ ++ if (is_wifi_fastlane_mode(tx_dev)) ++ return 0; ++#endif ++ if (found == 0) ++ { ++ if (entry_cnt == 0) ++ { ++ if (is_wifi_concurrent_mode(tx_dev) && ++ IS_PACKET_FROM_ETHER(band_from)) ++ { ++ if (rep_net_dev == eth_traffic_band_5g) ++ { ++ if (REP_IS_5G(tx_dev)) ++ return 0; ++ } ++ else if (rep_net_dev == eth_traffic_band_2g) ++ { ++ if (REP_IS_2G(tx_dev)) ++ return 0; ++ } ++ } ++ } ++ } ++ ++ return 0; ++ } ++} ++ ++ ++/* ++ return value of struct net_device: ++ NULL: search fail ++ other: partner net_device ++*/ ++static struct net_device * wifi_fwd_lookup_entry(struct net_device *dev, unsigned char *type, struct sk_buff *skb) ++{ ++ struct FwdPair *entry = NULL; ++ struct net_device *src = NULL; ++ int i = 0; ++ ++ for (i=0; i<WIFI_FWD_TBL_SIZE; i++) ++ { ++ entry = WiFiFwdBase + i; ++ ++ if (entry->valid == 1) ++ { ++ if (entry->src == dev) ++ { ++ *type = ENTRY_TYPE_SRC; ++ src = wifi_fwd_insert_packet_source(skb, dev, entry->dest); ++ ++ if (src != NULL) ++ return src; ++ } ++ else if (entry->dest == dev) ++ { ++ *type = ENTRY_TYPE_DEST; ++ src = wifi_fwd_insert_packet_source(skb, dev, entry->src); ++ ++ if (src != NULL) ++ return src; ++ } ++ } ++ } ++ ++ *type = ENTRY_TYPE_INVALID; ++ return NULL; ++} ++ ++ ++static void wifi_fwd_entry_dump(void) ++{ ++ struct FwdPair *entry = NULL; ++ int i =0; ++ ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("\ndump wifi fwd table\n")); ++ ++ for (i=0; i<WIFI_FWD_TBL_SIZE; i++) ++ { ++ entry = WiFiFwdBase + i; ++ ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%d] valid=%d, src=0x%08X, dest=0x%08X\n", ++ i, entry->valid, (int)entry->src, (int)entry->dest)); ++ } ++ ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("\n")); ++} ++ ++ ++void wifi_fwd_probe_adapter(void *adapter) ++{ ++ if (!WIFI_FWD_TEST_FLAG(fOP_WIFI_FWD_ENABLED)) ++ return; ++ ++ if ((adapter != NULL) && (adapter_tmp_1 == NULL)) { ++ adapter_tmp_1 = adapter; ++ } else if ((adapter != NULL) && (adapter_tmp_2 == NULL)) { ++ if (adapter != adapter_tmp_1) ++ adapter_tmp_2 = adapter; ++ } ++} ++ ++ ++void wifi_fwd_feedback_peer_adapter(void *adapter, void **peer) ++{ ++ if (!WIFI_FWD_TEST_FLAG(fOP_WIFI_FWD_ENABLED)) ++ return; ++ ++ if ((adapter == adapter_2g) && (adapter_5g != NULL)) { ++ *peer = adapter_5g; ++ } else if ((adapter == adapter_5g) && (adapter_2g != NULL)) { ++ *peer = adapter_2g; ++ } else { ++ *peer = NULL; ++ } ++} ++ ++void wifi_fwd_feedback_map_table(void *adapter, void **peer, void **opp_peer) ++{ ++ if (!WIFI_FWD_TEST_FLAG(fOP_WIFI_FWD_ENABLED)) ++ return; ++ ++ ++ FWD_IRQ_LOCK(&global_band_tbl_lock, global_band_tbl_irq_flags); ++ ++ if (adapter == adapter_2g) { ++ ++ if (global_map_2g_tbl.Enabled == TRUE) ++ *peer = &global_map_2g_tbl; ++ else ++ *peer = NULL; ++ ++ if (global_map_5g_tbl.Enabled == TRUE) ++ *opp_peer = &global_map_5g_tbl; ++ else ++ *opp_peer = NULL; ++ ++ ++ } else if (adapter == adapter_5g) { ++ ++ if (global_map_5g_tbl.Enabled == TRUE) ++ *peer = &global_map_5g_tbl; ++ else ++ *peer = NULL; ++ ++ if (global_map_2g_tbl.Enabled == TRUE) ++ *opp_peer = &global_map_2g_tbl; ++ else ++ *opp_peer = NULL; ++ ++ ++ } else { ++ *peer = NULL; ++ *opp_peer = NULL; ++ } ++ ++ FWD_IRQ_UNLOCK(&global_band_tbl_lock, global_band_tbl_irq_flags); ++ ++} ++ ++void wifi_fwd_insert_repeater_mapping(void *adapter, void *lock, void *cli_mapping, void *map_mapping, void *ifAddr_mapping) ++{ ++ ++ if (!WIFI_FWD_TEST_FLAG(fOP_WIFI_FWD_ENABLED)) ++ return; ++ ++ FWD_IRQ_LOCK(&global_band_tbl_lock, global_band_tbl_irq_flags); ++ ++ if ( adapter == adapter_2g ) { ++ global_map_2g_tbl.EntryLock = lock; ++ global_map_2g_tbl.CliHash = cli_mapping; ++ global_map_2g_tbl.MapHash = map_mapping; ++ global_map_2g_tbl.Wdev_ifAddr = ifAddr_mapping; ++ global_map_2g_tbl.Enabled = TRUE; ++ ++ } else if ( adapter == adapter_5g ) { ++ global_map_5g_tbl.EntryLock = lock; ++ global_map_5g_tbl.CliHash = cli_mapping; ++ global_map_5g_tbl.MapHash = map_mapping; ++ global_map_5g_tbl.Wdev_ifAddr = ifAddr_mapping; ++ global_map_5g_tbl.Enabled = TRUE; ++ } ++ ++ if (0) { ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s] global_map_2g_tbl address %p\n", __FUNCTION__, &global_map_2g_tbl)); ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s] global_map_5g_tbl address %p\n", __FUNCTION__, &global_map_5g_tbl)); ++ } ++ ++ ++ FWD_IRQ_UNLOCK(&global_band_tbl_lock, global_band_tbl_irq_flags); ++ ++} ++ ++void wifi_fwd_insert_bridge_mapping(struct sk_buff *skb) ++{ ++ struct net_device *net_dev = NULL; ++ struct APCLI_BRIDGE_LEARNING_MAPPING_STRUCT *map_tbl_entry = NULL; ++ unsigned char pkt_from, tbl_size = 0; ++ ++ net_dev = skb->dev; ++ ++ if (!WIFI_FWD_TEST_FLAG(fOP_WIFI_FWD_ENABLED)) ++ return; ++ ++ if ((net_dev == ap_5g) || (net_dev == apcli_5g)) ++ pkt_from = WIFI_FWD_PACKET_SPECIFIC_5G; ++ else ++ pkt_from = WIFI_FWD_PACKET_SPECIFIC_2G; ++ ++ FWD_IRQ_LOCK(&global_map_tbl_lock, global_map_tbl_irq_flags); ++ ++ if (global_map_tbl.entry_num < 0) { ++ FWD_IRQ_UNLOCK(&global_map_tbl_lock, global_map_tbl_irq_flags); ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s] no entry found in the list\n", __FUNCTION__)); ++ return; ++ } ++ ++ tbl_size = sizeof(struct APCLI_BRIDGE_LEARNING_MAPPING_STRUCT); ++ map_tbl_entry = (struct APCLI_BRIDGE_LEARNING_MAPPING_STRUCT *) kmalloc(tbl_size, GFP_ATOMIC); ++ ++ if (map_tbl_entry) { ++ memset(map_tbl_entry, 0, tbl_size); ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s] size of map_tbl_entry = %dbytes\n", __FUNCTION__, tbl_size)); ++ } else ++ return; ++ ++ map_tbl_entry->rcvd_net_dev = net_dev; ++ map_tbl_entry->entry_from = pkt_from; ++ memcpy(map_tbl_entry->src_addr, ((unsigned char *)skb->data)[6], ETH_ALEN); ++ ++ if (global_map_tbl.entry_num == 0) { ++ global_map_tbl.pHead = map_tbl_entry; ++ global_map_tbl.pTail = map_tbl_entry; ++ map_tbl_entry->pBefore = NULL; ++ map_tbl_entry->pNext = NULL; ++ } ++ else if (global_map_tbl.entry_num > 0) { ++ global_map_tbl.pTail->pNext = map_tbl_entry; ++ map_tbl_entry->pBefore = global_map_tbl.pTail; ++ global_map_tbl.pTail = map_tbl_entry; ++ } ++ ++ global_map_tbl.entry_num++; ++ FWD_IRQ_UNLOCK(&global_map_tbl_lock, global_map_tbl_irq_flags); ++ ++ if (0) { ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s] %s\n", __FUNCTION__, (pkt_from == WIFI_FWD_PACKET_SPECIFIC_5G ? "5G" : "2.4G"))); ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s] inserting mac addr = %02X:%02X:%02X:%02X:%02X:%02X\n", ++ __FUNCTION__, PRINT_MAC(map_tbl_entry->src_addr))); ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s] rcvd from %s\n", __FUNCTION__, WIFI_FWD_NETDEV_GET_DEVNAME(map_tbl_entry->rcvd_net_dev))); ++ } ++ ++ return; ++} ++ ++ ++/* ++ return value: ++ 1: success ++ 0: fail ++*/ ++static int wifi_fwd_search_mapping_table(struct sk_buff *skb, struct APCLI_BRIDGE_LEARNING_MAPPING_STRUCT **tbl_entry) ++{ ++ struct net_device *net_dev = NULL; ++ struct APCLI_BRIDGE_LEARNING_MAPPING_STRUCT *map_tbl_entry = NULL; ++ unsigned char pkt_from, idx = 0; ++ ++ net_dev = skb->dev; ++ ++ if (!WIFI_FWD_TEST_FLAG(fOP_WIFI_FWD_ENABLED)) ++ return 0; ++ ++ if ((net_dev == ap_5g) || (net_dev == apcli_5g)) ++ pkt_from = WIFI_FWD_PACKET_SPECIFIC_5G; ++ else ++ pkt_from = WIFI_FWD_PACKET_SPECIFIC_2G; ++ ++ FWD_IRQ_LOCK(&global_map_tbl_lock, global_map_tbl_irq_flags); ++ ++ if (global_map_tbl.entry_num <= 0) { ++ FWD_IRQ_UNLOCK(&global_map_tbl_lock, global_map_tbl_irq_flags); ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s] no entry found in the list\n", __FUNCTION__)); ++ return 0; ++ } ++ else ++ { ++ if (global_map_tbl.pHead != NULL) { ++ map_tbl_entry = global_map_tbl.pHead; ++ } ++ else ++ { ++ FWD_IRQ_UNLOCK(&global_map_tbl_lock, global_map_tbl_irq_flags); ++ return 0; ++ } ++ ++ for (idx=0; idx<global_map_tbl.entry_num; idx++) ++ { ++ if (MAC_ADDR_EQUAL(map_tbl_entry->src_addr, ((unsigned char *)skb->data)[6]) && ++ (net_dev != map_tbl_entry->rcvd_net_dev)) ++ { ++ if (map_tbl_entry->entry_from == WIFI_FWD_PACKET_SPECIFIC_5G) { ++ /* indicate this entry exist in dual band. packets sending to this entry need to be monitored */ ++ map_tbl_entry->entry_from |= pkt_from; ++ map_tbl_entry->rcvd_net_dev = net_dev; ++ } ++ else ++ { ++ /* make sure the net device reported in the packet is up */ ++ if (dev_get_flags(map_tbl_entry->rcvd_net_dev) & IFF_UP) { ++ map_tbl_entry->entry_from |= pkt_from; /* indicate this entry exist in dual band. packet need to send to this */ ++ SET_OS_PKT_NETDEV(RTPKT_TO_OSPKT(skb), map_tbl_entry->rcvd_net_dev); /* change net_device of packet to 2G */ ++ } ++ } ++ ++ *tbl_entry = map_tbl_entry; ++ FWD_IRQ_UNLOCK(&global_map_tbl_lock, global_map_tbl_irq_flags); ++ return 1; ++ } ++ else if (MAC_ADDR_EQUAL(map_tbl_entry->src_addr, ((unsigned char *)skb->data)[6]) && ++ (net_dev == map_tbl_entry->rcvd_net_dev)) ++ { ++ *tbl_entry = map_tbl_entry; ++ FWD_IRQ_UNLOCK(&global_map_tbl_lock, global_map_tbl_irq_flags); ++ return 1; ++ } ++ ++ map_tbl_entry = map_tbl_entry->pNext; ++ } ++ ++ FWD_IRQ_UNLOCK(&global_map_tbl_lock, global_map_tbl_irq_flags); ++ } ++ ++ return 0; ++} ++ ++ ++/* ++ return value: ++ 1: Allocate Success ++ 0: Allocate FAIL ++*/ ++static int wifi_fwd_alloc_tbl(unsigned int NumOfEntry) ++{ ++ unsigned int TblSize = 0; ++ ++ TblSize = NumOfEntry * sizeof(struct FwdPair); ++ WiFiFwdBase = (struct FwdPair *) kmalloc(TblSize, GFP_ATOMIC); ++ if (WiFiFwdBase) { ++ memset(WiFiFwdBase, 0, TblSize); ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s] size of WiFiFwdBase = %dbytes\n", __FUNCTION__, TblSize)); ++ } ++ else ++ return 0; ++ ++ TblSize = NumOfEntry * sizeof(struct PacketSource); ++ pkt_src = (struct PacketSource *) kmalloc(TblSize, GFP_ATOMIC); ++ if (pkt_src) { ++ memset(pkt_src, 0, TblSize); ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s] size of pkt_src = %dbytes\n", __FUNCTION__, TblSize)); ++ } ++ else ++ return 0; ++ ++ TblSize = NumOfEntry * sizeof(struct TxSourceEntry); ++ tx_src_tbl = (struct TxSourceEntry *) kmalloc(TblSize, GFP_ATOMIC); ++ if (tx_src_tbl) { ++ memset(tx_src_tbl, 0, TblSize); ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("[%s] size of tx_src_tbl = %dbytes\n", __FUNCTION__, TblSize)); ++ } ++ else ++ return 0; ++ ++ TblSize = sizeof(struct APCLI_BRIDGE_LEARNING_MAPPING_MAP); ++ memset(&global_map_tbl, 0, TblSize); ++ ++ TblSize = sizeof(struct _REPEATER_ADAPTER_DATA_TABLE); ++ memset(&global_map_2g_tbl, 0, TblSize); ++ memset(&global_map_5g_tbl, 0, TblSize); ++ ++ return 1; ++} ++ ++ ++static unsigned char wifi_fwd_check_and_forward(struct sk_buff *skb) ++{ ++ struct ethhdr *mh = NULL; ++ struct iphdr *iph = NULL; ++ struct udphdr *uh = NULL; ++ struct tcphdr *th = NULL; ++ struct ipv6hdr *ipv6h = NULL; ++ void *ptr = NULL; ++ unsigned short type = 0; ++ ++ mh = eth_hdr(skb); ++ if (mh) ++ { ++ type = ntohs(mh->h_proto); ++ switch(type) ++ { ++ /* ++ Forward LLTD EthType: 0x88D9 ++ */ ++ case LLTD_ETH_TYPE: ++#if 0 ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("Forward - LLTD_ETH_TYPE: 0x%02x\n", type)); ++#endif ++ if (!WIFI_FWD_TEST_FLAG(fOP_WIFI_FWD_ACCESS_SCHED_ACTIVE)) ++ return TRUE; ++ break; ++ ++ /* ++ Forward ARP EthType: 0x0806 ++ */ ++ case ARP_ETH_TYPE: ++#if 0 ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("Forward - ARP_ETH_TYPE: 0x%02x\n", type)); ++#endif ++ if (WIFI_FWD_TEST_FLAG(fOP_WIFI_FWD_ACCESS_SCHED_ACTIVE)) ++ return TRUE; ++ break; ++ ++ case ETH_P_IP: ++ iph = (struct iphdr *)(skb->data); ++#if 0 ++ hex_dump_("Data", skb->data, (iph->ihl<<2)); ++#endif ++ if (iph) ++ { ++ ptr = (void *)(skb->data+(iph->ihl<<2)); ++ if (ptr) ++ { ++#if 0 ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("wifi_fwd_check_and_forward - iph->protocol: 0x%02x\n", iph->protocol)); ++#endif ++ switch(iph->protocol) ++ { ++ case UDP: ++ /* ++ Forward UDP port 53 and 67 ++ */ ++ uh = (struct udphdr*)(ptr); ++ if ((ntohs(uh->source) == 53) || (ntohs(uh->dest) == 53) || ++ (ntohs(uh->source) == 67) || (ntohs(uh->dest) == 67)) ++ { ++#if 0 ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("Forward - udp source port: %d, dest port: %d\n", ntohs(uh->source), ntohs(uh->dest))); ++#endif ++ return TRUE; ++ } ++ break; ++ ++ case TCP: ++ /* ++ Forward TCP port 80 and 5000 ++ */ ++ th = (struct tcphdr *)(ptr); ++ if ((ntohs(th->source) == 80) || ++ (ntohs(th->dest) == 80) || ++ (ntohs(th->source) == 5000) || ++ (ntohs(th->dest) == 5000)) ++ { ++#if 0 ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("Forward - tcp source port: %d, dest port: %d\n", ntohs(th->source), ntohs(th->dest))); ++#endif ++ if (!WIFI_FWD_TEST_FLAG(fOP_WIFI_FWD_ACCESS_SCHED_ACTIVE)) ++ return TRUE; ++ } ++ break; ++ ++ default: ++ break; ++ } ++ } ++ } ++ break; ++ ++ case ETH_P_IPV6: ++#if 0 ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("IPv6: IPV6_HDR_LEN = %d\n", IPV6_HDR_LEN)); ++ hex_dump_("Data", skb->data, LENGTH_802_3+IPV6_HDR_LEN); ++#endif ++ ipv6h = (struct ipv6hdr *)(skb->data); ++ if (ipv6h) ++ { ++#if 0 ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("ipv6h->version = 0x%x\n", ipv6h->version)); ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("ipv6h->nexthdr = 0x%x\n", ipv6h->nexthdr)); ++#endif ++ ptr = (void *)(skb->data+IPV6_HDR_LEN); ++ if (ptr) ++ { ++ switch(ipv6h->nexthdr) ++ { ++ /* ++ Forward IPv6 UDP port 53 ++ */ ++ case IPV6_NEXT_HEADER_UDP: ++ uh = (struct udphdr*)(ptr); ++#if 0 ++ WF_FWD_PRINT(WF_DEBUG_TRACE, ("udp source port: %d, dest port: %d\n", ntohs(uh->source), ntohs(uh->dest))); ++#endif ++ if ((ntohs(uh->source) == 53) || (ntohs(uh->dest) == 53)) ++ { ++ return TRUE; ++ } ++ break; ++ ++ default: ++ break; ++ } ++ } ++ } ++ break; ++ ++ default: ++ break; ++ } ++ } ++ ++ return FALSE; ++} ++ ++/* ++ return value: ++ 0: return to driver and handle ++ 1: return to driver and release ++*/ ++static int wifi_fwd_tx_handler(struct sk_buff *skb) ++{ ++ struct net_device *net_dev = NULL; ++ net_dev = skb->dev; ++ unsigned char ret = 0; ++ ++ /* ++ return this skb to driver and handle while: ++ 1. path of WiFi forwarding is inactive ++ 2. the skb does not exist ++ 3. no forwarding connection is established ++ */ ++ if (!WIFI_FWD_TEST_FLAG(fOP_WIFI_FWD_ACTIVE) || !WIFI_FWD_TEST_FLAG(fOP_WIFI_FWD_ENABLED) || !skb || (fwd_counter == 0)) ++ return 0; ++ ++ ret = wifi_fwd_tx_lookup_entry(net_dev, skb); ++ return ret; ++} ++ ++ ++/* ++ return value: ++ 0: skb is handled by wifi_fwd module ++ 1: return to driver and bridge ++ 2: return to driver and release ++*/ ++static int wifi_fwd_rx_handler(struct sk_buff *skb) ++{ ++ struct net_device *net_dev = NULL; ++ struct net_device *target = NULL; ++ struct ethhdr *mh = eth_hdr(skb); ++ ++ unsigned char type = ENTRY_TYPE_INVALID; ++ net_dev = skb->dev; ++ ++ unsigned int recv_from = 0, band_from = 0, ret = 0; ++ recv_from = WIFI_FWD_GET_PACKET_RECV_FROM(skb, recv_from_cb_offset); ++ band_from = WIFI_FWD_GET_PACKET_BAND(skb, band_cb_offset); ++ ++ /* ++ return this skb to driver and bridge while: ++ 1. path of WiFi forwarding is inactive ++ 2. the skb does not exist ++ 3. no forwarding connection is established ++ 4. the destination is bridge ++ 5. in FastLane topology ++ 6. handling multicast/broadcast Rx ++ 7. hit hijack ++ */ ++ if (!WIFI_FWD_TEST_FLAG(fOP_WIFI_FWD_ACTIVE) || !WIFI_FWD_TEST_FLAG(fOP_WIFI_FWD_ENABLED) || !skb || (fwd_counter == 0)) ++ return 1; ++ ++ if (IS_PACKET_FROM_APCLI(recv_from) && !MAIN_SSID_OP(net_dev)) ++ return 2; ++ ++ /* handle access schedule */ ++ if (WIFI_FWD_TEST_FLAG(fOP_WIFI_FWD_ACCESS_SCHED_ACTIVE)) ++ { ++ if (IS_PACKET_FROM_APCLI(recv_from)) ++ { ++ if (wifi_fwd_check_and_forward(skb) == FALSE) ++ return 2; ++ } ++ } ++ ++ /* handle packets from bridge no matter unicast or broadcast */ ++ if (MAC_ADDR_EQUAL(mh->h_dest, br_lan->dev_addr)) ++ return 1; ++ ++#if 0 ++ if (((mh->h_dest[0] & 0x1) == 0x1) && ((mh->h_source[0] & 0x2) == 0x2)) ++ { ++ void * adapter = NULL; ++ ++ if (IS_PACKET_FROM_2G(band_from) && (adapter_2g != NULL)) ++ adapter = adapter_2g; ++ else if (IS_PACKET_FROM_5G(band_from) && (adapter_5g != NULL)) ++ adapter = adapter_5g; ++ ++ if (IS_PACKET_FROM_APCLI(recv_from) && (adapter != NULL) && ++ RTMPQueryLookupRepeaterCliEntry(adapter, mh->h_source) == TRUE) ++ return 2; ++ } ++#endif ++ ++ /* ++ in FastLane topology: ++ 1. forward Rx packets to bridge and let flooding work done by bridge ++ 2. no matter unicast or multicast/broadcast ++ */ ++ if (is_wifi_fastlane_mode(net_dev) && !GUEST_SSID_OP(net_dev)) ++ return 1; ++ ++ /* handle looping */ ++ ret = wifi_fwd_check_looping(skb, net_dev); ++ if(ret == 1) ++ return 2; ++ else if(ret == 2) ++ return 1; ++ ++ /* handle multicast/broadcast Rx */ ++ if ((mh->h_dest[0] & 0x1) == 0x1) ++ return 1; ++ ++ /* handle hijack */ ++ if (WIFI_FWD_TEST_FLAG(fOP_WIFI_FWD_HIJACK_ACTIVE)) ++ { ++ if (wifi_fwd_check_and_forward(skb) == TRUE) ++ { ++ WIFI_FWD_SET_PACKET_BAND(skb,WIFI_FWD_PACKET_SPECIFIC_TAG, band_cb_offset); ++ return 1; ++ } ++ } ++ ++ target = wifi_fwd_lookup_entry(net_dev, &type, skb); ++ ++ /* handle unicast Rx for non-FastLane cases */ ++ if (target != NULL) ++ { ++#if 0 /* move to earlier and handle it */ ++ /* in FastLane case, forward Rx packets to bridge and let flooding work done by bridge */ ++ if (is_wifi_fastlane_mode(net_dev)) ++ return 1; ++#endif ++ /* prevent from looping */ ++ if (wifi_fwd_find_sa_entry_by_sa_and_nd(skb, net_dev, 0) == 0) ++ { ++ return 2; ++ } ++ else ++ { ++ unsigned char hit = 0; ++ ++ /* forward to bridge if it is not a WiFi net device back-end packet */ ++ hit = wifi_fwd_check_from_bridge_by_dest_addr(skb, net_dev); ++ ++ if (hit == 0) ++ { ++ if (is_wifi_concurrent_mode(net_dev) && ++ IS_PACKET_FROM_ETHER(band_from)) ++ { ++ if (rep_net_dev == eth_traffic_band_5g) ++ { ++ if (REP_IS_5G(net_dev)) ++ return 1; ++ else ++ return 2; ++ } ++ else if (rep_net_dev == eth_traffic_band_2g) ++ { ++ if (REP_IS_2G(net_dev)) ++ return 1; ++ else ++ return 2; ++ } ++ } ++ else ++ return 1; ++ } ++ else if (hit == 2) ++ { ++ /* match inner communication case */ ++ return 1; ++ } ++ else ++ { ++ skb_push(skb, ETH_HLEN); ++ skb->dev = target; ++ dev_queue_xmit(skb); ++ return 0; ++ } ++ } ++ } ++ else ++ return 1; ++} ++ ++ ++static int wifi_fwd_init_mod(void) ++{ ++ if (!wifi_fwd_alloc_tbl(WIFI_FWD_TBL_SIZE)) { ++ return -ENOMEM; /* memory allocation failed */ ++ } ++ ++ WIFI_FWD_CLEAR_FLAG(fOP_GET_NET_DEVICE_STATUS_DONE); ++ WIFI_FWD_CLEAR_FLAG(fOP_WIFI_FWD_ACCESS_SCHED_ACTIVE); ++ WIFI_FWD_SET_FLAG(fOP_WIFI_FWD_ENABLED); ++ WIFI_FWD_SET_FLAG(fOP_WIFI_FWD_ACTIVE); ++ WIFI_FWD_SET_FLAG(fOP_WIFI_FWD_HIJACK_ACTIVE); ++ ++ wifi_fwd_reset_link_count(); ++ ++ eth_rep5g_wrg_uni_cnt = 0; ++ eth_rep5g_wrg_bct_cnt = 0; ++ eth_rep2g_wrg_uni_cnt = 0; ++ eth_rep2g_wrg_bct_cnt = 0; ++ rep_net_dev = eth_traffic_band_5g; ++ band_cb_offset = DEFAULT_BAND_CB_OFFSET; ++ recv_from_cb_offset = DEFAULT_RECV_FROM_CB_OFFSET; ++ wf_debug_level = WF_DEBUG_OFF; ++ ++ wf_fwd_tx_hook = wifi_fwd_tx_handler; ++ wf_fwd_rx_hook = wifi_fwd_rx_handler; ++ wf_fwd_entry_insert_hook = wifi_fwd_insert_entry; ++ wf_fwd_entry_delete_hook = wifi_fwd_delete_entry; ++ wf_fwd_set_cb_num = wifi_fwd_set_cb_num; ++ wf_fwd_get_rep_hook = wifi_fwd_get_rep; ++ wf_fwd_pro_active_hook = wifi_fwd_pro_active; ++ wf_fwd_pro_halt_hook = wifi_fwd_pro_halt; ++ wf_fwd_pro_enabled_hook = wifi_fwd_pro_enabled; ++ wf_fwd_pro_disabled_hook = wifi_fwd_pro_disabled; ++ wf_fwd_access_schedule_active_hook = wifi_fwd_access_schedule_active; ++ wf_fwd_access_schedule_halt_hook = wifi_fwd_access_schedule_halt; ++ wf_fwd_hijack_active_hook = wifi_fwd_hijack_active; ++ wf_fwd_hijack_halt_hook = wifi_fwd_hijack_halt; ++ wf_fwd_show_entry_hook = wifi_fwd_show_entry; ++ wf_fwd_needed_hook = wifi_fwd_needed; ++ wf_fwd_delete_entry_hook = wifi_fwd_delete_entry_by_idx; ++ packet_source_show_entry_hook = packet_source_show_entry; ++ packet_source_delete_entry_hook = packet_source_delete_entry; ++ wf_fwd_feedback_peer_adapter = wifi_fwd_feedback_peer_adapter; ++ wf_fwd_feedback_map_table = wifi_fwd_feedback_map_table; ++ wf_fwd_probe_adapter = wifi_fwd_probe_adapter; ++ wf_fwd_insert_bridge_mapping_hook = wifi_fwd_insert_bridge_mapping; ++ wf_fwd_insert_repeater_mapping_hook = wifi_fwd_insert_repeater_mapping; ++ wf_fwd_search_mapping_table_hook = wifi_fwd_search_mapping_table; ++ wf_fwd_delete_entry_inform_hook = wf_fwd_delete_entry_inform; ++ wf_fwd_debug_level_hook = wifi_fwd_set_debug_level; ++ ++ return 0; ++} ++ ++ ++static void wifi_fwd_cleanup_mod(void) ++{ ++ if (WiFiFwdBase) ++ kfree(WiFiFwdBase); ++ WiFiFwdBase = NULL; ++ ++ if (pkt_src) ++ kfree(pkt_src); ++ pkt_src = NULL; ++ ++ if(tx_src_tbl) ++ kfree(tx_src_tbl); ++ tx_src_tbl = NULL; ++ ++ wf_fwd_tx_hook = NULL; ++ wf_fwd_rx_hook = NULL; ++ wf_fwd_entry_insert_hook = NULL; ++ wf_fwd_entry_delete_hook = NULL; ++ wf_fwd_set_cb_num = NULL; ++ wf_fwd_get_rep_hook = NULL; ++ wf_fwd_pro_active_hook = NULL; ++ wf_fwd_pro_halt_hook = NULL; ++ wf_fwd_pro_enabled_hook = NULL; ++ wf_fwd_pro_disabled_hook = NULL; ++ wf_fwd_access_schedule_active_hook = NULL; ++ wf_fwd_access_schedule_halt_hook = NULL; ++ wf_fwd_hijack_active_hook = NULL; ++ wf_fwd_hijack_halt_hook = NULL; ++ wf_fwd_show_entry_hook = NULL; ++ wf_fwd_needed_hook = NULL; ++ wf_fwd_delete_entry_hook = NULL; ++ packet_source_show_entry_hook = NULL; ++ packet_source_delete_entry_hook = NULL; ++ wf_fwd_feedback_peer_adapter = NULL; ++ wf_fwd_feedback_map_table = NULL; ++ wf_fwd_probe_adapter = NULL; ++ wf_fwd_insert_bridge_mapping_hook = NULL; ++ wf_fwd_insert_repeater_mapping_hook = NULL; ++ wf_fwd_search_mapping_table_hook = NULL; ++ wf_fwd_delete_entry_inform_hook = NULL; ++ wf_fwd_debug_level_hook = NULL; ++ ++ return; ++} ++ ++ ++module_init(wifi_fwd_init_mod); ++module_exit(wifi_fwd_cleanup_mod); ++ ++MODULE_AUTHOR("MediaTek Inc"); ++MODULE_LICENSE("Proprietary"); ++MODULE_DESCRIPTION("MediaTek WiFi Packet Forwarding Module\n"); ++ +Index: linux-3.10.20/drivers/net/wireless/wifi_forward/wifi_fwd_v1/wifi_fwd.h +=================================================================== +--- /dev/null ++++ linux-3.10.20/drivers/net/wireless/wifi_forward/wifi_fwd_v1/wifi_fwd.h +@@ -0,0 +1,276 @@ ++/**************************************************************************** ++ * Mediatek Inc. ++ * 5F., No.5, Taiyuan 1st St., Zhubei City, ++ * Hsinchu County 302, Taiwan, R.O.C. ++ * (c) Copyright 2014, Mediatek, Inc. ++ * ++ * All rights reserved. Ralink's source code is an unpublished work and the ++ * use of a copyright notice does not imply otherwise. This source code ++ * contains confidential trade secret material of Ralink Tech. Any attemp ++ * or participation in deciphering, decoding, reverse engineering or in any ++ * way altering the source code is stricitly prohibited, unless the prior ++ * written consent of Ralink Technology, Inc. is obtained. ++ **************************************************************************** ++ ++ Module Name: ++ wifi_fwd.h ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Annie Lu 2014-06-30 Initial version ++*/ ++ ++#ifndef __WF_FWD_H__ ++#define __WF_FWD_H__ ++ ++#include <linux/version.h> ++#include <linux/module.h> ++#include <linux/skbuff.h> ++#include <linux/kernel.h> ++#include <linux/net.h> ++#include <linux/netdevice.h> ++#include <linux/ip.h> ++#include <linux/ipv6.h> ++#include <linux/udp.h> ++#include <linux/tcp.h> ++ ++ ++#ifndef TRUE ++#define TRUE 1 ++#endif ++ ++#ifndef FALSE ++#define FALSE 0 ++#endif ++ ++/* enternal symbol */ ++extern int (*wf_fwd_rx_hook) (struct sk_buff *skb); ++extern int (*wf_fwd_tx_hook) (struct sk_buff *skb); ++ ++extern unsigned char (*wf_fwd_entry_insert_hook) (struct net_device *src, struct net_device *dest, void *adapter); ++extern unsigned char (*wf_fwd_entry_delete_hook) (struct net_device *src, struct net_device *dest, unsigned char link_down); ++extern void (*wf_fwd_set_cb_num) (unsigned int band_cb_num, unsigned int receive_cb_num); ++ ++extern void (*wf_fwd_get_rep_hook) (unsigned char idx); ++extern void (*wf_fwd_pro_active_hook) (void); ++extern void (*wf_fwd_pro_halt_hook) (void); ++extern void (*wf_fwd_pro_enabled_hook) (void); ++extern void (*wf_fwd_pro_disabled_hook) (void); ++extern void (*wf_fwd_access_schedule_active_hook) (void); ++extern void (*wf_fwd_access_schedule_halt_hook) (void); ++extern void (*wf_fwd_hijack_active_hook) (void); ++extern void (*wf_fwd_hijack_halt_hook) (void); ++ ++extern void (*wf_fwd_show_entry_hook) (void); ++extern bool (*wf_fwd_needed_hook) (void); ++extern void (*wf_fwd_delete_entry_hook) (unsigned char idx); ++extern void (*packet_source_show_entry_hook) (void); ++extern void (*packet_source_delete_entry_hook) (unsigned char idx); ++ ++extern void (*wf_fwd_feedback_peer_adapter) (void *adapter, void *peer); ++extern void (*wf_fwd_feedback_map_table) (void *adapter, void *peer, void *opp_peer); ++extern void (*wf_fwd_probe_adapter) (void *adapter); ++extern void (*wf_fwd_insert_repeater_mapping_hook)(void *adapter, void *lock, void *cli_mapping, void *map_mapping, void *ifAddr_mapping); ++extern void (*wf_fwd_insert_bridge_mapping_hook) (struct sk_buff *skb); ++extern int (*wf_fwd_search_mapping_table_hook) (struct sk_buff *skb, struct APCLI_BRIDGE_LEARNING_MAPPING_STRUCT **tbl_entry); ++extern void (*wf_fwd_delete_entry_inform_hook) (unsigned char *addr); ++extern void (*wf_fwd_debug_level_hook) (unsigned char level); ++ ++#ifndef ETH_ALEN ++#define ETH_ALEN 6 ++#endif ++#define MAC_ADDR_LEN 6 ++ ++#define fOP_GET_NET_DEVICE_STATUS_DONE 0x00000001 ++#define fOP_WIFI_FWD_ENABLED 0x00000002 ++#define fOP_WIFI_FWD_ACTIVE 0x00000010 ++#define fOP_WIFI_FWD_ACCESS_SCHED_ACTIVE 0x00000100 ++#define fOP_WIFI_FWD_HIJACK_ACTIVE 0x00001000 ++ ++#define WIFI_FWD_SET_FLAG(_F) (wifi_fwd_op_flag |= (_F)) ++#define WIFI_FWD_CLEAR_FLAG(_F) (wifi_fwd_op_flag &= ~(_F)) ++#define WIFI_FWD_CLEAR_FLAGS (wifi_fwd_op_flag = 0) ++#define WIFI_FWD_TEST_FLAG(_F) ((wifi_fwd_op_flag & (_F)) != 0) ++#define WIFI_FWD_TEST_FLAGS(_F) ((wifi_fwd_op_flag & (_F)) == (_F)) ++ ++#define REP_IS_5G(_p) (((_p) == apcli_5g) || ((_p) == ap_5g) || ((_p) == apcli1_5g) || ((_p) == ap1_5g)) ++#define REP_IS_2G(_p) (((_p) == apcli_2g) || ((_p) == ap_2g) || ((_p) == apcli1_2g) || ((_p) == ap1_2g)) ++#define CMP_TO_REP(_p, _x) (REP_IS_##_x##G(_p)) ++ ++#define IS_MAIN_SSID_DEV(_p) (((_p) == ap_2g) || ((_p) == ap_5g) || ((_p) == apcli_2g) || ((_p) == apcli_5g)) ++#define IS_GUEST_SSID_DEV(_p) (((_p) == ap1_2g) || ((_p) == ap1_5g) || ((_p) == apcli1_2g) || ((_p) == apcli1_5g)) ++ ++#define MAIN_SSID_OP(_p) ((main_2g_link_cnt != 0) || (main_5g_link_cnt != 0)) ++#define GUEST_SSID_OP(_p) ((guest_2g_link_cnt != 0) || (guest_5g_link_cnt != 0)) ++ ++#define WIFI_FWD_TBL_SIZE 50 ++ ++#define ENTRY_TYPE_INVALID 0 ++#define ENTRY_TYPE_SRC 1 ++#define ENTRY_TYPE_DEST 2 ++ ++/* macro */ ++#define dbg_print printk ++#define WF_DEBUG_OFF 0 ++#define WF_DEBUG_TRACE 1 ++#define WF_DEBUG_ON 2 ++ ++extern unsigned char wf_debug_level; ++ ++#define WF_FWD_PRINT(Level, Fmt) \ ++do{ \ ++ unsigned char __gLevel = (Level);\ ++ if (__gLevel <= wf_debug_level) \ ++ { \ ++ printk Fmt; \ ++ } \ ++}while(0) ++ ++/* CB related */ ++#define CB_OFF 10 ++#define RTPKT_TO_OSPKT(_p) ((struct sk_buff *)(_p)) ++#define GET_OS_PKT_CB(_p) (RTPKT_TO_OSPKT(_p)->cb) ++#define PACKET_CB(_p, _offset) ((RTPKT_TO_OSPKT(_p)->cb[CB_OFF + (_offset)])) ++ ++/* [CB_OFF + 34]: tag the packet is sent by which band */ ++#define DEFAULT_BAND_CB_OFFSET 34 ++#define WIFI_FWD_PACKET_SPECIFIC_2G 0x1 ++#define WIFI_FWD_PACKET_SPECIFIC_5G 0x2 ++#define WIFI_FWD_PACKET_SPECIFIC_ETHER 0x4 ++#define WIFI_FWD_PACKET_SPECIFIC_TAG 0x8 ++ ++ ++#define WIFI_FWD_SET_PACKET_BAND(_p, _offset, _flg) \ ++ do{ \ ++ if (_flg) \ ++ PACKET_CB(_p, _offset) |= (_flg); \ ++ else \ ++ PACKET_CB(_p, _offset) &= (~_flg); \ ++ }while(0) ++ ++#define WIFI_FWD_GET_PACKET_BAND(_p, _offset) (PACKET_CB(_p, _offset)) ++ ++/* [CB_OFF + 35]: tag the packet received from which net device */ ++#define DEFAULT_RECV_FROM_CB_OFFSET 35 ++#define WIFI_FWD_PACKET_RECV_FROM_2G_CLIENT 0x01 ++#define WIFI_FWD_PACKET_RECV_FROM_5G_CLIENT 0x02 ++#define WIFI_FWD_PACKET_RECV_FROM_2G_AP 0x04 ++#define WIFI_FWD_PACKET_RECV_FROM_5G_AP 0x08 ++#define WIFI_FWD_PACKET_RECV_FROM_2G_GUEST_CLIENT 0x10 ++#define WIFI_FWD_PACKET_RECV_FROM_5G_GUEST_CLIENT 0x20 ++#define WIFI_FWD_PACKET_RECV_FROM_2G_GUEST_AP 0x40 ++#define WIFI_FWD_PACKET_RECV_FROM_5G_GUEST_AP 0x80 ++ ++ ++#define WIFI_FWD_SET_PACKET_RECV_FROM(_p, _offset, _flg) \ ++ do{ \ ++ if (_flg) \ ++ PACKET_CB(_p, _offset) |= (_flg); \ ++ else \ ++ PACKET_CB(_p, _offset) &= (~_flg); \ ++ }while(0) ++ ++#define WIFI_FWD_GET_PACKET_RECV_FROM(_p, _offset) (PACKET_CB(_p, _offset)) ++ ++#define IS_PACKET_FROM_APCLI(_x) \ ++ ((((_x) & WIFI_FWD_PACKET_RECV_FROM_2G_CLIENT) == WIFI_FWD_PACKET_RECV_FROM_2G_CLIENT) ||\ ++ (((_x) & WIFI_FWD_PACKET_RECV_FROM_5G_CLIENT) == WIFI_FWD_PACKET_RECV_FROM_5G_CLIENT) ||\ ++ (((_x) & WIFI_FWD_PACKET_RECV_FROM_2G_GUEST_CLIENT) == WIFI_FWD_PACKET_RECV_FROM_2G_GUEST_CLIENT) ||\ ++ (((_x) & WIFI_FWD_PACKET_RECV_FROM_5G_GUEST_CLIENT) == WIFI_FWD_PACKET_RECV_FROM_5G_GUEST_CLIENT)) ++ ++#define IS_PACKET_FROM_2G(_x) \ ++ (((_x) & WIFI_FWD_PACKET_SPECIFIC_2G) == WIFI_FWD_PACKET_SPECIFIC_2G) ++ ++#define IS_PACKET_FROM_5G(_x) \ ++ (((_x) & WIFI_FWD_PACKET_SPECIFIC_5G) == WIFI_FWD_PACKET_SPECIFIC_5G) ++ ++#define IS_TAG_PACKET(_x) \ ++ (((_x) & WIFI_FWD_PACKET_SPECIFIC_TAG) == WIFI_FWD_PACKET_SPECIFIC_TAG) ++ ++#define IS_PACKET_FROM_ETHER(_x) \ ++ ((((_x) & WIFI_FWD_PACKET_SPECIFIC_2G) != WIFI_FWD_PACKET_SPECIFIC_2G) &&\ ++ (((_x) & WIFI_FWD_PACKET_SPECIFIC_5G) != WIFI_FWD_PACKET_SPECIFIC_5G)) ++ ++#define IS_PACKET_FROM_MAIN_SSID(_x) \ ++ (((_x) & 0x0F) != 0x0) ++ ++#define IS_PACKET_FROM_GUEST_SSID(_x) \ ++ (((_x) & 0x0F) == 0x0) ++ ++ ++ ++typedef enum _ETHER_BAND_BINDDING { ++ eth_traffic_band_2g = 2, ++ eth_traffic_band_5g = 5, ++} ETHER_BAND_BINDDING, *PETHER_BAND_BINDDING; ++ ++/* data structure */ ++struct FwdPair { ++ unsigned char valid; /* 1: valid, 0: invalid */ ++ struct net_device *src; ++ struct net_device *dest; ++}; ++ ++struct PacketSource { ++ unsigned char valid; /* 1: valid, 0: invalid */ ++ struct net_device *peer; ++ struct net_device *src; ++ unsigned char h_source[ETH_ALEN]; ++ unsigned char h_dest[ETH_ALEN]; ++}; ++ ++struct TxSourceEntry { ++ unsigned char valid; /* 1: valid, 0: invalid */ ++ unsigned char h_source[ETH_ALEN]; ++}; ++ ++struct APCLI_BRIDGE_LEARNING_MAPPING_STRUCT { ++ struct net_device *rcvd_net_dev; ++ unsigned char src_addr[ETH_ALEN]; ++ unsigned char entry_from; ++ struct APCLI_BRIDGE_LEARNING_MAPPING_STRUCT *pBefore; ++ struct APCLI_BRIDGE_LEARNING_MAPPING_STRUCT *pNext; ++}; ++ ++struct APCLI_BRIDGE_LEARNING_MAPPING_MAP { ++ struct APCLI_BRIDGE_LEARNING_MAPPING_STRUCT *pHead; ++ struct APCLI_BRIDGE_LEARNING_MAPPING_STRUCT *pTail; ++ unsigned int entry_num; ++}; ++ ++ ++typedef struct _REPEATER_ADAPTER_DATA_TABLE { ++ bool Enabled; ++ void *EntryLock; ++ void **CliHash; ++ void **MapHash; ++ void *Wdev_ifAddr; ++} REPEATER_ADAPTER_DATA_TABLE; ++ ++ ++#define FWD_IRQ_LOCK(__lock, __irqflags) \ ++{ \ ++ __irqflags = 0; \ ++ spin_lock_irqsave((spinlock_t *)(__lock), __irqflags); \ ++} ++ ++#define FWD_IRQ_UNLOCK(__lock, __irqflag) \ ++{ \ ++ spin_unlock_irqrestore((spinlock_t *)(__lock), __irqflag); \ ++} ++ ++#define PRINT_MAC(addr) \ ++ addr[0], addr[1], addr[2], addr[3], addr[4], addr[5] ++ ++#define MAC_ADDR_EQUAL(addr1,addr2) (!memcmp((void *)(addr1), (void *)(addr2), ETH_ALEN)) ++#define COPY_MAC_ADDR(addr1, addr2) (memcpy((addr1), (addr2), ETH_ALEN)) ++ ++#define WIFI_FWD_NETDEV_GET_DEVNAME(_pNetDev) ((_pNetDev)->name) ++#define WIFI_FWD_NETDEV_GET_PHYADDR(_pNetDev) ((_pNetDev)->dev_addr) ++ ++#define SET_OS_PKT_NETDEV(_pkt, _pNetDev) \ ++ (RTPKT_TO_OSPKT(_pkt)->dev) = (_pNetDev) ++#endif +Index: linux-3.10.20/drivers/net/wireless/wifi_forward/wifi_hook_v1/Makefile +=================================================================== +--- /dev/null ++++ linux-3.10.20/drivers/net/wireless/wifi_forward/wifi_hook_v1/Makefile +@@ -0,0 +1,2 @@ ++obj-y += wifi_hook.o ++wifi_hook-objs := hook.o +Index: linux-3.10.20/drivers/misc/mediatek/Kconfig.wcn +=================================================================== +--- linux-3.10.20.orig/drivers/misc/mediatek/Kconfig.wcn ++++ linux-3.10.20/drivers/misc/mediatek/Kconfig.wcn +@@ -198,6 +198,17 @@ source "drivers/net/wireless/mt_wifi/emb + + endif # WIFI_DRIVER + ++source "drivers/net/wireless/wifi_forward/wifi_fwd/Kconfig" ++ ++config RTDEV ++ bool ++ default y if WIFI_DRIVER && !SECOND_IF_NONE || RTDEV_MII ++ default y if RTDEV_PLC ++ ++config WIFI_PKT_FWD ++ bool "WiFi packet forwarding" ++ depends on WIFI_DRIVER ++ default n + + config RTDEV + bool +Index: linux-3.10.20/drivers/net/wireless/Makefile +=================================================================== +--- linux-3.10.20.orig/drivers/net/wireless/Makefile ++++ linux-3.10.20/drivers/net/wireless/Makefile +@@ -62,6 +62,20 @@ obj-$(CONFIG_MTK_CONNSYS_WIFI) += mt_soc + ifneq ($(CONFIG_ARCH_MT6595), y) + #obj-$(CONFIG_MTK_COMBO_WIFI) += mt66xx/ + endif ++ ++ifneq ($(CONFIG_WIFI_PKT_FWD),) ++ifneq ($(CONFIG_WIFI_PKT_FWD_V1),) ++obj-y += wifi_forward/wifi_hook_v1/ ++else ++obj-y += wifi_forward/wifi_hook/ ++endif ++endif ++ ++ifneq ($(CONFIG_WIFI_PKT_FWD_V1),) ++obj-$(CONFIG_WIFI_PKT_FWD) += wifi_forward/wifi_fwd_v1/ ++else ++obj-$(CONFIG_WIFI_PKT_FWD) += wifi_forward/wifi_fwd/ ++endif + ifneq ($(CONFIG_RLT_AP_SUPPORT),) + obj-$(CONFIG_RLT_AP_SUPPORT) += rlt_wifi_ap/ + endif +@@ -74,3 +88,8 @@ endif + ifneq ($(CONFIG_MT_STA_SUPPORT),) + obj-$(CONFIG_MT_STA_SUPPORT) += mt_wifi_sta/ + endif ++ ++#ifneq ($(CONFIG_WIFI_PKT_FWD),) ++#obj-y += wifi_forward/wifi_hook/ ++#endif ++#obj-$(CONFIG_WIFI_PKT_FWD) += wifi_forward/wifi_fwd/ +Index: linux-3.10.20/drivers/net/wireless/wifi_forward/wifi_hook/Makefile +=================================================================== +--- /dev/null ++++ linux-3.10.20/drivers/net/wireless/wifi_forward/wifi_hook/Makefile +@@ -0,0 +1,2 @@ ++obj-y += wifi_hook.o ++wifi_hook-objs := hook.o +Index: linux-3.10.20/drivers/net/wireless/wifi_forward/wifi_hook/hook.c +=================================================================== +--- /dev/null ++++ linux-3.10.20/drivers/net/wireless/wifi_forward/wifi_hook/hook.c +@@ -0,0 +1,101 @@ ++/**************************************************************************** ++ * Mediatek Inc. ++ * 5F., No.5, Taiyuan 1st St., Zhubei City, ++ * Hsinchu County 302, Taiwan, R.O.C. ++ * (c) Copyright 2014, Mediatek, Inc. ++ * ++ * All rights reserved. Ralink's source code is an unpublished work and the ++ * use of a copyright notice does not imply otherwise. This source code ++ * contains confidential trade secret material of Ralink Tech. Any attemp ++ * or participation in deciphering, decoding, reverse engineering or in any ++ * way altering the source code is stricitly prohibited, unless the prior ++ * written consent of Ralink Technology, Inc. is obtained. ++ **************************************************************************** ++ ++ Module Name: ++ hook.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Name Date Modification logs ++ Annie Lu 2014-06-30 Initial version ++*/ ++ ++#include <linux/version.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/types.h> ++#include <linux/skbuff.h> ++#include <linux/net.h> ++#include <linux/netdevice.h> ++ ++ ++int (*wf_fwd_rx_hook) (struct sk_buff * skb) = NULL; ++int (*wf_fwd_tx_hook) (struct sk_buff * skb) = NULL; ++ ++unsigned char (*wf_fwd_entry_insert_hook) (struct net_device *src, struct net_device *dest, void *adapter) = NULL; ++unsigned char (*wf_fwd_entry_delete_hook) (struct net_device *src, struct net_device *dest, unsigned char link_down) = NULL; ++void (*wf_fwd_set_cb_num) (unsigned int band_cb_num, unsigned int receive_cb_num) = NULL; ++bool (*wf_fwd_check_active_hook) (void) = NULL; ++ ++void (*wf_fwd_get_rep_hook) (unsigned char idx) = NULL; ++void (*wf_fwd_pro_active_hook) (void) = NULL; ++void (*wf_fwd_pro_halt_hook) (void) = NULL; ++void (*wf_fwd_pro_enabled_hook) (void) = NULL; ++void (*wf_fwd_pro_disabled_hook) (void) = NULL; ++ ++void (*wf_fwd_access_schedule_active_hook) (void) = NULL; ++void (*wf_fwd_access_schedule_halt_hook) (void) = NULL; ++void (*wf_fwd_hijack_active_hook) (void) = NULL; ++void (*wf_fwd_hijack_halt_hook) (void) = NULL; ++ ++void (*wf_fwd_show_entry_hook) (void) = NULL; ++bool (*wf_fwd_needed_hook) (void) = NULL; ++void (*packet_source_show_entry_hook) (void) = NULL; ++void (*packet_source_delete_entry_hook) (unsigned char idx) = NULL; ++void (*wf_fwd_delete_entry_hook) (unsigned char idx) = NULL; ++ ++void (*wf_fwd_feedback_map_table) (void *adapter, void *peer, void *opp_peer, void *oth_peer) = NULL; ++void (*wf_fwd_probe_adapter)(void *adapter) = NULL; ++void (*wf_fwd_insert_repeater_mapping_hook)(void *adapter, void *lock, void *cli_mapping, void *map_mapping, void *ifAddr_mapping) = NULL; ++void (*wf_fwd_insert_bridge_mapping_hook) (struct sk_buff *skb) = NULL; ++int (*wf_fwd_search_mapping_table_hook) (struct sk_buff *skb, struct APCLI_BRIDGE_LEARNING_MAPPING_STRUCT **tbl_entry) = NULL; ++void (*wf_fwd_delete_entry_inform_hook) (unsigned char *addr) = NULL; ++void (*wf_fwd_check_device_hook) ( struct net_device *net_dev, signed int type, signed int mbss_idx, unsigned char channel, unsigned char link) = NULL; ++void (*wf_fwd_add_entry_inform_hook) (unsigned char *addr) = NULL; ++void (*wf_fwd_debug_level_hook) (unsigned char level) = NULL; ++ ++ ++EXPORT_SYMBOL(wf_fwd_rx_hook); ++EXPORT_SYMBOL(wf_fwd_tx_hook); ++EXPORT_SYMBOL(wf_fwd_entry_insert_hook); ++EXPORT_SYMBOL(wf_fwd_entry_delete_hook); ++EXPORT_SYMBOL(wf_fwd_set_cb_num); ++EXPORT_SYMBOL(wf_fwd_check_active_hook); ++EXPORT_SYMBOL(wf_fwd_get_rep_hook); ++EXPORT_SYMBOL(wf_fwd_pro_active_hook); ++EXPORT_SYMBOL(wf_fwd_pro_halt_hook); ++EXPORT_SYMBOL(wf_fwd_pro_enabled_hook); ++EXPORT_SYMBOL(wf_fwd_pro_disabled_hook); ++EXPORT_SYMBOL(wf_fwd_access_schedule_active_hook); ++EXPORT_SYMBOL(wf_fwd_access_schedule_halt_hook); ++EXPORT_SYMBOL(wf_fwd_hijack_active_hook); ++EXPORT_SYMBOL(wf_fwd_hijack_halt_hook); ++EXPORT_SYMBOL(wf_fwd_show_entry_hook); ++EXPORT_SYMBOL(wf_fwd_needed_hook); ++EXPORT_SYMBOL(wf_fwd_delete_entry_hook); ++EXPORT_SYMBOL(packet_source_show_entry_hook); ++EXPORT_SYMBOL(packet_source_delete_entry_hook); ++EXPORT_SYMBOL(wf_fwd_feedback_map_table); ++EXPORT_SYMBOL(wf_fwd_insert_repeater_mapping_hook); ++EXPORT_SYMBOL(wf_fwd_probe_adapter); ++EXPORT_SYMBOL(wf_fwd_insert_bridge_mapping_hook); ++EXPORT_SYMBOL(wf_fwd_search_mapping_table_hook); ++EXPORT_SYMBOL(wf_fwd_delete_entry_inform_hook); ++EXPORT_SYMBOL(wf_fwd_check_device_hook); ++EXPORT_SYMBOL(wf_fwd_add_entry_inform_hook); ++EXPORT_SYMBOL(wf_fwd_debug_level_hook); ++ |