From e6d87036412b952cb083eff2dc716aee97a771f2 Mon Sep 17 00:00:00 2001 From: Roman Yeryomin Date: Fri, 17 May 2013 20:40:24 +0300 Subject: Move to rsdk 3.2.4. Compiles cleanly. Signed-off-by: Roman Yeryomin --- target/linux/realtek/files/drivers/net/rtk_vlan.c | 429 ++++++++++++++++++---- 1 file changed, 366 insertions(+), 63 deletions(-) (limited to 'target/linux/realtek/files/drivers/net/rtk_vlan.c') diff --git a/target/linux/realtek/files/drivers/net/rtk_vlan.c b/target/linux/realtek/files/drivers/net/rtk_vlan.c index 97b78ab88..dd4cacd22 100644 --- a/target/linux/realtek/files/drivers/net/rtk_vlan.c +++ b/target/linux/realtek/files/drivers/net/rtk_vlan.c @@ -1,9 +1,9 @@ /* - * Realtek VLAN handler + * Realtek VLAN handler * * $Id: rtk_vlan.c,v 1.5 2009/06/09 12:58:30 davidhsu Exp $ */ - + #include #include #include @@ -30,9 +30,161 @@ #define DEBUG_TRACE(format, args...) #endif +#if defined(CONFIG_RTK_VLAN_NEW_FEATURE) +#define MAX_IFACE_VLAN_CONFIG 17 +#define WAN_IFACE_INDEX MAX_IFACE_VLAN_CONFIG-1 +#define VIRTUAL_IFACE_INDEX MAX_IFACE_VLAN_CONFIG-2 +static struct vlan_info_item vlan_info_items[MAX_IFACE_VLAN_CONFIG]; +static unsigned char wan_macaddr[6] = {0}; +unsigned char lan_macaddr[6] = {0}; + +unsigned char BRCST_MAC[6] = {0xff,0xff,0xff,0xff,0xff,0xff}; +static unsigned short eth_arp = 0x0806; + +int is_management_packets(struct sk_buff *skb) +{ + /*add code to check whether skb is management pacekts*/ + return 0; +} + + +struct net_device *rtl_get_wan_from_vlan_info(void) +{ + return vlan_info_items[WAN_IFACE_INDEX].dev; +} + +struct net_device* rtl_get_virtual_dev_from_vlan_info(void) +{ + return vlan_info_items[VIRTUAL_IFACE_INDEX].dev; +} +struct net_device *rtl_get_dev_bridged_with_wan(void) +{ + int index; + + for(index=0 ;indexdev && item->info.id == vid ) + return item; + } + + return NULL; +} + +struct vlan_info_item *rtl_get_vlan_info_item_by_dev(struct net_device *dev) +{ + struct vlan_info_item *item = NULL; + int index; + + for(index=0; indexdev && (memcmp(dev->name, item->dev->name,16) == 0) ) { // IFNAMSIZ = 16 + DEBUG_TRACE("found in list id:%d, is LAN:%d, enable:%d\n",item->info.id,item->info.is_lan,item->info.vlan); + return item; + } + } + + return NULL; +} + + +int rtl_add_vlan_info(struct vlan_info *info, struct net_device *dev) +{ + struct vlan_info_item *item = NULL; + int index; + + if( memcmp(dev->name,"eth0",4) == 0 ){ + memcpy(lan_macaddr, dev->dev_addr, 6); + } + + + if( memcmp(dev->name,"eth1",4) == 0 ){ + item = &vlan_info_items[WAN_IFACE_INDEX]; + + memset(item, 0, sizeof(struct vlan_info_item)); + memcpy(&item->info, info, sizeof(struct vlan_info)); + item->dev = dev; + memcpy(wan_macaddr, dev->dev_addr, 6); + + DEBUG_TRACE("WAN port vlan id:%d, is LAN:%d, fowarding:%d\n",item->info.id,item->info.is_lan,item->info.forwarding_rule); + return 0; + } + + if( memcmp(dev->name,"eth7",4) == 0 ){ + item = &vlan_info_items[VIRTUAL_IFACE_INDEX]; + + memset(item, 0, sizeof(struct vlan_info_item)); + #if 0 + for(index=0; indexinfo, info, sizeof(struct vlan_info)); + item->dev = dev; + DEBUG_TRACE("Virtual port vlan id:%d, is LAN:%d, fowarding:%d\n",item->info.id,item->info.is_lan,item->info.forwarding_rule); + return 0; + } + + if((item = rtl_get_vlan_info_item_by_dev(dev)) != NULL){ + memcpy(&item->info, info, sizeof(struct vlan_info)); + return 0; + } + + for(index=0; indexinfo, info, sizeof(*info)); + item->dev = dev; + + DEBUG_TRACE("insert vlan id:%d, is LAN:%d, enable:%d\n",item->info.id,item->info.is_lan,item->info.vlan); + return 0; + } + } + + if( item == NULL ) { + DEBUG_ERR("VLAN info. list is FULL\n"); + return -1; + } +} + +int rtl_delete_vlan_info(struct net_device *dev) +{ + struct vlan_info_item *item = NULL; + + if((item = rtl_get_vlan_info_item_by_dev(dev)) != NULL){ + memset(item, 0, sizeof(struct vlan_info_item)); + return 0; + } else { + DEBUG_ERR("Delete dev from vlan_info_items failed\n"); + return -1; + } +} + +#endif + //--------------------------------------------------------------------------- + #define COPY_TAG(tag, info) { \ tag.f.tpid = htons(ETH_P_8021Q); \ tag.f.pci = (unsigned short) (((((unsigned char)info->pri)&0x7) << 13) | \ @@ -53,11 +205,24 @@ extern int rtk_vlan_support_enable; #endif -int rx_vlan_process(struct net_device *dev, struct vlan_info *info, struct sk_buff *skb) +#if defined(CONFIG_RTK_VLAN_NEW_FEATURE) +int rx_vlan_process(struct net_device *dev, struct vlan_info *info_ori, struct sk_buff *skb, struct sk_buff **new_skb) +#else +int rx_vlan_process(struct net_device *dev, struct vlan_info *info, struct sk_buff *skb) +#endif { struct vlan_tag tag; unsigned short vid; +#if defined(CONFIG_RTK_VLAN_NEW_FEATURE) + struct vlan_info_item *item = NULL; + struct vlan_info *info, info_backup; + memcpy(&info_backup, info_ori, sizeof(struct vlan_info)); //because may need to modify info,so create a info_backup + info= &info_backup; + if(new_skb) + *new_skb = NULL; +#endif + DEBUG_TRACE("==> Process Rx packet\n"); if (!info->global_vlan) { @@ -67,6 +232,12 @@ int rx_vlan_process(struct net_device *dev, struct vlan_info *info, struct sk_b memcpy(&tag, skb->data+ETH_ALEN*2, VLAN_HLEN); +#if defined(CONFIG_RTK_VLAN_NEW_FEATURE) + if (info->is_lan) { + skb->src_info = info_ori; + } +#endif + // When port-vlan is disabled, discard tag packet if (!info->vlan) { if (tag.f.tpid == htons(ETH_P_8021Q)) { @@ -78,6 +249,15 @@ int rx_vlan_process(struct net_device *dev, struct vlan_info *info, struct sk_b return 0; } +#if defined(CONFIG_RTK_VLAN_NEW_FEATURE) + if (!info->is_lan && (info->tag&0x1)) //wan port do not need to select tag + { + info->tag = 1; + } + else + info->tag = 0; +#endif + // Drop all no-tag packet if port-tag is enabled #if 1 if (info->tag && tag.f.tpid != htons(ETH_P_8021Q)) { @@ -86,47 +266,136 @@ int rx_vlan_process(struct net_device *dev, struct vlan_info *info, struct sk_b } #endif - if (tag.f.tpid == htons(ETH_P_8021Q)) { // tag existed in incoming packet - if (info->is_lan) { + if (tag.f.tpid == htons(ETH_P_8021Q)) { // tag existed in incoming packet + if (info->is_lan) { // Drop all tag packets if VID is not matched vid = ntohs(tag.f.pci & 0xfff); + DEBUG_TRACE("rx from lan!\n"); if (vid != (unsigned short)info->id) { DEBUG_ERR(" due to VID not matched!\n"); - return 1; - } + return 1; + } } +#if defined(CONFIG_RTK_VLAN_NEW_FEATURE) + else { //wan interface + vid = ntohs(tag.f.pci & 0xfff); + item = rtl_get_vlan_info_item_by_vid(vid); + + if( item ) { + if( item->info.forwarding_rule == 1 ){ + skb->dev = rtl_get_virtual_dev_from_vlan_info(); //return virtual interface + DEBUG_TRACE("vid is bridge vid\n"); + if(skb->dev == NULL) + return 1; + } else if ( item->info.forwarding_rule == 0 ) { + DEBUG_TRACE(" due to VLAN is disabled\n"); + return 1; + } else { //forwarding_rule is nat + DEBUG_TRACE("Recv from WAN normally\n"); + } + } + } +#endif memcpy(&skb->tag, &tag, sizeof(struct vlan_tag)); STRIP_TAG(skb); #if defined(CONFIG_RTL_QOS_8021P_SUPPORT) skb->srcVlanPriority = ntohs(tag.f.pci>>13)&0x7; #endif - DEBUG_ERR("<==%s(%d) Tag [%x, vid=%d] existed in Rx packet, strip it and pass up\n", __FUNCTION__,__LINE__, - tag.v, (int)ntohs(tag.f.pci&0xfff)); - } - else { - // Store port tag to skb and then pass up - COPY_TAG(skb->tag, info); - DEBUG_TRACE("<== No tag existed, carry port tag [%x, vid=%d] and pass up\n", - skb->tag.v, (int)ntohs(skb->tag.f.pci&0xfff)); + DEBUG_TRACE("<==%s(%d) Tag [vid=%d] existed in Rx packet, strip it and pass up\n", __FUNCTION__,__LINE__, + (int)ntohs(tag.f.pci&0xfff)); + } + else { + if( info->is_lan ) { +#if defined(CONFIG_RTK_VLAN_NEW_FEATURE) + if(is_management_packets(skb)){ + COPY_TAG(skb->tag, (&management_vlan)); + DEBUG_TRACE("<== Management packet from lan, carry port tag [vid=%d] and pass up\n", + (int)ntohs(skb->tag.f.pci&0xfff)); + }else +#endif + { + COPY_TAG(skb->tag, info); + DEBUG_TRACE("<== No tag existed, carry port tag [vid=%d] and pass up\n", + (int)ntohs(skb->tag.f.pci&0xfff)); + } + } else { +#if defined(CONFIG_RTK_VLAN_NEW_FEATURE) + if (!memcmp(wan_macaddr, skb->data, 6)){ /*unicast for nat*/ + if(is_management_packets(skb)){ + COPY_TAG(skb->tag, (&management_vlan)); + DEBUG_TRACE("<== Management packet from wan to nat, carry port tag [vid=%d] and pass up\n", + (int)ntohs(skb->tag.f.pci&0xfff)); + } + }else if (skb->data[0] & 0x01){ /*multicast*/ + skb->src_info = info_ori; + if (new_skb) { + *new_skb = skb_clone(skb, GFP_ATOMIC); + if (*new_skb == NULL) { + DEBUG_ERR("skb_clone() failed!\n"); + } + else { + struct vlan_info *new_info = &vlan_info_items[VIRTUAL_IFACE_INDEX].info; + (*new_skb)->dev = rtl_get_virtual_dev_from_vlan_info(); + if((*new_skb)->dev == NULL) + return 2; + //COPY_TAG((*new_skb)->tag, new_info); + (*new_skb)->src_info = new_info; + (*new_skb)->src_info->index=1; + } + } + }else if(memcmp(BRCST_MAC, skb->data, 6)){ /*unicast for bridge*/ + /*management packest are unicast!!!!*/ + if(is_management_packets(skb)){ + COPY_TAG(skb->tag, (&management_vlan)); + DEBUG_TRACE("<== Management packet from wan to bridge, carry port tag [vid=%d] and pass up\n", + (int)ntohs(skb->tag.f.pci&0xfff)); + } + skb->dev = rtl_get_virtual_dev_from_vlan_info(); + if(skb->dev == NULL) + return 1; + } +#endif + } + } + return 0; } + EXPORT_SYMBOL(rx_vlan_process); -int tx_vlan_process(struct net_device *dev, struct vlan_info *info, struct sk_buff *skb, int wlan_pri) +#if defined(CONFIG_RTK_VLAN_NEW_FEATURE) +int tx_vlan_process(struct net_device *dev, struct vlan_info *info_ori, struct sk_buff *skb, int wlan_pri) +#else +int tx_vlan_process(struct net_device *dev, struct vlan_info *info, struct sk_buff *skb, int wlan_pri) +#endif { struct vlan_tag tag, *adding_tag; +#if defined(CONFIG_RTK_VLAN_NEW_FEATURE) + struct vlan_info *info, info_backup; + + if (skb->src_info != NULL && !info_ori->is_lan) { + memcpy(&info_backup, skb->src_info, sizeof(struct vlan_info)); //use lan port vlan info + info_backup.is_lan = info_ori->is_lan; //info is wan port + } + else{ + memcpy(&info_backup, info_ori, sizeof(struct vlan_info)); + } + info= &info_backup; +#endif + DEBUG_TRACE("==> Process Tx packet\n"); //printk("---------%s(%d), dev(%s),skb->tag.f.tpid(0x%x)\n",__FUNCTION__,__LINE__,dev->name,skb->tag.f.tpid); if (wlan_pri) skb->cb[0] = '\0'; // for WMM priority - + if (!info->global_vlan) { DEBUG_TRACE("<== Return w/o change due to gvlan not enabled\n"); return 0; } + if (!info->vlan) { // When port-vlan is disabled, discard packet if packet come from source port w/ vlan enabled if (skb->tag.f.tpid == htons(ETH_P_8021Q)) { @@ -135,7 +404,7 @@ int tx_vlan_process(struct net_device *dev, struct vlan_info *info, struct sk_b } DEBUG_TRACE("<== Return w/o change because both Tx port and source vlan not enabled\n"); return 0; - } + } // Discard packet if packet come from source port w/o vlan enabled except from protocol stack if (skb->tag.f.tpid != 0) { @@ -143,65 +412,99 @@ int tx_vlan_process(struct net_device *dev, struct vlan_info *info, struct sk_b DEBUG_ERR(" due to port-vlan is enabled but not from vlan enabled port!\n"); return 1; } - + // Discard packet if its vid not matched, except it come from protocol stack or lan - if (info->is_lan && ntohs(skb->tag.f.pci&0xfff) != ((unsigned short)info->id)) { - DEBUG_ERR(" due to VID is not matched!\n"); - return 1; - } + if (info->is_lan && ((ntohs(skb->tag.f.pci&0xfff) != ((unsigned short)info->id)) && (ntohs(skb->tag.f.pci&0xfff) != 0xd1))) { + DEBUG_ERR(" due to VID is not matched!\n"); + return 1; + } } + +#if defined(CONFIG_RTK_VLAN_NEW_FEATURE) + if (!info->is_lan) + { + /* + lan->wan: if the lan port receive this packet is tagged or this packet is original tagged, + it will go out of wan port as tagged + */ + if (info->tag&0x1) + info->tag = 1; + } + else { + /*wan->lan: all packets are untag to lan, no matter lan port is tagged or not*/ + info->tag = 0; + } + if((!memcmp(lan_macaddr,skb->data+6, 6)) && (info->forwarding_rule==1) && (skb->data[37] == 68)) + { + return 1; + } +#endif #if defined(CONFIG_RTK_VLAN_FOR_CABLE_MODEM) if(rtk_vlan_support_enable == 1) #endif - if (!info->tag) - { - DEBUG_TRACE("<== Return w/o tagging\n"); - if (wlan_pri) { - if (!info->is_lan && skb->tag.f.tpid == htons(ETH_P_8021Q)) - skb->cb[0] = (unsigned char)((ntohs(skb->tag.f.pci)>>13)&0x7); - else - skb->cb[0] = (unsigned char)info->pri; - } - return 0; + if (!info->tag) + { + //printk("[%s][%d]-skb->dev[%s],proto(0x%x)\n", __FUNCTION__, __LINE__, skb->dev->name,skb->protocol); + DEBUG_TRACE("<== Return w/o tagging\n"); + if (wlan_pri) { + if (!info->is_lan && skb->tag.f.tpid == htons(ETH_P_8021Q)) + skb->cb[0] = (unsigned char)((ntohs(skb->tag.f.pci)>>13)&0x7); + else + skb->cb[0] = (unsigned char)info->pri; + } + + return 0; + } + + // Add tagging + + // if (!info->is_lan && skb->tag && skb->tag.f.tpid != 0) { // WAN port and not from local, add source tag + if (skb->tag.f.tpid != 0) { // WAN port and not from local, add source tag +#if defined(CONFIG_RTK_VLAN_NEW_FEATURE) + struct vlan_info_item *item = rtl_get_vlan_info_item_by_vid(skb->tag.f.pci & 0xfff); + if( item && item->info.forwarding_rule == 0 ) { //check if packet form VLAN that disable traffic to/from WAN + DEBUG_ERR(" due to VLAN is disabled\n"); + return 1; + } else +#endif + { + adding_tag = &skb->tag; + DEBUG_TRACE("---%s(%d) source port tagging [vid=%d]\n",__FUNCTION__,__LINE__, (int)ntohs(skb->tag.f.pci&0xfff)); + } + } + else { + adding_tag = NULL; + DEBUG_TRACE("---%s(%d) Return w/ port tagging [vid=%d]\n", __FUNCTION__,__LINE__,info->id); } - - // Add tagging - if (!info->is_lan && skb->tag.f.tpid != 0) { // WAN port and not from local, add source tag - adding_tag = &skb->tag; - DEBUG_TRACE("---%s(%d) source port tagging [vid=%d]\n",__FUNCTION__,__LINE__, (int)ntohs(skb->tag.f.pci&0xfff)); - } - else { - adding_tag = NULL; - DEBUG_TRACE("---%s(%d) Return w/ port tagging [vid=%d]\n", __FUNCTION__,__LINE__,info->id); - } #if defined(CONFIG_RTK_VLAN_FOR_CABLE_MODEM) - if(rtk_vlan_support_enable == 2 && adding_tag == NULL) - return 0; + if(rtk_vlan_support_enable == 2 && adding_tag == NULL) + return 0; #endif - memcpy(&tag, skb->data+ETH_ALEN*2, VLAN_HLEN); - if (tag.f.tpid != htons(ETH_P_8021Q)) { // tag not existed, insert tag - if (skb_headroom(skb) < VLAN_HLEN && skb_cow(skb, VLAN_HLEN) !=0 ) { - printk("%s-%d: error! (skb_headroom(skb) == %d < 4). Enlarge it!\n", - __FUNCTION__, __LINE__, skb_headroom(skb)); - while (1) ; + memcpy(&tag, skb->data+ETH_ALEN*2, VLAN_HLEN); + if (tag.f.tpid != htons(ETH_P_8021Q)) { // tag not existed, insert tag + if (skb_headroom(skb) < VLAN_HLEN && skb_cow(skb, VLAN_HLEN) !=0 ) { + printk("%s-%d: error! (skb_headroom(skb) == %d < 4). Enlarge it!\n", + __FUNCTION__, __LINE__, skb_headroom(skb)); + while (1) ; + } + skb_push(skb, VLAN_HLEN); + memmove(skb->data, skb->data+VLAN_HLEN, ETH_ALEN*2); } - skb_push(skb, VLAN_HLEN); - memmove(skb->data, skb->data+VLAN_HLEN, ETH_ALEN*2); - } - if (!adding_tag) { // add self-tag - COPY_TAG(tag, info); - adding_tag = &tag; - } + if (!adding_tag) { // add self-tag + COPY_TAG(tag, info); + adding_tag = &tag; + } - memcpy(skb->data+ETH_ALEN*2, adding_tag, VLAN_HLEN); + memcpy(skb->data+ETH_ALEN*2, adding_tag, VLAN_HLEN); - if (wlan_pri) - skb->cb[0] = (unsigned char)((ntohs(adding_tag->f.pci)>>13)&0x7); - return 0; + if (wlan_pri) + skb->cb[0] = (unsigned char)((ntohs(adding_tag->f.pci)>>13)&0x7); + return 0; } + EXPORT_SYMBOL(tx_vlan_process); - + -- cgit v1.2.3