845 lines
23 KiB
C
Executable File
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
|
|
|