/*************************************************************************** * File Name : smux.c * Description : smux mean server mux. ***************************************************************************/ #include <asm/uaccess.h> #include <linux/capability.h> #include <linux/module.h> #include <linux/mm.h> #include <linux/in.h> #include <linux/init.h> #include <linux/rtnetlink.h> #include <linux/notifier.h> #include <linux/if_smux.h> #ifdef CONFIG_IP_MROUTE #include <linux/inetdevice.h> #endif //#include <linux/if_vlan.h> #include <linux/etherdevice.h> #include <net/rtl/rtl_nic.h> #include <net/rtl/rtl867x_hwnat_api.h> #ifdef CONFIG_PORT_MIRROR extern void nic_tx_mirror (struct sk_buff *skb); static inline void smux_mirror_pkt(struct sk_buff *skb, const struct smux_dev_info *dev_info, const int flag); #define IN 0x1 #define OUT 0x2 #endif #ifdef DEBUG #define DPRINTK(format, args...) printk(KERN_DEBUG "SMUX: " format, ##args) #else #define DPRINTK(format, args...) #endif //extern unsigned int pvid_per_port[RTL8651_PORT_NUMBER+3]; //#define UNIQUE_MAC_PER_DEV #undef UNIQUE_MAC_PER_DEV /*************************************************************************** Global variables ***************************************************************************/ #define SET_MODULE_OWNER(dev) do { } while (0) static DEFINE_RWLOCK(smux_lock); static LIST_HEAD(smux_grp_devs); static int smux_device_event(struct notifier_block *, unsigned long, void *); static struct notifier_block smux_notifier_block = { .notifier_call = smux_device_event, }; #if defined(CONFIG_COMPAT_NET_DEV_OPS) #else static const struct net_device_ops smux_netdev_ops = { .ndo_open = smux_dev_open, .ndo_stop = smux_dev_stop, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = smux_dev_set_mac_address, .ndo_do_ioctl = smux_dev_ioctl, .ndo_start_xmit = smux_dev_hard_start_xmit, .ndo_change_mtu = smux_dev_change_mtu, }; #endif #ifdef UNIQUE_MAC_PER_DEV unsigned char wan_dev_def_vid[9]={[0 ... 8]=0};//index 0 is reserved /* * return value: -1 : FAIL */ int allocSmuxDevVid(void) { int i; for (i=1; i<9; i++) { if (!wan_dev_def_vid[i]) break; } if (i<9) return i; return -1; } int freeSmuxDevVid(int vid) { if ((vid >= 9) || (vid <= 0)) return -1; wan_dev_def_vid[vid] = 0; return 0; } #endif /*************************************************************************** Function Definisions ***************************************************************************/ static int smux_ioctl_handler(void __user *); #if 0 int getUnusedVlanID(void); #endif static inline struct smux_group *list_entry_smuxgrp(const struct list_head *le) { return list_entry(le, struct smux_group, smux_grp_devs); } /*************************************************************************** * Function Name: __find_smux_group * Description : returns the smux group of interfaces/devices from list * Returns : struct smux_group. ***************************************************************************/ static struct smux_group *__find_smux_group(const char *ifname) { struct list_head *lh; struct smux_group *smux_grp; struct smux_group *ret_smux = NULL; read_lock(&smux_lock); list_for_each(lh, &smux_grp_devs) { smux_grp = (struct smux_group *)list_entry_smuxgrp(lh); if (!strncmp(smux_grp->real_dev->name, ifname, IFNAMSIZ)) { ret_smux = smux_grp; break; } } read_unlock(&smux_lock); return ret_smux; } /* __find_smux_group */ static inline struct smux_dev_info *list_entry_smuxdev(const struct list_head *le) { return list_entry(le, struct smux_dev_info, list); } /*************************************************************************** * Function Name: __find_smux_in_smux_group * Description : returns the smux device from smux group of devices * Returns : struct net_device ***************************************************************************/ static struct net_device *__find_smux_in_smux_group( struct smux_group *smux_grp, const char *ifname) { struct list_head *lh; struct smux_dev_info * sdev = NULL; struct net_device * ret_dev = NULL; read_lock(&smux_lock); list_for_each(lh, &smux_grp->virtual_devs) { sdev = list_entry_smuxdev(lh); if(!strncmp(sdev->vdev->name, ifname, IFNAMSIZ)) { ret_dev = sdev->vdev; break; } } read_unlock(&smux_lock); return ret_dev; } /* __find_smux_in_smux_group */ /*************************************************************************** * Function Name: smux_pkt_recv * Description : packet recv routine for all smux devices from real dev. * Returns : 0 on Success ***************************************************************************/ int smux_pkt_recv(struct sk_buff *skb, struct net_device *dev) { struct smux_group *grp; unsigned char *dstAddr; struct sk_buff *skb2; struct smux_dev_info *dev_info; struct smux_dev_info *dev_info_first; struct list_head *lh; struct net_device *vdev; //struct vlan_hdr *vhdr=NULL; unsigned short protocol=skb->protocol; int isTxDone = 0; if(!dev) { dev_kfree_skb(skb); return 0; } grp = __find_smux_group(dev->name); if(!grp) { dev_kfree_skb(skb); return 0; } dstAddr = eth_hdr(skb)->h_dest; //if (protocol == __constant_htons(ETH_P_8021Q)) { // vhdr = (struct vlan_hdr *)(skb->data); // protocol = vhdr->h_vlan_encapsulated_proto; //} //printk("%s %d enter=================>\n", __func__, __LINE__); read_lock(&smux_lock); /* Multicast Traffic will go on all intf.*/ if (dstAddr[0] & 1) { dev_info_first = NULL; /* multicast or broadcast frames */ list_for_each(lh, &grp->virtual_devs) { dev_info = list_entry_smuxdev(lh); vdev = dev_info->vdev; if (((skb->vlan_tci&VLAN_VID_MASK) && !(vdev->priv_flags&IFF_VSMUX)) || ((vdev->priv_flags&IFF_VSMUX) && (!(skb->vlan_tci&VLAN_VID_MASK) || (((skb->vlan_tci&VLAN_VID_MASK)-1)!=dev_info->vid)))) continue; if (((dev_info->proto == SMUX_PROTO_PPPOE) && (protocol != htons(ETH_P_PPP_DISC)) && (protocol != htons(ETH_P_PPP_SES))) || ((dev_info->proto == SMUX_PROTO_IPOE) && ((protocol == htons(ETH_P_PPP_DISC)) || (protocol == htons(ETH_P_PPP_SES))))) { DPRINTK("TRACE %d: packet dropped on RX dev %s\n", __LINE__, vdev->name); continue; } if(!dev_info_first) { dev_info_first = dev_info; continue; } #ifdef CONFIG_PORT_MIRROR if(IN_NEED_MIR(dev_info->port_mirror)) { smux_mirror_pkt(skb, dev_info, IN); } #endif skb2 = skb_clone(skb, GFP_ATOMIC); dev_info->stats.rx_packets++; dev_info->stats.rx_bytes += skb2->len; skb2->dev = vdev; skb2->from_dev = vdev; //skb2->pkt_type = PACKET_HOST; netif_rx(skb2); } if (!dev_info_first) { dev_kfree_skb(skb); } else { dev_info_first->stats.rx_packets++; dev_info_first->stats.rx_bytes += skb->len; skb->dev = dev_info_first->vdev; skb->from_dev = dev_info_first->vdev; //skb->pkt_type = PACKET_HOST; #ifdef CONFIG_PORT_MIRROR if(IN_NEED_MIR(dev_info->port_mirror)) { smux_mirror_pkt(skb, dev_info, IN); } #endif netif_rx(skb); } isTxDone = 1; } else /* route Traffic.*/ { #ifndef UNIQUE_MAC_PER_DEV dev_info_first = NULL; #endif /* Routing Interface Traffic : check dst mac */ list_for_each(lh, &grp->virtual_devs) { dev_info = list_entry_smuxdev(lh); if (dev_info->proto == SMUX_PROTO_BRIDGE) continue; vdev = dev_info->vdev; if (((skb->vlan_tci&VLAN_VID_MASK) && !(vdev->priv_flags&IFF_VSMUX)) || ((vdev->priv_flags&IFF_VSMUX) && (!(skb->vlan_tci&VLAN_VID_MASK) || (((skb->vlan_tci&VLAN_VID_MASK)-1)!=dev_info->vid)))) continue; if (((dev_info->proto == SMUX_PROTO_PPPOE) && (protocol != htons(ETH_P_PPP_DISC)) && (protocol != htons(ETH_P_PPP_SES))) || ((dev_info->proto == SMUX_PROTO_IPOE) && ((protocol == htons(ETH_P_PPP_DISC)) || (protocol == htons(ETH_P_PPP_SES))))) { DPRINTK("TRACE %d: packet dropped on RX dev %s\n", __LINE__, vdev->name); continue; } #ifndef UNIQUE_MAC_PER_DEV if (!memcmp(dstAddr, vdev->dev_addr, ETH_ALEN)) { if(!dev_info_first) { dev_info_first = dev_info; continue; } skb2 = skb_copy(skb, GFP_ATOMIC); skb2->dev = vdev; skb2->from_dev = vdev; dev_info->stats.rx_packets++; dev_info->stats.rx_bytes += skb2->len; skb2->pkt_type = PACKET_HOST; //printk("(route) receive from %s\n", vdev->name); #ifdef CONFIG_PORT_MIRROR if(IN_NEED_MIR(dev_info->port_mirror)) { smux_mirror_pkt(skb, dev_info, IN); } #endif netif_rx(skb2); isTxDone = 1; } #else if (!memcmp(dstAddr, vdev->dev_addr, ETH_ALEN)) { skb->dev = vdev; skb->from_dev = vdev; dev_info->stats.rx_packets++; dev_info->stats.rx_bytes += skb->len; skb->pkt_type = PACKET_HOST; //printk("(route) receive from %s\n", vdev->name); #ifdef CONFIG_PORT_MIRROR if(IN_NEED_MIR(dev_info->port_mirror)) { smux_mirror_pkt(skb, dev_info, IN); } #endif netif_rx(skb); isTxDone = 1; break; } #endif } #ifndef UNIQUE_MAC_PER_DEV if (dev_info_first) { dev_info_first->stats.rx_packets++; dev_info_first->stats.rx_bytes += skb->len; skb->dev = dev_info_first->vdev; skb->from_dev = dev_info_first->vdev; skb->pkt_type = PACKET_HOST; //printk("(route) receive from %s\n", dev_info_first->vdev->name); #ifdef CONFIG_PORT_MIRROR if(IN_NEED_MIR(dev_info->port_mirror)) { smux_mirror_pkt(skb, dev_info, IN); } #endif netif_rx(skb); isTxDone = 1; } #endif } if(isTxDone != 1) { /* Bridging Interface Traffic */ list_for_each(lh, &grp->virtual_devs) { dev_info = list_entry_smuxdev(lh); if (dev_info->proto != SMUX_PROTO_BRIDGE) continue; vdev = dev_info->vdev; if (((skb->vlan_tci&VLAN_VID_MASK) && !(vdev->priv_flags&IFF_VSMUX)) || ((vdev->priv_flags&IFF_VSMUX) && (!(skb->vlan_tci&VLAN_VID_MASK) || (((skb->vlan_tci&VLAN_VID_MASK)-1)!=dev_info->vid)))) continue; if (vdev->promiscuity) { skb->dev = vdev; skb->from_dev = vdev; dev_info->stats.rx_packets++; dev_info->stats.rx_bytes += skb->len; skb->pkt_type = PACKET_OTHERHOST; //printk("(bridge) receive from %s\n", vdev->name); #ifdef CONFIG_PORT_MIRROR if(IN_NEED_MIR(dev_info->port_mirror)) { smux_mirror_pkt(skb, dev_info, IN); } #endif netif_rx(skb); isTxDone = 1; break; } } } read_unlock(&smux_lock); //printk("=================>%s %d exit.\n", __func__, __LINE__); if(!isTxDone) { DPRINTK("dropping packet that has wrong dest. on RX dev %s\n", dev->name); dev_kfree_skb(skb); } return 0; } /* smux_pkt_recv */ /*Start:add by caoxiafei cKF24361 20100426 for fastpath*/ /*************************************************************************** * Function Name: getSmuxDev * Description : fetch smux devices according to real dev. * Returns : 0 on fail ***************************************************************************/ struct net_device * getSmuxDev(struct sk_buff *skb) { struct smux_group *grp; unsigned char *dstAddr; struct smux_dev_info *dev_info; struct list_head *lh; struct net_device *vdev; grp = __find_smux_group(skb->dev->name); if (!grp) return NULL; dstAddr = eth_hdr(skb)->h_dest; if (dstAddr[0]&0x01) return NULL; read_lock(&smux_lock); list_for_each(lh, &grp->virtual_devs) { dev_info = list_entry_smuxdev(lh); vdev = dev_info->vdev; if (!compare_ether_addr(dstAddr, vdev->dev_addr)) { skb->dev = vdev; read_unlock(&smux_lock); return vdev; } } read_unlock(&smux_lock); return NULL; } /*End:add by caoxiafei cKF24361 20100426 for fastpath*/ /*************************************************************************** * Function Name: smux_dev_hard_start_xmit * Description : xmit routine for all smux devices on real dev. * Returns : 0 on Success ***************************************************************************/ __IRAM_FWD int smux_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct net_device_stats *stats = smux_dev_get_stats(dev); struct smux_dev_info *dev_info; stats->tx_packets++; stats->tx_bytes += skb->len; dev_info = SMUX_DEV_INFO(dev); skb->dev = dev_info->smux_grp->real_dev; if (-1 == dev_info->vid) { #if 1 if (dev_info->proto == SMUX_PROTO_BRIDGE) skb->vlan_tci = RTL_BridgeWANVLANID; else skb->vlan_tci = RTL_WANVLANID; #else skb->vlan_tci = RTL_LANVLANID; #endif } else { if(dev_info->m_1p==0) skb->vlan_tci = (dev_info->vid&VLAN_VID_MASK); else { skb->vlan_tci = (dev_info->vid&VLAN_VID_MASK)|((dev_info->m_1p-1)<<13); } } skb->vlan_member = dev_info->member; #ifdef CONFIG_PORT_MIRROR if((OUT_NEED_MIR(dev_info->port_mirror))) { smux_mirror_pkt(skb, dev_info, OUT); } #endif //printk("%s,%d::dev_info->member: %x\n",__func__,__LINE__,skb->vlan_member); skb->dev->hard_start_xmit(skb, skb->dev); //dev_queue_xmit(skb); return 0; } /* smux_dev_hard_start_xmit */ /*************************************************************************** * Function Name: smux_dev_open * Description : * Returns : 0 on Success ***************************************************************************/ int smux_dev_open(struct net_device *vdev) { if (!(SMUX_DEV_INFO(vdev)->smux_grp->real_dev->flags & IFF_UP)) return -ENETDOWN; return 0; } /* smux_dev_open */ /*************************************************************************** * Function Name: smux_dev_stop * Description : * Returns : 0 on Success ***************************************************************************/ int smux_dev_stop(struct net_device *dev) { return 0; } /* smux_dev_stop */ /*************************************************************************** * Function Name: smux_dev_set_mac_address * Description : sets the mac for devs * Returns : 0 on Success ***************************************************************************/ int smux_dev_set_mac_address(struct net_device *dev, void *addr_struct_p) { struct sockaddr *addr = (struct sockaddr *)(addr_struct_p); int i, flgs; #if 0 #ifdef CONFIG_RTL_8676HWNAT rtl865x_netif_t netif; #endif #endif #ifdef UNIQUE_MAC_PER_DEV struct smux_group *grp = NULL; struct smux_dev_info *vdev_info = NULL; struct list_head *lh; #endif if (netif_running(dev)) return -EBUSY; memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); memset(dev->broadcast, 0xff, ETH_ALEN); #ifdef CONFIG_RTL_8676HWNAT //memcpy(netif.macAddr.octet,addr->sa_data,ETHER_ADDR_LEN); //memcpy(netif.name,dev->name,MAX_IFNAMESIZE); //rtl865x_setNetifMac(&netif); rtl8676_set_Multiwan_NetifMacAddr(dev->name, addr->sa_data); #endif return 0; #ifdef UNIQUE_MAC_PER_DEV grp = __find_smux_group(ALIASNAME_NAS0); //grp = __find_smux_group("nas0"); if (!grp) return -EADDRNOTAVAIL; if (list_empty(&grp->virtual_devs)) { return -EADDRNOTAVAIL; } list_for_each(lh, &grp->virtual_devs) { vdev_info = list_entry_smuxdev(lh); if (vdev_info->vdev == dev) continue; if (!memcmp(vdev_info->vdev->dev_addr, addr->sa_data, ETH_ALEN)) { return -EADDRNOTAVAIL; } } #endif memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); printk("%s: Setting MAC address to ", dev->name); for (i = 0; i < 6; i++) printk(" %2.2x", dev->dev_addr[i]); printk(".\n"); if (memcmp(SMUX_DEV_INFO(dev)->smux_grp->real_dev->dev_addr, dev->dev_addr, dev->addr_len) != 0) { if (!(SMUX_DEV_INFO(dev)->smux_grp->real_dev->flags & IFF_PROMISC)) { flgs = SMUX_DEV_INFO(dev)->smux_grp->real_dev->flags; /* Increment our in-use promiscuity counter */ dev_set_promiscuity(SMUX_DEV_INFO(dev)->smux_grp->real_dev, 1); /* Make PROMISC visible to the user. */ flgs |= IFF_PROMISC; printk("SMUX (%s): Setting underlying device (%s) to promiscious mode.\n", dev->name, SMUX_DEV_INFO(dev)->smux_grp->real_dev->name); dev_change_flags(SMUX_DEV_INFO(dev)->smux_grp->real_dev, flgs); } } else { printk("SMUX (%s): Underlying device (%s) has same MAC, not checking promiscious mode.\n", dev->name, SMUX_DEV_INFO(dev)->smux_grp->real_dev->name); } SMUX_DEV_INFO(dev)->smux_grp->real_dev->set_mac_address(dev, addr_struct_p); return 0; } /* smux_dev_set_mac_address */ /*************************************************************************** * Function Name: smux_dev_ioctl * Description : handles device related ioctls * Returns : 0 on Success ***************************************************************************/ int smux_dev_ioctl(struct net_device *vdev, struct ifreq *ifr, int cmd) { struct net_device *real_dev = SMUX_DEV_INFO(vdev)->smux_grp->real_dev; struct ifreq ifrr; int err = -EOPNOTSUPP; extern int set_port_mapping(struct net_device *dev, struct ifreq *rq, int cmd); strncpy(ifrr.ifr_name, real_dev->name, IFNAMSIZ); ifrr.ifr_ifru = ifr->ifr_ifru; printk("%s %d cmd 0x%x (dev:%s)\n", __func__, __LINE__, cmd,vdev->name); switch(cmd) { case SIOCGMIIPHY: case SIOCGMIIREG: case SIOCSMIIREG: if (real_dev->do_ioctl && netif_device_present(real_dev)) err = real_dev->do_ioctl(real_dev, &ifrr, cmd); break; case SIOCETHTOOL: err = dev_ethtool(&init_net, &ifrr); if (!err) ifr->ifr_ifru = ifrr.ifr_ifru; break; #ifdef CONFIG_PORT_MIRROR case SIOCPORTMIRROR: { struct portmir *pmr; struct smux_dev_info *dev_info = SMUX_DEV_INFO(vdev); struct net_device *dev = NULL; pmr = (struct portmir *)ifr->ifr_data; //AUG_DBG("the pmr->mir_dev_name is %s\n", pmr->mir_dev_name); dev = dev_get_by_name(&init_net, pmr->mir_dev_name); if(!dev) { printk("error lan device!\n"); break; } if((dev->priv_flags & IFF_DOMAIN_ELAN) == 0) { printk("error lan device!\n"); break; } dev_info->port_mirror = pmr->port_mirror; dev_info->mirror_dev = dev; err = 0; break; } #endif case SIOCSITFGROUP: { struct ifvlan *ifvl; struct smux_dev_info *dev_info = SMUX_DEV_INFO(vdev); ifvl = (struct ifvlan *)ifr->ifr_data; if (ifvl->enable) dev_info->member = ifvl->member; else dev_info->member = 0xFFFFFFFF; printk("%s %d set portmapping (dev:%s member:0x%X) \n", __func__, __LINE__,vdev->name,dev_info->member); err = set_port_mapping(vdev, ifr, cmd); #ifdef CONFIG_RTL_8676HWNAT rtl8676_update_portmapping_Multiwan_dev(vdev->name,dev_info->member); #endif } //rtl865x_updateNetifForPortmapping(); return err; } return err; } /* smux_dev_ioctl */ /*************************************************************************** * Function Name: smux_dev_change_mtu * Description : changes mtu for dev * Returns : 0 on Success ***************************************************************************/ int smux_dev_change_mtu(struct net_device *vdev, int new_mtu) { //MTU should be larger than real device. if (SMUX_DEV_INFO(vdev)->smux_grp->real_dev->mtu < new_mtu) return -ERANGE; //vdev->mtu = new_mtu; SMUX_DEV_INFO(vdev)->smux_grp->real_dev->change_mtu(vdev, new_mtu); return 0; } /*************************************************************************** * Function Name: smux_setup * Description : inits device api * Returns : None ***************************************************************************/ static void smux_setup(struct net_device *new_dev) { SET_MODULE_OWNER(new_dev); new_dev->get_stats = smux_dev_get_stats; /* Make this thing known as a SMUX device */ new_dev->priv_flags |= IFF_OSMUX; new_dev->tx_queue_len = 0; #ifdef CONFIG_COMPAT_NET_DEV_OPS /* set up method calls */ new_dev->change_mtu = smux_dev_change_mtu; new_dev->open = smux_dev_open; new_dev->stop = smux_dev_stop; new_dev->set_mac_address = smux_dev_set_mac_address; /*new_dev->set_multicast_list = smux_dev_set_multicast_list; TODO: */ new_dev->destructor = free_netdev; new_dev->do_ioctl = smux_dev_ioctl; #endif } /* smux_setup */ /*************************************************************************** * Function Name: smux_transfer_operstate * Description : updates the operstate of overlay device * Returns : None. ***************************************************************************/ static void smux_transfer_operstate(const struct net_device *rdev, struct net_device *vdev) { if (rdev->operstate == IF_OPER_DORMANT) netif_dormant_on(vdev); else netif_dormant_off(vdev); if (netif_carrier_ok(rdev)) { if (!netif_carrier_ok(vdev)) netif_carrier_on(vdev); } else { if (netif_carrier_ok(vdev)) netif_carrier_off(vdev); } } /* smux_transfer_operstate */ /*************************************************************************** * Function Name: smux_register_device * Description : regists new overlay device on real device & registers for packet handlers depending on the protocol types * Returns : 0 on Success ***************************************************************************/ static struct net_device *smux_register_device(const char *rifname, const char *nifname, int smux_proto, int vid, int napt) { struct net_device *new_dev = NULL; struct net_device *real_dev = NULL; struct smux_group *grp = NULL; struct smux_dev_info *vdev_info = NULL; //int mac_reused = 0; //unsigned char LSB=0; //struct list_head *lh; //printk("%s %d enter\n", __func__, __LINE__); real_dev = dev_get_by_name(&init_net, rifname); if (!real_dev) { goto real_dev_invalid; } if (!(real_dev->flags & IFF_UP)) { goto real_dev_invalid; } new_dev = alloc_netdev(sizeof(struct smux_dev_info), nifname, smux_setup); if (new_dev == NULL) { printk("netdev alloc failure\n"); goto new_dev_invalid; } //dev->netdev_ops = &rtl819x_netdev_ops; ether_setup(new_dev); if (vid != -1) new_dev->priv_flags |= IFF_VSMUX; new_dev->flags &= ~IFF_UP; new_dev->flags &= ~IFF_MULTICAST; new_dev->priv_flags |= IFF_DOMAIN_WAN; real_dev->priv_flags |= IFF_RSMUX; new_dev->state = (real_dev->state & ((1<<__LINK_STATE_NOCARRIER) | (1<<__LINK_STATE_DORMANT))) | (1<<__LINK_STATE_PRESENT); new_dev->mtu = real_dev->mtu; new_dev->type = real_dev->type; new_dev->hard_header_len = real_dev->hard_header_len; #ifdef CONFIG_COMPAT_NET_DEV_OPS new_dev->hard_start_xmit = smux_dev_hard_start_xmit; new_dev->set_mac_address = smux_dev_set_mac_address; #else new_dev->netdev_ops = &smux_netdev_ops; #endif /* find smux group name. if not found create all new smux group */ grp = __find_smux_group(rifname); if (!grp) { grp = kzalloc(sizeof(struct smux_group), GFP_KERNEL); if(grp) { INIT_LIST_HEAD(&grp->virtual_devs); INIT_LIST_HEAD(&grp->smux_grp_devs); grp->real_dev = real_dev; write_lock_irq(&smux_lock); list_add_tail(&grp->smux_grp_devs, &smux_grp_devs); write_unlock_irq(&smux_lock); } else { free_netdev(new_dev); new_dev = NULL; } } if(grp && new_dev) { #if 0 /* Assign default mac to bridge so that we can add it to linux bridge */ if(smux_proto == SMUX_PROTO_BRIDGE) { memcpy( new_dev->dev_addr, "\xFE\xFF\xFF\xFF\xFF\xFF", ETH_ALEN ); } else { #ifdef UNIQUE_MAC_PER_DEV if (list_empty(&grp->virtual_devs)) { memcpy(new_dev->dev_addr, real_dev->dev_addr, ETH_ALEN); } else { list_for_each(lh, &grp->virtual_devs) { vdev_info = list_entry_smuxdev(lh); if (!memcmp(real_dev->dev_addr, vdev_info->vdev->dev_addr, ETH_ALEN)) { mac_reused = 1; } if (LSB < vdev_info->vdev->dev_addr[5]) LSB = vdev_info->vdev->dev_addr[5]; } memcpy(new_dev->dev_addr, real_dev->dev_addr, ETH_ALEN); if (mac_reused) { //generate new mac address, real_addr mac addr increased by 1. new_dev->dev_addr[5] = LSB+1; } } #else memcpy(new_dev->dev_addr, real_dev->dev_addr, ETH_ALEN); #endif } #else char landev_ifname[16]=""; struct net_device *landev; sprintf(landev_ifname, "%s%d",ALIASNAME_ELAN_PREFIX,ORIGINATE_NUM); // const char landev_ifname[16]="eth0.2"; landev = dev_get_by_name(&init_net, landev_ifname); if (landev) { memcpy(new_dev->dev_addr, landev->dev_addr, ETH_ALEN); dev_put(landev); } else printk("%s %d eth0.2 not created.\n", __func__, __LINE__); #endif } if(grp && new_dev) { struct net_device *ret_dev; /*find new smux in smux group if it does not exit create one*/ if(NULL == (ret_dev=__find_smux_in_smux_group(grp, nifname))) { vdev_info = SMUX_DEV_INFO(new_dev); memset(vdev_info, 0, sizeof(struct smux_dev_info)); //m_1p : 0~8, 0 is meaning disable if(vid>=0) vdev_info->m_1p=vid>>13; else vdev_info->m_1p=0; vdev_info->smux_grp = grp; vdev_info->vdev = new_dev; vdev_info->proto = smux_proto; #ifdef UNIQUE_MAC_PER_DEV if ((vid == -1) && (smux_proto != SMUX_PROTO_BRIDGE)) { if ((vid = allocSmuxDevVid()) == -1) printk("fatal error, too many wan interface created.\n"); } #endif if(vid!=-1) vdev_info->vid = (vid&VLAN_VID_MASK); else vdev_info->vid = vid; vdev_info->napt = napt; vdev_info->member = 0xFFFFFFFF; //init membership to include all interface. #ifdef CONFIG_PORT_MIRROR vdev_info->port_mirror = 0; vdev_info->mirror_dev = NULL; #endif INIT_LIST_HEAD(&vdev_info->list); write_lock_irq(&smux_lock); list_add_tail(&vdev_info->list, &grp->virtual_devs); write_unlock_irq(&smux_lock); if(smux_proto == SMUX_PROTO_BRIDGE) { new_dev->promiscuity = 1; } else if(smux_proto == SMUX_PROTO_IPOE) { new_dev->flags |= IFF_MULTICAST; } if (register_netdev(new_dev)) { printk("register_netdev failed\n"); list_del(&vdev_info->list); free_netdev(new_dev); new_dev = NULL; } else { smux_transfer_operstate(real_dev, new_dev); } #ifdef CONFIG_RTL_8676HWNAT if(new_dev){ rtl8676_register_Multiwan_dev(vdev_info->vdev->name, smux_proto, vid, napt); } #endif } else { printk("device %s already exist.\n", nifname); free_netdev(new_dev); new_dev = ret_dev; } } return new_dev; real_dev_invalid: new_dev_invalid: return NULL; } /* smux_register_device */ /*************************************************************************** * Function Name: smux_unregister_device * Description : unregisters the smux devices along with releasing mem. * Returns : 0 on Success ***************************************************************************/ static int smux_unregister_device(const char* vifname) { struct net_device *vdev = NULL; struct net_device *real_dev = NULL; int ret; struct smux_dev_info *dev_info; ret = -EINVAL; vdev = dev_get_by_name(&init_net, vifname); if(vdev) { printk("%s remove smux dev %s\n", __func__, vifname); /* remove related acl rule */ #if 0 #ifdef CONFIG_RTL8676_Dynamic_ACL rtl865x_acl_control_delete_all_by_netif(vdev->name); #endif rtl865x_delNetif(vdev->name); #endif dev_info = SMUX_DEV_INFO(vdev); #ifdef CONFIG_RTL_8676HWNAT rtl8676_unregister_Multiwan_dev(vdev->name); #endif #ifdef UNIQUE_MAC_PER_DEV freeSmuxDevVid(dev_info->vid); #endif real_dev = dev_info->smux_grp->real_dev; write_lock_irq(&smux_lock); list_del(&dev_info->list); write_unlock_irq(&smux_lock); if (list_empty(&dev_info->smux_grp->virtual_devs)) { write_lock_irq(&smux_lock); list_del(&dev_info->smux_grp->smux_grp_devs); write_unlock_irq(&smux_lock); kfree(dev_info->smux_grp); } dev_put(vdev); unregister_netdev(vdev); synchronize_net(); dev_put(real_dev); ret = 0; } return ret; } /* smux_unregister_device */ /*************************************************************************** * Function Name: smux_device_event * Description : handles real device events to update overlay devs. status * Returns : 0 on Success ***************************************************************************/ static int smux_device_event(struct notifier_block *unused, unsigned long event, void *ptr) { struct net_device *rdev = ptr; struct smux_group *grp = __find_smux_group(rdev->name); int flgs; struct list_head *lh; struct list_head *lhp; struct smux_dev_info *dev_info; if (!grp) goto out; switch (event) { case NETDEV_CHANGE: /* Propagate real device state to overlay devices */ read_lock(&smux_lock); list_for_each(lh, &grp->virtual_devs) { dev_info = list_entry_smuxdev(lh); if(dev_info) { smux_transfer_operstate(rdev, dev_info->vdev); } } read_unlock(&smux_lock); break; case NETDEV_DOWN: /* Put all Overlay devices for this dev in the down state too.*/ read_lock(&smux_lock); list_for_each(lh, &grp->virtual_devs) { dev_info = list_entry_smuxdev(lh); if(dev_info) { flgs = dev_info->vdev->flags; if (!(flgs & IFF_UP)) continue; dev_change_flags(dev_info->vdev, flgs & ~IFF_UP); } } read_unlock(&smux_lock); break; case NETDEV_UP: /* Put all Overlay devices for this dev in the up state too. */ read_lock(&smux_lock); list_for_each(lh, &grp->virtual_devs) { dev_info = list_entry_smuxdev(lh); if(dev_info) { flgs = dev_info->vdev->flags; if (flgs & IFF_UP) continue; dev_change_flags(dev_info->vdev, flgs & IFF_UP); } } read_unlock(&smux_lock); break; case NETDEV_UNREGISTER: /* Delete all Overlay devices for this dev. */ write_lock_irq(&smux_lock); list_for_each_safe(lh, lhp, &grp->virtual_devs) { dev_info = list_entry_smuxdev(lh); if(dev_info) { /* delete by l67530 for cpu0 when reboot system. HG551c.2010/12/07 */ //list_del(&dev_info->list); smux_unregister_device(dev_info->vdev->name); } } write_unlock_irq(&smux_lock); break; } out: return NOTIFY_DONE; } /* smux_device_event */ /*************************************************************************** * Function Name: smux_ioctl_handler * Description : ioctl handler for user apps * Returns : 0 on Success ***************************************************************************/ static int smux_ioctl_handler(void __user *arg) { int err = 0; struct smux_ioctl_args args; if (copy_from_user(&args, arg, sizeof(struct smux_ioctl_args))) return -EFAULT; args.rsmux_ifname[IFNAMSIZ-1] = 0; args.osmux_ifname[IFNAMSIZ-1] = 0; switch (args.cmd) { case ADD_SMUX_CMD: if (!capable(CAP_NET_ADMIN)) return -EPERM; if(smux_register_device(args.rsmux_ifname, args.osmux_ifname, args.proto, args.vid, args.napt)) { err = 0; } else { err = -EINVAL; } break; case REM_SMUX_CMD: if (!capable(CAP_NET_ADMIN)) return -EPERM; err = smux_unregister_device(args.u.ifname); break; default: printk("%s: Unknown SMUX CMD: %x \n", __FUNCTION__, args.cmd); return -EINVAL; } return err; } /* smux_ioctl_handler */ /*************************************************************************** * Function Name: smux_drv_init * Description : Initialization of smux driver * Returns : struct net_device ***************************************************************************/ static int __init smux_drv_init(void) { register_netdevice_notifier(&smux_notifier_block); smux_ioctl_set(smux_ioctl_handler); return 0; } /* smux_drv_init */ /*************************************************************************** * Function Name: smux_cleanup_devices * Description : cleans up all the smux devices and releases memory on exit * Returns : None ***************************************************************************/ static void __exit smux_cleanup_devices(void) { struct net_device *dev; struct list_head *lh; struct list_head *lhp; struct smux_dev_info *dev_info; struct smux_group *grp; /* clean up all the smux devices */ rtnl_lock(); for_each_netdev(&init_net, dev) { if (dev->priv_flags & IFF_OSMUX) { dev_info = SMUX_DEV_INFO(dev); write_lock_irq(&smux_lock); list_del(&dev_info->list); write_unlock_irq(&smux_lock); unregister_netdevice(dev); } } rtnl_unlock(); /* cleanup all smux groups */ write_lock_irq(&smux_lock); list_for_each_safe(lh, lhp, &smux_grp_devs) { grp = list_entry_smuxgrp(lh); if(grp) { list_del(&grp->virtual_devs); } } write_unlock_irq(&smux_lock); } /* smux_cleanup_devices */ /*************************************************************************** * Function Name: smux_drv_exit * Description : smux module clean routine * Returns : None ***************************************************************************/ static void __exit smux_drv_exit(void) { smux_ioctl_set(NULL); /* Un-register us from receiving netdevice events */ unregister_netdevice_notifier(&smux_notifier_block); smux_cleanup_devices(); synchronize_net(); } /* smux_drv_exit */ int getVidOfSmuxDev(char *name) { struct smux_dev_info *dev_info; struct net_device *vdev; vdev = dev_get_by_name(&init_net, name); if (!vdev) return -1; dev_put(vdev); dev_info = SMUX_DEV_INFO(vdev); if (dev_info->vid != -1) return dev_info->vid; else { #if 1 if (dev_info->proto == SMUX_PROTO_BRIDGE) return RTL_BridgeWANVLANID; else return RTL_WANVLANID; #else return RTL_LANVLANID; #endif } } unsigned int getMemberOfSmuxDevByVid(unsigned int vid) { struct smux_dev_info *dev_info; struct net_device *vdev; unsigned char name[MAX_IFNAMESIZE]; rtl865x_getMasterNetifByVid(vid, name); vdev = dev_get_by_name(&init_net, name); if (!vdev) return -1; dev_put(vdev); dev_info = SMUX_DEV_INFO(vdev); return dev_info->member; } /*attention: curridx>=11 is reserved for ppp interface*/ #if 0 int getVlanconfigIdx(struct rtl865x_vlanConfig *vconfig, int *curridx, int vid) #endif #if 0 int getVlanconfigIdx(struct rtl865x_vlanConfig *vconfig, int vid) { unsigned int i; #if 0 if (vconfig[1].vid && (vid == vconfig[1].vid))//get { if (*curridx == 0) *curridx = 1; return 1; } for (i=5; (i<=*curridx) && (i<=10); i++) { if (vconfig[i].vid && (vconfig[i].vid == vid))//get return i; } *curridx = (*curridx==1)?5:(*curridx+1); return (*curridx); #else for(i=0; vconfig[i].ifname[0] != '\0' ; i++) { //if( vconfig[i].vid && vconfig[i].isWan==1 && vconfig[i].is_slave==0) if( vconfig[i].vid && vconfig[i].is_slave==0) { if(vconfig[i].vid == vid) return i; } } for(i=0; vconfig[i].ifname[0] != '\0' ; i++) { //if( !vconfig[i].vid && vconfig[i].isWan==1 && vconfig[i].is_slave==0) if( !vconfig[i].vid && vconfig[i].is_slave==0) return i; } return -1; #endif } #endif /* vconfig: vlanconfig */ /* * BRIDGE: vlan enable vid=CUSTOM_VAL * vlan disable vid=RTL_LANVLANID * ROUTE: vlan enable vid=CUSTOM_VAL * vlan disable vid=RTL_LANVLANID */ #if 0 void rtl_adjust_wanport_vlanconfig(struct rtl865x_vlanConfig *vconfig,int *curr_idx) { struct smux_group *grp; struct list_head *lh; struct smux_dev_info * sdev = NULL; //int vid=1; /* vlanconfig index 1,5-10 is for wan interface. */ #if 0 int idx=0, curridx=0; #else int idx=0; #endif #ifdef CONFIG_RTL_ALIASNAME grp = __find_smux_group(ALIASNAME_NAS0); #else grp = __find_smux_group("nas0"); #endif if (!grp) return; /*init vconfig firstly */ #if 0 vconfig[1].vid = 0; vconfig[1].untagSet = RTL_WANPORT_MASK; vconfig[1].memPort = RTL_WANPORT_MASK; for (idx=5; idx<11; idx++) { vconfig[idx].vid = 0; vconfig[idx].untagSet = RTL_WANPORT_MASK; vconfig[idx].memPort = RTL_WANPORT_MASK; } #else //strcpy(vconfig[*curr_idx].ifname,RTL_DRV_WAN0_NETIF_NAME); vconfig[*curr_idx].isWan = 1; vconfig[*curr_idx].if_type = IF_ETHER; vconfig[*curr_idx].vid = 0; vconfig[*curr_idx].fid = RTL_WAN_FID; vconfig[*curr_idx].memPort = RTL_WANPORT_MASK; vconfig[*curr_idx].untagSet = RTL_WANPORT_MASK; vconfig[*curr_idx].is_slave = 0; (*curr_idx)++; //strcpy(vconfig[*curr_idx].ifname,RTL_DRV_WAN1_NETIF_NAME); vconfig[*curr_idx].isWan = 1; vconfig[*curr_idx].if_type = IF_ETHER; vconfig[*curr_idx].vid = 0; vconfig[*curr_idx].fid = RTL_WAN_FID; vconfig[*curr_idx].memPort = RTL_WANPORT_MASK; vconfig[*curr_idx].untagSet = RTL_WANPORT_MASK; vconfig[*curr_idx].is_slave = 0; (*curr_idx)++; //strcpy(vconfig[*curr_idx].ifname,RTL_DRV_WAN2_NETIF_NAME); vconfig[*curr_idx].isWan = 1; vconfig[*curr_idx].if_type = IF_ETHER; vconfig[*curr_idx].vid = 0; vconfig[*curr_idx].fid = RTL_WAN_FID; vconfig[*curr_idx].memPort = RTL_WANPORT_MASK; vconfig[*curr_idx].untagSet = RTL_WANPORT_MASK; vconfig[*curr_idx].is_slave = 0; (*curr_idx)++; //strcpy(vconfig[*curr_idx].ifname,RTL_DRV_WAN3_NETIF_NAME); vconfig[*curr_idx].isWan = 1; vconfig[*curr_idx].if_type = IF_ETHER; vconfig[*curr_idx].vid = 0; vconfig[*curr_idx].fid = RTL_WAN_FID; vconfig[*curr_idx].memPort = RTL_WANPORT_MASK; vconfig[*curr_idx].untagSet = RTL_WANPORT_MASK; vconfig[*curr_idx].is_slave = 0; (*curr_idx)++; //strcpy(vconfig[*curr_idx].ifname,RTL_DRV_WAN4_NETIF_NAME); vconfig[*curr_idx].isWan = 1; vconfig[*curr_idx].if_type = IF_ETHER; vconfig[*curr_idx].vid = 0; vconfig[*curr_idx].fid = RTL_WAN_FID; vconfig[*curr_idx].memPort = RTL_WANPORT_MASK; vconfig[*curr_idx].untagSet = RTL_WANPORT_MASK; vconfig[*curr_idx].is_slave = 0; (*curr_idx)++; //strcpy(vconfig[*curr_idx].ifname,RTL_DRV_WAN5_NETIF_NAME); vconfig[*curr_idx].isWan = 1; vconfig[*curr_idx].if_type = IF_ETHER; vconfig[*curr_idx].vid = 0; vconfig[*curr_idx].fid = RTL_WAN_FID; vconfig[*curr_idx].memPort = RTL_WANPORT_MASK; vconfig[*curr_idx].untagSet = RTL_WANPORT_MASK; vconfig[*curr_idx].is_slave = 0; (*curr_idx)++; //strcpy(vconfig[*curr_idx].ifname,RTL_DRV_WAN6_NETIF_NAME); vconfig[*curr_idx].isWan = 1; vconfig[*curr_idx].if_type = IF_ETHER; vconfig[*curr_idx].vid = 0; vconfig[*curr_idx].fid = RTL_WAN_FID; vconfig[*curr_idx].memPort = RTL_WANPORT_MASK; vconfig[*curr_idx].untagSet = RTL_WANPORT_MASK; vconfig[*curr_idx].is_slave = 0; (*curr_idx)++; //strcpy(vconfig[*curr_idx].ifname,RTL_DRV_PPP0_NETIF_NAME); vconfig[*curr_idx].isWan = 1; vconfig[*curr_idx].if_type = IF_PPPOE; vconfig[*curr_idx].vid = RTL_WANVLANID; vconfig[*curr_idx].fid = RTL_WAN_FID; vconfig[*curr_idx].memPort = RTL_WANPORT_MASK; vconfig[*curr_idx].untagSet = RTL_WANPORT_MASK; vconfig[*curr_idx].is_slave = 1; (*curr_idx)++; //strcpy(vconfig[*curr_idx].ifname,RTL_DRV_PPP1_NETIF_NAME); vconfig[*curr_idx].isWan = 1; vconfig[*curr_idx].if_type = IF_PPPOE; vconfig[*curr_idx].vid = RTL_WANVLANID; vconfig[*curr_idx].fid = RTL_WAN_FID; vconfig[*curr_idx].memPort = RTL_WANPORT_MASK; vconfig[*curr_idx].untagSet = RTL_WANPORT_MASK; vconfig[*curr_idx].is_slave = 1; (*curr_idx)++; //strcpy(vconfig[*curr_idx].ifname,RTL_DRV_PPP2_NETIF_NAME); vconfig[*curr_idx].isWan = 1; vconfig[*curr_idx].if_type = IF_PPPOE; vconfig[*curr_idx].vid = RTL_WANVLANID; vconfig[*curr_idx].fid = RTL_WAN_FID; vconfig[*curr_idx].memPort = RTL_WANPORT_MASK; vconfig[*curr_idx].untagSet = RTL_WANPORT_MASK; vconfig[*curr_idx].is_slave = 1; (*curr_idx)++; //strcpy(vconfig[*curr_idx].ifname,RTL_DRV_PPP3_NETIF_NAME); vconfig[*curr_idx].isWan = 1; vconfig[*curr_idx].if_type = IF_PPPOE; vconfig[*curr_idx].vid = RTL_WANVLANID; vconfig[*curr_idx].fid = RTL_WAN_FID; vconfig[*curr_idx].memPort = RTL_WANPORT_MASK; vconfig[*curr_idx].untagSet = RTL_WANPORT_MASK; vconfig[*curr_idx].is_slave = 1; (*curr_idx)++; //strcpy(vconfig[*curr_idx].ifname,RTL_DRV_PPP4_NETIF_NAME); vconfig[*curr_idx].isWan = 1; vconfig[*curr_idx].if_type = IF_PPPOE; vconfig[*curr_idx].vid = RTL_WANVLANID; vconfig[*curr_idx].fid = RTL_WAN_FID; vconfig[*curr_idx].memPort = RTL_WANPORT_MASK; vconfig[*curr_idx].untagSet = RTL_WANPORT_MASK; vconfig[*curr_idx].is_slave = 1; (*curr_idx)++; //strcpy(vconfig[*curr_idx].ifname,RTL_DRV_PPP5_NETIF_NAME); vconfig[*curr_idx].isWan = 1; vconfig[*curr_idx].if_type = IF_PPPOE; vconfig[*curr_idx].vid = RTL_WANVLANID; vconfig[*curr_idx].fid = RTL_WAN_FID; vconfig[*curr_idx].memPort = RTL_WANPORT_MASK; vconfig[*curr_idx].untagSet = RTL_WANPORT_MASK; vconfig[*curr_idx].is_slave = 1; (*curr_idx)++; //strcpy(vconfig[*curr_idx].ifname,RTL_DRV_PPP6_NETIF_NAME); vconfig[*curr_idx].isWan = 1; vconfig[*curr_idx].if_type = IF_PPPOE; vconfig[*curr_idx].vid = RTL_WANVLANID; vconfig[*curr_idx].fid = RTL_WAN_FID; vconfig[*curr_idx].memPort = RTL_WANPORT_MASK; vconfig[*curr_idx].untagSet = RTL_WANPORT_MASK; vconfig[*curr_idx].is_slave = 1; (*curr_idx)++; #endif //for (i=0; i<RTL8651_PORT_NUMBER+3; i++) // pvid_per_port[i]=RTL_LANVLANID; read_lock(&smux_lock); list_for_each(lh, &grp->virtual_devs) { sdev = list_entry_smuxdev(lh); if (sdev->vid != -1) { idx = getVlanconfigIdx(vconfig, sdev->vid); if (idx <0) break; vconfig[idx].vid = sdev->vid; #ifdef UNIQUE_MAC_PER_DEV if (sdev->vid > 8) #endif //vconfig[idx].untagSet = 0; } else { if (sdev->proto == SMUX_PROTO_BRIDGE) idx = getVlanconfigIdx(vconfig, RTL_BridgeWANVLANID); else idx = getVlanconfigIdx(vconfig, RTL_WANVLANID); if (idx <0) break; if (sdev->proto == SMUX_PROTO_BRIDGE) vconfig[idx].vid = RTL_BridgeWANVLANID; else vconfig[idx].vid = RTL_WANVLANID; } //skip interface name set if this vconfig[idx] had been set to a route intf. if((vconfig[idx].memPort!=RTL_WANPORT_MASK) || (vconfig[idx].untagSet!=0) || (sdev->proto != SMUX_PROTO_BRIDGE)){ strcpy(vconfig[idx].ifname, sdev->vdev->name); memcpy(vconfig[idx].mac.octet, sdev->vdev->dev_addr, ETH_ALEN); } if (sdev->proto == SMUX_PROTO_BRIDGE) { //vconfig[idx].fid = RTL_WAN_FID; //set membership if (sdev->member == 0xFFFFFFFF) { vconfig[idx].memPort |= (RTL_LANPORT_MASK | RTL_WANPORT_MASK); vconfig[idx].untagSet |= (RTL_LANPORT_MASK | RTL_WANPORT_MASK); } else { vconfig[idx].memPort |= ((sdev->member&RTL_LANPORT_MASK)|0x100); vconfig[idx].untagSet |= ((sdev->member&RTL_LANPORT_MASK)|0x100); //for (i=1; i<RTL8651_PORT_NUMBER; i++) { // if (vconfig[idx].memPort & (1<<i)) // pvid_per_port[i] = vconfig[idx].vid; //} } } else{ //set napt vconfig[idx].isWan = sdev->napt; } if ((sdev->vid != -1) #ifdef UNIQUE_MAC_PER_DEV && (sdev->vid > 8) #endif ) { vconfig[idx].untagSet &= (~RTL_WANPORT_MASK); } } read_unlock(&smux_lock); } #endif int smuxUpstreamPortmappingCheck(struct sk_buff *skb) { struct net_device *from, *to; struct smux_dev_info *dev_info,*dev_info2; unsigned int member, port; from = skb->from_dev; to = skb->dev; dev_info = SMUX_DEV_INFO(to); dev_info2 = SMUX_DEV_INFO(from); member = dev_info->member; if (from->priv_flags & IFF_DOMAIN_ELAN) { //sscanf(from->name, "eth0.%d", &port); TOKEN_NUM(from->name,&port); port -= 1; } else if (from->priv_flags & IFF_DOMAIN_WLAN) { TOKEN_NUM(from->name,&port); // sscanf(from->name, "wlan0-vap%d", &port); } else { //printk("%s not from lan dev.\n", __func__); return 0; } if (member & (1<<port)) { return 1; } else { //printk("%s skb block in %s\n", __func__, to->name); return 0; } } int smuxDownstreamPortmappingCheck(struct sk_buff *skb) { struct net_device *from, *to; struct smux_dev_info *dev_info,*dev_info2; unsigned int member, port; from = skb->from_dev; to = skb->dev; dev_info = SMUX_DEV_INFO(from); dev_info2 = SMUX_DEV_INFO(to); //member=skb->vlan_member; member = dev_info->member; if (to->priv_flags & IFF_DOMAIN_ELAN) { //sscanf(to->name, "eth0.%d", &port); TOKEN_NUM(to->name,&port); port -= 1; } else if (to->priv_flags & IFF_DOMAIN_WLAN) { TOKEN_NUM(to->name,&port); // sscanf(to->name, "wlan0-vap%d", &port); } else { // printk("%s not from lan dev.\n", __func__); return 0; } if (member & (1<<port)) { //printk("%s %d from %s to %s member0x%x member & (1<<port)=true \n", __func__, __LINE__, from->name, to->name, member); return 1; } //printk("%s %d from %s to %s member0x%x\n", __func__, __LINE__, from->name, to->name, member); return 0; } #if 0 int smuxDevMacUpdate(unsigned char *pmac) { struct smux_group *grp; struct list_head *lh; struct smux_dev_info * sdev = NULL; //int i; grp = __find_smux_group("nas0"); if (!grp) return; read_lock(&smux_lock); list_for_each(lh, &grp->virtual_devs) { sdev = list_entry_smuxdev(lh); if (sdev->proto != SMUX_PROTO_BRIDGE) { smux_dev_set_mac_address(sdev->vdev, pmac); } } read_unlock(&smux_lock); } #endif #ifdef CONFIG_PORT_MIRROR static inline void smux_mirror_pkt(struct sk_buff *skb, const struct smux_dev_info *dev_info, const int flag) { struct sk_buff *skb2; //AUG_DBG("the dev_info->port_mirror is %d\n", dev_info->port_mirror); if ((skb2 = skb_clone(skb, GFP_ATOMIC)) != NULL) { skb2->dev = dev_info->mirror_dev; if(IN == flag) skb_push(skb2, ETH_HLEN); //AUG_DBG("the dev_info->mirror_dev is %s\n", dev_info->mirror_dev->name); nic_tx_mirror(skb2); } } #endif module_init(smux_drv_init); module_exit(smux_drv_exit); EXPORT_SYMBOL(smux_pkt_recv);