1
0
This repository has been archived on 2024-07-22. You can view files and clone it, but cannot push or open issues or pull requests.
TP-Link_Archer-XR500v/EN7526G_3.18Kernel_SDK/linux-3.18.21/net/bridge/ecnt_br.h
2024-07-22 01:58:46 -03:00

845 lines
23 KiB
C
Executable File

#ifndef _LINUX_ECNT_BR_H
#define _LINUX_ECNT_BR_H
#include <linux/kernel.h>
#include <linux/kmemcheck.h>
#include <linux/compiler.h>
#include <linux/time.h>
#include <linux/bug.h>
#include <linux/cache.h>
#include <linux/if_bridge.h>
#include <linux/atomic.h>
#include <asm/types.h>
#include <linux/spinlock.h>
#include <linux/net.h>
#include <linux/textsearch.h>
#include <net/checksum.h>
#include <linux/rcupdate.h>
#include <linux/hrtimer.h>
#include <linux/dma-mapping.h>
#include <linux/netdev_features.h>
#include <linux/sched.h>
#include <ecnt_hook/ecnt_hook.h>
#include <linux/igmp.h>
#if IS_ENABLED(CONFIG_IPV6)
#include <net/ipv6.h>
#include <net/mld.h>
#endif
#include <linux/spinlock.h>
#include "br_private.h"
#define WLAN_DEV_OFFSET 5
#ifdef TCSUPPORT_WLAN_AC
#define WLAN_AC_DEV_OFFSET 11
#endif
#define USB_DEV_OFFSET 9
#define WDS_DEV_OFFSET 10
#define DEV_OFFSET 28
/*-----------------------------------------------------------------*/
/*TCSUPPORT_XPON_IGMP && TCSUPPORT_MULTICAST_SPEED start*/
extern int g_last_snoop_state;
extern unsigned int hw_igmp_flood_enable;
extern unsigned int g_snooping_enable;
/*TCSUPPORT_XPON_IGMP && TCSUPPORT_MULTICAST_SPEED end*/
/*TCSUPPORT_IGMP_SNOOPING start*/
extern int snoopingdebug;
/*TCSUPPORT_IGMP_SNOOPING end*/
/*-----------------------------------------------------------------*/
#define DEBUGP_SNOOP(x, args...) if(snoopingdebug) printk(x, ## args)
extern int br_mdb_fillbuf(struct net_bridge *br, void *buf,
unsigned long maxnum, unsigned long skip);
extern int br_multicast_equal_port_group(struct net_bridge_port_group *pg,
struct net_bridge_port *port, struct br_ip *group);
extern char* ip6_sprintf(const struct in6_addr *addr);
extern int igmp_hwnat_get_port(struct net_bridge_port* p);
extern int igmp_hwnat_update_all(struct net_bridge *br);
extern int igmp_hwnat_multicast_undrop(void);
extern void igmp_hwnat_init(struct net_bridge *br);
extern void igmp_hwnat_fini(void);
extern void add_multicast_flood_hwentry(struct sk_buff* skb);
extern int clear_multicast_flood_hwentry(void);
extern int (*xpon_hgu_multicast_data_hook)(struct sk_buff *skb);
/*-----------------------------------------------------------------*/
#if defined(TCSUPPORT_CT_PON)
static void fdb_delete(struct net_bridge *br, struct net_bridge_fdb_entry *f);
static inline unsigned long hold_time(const struct net_bridge *br);
static inline int has_expired(const struct net_bridge *br,
const struct net_bridge_fdb_entry *fdb);
static int host_list_read_proc(char *buf, char **start, off_t off, int count, int *eof, void *data);
#endif
#if defined(TCSUPPORT_XPON_IGMP)
extern int (*xpon_igmp_ioctl_hook)(unsigned long subcmd,unsigned long argv1,unsigned long argv2);
#endif
static inline int ecnt_br_forward_inline_hook(struct sk_buff *skb)
{
#if defined(TCSUPPORT_RA_HWNAT)
skb->bridge_flag = 1;
#endif
return ECNT_CONTINUE;
}
#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
static inline int ecnt_br_multicast_ipv4_rcv_inline_hook(struct net_bridge_port *port,struct sk_buff *skb,struct sk_buff *skb2,
struct iphdr *iph,struct igmphdr *ih,int* err)
{
#if defined(TCSUPPORT_IGMPSNOOPING_ENHANCE)
if(iph->daddr == UPNP_MCAST)/*flooding UPNP packets,239.255.255.250*/
return ECNT_RETURN ;
#endif
#if defined(TCSUPPORT_IGMP_SNOOPING)
if(port){
memcpy(port->macAddr.addr, eth_hdr(skb)->h_source,ETH_ALEN);
memset(&port->src_entry, 0, sizeof(port->src_entry));
port->version = 4;
}
#endif
switch(ih->type)
{
case IGMP_HOST_MEMBERSHIP_REPORT:
case IGMPV2_HOST_MEMBERSHIP_REPORT:
//ignore wan site control packet.
if((skb2->dev != NULL) && (skb2->dev->name[0] == 'n')){
//printk("\r\nignore wan site report packet(v1/v2)!");
*err = 0;
return ECNT_RETURN_DROP;
}
break;
case IGMPV3_HOST_MEMBERSHIP_REPORT:
//ignore wan site control packet.
if((skb2->dev != NULL) && (skb2->dev->name[0] == 'n')){
//printk("\r\nignore wan site report packet(v3)!");
*err = 0;
return ECNT_RETURN_DROP;
}
break;
case IGMP_HOST_MEMBERSHIP_QUERY:
#if defined(TCSUPPORT_CT_PORTSLIMIT)
if ( !port )
skb->vlan_tag_flag |= VLAN_TAG_IGMP_QUERYFLAG;
#endif
break;
case IGMP_HOST_LEAVE_MESSAGE:
//ignore wan site control packet.
if((skb2->dev != NULL) && (skb2->dev->name[0] == 'n')){
//printk("\r\nignore wan site leave packet!");
*err = 0;
return ECNT_RETURN_DROP;
}
break;
}
return ECNT_CONTINUE ;
}
#if IS_ENABLED(CONFIG_IPV6)
static void MultiIP2MAC(struct in6_addr *pIpaddr, unsigned char *mac)
{
if(pIpaddr == NULL || mac == NULL)
return;
*mac = 0x33;
*(mac + 1) = 0x33;
*(mac + 2) = pIpaddr->s6_addr[12];
*(mac + 3) = pIpaddr->s6_addr[13];
*(mac + 4) = pIpaddr->s6_addr[14];
*(mac + 5) = pIpaddr->s6_addr[15];
return;
}
static inline int ecnt_br_multicast_ipv6_rcv_inline_hook(struct net_bridge_port *port,struct sk_buff *skb,struct sk_buff *skb2,
u8 type, int* err)
{
if(port){
struct mld_msg *mld = (struct mld_msg *)icmp6_hdr(skb2);
MultiIP2MAC(&mld->mld_mca, port->groupMacAddr.addr);
memcpy(port->macAddr.addr, eth_hdr(skb)->h_source,ETH_ALEN);
memset(&port->src_entry, 0, sizeof(port->src_entry));
port->version = 6;
}
switch(type)
{
case ICMPV6_MGM_REPORT:
case ICMPV6_MLD2_REPORT:
if((skb2->dev != NULL) && (skb2->dev->name[0] == 'n')){
*err = 0;
return ECNT_RETURN_DROP;
}
break;
case ICMPV6_MGM_QUERY:
#if defined(TCSUPPORT_CT_PORTSLIMIT)
if ( !port )
skb->vlan_tag_flag |= VLAN_TAG_IGMP_QUERYFLAG;
#endif
break;
case ICMPV6_MGM_REDUCTION:
if((skb2->dev != NULL) && (skb2->dev->name[0] == 'n')){
*err = 0;
return ECNT_RETURN_DROP;
}
break;
default:
break;
}
return ECNT_CONTINUE;
}
#endif
#else
static inline int ecnt_br_multicast_ipv4_rcv_inline_hook(struct net_bridge_port *port,struct sk_buff *skb,struct sk_buff *skb2,
struct iphdr *iph,struct igmphdr *ih,int* err)
{
return 0 ;
}
#if IS_ENABLED(CONFIG_IPV6)
static inline int ecnt_br_multicast_ipv6_rcv_inline_hook(struct net_bridge_port *port,struct sk_buff *skb,u8 type)
{
return 0 ;
}
#endif
#endif
static inline int ecnt_br_input_state_forward_inline_hook(struct sk_buff *skb)
{
#if 1 //defined(CONFIG_PORT_BINDING) || defined(TCSUPPORT_REDIRECT_WITH_PORTMASK)
/*_____________________________________________
** remark packet from different lan interfac,
** use the highest 4 bits.
**
** eth0 0x10000000
** eth0.1 0x10000000
** eth0.2 0x20000000
** eth0.3 0x30000000
** eth0.4 0x40000000
** ra0 0x50000000
** ra1 0x60000000
** ra2 0x70000000
** ra3 0x80000000
** usb0 0x90000000
** wds0~3 0xA0000000
** rai0 0xB0000000
** rai1 0xC0000000
** rai2 0xD0000000
** rai3 0xE0000000
**_________________________________________
*/
switch (skb->dev->name[0]) {
case 'e':
#ifdef TCSUPPORT_TC2031
/* device name format must be eth0 */
skb->mark |= 0x10000000;
#else
//single lan port
if(!strcmp(skb->dev->name, "eth0"))
{
skb->mark |= 0x10000000;
}
/* device name format must be eth0.x */
if (skb->dev->name[4] == '.')
skb->mark |= (skb->dev->name[5] - '0') << DEV_OFFSET;
#endif
break;
case 'r':
#ifdef TCSUPPORT_WLAN_AC
if (skb->dev->name[2] == 'i')
/* device name must be raix */
skb->mark |= ((skb->dev->name[3] - '0') + WLAN_AC_DEV_OFFSET) << DEV_OFFSET;
else
#endif
/* device name must be rax */
skb->mark |= ((skb->dev->name[2] - '0') + WLAN_DEV_OFFSET) << DEV_OFFSET;
break;
case 'u':
/* device name must be usbx */
skb->mark |= ((skb->dev->name[3] - '0') + USB_DEV_OFFSET) << DEV_OFFSET;
break;
case 'w':
/* device name must be wdsx */
skb->mark |= (WDS_DEV_OFFSET) << DEV_OFFSET;
break;
default:
break;
}
#if defined(TCSUPPORT_CT)
#ifdef TCSUPPORT_PORTBIND
skb->portbind_mark |= MASK_ORIGIN_DEV;
skb->orig_dev = skb->dev;
#endif
#endif
#endif
return ECNT_CONTINUE;
}
static inline int ecnt_old_dev_ioctl_inline_hook(struct net_bridge *br,struct ifreq *rq , int* ret)
{
unsigned long args[4];
#if defined(TCSUPPORT_XPON_IGMP)
typeof(xpon_igmp_ioctl_hook) xpon_igmp_ioctl;
#endif
if (copy_from_user(args, rq->ifr_data, sizeof(args)))
return ECNT_HOOK_ERROR;
switch(args[0])
{
case BRCTL_GET_BRIDGE_INFO:
{
struct __bridge_info b;
memset(&b, 0, sizeof(struct __bridge_info));
rcu_read_lock();
memcpy(&b.designated_root, &br->designated_root, 8);
memcpy(&b.bridge_id, &br->bridge_id, 8);
b.root_path_cost = br->root_path_cost;
b.max_age = jiffies_to_clock_t(br->max_age);
b.hello_time = jiffies_to_clock_t(br->hello_time);
b.forward_delay = br->forward_delay;
b.bridge_max_age = br->bridge_max_age;
b.bridge_hello_time = br->bridge_hello_time;
b.bridge_forward_delay = jiffies_to_clock_t(br->bridge_forward_delay);
b.topology_change = br->topology_change;
b.topology_change_detected = br->topology_change_detected;
b.root_port = br->root_port;
b.stp_enabled = (br->stp_enabled != BR_NO_STP);
b.ageing_time = jiffies_to_clock_t(br->ageing_time);
b.hello_timer_value = br_timer_value(&br->hello_timer);
b.tcn_timer_value = br_timer_value(&br->tcn_timer);
b.topology_change_timer_value = br_timer_value(&br->topology_change_timer);
b.gc_timer_value = br_timer_value(&br->gc_timer);
#if defined(CONFIG_BRIDGE_IGMP_SNOOPING) && defined(TCSUPPORT_IGMPSNOOPING_ENHANCE)
b.igmpsnoop_ageing_time = br->multicast_membership_interval;
b.igmpsnoop_enabled = !br->multicast_disabled;
b.igmpsnoop_quickleave = br->quick_leave;
b.igmpsnoop_dbg = (__u8)snoopingdebug;
#endif
rcu_read_unlock();
if (copy_to_user((void __user *)args[1], &b, sizeof(b)))
return -EFAULT;
return ECNT_RETURN_DROP;
}
case BRCTL_GET_PORT_INFO:
{
struct __port_info p;
struct net_bridge_port *pt;
rcu_read_lock();
if ((pt = br_get_port(br, args[2])) == NULL) {
rcu_read_unlock();
return -EINVAL;
}
memset(&p, 0, sizeof(struct __port_info));
memcpy(&p.designated_root, &pt->designated_root, 8);
memcpy(&p.designated_bridge, &pt->designated_bridge, 8);
p.port_id = pt->port_id;
p.designated_port = pt->designated_port;
p.path_cost = pt->path_cost;
p.designated_cost = pt->designated_cost;
p.state = pt->state;
p.top_change_ack = pt->topology_change_ack;
p.config_pending = pt->config_pending;
p.message_age_timer_value = br_timer_value(&pt->message_age_timer);
p.forward_delay_timer_value = br_timer_value(&pt->forward_delay_timer);
p.hold_timer_value = br_timer_value(&pt->hold_timer);
#if defined(CONFIG_BRIDGE_IGMP_SNOOPING) && defined(TCSUPPORT_IGMPSNOOPING_ENHANCE)
p.is_router = pt->multicast_router;
#endif
rcu_read_unlock();
if (copy_to_user((void __user *)args[1], &p, sizeof(p)))
return -EFAULT;
return ECNT_RETURN_DROP;
}
#if defined(CONFIG_BRIDGE_IGMP_SNOOPING) && defined(TCSUPPORT_IGMPSNOOPING_ENHANCE)
case BRCTL_SET_IGMPSNOOPING_STATE:
if (!capable(CAP_NET_ADMIN))
return ECNT_HOOK_ERROR;
br_multicast_toggle(br, args[1]);
return ECNT_RETURN_DROP;
case BRCTL_SET_IGMPSNOOPING_AGEING_TIME:
if (!capable(CAP_NET_ADMIN))
return ECNT_HOOK_ERROR;
spin_lock_bh(&br->lock);
br->multicast_membership_interval = clock_t_to_jiffies(args[1]);
spin_unlock_bh(&br->lock);
return ECNT_RETURN_DROP;
case BRCTL_GET_MC_FDB_ENTRIES:
if (!capable(CAP_NET_ADMIN))
return ECNT_HOOK_ERROR;
*ret = get_mc_fdb_entries(br, (void __user *)args[1],
args[2], args[3]);
return ECNT_RETURN;
case BRCTL_SET_IGMPSNOOPING_QUICKLEAVE:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
br->quick_leave = args[1];
return ECNT_RETURN_DROP;
case BRCTL_SET_IGMPSNOOPING_DBG:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
snoopingdebug = (int)args[1] ;
return ECNT_RETURN_DROP;
#endif
#if defined(TCSUPPORT_XPON_IGMP)
case BRCTL_XPON_IGMP_CMD:
xpon_igmp_ioctl = rcu_dereference(xpon_igmp_ioctl_hook);
if (xpon_igmp_ioctl)
return xpon_igmp_ioctl(args[1],args[2],args[3]);
return ECNT_RETURN;
#endif
default:
return ECNT_CONTINUE;
}
return ECNT_CONTINUE;
}
#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
static inline void ecnt_br_multicast_del_pg_inline_hook(struct net_bridge *br,
struct net_bridge_port_group *pg)
{
#ifdef TCSUPPORT_IGMPSNOOPING_ENHANCE
if(pg->version == 4){
DEBUGP_SNOOP("mc_fdb_delete delete dev=%s group=" NIPQUAD_FMT " src ip=" NIPQUAD_FMT "\n",
pg->port->dev->name, NIPQUAD(pg->addr.u.ip4),NIPQUAD(pg->src_entry.src.s_addr));
}
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
else if(pg->version == 6)
{
DEBUGP_SNOOP("mc_fdb_delete deleteV6 dev=%s group=[%s] src ip=[%s]\n",
pg->port->dev->name, ip6_sprintf(&pg->addr.u.ip6),ip6_sprintf(&pg->src_entry.src6));
}
#endif
#endif
#if defined(TCSUPPORT_XPON_IGMP) || defined(TCSUPPORT_MULTICAST_SPEED)
igmp_hwnat_update_all(br);
#endif
return ;
}
static inline void ecnt_br_multicast_new_port_group_inline_hook(struct net_bridge_port *port,struct br_ip *group,struct net_bridge_port_group *p)
{
#ifdef TCSUPPORT_IGMPSNOOPING_ENHANCE
if(port->version == 4){
DEBUGP_SNOOP("br_multicast_add_group new portgroup dev=%s group=" NIPQUAD_FMT " src ip=" NIPQUAD_FMT "\n",
port->dev->name, NIPQUAD(group->u.ip4),NIPQUAD(port->src_entry.src.s_addr));
}
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
else{
DEBUGP_SNOOP("br_multicast_add_group newV6 portgroup dev=%s group=[%s] src ip=[%s]\n",
port->dev->name, ip6_sprintf(&group->u.ip6), ip6_sprintf(&port->src_entry.src6));
}
#endif
memcpy(&p->src_entry, &port->src_entry, sizeof(port->src_entry));
memcpy(p->group_mac, port->groupMacAddr.addr, sizeof(port->groupMacAddr.addr));
memcpy(p->host_mac, port->macAddr.addr, sizeof(port->macAddr.addr));
p->version = port->version;
#endif
}
static inline int ecnt_br_multicast_add_group_inline_hook(struct net_bridge_mdb_entry *mp,struct net_bridge_port *port,
struct br_ip *group,struct net_bridge *br,unsigned long now)
{
struct net_bridge_port_group __rcu **pp;
struct net_bridge_port_group *p;
for (pp = &mp->ports ; (p = mlock_dereference(*pp, br)) != NULL ; pp = &p->next)
{
#ifdef TCSUPPORT_IGMPSNOOPING_ENHANCE
if(br_multicast_equal_port_group(p, port, group)){
if(port->version == 4){
DEBUGP_SNOOP("br_multicast_add_group update portgroup dev=%s group=" NIPQUAD_FMT " src ip=" NIPQUAD_FMT "\n",
port->dev->name, NIPQUAD(group->u.ip4),NIPQUAD(port->src_entry.src.s_addr));
}
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
else{
DEBUGP_SNOOP("br_multicast_add_group updateV6 portgroup dev=%s group=[%s] src ip=[%s]\n",
port->dev->name, ip6_sprintf(&group->u.ip6),ip6_sprintf(&port->src_entry.src6));
}
#endif
memcpy(&p->src_entry, &port->src_entry, sizeof(port->src_entry));
goto found;
}
#else
if (p->port == port)
goto found;
#endif
if ((unsigned long)p->port < (unsigned long)port)
break;
}
p = br_multicast_new_port_group(port, group, *pp, MDB_TEMPORARY);
if (unlikely(!p))
return ECNT_HOOK_ERROR;
rcu_assign_pointer(*pp, p);
br_mdb_notify(br->dev, port, group, RTM_NEWMDB);
#if defined(TCSUPPORT_XPON_IGMP) || defined(TCSUPPORT_MULTICAST_SPEED)
igmp_hwnat_update_all(br);
#ifdef TCSUPPORT_XPON_IGMP
igmp_hwnat_multicast_undrop();/*delete all drop entry*/
#endif
#endif
found:
#if defined(TCSUPPORT_IGMP_SNOOPING)
p->ageing_time = now;
p->leave_count = 3;
#endif
mod_timer(&p->timer, now + br->multicast_membership_interval);
return ECNT_CONTINUE;
}
static inline void ecnt_br_multicast_rcv_inline_hook(struct net_bridge *br)
{
#if defined(TCSUPPORT_XPON_IGMP) && defined(TCSUPPORT_MULTICAST_SPEED)
if(g_last_snoop_state != br->multicast_disabled)
{
if(br->multicast_disabled)
{
igmp_hwnat_clear_flows();
igmp_hwnat_multicast_undrop();
}
else
{
/*snoop disable to enable*/
clear_multicast_flood_hwentry();
}
g_last_snoop_state = br->multicast_disabled;
}
#endif
}
static inline void ecnt_br_multicast_toggle_inline_hook(unsigned long val)
{
#if defined(TCSUPPORT_XPON_IGMP) && defined(TCSUPPORT_MULTICAST_SPEED)
if(val)
{
g_snooping_enable = 1;
}
else
{
g_snooping_enable = 0;
}
igmp_hwnat_clear_flows();
clear_multicast_flood_hwentry();
igmp_hwnat_multicast_undrop();
#endif
}
static inline void ecnt_br_multicast_init_inline_hook(struct net_bridge *br)
{
br_multicast_set_querier(br,1);
#if defined(TCSUPPORT_XPON_IGMP)|| defined(TCSUPPORT_MULTICAST_SPEED)
igmp_hwnat_init(br);
#endif
return ;
}
#else
static inline void ecnt_br_multicast_del_pg_inline_hook(struct net_bridge *br,
struct net_bridge_port_group *pg)
{
return ;
}
static inline void ecnt_br_multicast_new_port_group_inline_hook(struct net_bridge_port *port,struct br_ip *group,struct net_bridge_port_group *p)
{
return ;
}
static inline int ecnt_br_multicast_add_group_inline_hook(struct net_bridge_mdb_entry *mp,struct net_bridge_port *port,
struct br_ip *group,struct net_bridge *br,unsigned long now)
{
return 0;
}
static inline void ecnt_br_multicast_rcv_inline_hook(struct net_bridge *br)
{
return ;
}
static inline void ecnt_br_multicast_toggle_inline_hook(unsigned long val)
{
return ;
}
static inline void ecnt_br_multicast_init_inline_hook(struct net_bridge *br)
{
return ;
}
#endif
/*-------------------------------------------------------------------------*/
/* Don't forward packets to originating port or forwarding diasabled */
static inline int ecnt_should_deliver(const struct net_bridge_port *p,
const struct sk_buff *skb)
{
return (((p->flags & BR_HAIRPIN_MODE) || skb->dev != p->dev) &&
p->state == BR_STATE_FORWARDING);
}
static inline void ecnt_br_flood_inline_hook(struct net_bridge *br, struct sk_buff *skb )
{
struct net_bridge_port *p;
#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
#if defined(TCSUPPORT_XPON_IGMP) && defined(TCSUPPORT_MULTICAST_SPEED)
int igmp_snoop_flag = false;
int hw_flood_flag = false;
int switch_port = 0;
int port = 0;
int mask = 0;
int index = -1;
int proc_hw_flag = 0;
#endif
/*step1 : add to multicast_flood list*/
#ifdef TCSUPPORT_RA_HWNAT
#if defined(TCSUPPORT_XPON_IGMP) && defined(TCSUPPORT_MULTICAST_SPEED)
proc_hw_flag = hw_igmp_flood_enable ;
igmp_snoop_flag = g_snooping_enable ;
/*disable snooping*/
if(!igmp_snoop_flag && proc_hw_flag)
{
/*hgu multicast data flow*/
if(xpon_hgu_multicast_data_hook && xpon_hgu_multicast_data_hook(skb))
{
/*hw accelerating*/
index = igmp_hwnat_flow_index(skb);
if(index > 0)
{
hw_flood_flag = true;
}
//printk("line = %d, function= %s,index = %d.\n",__LINE__,__FUNCTION__, index);
}
}
if(hw_flood_flag)
{
add_multicast_flood_hwentry(skb);
}
else
{
if (ra_sw_nat_hook_free)
ra_sw_nat_hook_free(skb);
}
#else
{
if (ra_sw_nat_hook_free)
ra_sw_nat_hook_free(skb);
}
#endif
#endif
tc3162wdog_kick();
/*step2: check if some port can not be forward, cal the mask*/
#if defined(TCSUPPORT_XPON_IGMP) && defined(TCSUPPORT_MULTICAST_SPEED)
if(hw_flood_flag)
{
list_for_each_entry_rcu(p, &br->port_list, list)
{
if( ecnt_should_deliver(p, skb) )
{
/*calc mask*/
port = igmp_hwnat_get_port(p);
/*lan port*/
if(port >= 0 && port <= 3)
{
#if defined(TCSUPPORT_CPU_MT7520)
if(MT7530LanPortMap2Switch_hook)
{
switch_port = MT7530LanPortMap2Switch_hook(port);
}
port = switch_port;
#endif
mask |= 1 << port;
}
/*wifi port*/
else if(port >= HWNAT_WLAN_IF_BASE)
{
mask |= 1 << port;
}
}
}
}
#endif
#if defined(TCSUPPORT_XPON_IGMP) && defined(TCSUPPORT_MULTICAST_SPEED)
/*step3: update mask*/
if(hw_flood_flag)
{
update_multicast_flood_hwentry(index, mask);
update_multicast_flood_mask(index);
}
#endif
#endif
}
static inline int ecnt_br_fdb_init_inline_hook(void)
{
#if defined(TCSUPPORT_CT_PON)
struct proc_dir_entry *br_host_stb_proc = NULL;
proc_mkdir("br_fdb_host", NULL);
br_host_stb_proc = create_proc_entry("br_fdb_host/stb_list", 0, NULL);
if( NULL == br_host_stb_proc )
{
printk("ERROR!Create proc entry stb_list fail!\n");
return -ENOMEM;
}
br_host_stb_proc->read_proc = host_list_read_proc;
#endif
return ECNT_CONTINUE;
}
#if defined(TCSUPPORT_CT_PON)
static inline int host_list_read_proc(char *buf, char **start, off_t off, int count, int *eof, void *data)
{
int len = 0, i = 0;
char *stb_mac_list, stb_mac[20] = {0};
int hasnew = 0;
int max_stb_cnt = 256;
struct hlist_node *n = NULL;
struct net_bridge_fdb_entry *f = NULL;
unsigned char *addr = NULL;
int stb_count = 0;
static int stb_store_count = 0;
struct net_device *ndev = NULL;
struct net_bridge *br = NULL;
#define MAC_LIST_LEN (8192)
int portNum = 0;
// read lan link status
int link_status_read = 0;
char link_status[32] = {0};
int lanStatus[4] = {0};
mm_segment_t orgfs;
struct file *srcf = NULL;
char *src = "/proc/tc3162/eth_port_status";
stb_mac_list = kmalloc(MAC_LIST_LEN, GFP_ATOMIC);
if (buf == NULL) {
printk("Allocate memory for stb_mac fail.\n");
return -1;
}
memset(stb_mac_list, 0, MAC_LIST_LEN);
ndev = dev_get_by_name(&init_net, "br0");
if ( ndev )
br = netdev_priv(ndev);
// read lan link status
orgfs = get_fs();
set_fs(KERNEL_DS);
srcf = filp_open(src, O_RDONLY, 0);
if ( !IS_ERR(srcf) )
{
link_status_read = 1;
srcf->f_op->read(srcf, link_status, sizeof(link_status) - 1, &srcf->f_pos);
filp_close(srcf,NULL);
}
set_fs(orgfs);
sscanf(link_status, "%d %d %d %d", &lanStatus[0], &lanStatus[1], &lanStatus[2], &lanStatus[3]);
// end
if ( br )
{
spin_lock_bh(&br->hash_lock);
for ( i = 0; i < BR_HASH_SIZE; i ++ )
{
//hlist_for_each_entry_safe(f, h, n, &br->hash[i], hlist)
hlist_for_each_entry_safe(f, n, &br->hash[i], hlist)
{
if ( f->is_local
|| has_expired(br, f) )
continue;
#if defined(TCSUPPORT_CT_PMINFORM) || defined(TCSUPPORT_CT_JOYME)
portNum = 0;
#endif
if ( NULL != strstr(f->dst->dev->name, "eth0.") )
{
portNum = f->dst->dev->name[5] - '0';
#if !defined(TCSUPPORT_CT_JOYME)
if ( portNum >=1 && portNum <= 4
&& 0 == lanStatus[portNum-1] )
{
fdb_delete(br,f);
continue;
}
#endif
}
#if defined(TCSUPPORT_CT_JOYME)
if ( NULL != strstr(f->dst->dev->name, "ra") ) {
portNum = f->dst->dev->name[2] - '0' + 5;
}
#endif
#if defined(TCSUPPORT_CT_PMINFORM)
/* if port mac info not in LAN. */
if ( portNum < 1 || portNum > 4 )
continue;
#endif
stb_count ++;
if ( stb_count <= max_stb_cnt )
{
addr = f->addr.addr;
sprintf(stb_mac, "%d=%02x:%02x:%02x:%02x:%02x:%02x\n", portNum,addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
strcat(stb_mac_list, stb_mac);
}
} // hlist_for_each_entry_rcu(f, h, &br->hash[i], hlist)
} // for ( i = 0; i < BR_HASH_SIZE; i ++ )
spin_unlock_bh(&br->hash_lock);
} // if ( br )
len = sprintf(buf, "%s", stb_mac_list);
*start = buf + off;
if (len < off + count)
*eof = 1;
len -= off;
if (len > count)
len = count ;
if (len <0)
len = 0;
kfree(stb_mac_list);
return len;
}
#endif
#endif