/*
 *	Determine the packet's protocol ID. The rule here is that we
 *	assume 802.3 if the type field is short enough to be a length.
 *	This is normal practice and works for any 'now in use' protocol.
 *
 *  Also, at this point we assume that we ARE dealing exclusively with
 *  VLAN packets, or packets that should be made into VLAN packets based
 *  on a default VLAN ID.
 *
 *  NOTE:  Should be similar to ethernet/eth.c.
 *
 *  SANITY NOTE:  This method is called when a packet is moving up the stack
 *                towards userland.  To get here, it would have already passed
 *                through the ethernet/eth.c eth_type_trans() method.
 *  SANITY NOTE 2: We are referencing to the VLAN_HDR frields, which MAY be
 *                 stored UNALIGNED in the memory.  RISC systems don't like
 *                 such cases very much...
 *  SANITY NOTE 2a: According to Dave Miller & Alexey, it will always be
 *  		    aligned, so there doesn't need to be any of the unaligned
 *  		    stuff.  It has been commented out now...  --Ben
 *
 */
int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev,
		  struct packet_type *ptype, struct net_device *orig_dev)
{
	struct vlan_hdr *vhdr;
	struct vlan_rx_stats *rx_stats;
	u16 vlan_id;
	u16 vlan_tci;

	skb = skb_share_check(skb, GFP_ATOMIC);
	if (skb == NULL)
		goto err_free;

	if (unlikely(!pskb_may_pull(skb, VLAN_HLEN)))
		goto err_free;

	vhdr = (struct vlan_hdr *)skb->data;
	vlan_tci = ntohs(vhdr->h_vlan_TCI);
	vlan_id = vlan_tci & VLAN_VID_MASK;

	rcu_read_lock();
	skb->dev = __find_vlan_dev(dev, vlan_id);
	if (!skb->dev) {
		pr_debug("%s: ERROR: No net_device for VID: %u on dev: %s\n",
			 __func__, vlan_id, dev->name);
		goto err_unlock;
	}

	rx_stats = per_cpu_ptr(vlan_dev_info(skb->dev)->vlan_rx_stats,
			       smp_processor_id());
	rx_stats->rx_packets++;
	rx_stats->rx_bytes += skb->len;

	skb_pull_rcsum(skb, VLAN_HLEN);

	skb->priority = vlan_get_ingress_priority(skb->dev, vlan_tci);

	pr_debug("%s: priority: %u for TCI: %hu\n",
		 __func__, skb->priority, vlan_tci);

	switch (skb->pkt_type) {
	case PACKET_BROADCAST: /* Yeah, stats collect these together.. */
		/* stats->broadcast ++; // no such counter :-( */
		break;

	case PACKET_MULTICAST:
		rx_stats->multicast++;
		break;

	case PACKET_OTHERHOST:
		/* Our lower layer thinks this is not local, let's make sure.
		 * This allows the VLAN to have a different MAC than the
		 * underlying device, and still route correctly.
		 */
		if (!compare_ether_addr(eth_hdr(skb)->h_dest,
					skb->dev->dev_addr))
			skb->pkt_type = PACKET_HOST;
		break;
	default:
		break;
	}

	vlan_set_encap_proto(skb, vhdr);

	skb = vlan_check_reorder_header(skb);
	if (!skb) {
		rx_stats->rx_errors++;
		goto err_unlock;
	}

	netif_rx(skb);
	rcu_read_unlock();
	return NET_RX_SUCCESS;

err_unlock:
	rcu_read_unlock();
err_free:
	kfree_skb(skb);
	return NET_RX_DROP;
}
Ejemplo n.º 2
0
/*
 *	Determine the packet's protocol ID. The rule here is that we 
 *	assume 802.3 if the type field is short enough to be a length.
 *	This is normal practice and works for any 'now in use' protocol.
 *
 *  Also, at this point we assume that we ARE dealing exclusively with
 *  VLAN packets, or packets that should be made into VLAN packets based
 *  on a default VLAN ID.
 *
 *  NOTE:  Should be similar to ethernet/eth.c.
 *
 *  SANITY NOTE:  This method is called when a packet is moving up the stack
 *                towards userland.  To get here, it would have already passed
 *                through the ethernet/eth.c eth_type_trans() method.
 *  SANITY NOTE 2: We are referencing to the VLAN_HDR frields, which MAY be
 *                 stored UNALIGNED in the memory.  RISC systems don't like
 *                 such cases very much...
 *  SANITY NOTE 2a:  According to Dave Miller & Alexey, it will always be aligned,
 *                 so there doesn't need to be any of the unaligned stuff.  It has
 *                 been commented out now...  --Ben
 *
 */
int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev,
                  struct packet_type* ptype, struct net_device *orig_dev)
{
	unsigned char *rawp = NULL;
	struct vlan_hdr *vhdr = (struct vlan_hdr *)(skb->data);
	unsigned short vid;
	struct net_device_stats *stats;
	unsigned short vlan_TCI;
	__be16 proto;

	/* vlan_TCI = ntohs(get_unaligned(&vhdr->h_vlan_TCI)); */
	vlan_TCI = ntohs(vhdr->h_vlan_TCI);

	vid = (vlan_TCI & VLAN_VID_MASK);

#ifdef VLAN_DEBUG
	printk(VLAN_DBG "%s: skb: %p vlan_id: %hx\n",
		__FUNCTION__, skb, vid);
#endif

	/* Ok, we will find the correct VLAN device, strip the header,
	 * and then go on as usual.
	 */

	/* We have 12 bits of vlan ID.
	 *
	 * We must not drop allow preempt until we hold a
	 * reference to the device (netif_rx does that) or we
	 * fail.
	 */

	rcu_read_lock();
	skb->dev = __find_vlan_dev(dev, vid);
	if (!skb->dev) {
		rcu_read_unlock();

#ifdef VLAN_DEBUG
		printk(VLAN_DBG "%s: ERROR: No net_device for VID: %i on dev: %s [%i]\n",
			__FUNCTION__, (unsigned int)(vid), dev->name, dev->ifindex);
#endif
		kfree_skb(skb);
		return -1;
	}

	skb->dev->last_rx = jiffies;

	/* Bump the rx counters for the VLAN device. */
	stats = vlan_dev_get_stats(skb->dev);
	stats->rx_packets++;
	stats->rx_bytes += skb->len;

	skb_pull(skb, VLAN_HLEN); /* take off the VLAN header (4 bytes currently) */

	/* Need to correct hardware checksum */
	skb_postpull_rcsum(skb, vhdr, VLAN_HLEN);

	/* Ok, lets check to make sure the device (dev) we
	 * came in on is what this VLAN is attached to.
	 */

	if (dev != VLAN_DEV_INFO(skb->dev)->real_dev) {
		rcu_read_unlock();

#ifdef VLAN_DEBUG
		printk(VLAN_DBG "%s: dropping skb: %p because came in on wrong device, dev: %s  real_dev: %s, skb_dev: %s\n",
			__FUNCTION__, skb, dev->name, 
			VLAN_DEV_INFO(skb->dev)->real_dev->name, 
			skb->dev->name);
#endif
		kfree_skb(skb);
		stats->rx_errors++;
		return -1;
	}

	/*
	 * Deal with ingress priority mapping.
	 */
	skb->priority = vlan_get_ingress_priority(skb->dev, ntohs(vhdr->h_vlan_TCI));

#ifdef VLAN_DEBUG
	printk(VLAN_DBG "%s: priority: %lu  for TCI: %hu (hbo)\n",
		__FUNCTION__, (unsigned long)(skb->priority), 
		ntohs(vhdr->h_vlan_TCI));
#endif

	/* The ethernet driver already did the pkt_type calculations
	 * for us...
	 */
	switch (skb->pkt_type) {
	case PACKET_BROADCAST: /* Yeah, stats collect these together.. */
		// stats->broadcast ++; // no such counter :-(
		break;

	case PACKET_MULTICAST:
		stats->multicast++;
		break;

	case PACKET_OTHERHOST: 
		/* Our lower layer thinks this is not local, let's make sure.
		 * This allows the VLAN to have a different MAC than the underlying
		 * device, and still route correctly.
		 */
		if (memcmp(eth_hdr(skb)->h_dest, skb->dev->dev_addr, ETH_ALEN) == 0) {
			/* It is for our (changed) MAC-address! */
			skb->pkt_type = PACKET_HOST;
		}
		break;
	default:
		break;
	};

	/*  Was a VLAN packet, grab the encapsulated protocol, which the layer
	 * three protocols care about.
	 */
	/* proto = get_unaligned(&vhdr->h_vlan_encapsulated_proto); */
	proto = vhdr->h_vlan_encapsulated_proto;

	skb->protocol = proto;
	if (ntohs(proto) >= 1536) {
		/* place it back on the queue to be handled by
		 * true layer 3 protocols.
		 */

		/* See if we are configured to re-write the VLAN header
		 * to make it look like ethernet...
		 */
		skb = vlan_check_reorder_header(skb);

		/* Can be null if skb-clone fails when re-ordering */
		if (skb) {
			netif_rx(skb);
		} else {
			/* TODO:  Add a more specific counter here. */
			stats->rx_errors++;
		}
		rcu_read_unlock();
		return 0;
	}

	rawp = skb->data;

	/*
	 * This is a magic hack to spot IPX packets. Older Novell breaks
	 * the protocol design and runs IPX over 802.3 without an 802.2 LLC
	 * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
	 * won't work for fault tolerant netware but does for the rest.
	 */
	if (*(unsigned short *)rawp == 0xFFFF) {
		skb->protocol = __constant_htons(ETH_P_802_3);
		/* place it back on the queue to be handled by true layer 3 protocols.
		 */

		/* See if we are configured to re-write the VLAN header
		 * to make it look like ethernet...
		 */
		skb = vlan_check_reorder_header(skb);

		/* Can be null if skb-clone fails when re-ordering */
		if (skb) {
			netif_rx(skb);
		} else {
			/* TODO:  Add a more specific counter here. */
			stats->rx_errors++;
		}
		rcu_read_unlock();
		return 0;
	}

	/*
	 *	Real 802.2 LLC
	 */
	skb->protocol = __constant_htons(ETH_P_802_2);
	/* place it back on the queue to be handled by upper layer protocols.
	 */

	/* See if we are configured to re-write the VLAN header
	 * to make it look like ethernet...
	 */
	skb = vlan_check_reorder_header(skb);

	/* Can be null if skb-clone fails when re-ordering */
	if (skb) {
		netif_rx(skb);
	} else {
		/* TODO:  Add a more specific counter here. */
		stats->rx_errors++;
	}
	rcu_read_unlock();
	return 0;
}
Ejemplo n.º 3
0
/*  Attach a VLAN device to a mac address (ie Ethernet Card).
 *  Returns the device that was created, or NULL if there was
 *  an error of some kind.
 */
static struct net_device *register_vlan_device(const char *eth_IF_name,
					       unsigned short VLAN_ID)
{
	struct vlan_group *grp;
	struct net_device *new_dev;
	struct net_device *real_dev; /* the ethernet device */
	int malloc_size = 0;
	int r;

#ifdef VLAN_DEBUG
	printk(VLAN_DBG "%s: if_name -:%s:-	vid: %i\n",
		__FUNCTION__, eth_IF_name, VLAN_ID);
#endif

	if (VLAN_ID >= VLAN_VID_MASK)
		goto out_ret_null;

	/* find the device relating to eth_IF_name. */
	real_dev = dev_get_by_name(eth_IF_name);
	if (!real_dev)
		goto out_ret_null;

	if (real_dev->features & NETIF_F_VLAN_CHALLENGED) {
		printk(VLAN_DBG "%s: VLANs not supported on %s.\n",
			__FUNCTION__, real_dev->name);
		goto out_put_dev;
	}

	if ((real_dev->features & NETIF_F_HW_VLAN_RX) &&
	    (real_dev->vlan_rx_register == NULL ||
	     real_dev->vlan_rx_kill_vid == NULL)) {
		printk(VLAN_DBG "%s: Device %s has buggy VLAN hw accel.\n",
			__FUNCTION__, real_dev->name);
		goto out_put_dev;
	}

	if ((real_dev->features & NETIF_F_HW_VLAN_FILTER) &&
	    (real_dev->vlan_rx_add_vid == NULL ||
	     real_dev->vlan_rx_kill_vid == NULL)) {
		printk(VLAN_DBG "%s: Device %s has buggy VLAN hw accel.\n",
			__FUNCTION__, real_dev->name);
		goto out_put_dev;
	}

	/* From this point on, all the data structures must remain
	 * consistent.
	 */
	rtnl_lock();

	/* The real device must be up and operating in order to
	 * assosciate a VLAN device with it.
	 */
	if (!(real_dev->flags & IFF_UP))
		goto out_unlock;

	spin_lock_bh(&vlan_group_lock);
	r = (__find_vlan_dev(real_dev, VLAN_ID) != NULL);
	spin_unlock_bh(&vlan_group_lock);

	if (r) {
		/* was already registered. */
		printk(VLAN_DBG "%s: ALREADY had VLAN registered\n", __FUNCTION__);
		goto out_unlock;
	}

	malloc_size = (sizeof(struct net_device));
	new_dev = (struct net_device *) kmalloc(malloc_size, GFP_KERNEL);
	VLAN_MEM_DBG("net_device malloc, addr: %p  size: %i\n",
		     new_dev, malloc_size);

	if (new_dev == NULL)
		goto out_unlock;

	memset(new_dev, 0, malloc_size);

	/* Set us up to have no queue, as the underlying Hardware device
	 * can do all the queueing we could want.
	 */
	new_dev->tx_queue_len = 0;

	/* Gotta set up the fields for the device. */
#ifdef VLAN_DEBUG
	printk(VLAN_DBG "About to allocate name, vlan_name_type: %i\n",
	       vlan_name_type);
#endif
	switch (vlan_name_type) {
	case VLAN_NAME_TYPE_RAW_PLUS_VID:
		/* name will look like:	 eth1.0005 */
		sprintf(new_dev->name, "%s.%.4i", real_dev->name, VLAN_ID);
		break;
	case VLAN_NAME_TYPE_PLUS_VID_NO_PAD:
		/* Put our vlan.VID in the name.
		 * Name will look like:	 vlan5
		 */
		sprintf(new_dev->name, "vlan%i", VLAN_ID);
		break;
	case VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD:
		/* Put our vlan.VID in the name.
		 * Name will look like:	 eth0.5
		 */
		sprintf(new_dev->name, "%s.%i", real_dev->name, VLAN_ID);
		break;
	case VLAN_NAME_TYPE_PLUS_VID:
		/* Put our vlan.VID in the name.
		 * Name will look like:	 vlan0005
		 */
	default:
		sprintf(new_dev->name, "vlan%.4i", VLAN_ID);
	};
		    
#ifdef VLAN_DEBUG
	printk(VLAN_DBG "Allocated new name -:%s:-\n", new_dev->name);
#endif
	/* set up method calls */
	new_dev->init = vlan_dev_init;
	new_dev->destructor = vlan_dev_destruct;
	new_dev->features |= NETIF_F_DYNALLOC ; 
	    
	/* new_dev->ifindex = 0;  it will be set when added to
	 * the global list.
	 * iflink is set as well.
	 */
	new_dev->get_stats = vlan_dev_get_stats;
	    
	/* IFF_BROADCAST|IFF_MULTICAST; ??? */
	new_dev->flags = real_dev->flags;
	new_dev->flags &= ~IFF_UP;

	/* Make this thing known as a VLAN device */
	new_dev->priv_flags |= IFF_802_1Q_VLAN;
				
	/* need 4 bytes for extra VLAN header info,
	 * hope the underlying device can handle it.
	 */
	new_dev->mtu = real_dev->mtu;
	new_dev->change_mtu = vlan_dev_change_mtu;

	/* TODO: maybe just assign it to be ETHERNET? */
	new_dev->type = real_dev->type;

	new_dev->hard_header_len = real_dev->hard_header_len;
	if (!(real_dev->features & NETIF_F_HW_VLAN_TX)) {
		/* Regular ethernet + 4 bytes (18 total). */
		new_dev->hard_header_len += VLAN_HLEN;
	}

	new_dev->priv = kmalloc(sizeof(struct vlan_dev_info),
				GFP_KERNEL);
	VLAN_MEM_DBG("new_dev->priv malloc, addr: %p  size: %i\n",
		     new_dev->priv,
		     sizeof(struct vlan_dev_info));
	    
	if (new_dev->priv == NULL)
		goto out_free_newdev;

	memset(new_dev->priv, 0, sizeof(struct vlan_dev_info));

	memcpy(new_dev->broadcast, real_dev->broadcast, real_dev->addr_len);
	memcpy(new_dev->dev_addr, real_dev->dev_addr, real_dev->addr_len);
	new_dev->addr_len = real_dev->addr_len;

	new_dev->open = vlan_dev_open;
	new_dev->stop = vlan_dev_stop;

	if (real_dev->features & NETIF_F_HW_VLAN_TX) {
		new_dev->hard_header = real_dev->hard_header;
		new_dev->hard_start_xmit = vlan_dev_hwaccel_hard_start_xmit;
		new_dev->rebuild_header = real_dev->rebuild_header;
	} else {
		new_dev->hard_header = vlan_dev_hard_header;
		new_dev->hard_start_xmit = vlan_dev_hard_start_xmit;
		new_dev->rebuild_header = vlan_dev_rebuild_header;
	}
	new_dev->hard_header_parse = real_dev->hard_header_parse;
	new_dev->set_mac_address = vlan_dev_set_mac_address;
	new_dev->set_multicast_list = vlan_dev_set_multicast_list;

	VLAN_DEV_INFO(new_dev)->vlan_id = VLAN_ID; /* 1 through VLAN_VID_MASK */
	VLAN_DEV_INFO(new_dev)->real_dev = real_dev;
	VLAN_DEV_INFO(new_dev)->dent = NULL;
	VLAN_DEV_INFO(new_dev)->flags = vlan_default_dev_flags;

#ifdef VLAN_DEBUG
	printk(VLAN_DBG "About to go find the group for idx: %i\n",
	       real_dev->ifindex);
#endif
	    
	/* So, got the sucker initialized, now lets place
	 * it into our local structure.
	 */
	spin_lock_bh(&vlan_group_lock);
	grp = __vlan_find_group(real_dev->ifindex);
	spin_unlock_bh(&vlan_group_lock);

	/* Note, we are running under the RTNL semaphore
	 * so it cannot "appear" on us.
	 */
	if (!grp) { /* need to add a new group */
		grp = kmalloc(sizeof(struct vlan_group), GFP_KERNEL);
		if (!grp)
			goto out_free_newdev_priv;
					
		/* printk(KERN_ALERT "VLAN REGISTER:  Allocated new group.\n"); */
		memset(grp, 0, sizeof(struct vlan_group));
		grp->real_dev_ifindex = real_dev->ifindex;

		spin_lock_bh(&vlan_group_lock);
		__grp_hash(grp);
		spin_unlock_bh(&vlan_group_lock);

		if (real_dev->features & NETIF_F_HW_VLAN_RX)
			real_dev->vlan_rx_register(real_dev, grp);
	}
	    
	grp->vlan_devices[VLAN_ID] = new_dev;

	if (vlan_proc_add_dev(new_dev)<0)/* create it's proc entry */
            	printk(KERN_WARNING "VLAN: failed to add proc entry for %s\n",
					                 new_dev->name);

	if (real_dev->features & NETIF_F_HW_VLAN_FILTER)
		real_dev->vlan_rx_add_vid(real_dev, VLAN_ID);

	register_netdevice(new_dev);

	rtnl_unlock();
	    
	/* NOTE:  We have a reference to the real device,
	 * so hold on to the reference.
	 */
	MOD_INC_USE_COUNT; /* Add was a success!! */
#ifdef VLAN_DEBUG
	printk(VLAN_DBG "Allocated new device successfully, returning.\n");
#endif
	return new_dev;

out_free_newdev_priv:
	kfree(new_dev->priv);

out_free_newdev:
	kfree(new_dev);

out_unlock:
	rtnl_unlock();

out_put_dev:
	dev_put(real_dev);

out_ret_null:
	return NULL;
}
Ejemplo n.º 4
0
/*
 *	Determine the packet's protocol ID. The rule here is that we
 *	assume 802.3 if the type field is short enough to be a length.
 *	This is normal practice and works for any 'now in use' protocol.
 *
 *  Also, at this point we assume that we ARE dealing exclusively with
 *  VLAN packets, or packets that should be made into VLAN packets based
 *  on a default VLAN ID.
 *
 *  NOTE:  Should be similar to ethernet/eth.c.
 *
 *  SANITY NOTE:  This method is called when a packet is moving up the stack
 *                towards userland.  To get here, it would have already passed
 *                through the ethernet/eth.c eth_type_trans() method.
 *  SANITY NOTE 2: We are referencing to the VLAN_HDR frields, which MAY be
 *                 stored UNALIGNED in the memory.  RISC systems don't like
 *                 such cases very much...
 *  SANITY NOTE 2a: According to Dave Miller & Alexey, it will always be
 *  		    aligned, so there doesn't need to be any of the unaligned
 *  		    stuff.  It has been commented out now...  --Ben
 *
 */
int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev,
		  struct packet_type *ptype, struct net_device *orig_dev)
{
	struct vlan_hdr *vhdr;
	struct net_device_stats *stats;
	u16 vlan_id;
	u16 vlan_tci;

	skb = skb_share_check(skb, GFP_ATOMIC);
	if (skb == NULL)
		goto err_free;

	if (unlikely(!pskb_may_pull(skb, VLAN_HLEN)))
		goto err_free;

	vhdr = (struct vlan_hdr *)skb->data;
	vlan_tci = ntohs(vhdr->h_vlan_TCI);
	vlan_id = vlan_tci & VLAN_VID_MASK;

	rcu_read_lock();
	skb->dev = __find_vlan_dev(dev, vlan_id);
	if (!skb->dev) {
#if defined(CONFIG_BCM_SMUX)
        /* start bridge mode vlan pkt is discard A36D08034 by f00110348 */
        if (orig_dev->priv_flags & IFF_RSMUX)
        {
            skb->dev = NULL;
            rcu_read_unlock(); /* add unlock, or crash 20111225 by f00110348 */
            return 0;
        }
        /* end bridge mode vlan pkt is discard A36D08034 by f00110348 */
#endif        
		pr_debug("%s: ERROR: No net_device for VID: %u on dev: %s\n",
			 __func__, vlan_id, dev->name);
		goto err_unlock;
	}

	stats = &skb->dev->stats;
	stats->rx_packets++;
	stats->rx_bytes += skb->len;

	skb_pull_rcsum(skb, VLAN_HLEN);

	skb->priority = vlan_get_ingress_priority(skb->dev, vlan_tci);

	/* Start of modified by f00120964 for qos function 2012-4-2*/
#ifdef CONFIG_DT_QOS
	skb->mark |= s_dtQos8021PtoMark[((ntohs(vhdr->h_vlan_TCI) >> 13) & 0x7)];
#endif
    /* End of modified by f00120964 for qos function 2012-4-2*/

	pr_debug("%s: priority: %u for TCI: %hu\n",
		 __func__, skb->priority, vlan_tci);

	switch (skb->pkt_type) {
	case PACKET_BROADCAST: /* Yeah, stats collect these together.. */
		/* stats->broadcast ++; // no such counter :-( */
		break;

	case PACKET_MULTICAST:
		stats->multicast++;
		break;

	case PACKET_OTHERHOST:
		/* Our lower layer thinks this is not local, let's make sure.
		 * This allows the VLAN to have a different MAC than the
		 * underlying device, and still route correctly.
		 */
		if (!compare_ether_addr(eth_hdr(skb)->h_dest,
					skb->dev->dev_addr))
			skb->pkt_type = PACKET_HOST;
		break;
	default:
		break;
	}

	vlan_set_encap_proto(skb, vhdr);

	skb = vlan_check_reorder_header(skb);
	if (!skb) {
		stats->rx_errors++;
		goto err_unlock;
	}

	netif_rx(skb);
	rcu_read_unlock();
	return NET_RX_SUCCESS;

err_unlock:
	rcu_read_unlock();
err_free:
	kfree_skb(skb);
	return NET_RX_DROP;
}
Ejemplo n.º 5
0
/*
 *	Determine the packet's protocol ID. The rule here is that we
 *	assume 802.3 if the type field is short enough to be a length.
 *	This is normal practice and works for any 'now in use' protocol.
 *
 *  Also, at this point we assume that we ARE dealing exclusively with
 *  VLAN packets, or packets that should be made into VLAN packets based
 *  on a default VLAN ID.
 *
 *  NOTE:  Should be similar to ethernet/eth.c.
 *
 *  SANITY NOTE:  This method is called when a packet is moving up the stack
 *                towards userland.  To get here, it would have already passed
 *                through the ethernet/eth.c eth_type_trans() method.
 *  SANITY NOTE 2: We are referencing to the VLAN_HDR frields, which MAY be
 *                 stored UNALIGNED in the memory.  RISC systems don't like
 *                 such cases very much...
 *  SANITY NOTE 2a: According to Dave Miller & Alexey, it will always be
 *  		    aligned, so there doesn't need to be any of the unaligned
 *  		    stuff.  It has been commented out now...  --Ben
 *
 */
int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev,
		  struct packet_type *ptype, struct net_device *orig_dev)
{
	struct vlan_hdr *vhdr;
	struct vlan_rx_stats *rx_stats;
	struct net_device *vlan_dev;
	u16 vlan_id;
	u16 vlan_tci;
#if defined(CONFIG_TCSUPPORT_VLAN_TAG)
	u16 *proto = NULL;
#endif
#if defined(CONFIG_TCSUPPORT_PON_VLAN)
	int ret = 0;
#endif

	skb = skb_share_check(skb, GFP_ATOMIC);
	if (skb == NULL)
		goto err_free;

	if (unlikely(!pskb_may_pull(skb, VLAN_HLEN)))
		goto err_free;

	vhdr = (struct vlan_hdr *)skb->data;
	vlan_tci = ntohs(vhdr->h_vlan_TCI);
	vlan_id = vlan_tci & VLAN_VID_MASK;

#ifdef CONFIG_TCSUPPORT_PON_VLAN
#if 0
	if(orig_dev->name[0] == 'e')
		skb->pon_vlan_flag |= PON_PKT_FROM_LAN;
	else if(orig_dev->name[0] == 'n')
	{
		skb->pon_vlan_flag |= PON_PKT_FROM_WAN;
		skb->pon_vlan_flag |= PON_PKT_ROUTING_FLAG;
	}
#endif
	if(ptype->type != ETH_P_8021Q)
	{
		goto Pon_Handle;
	}
#endif

	rcu_read_lock();
	vlan_dev = __find_vlan_dev(dev, vlan_id);

	/* If the VLAN device is defined, we use it.
	 * If not, and the VID is 0, it is a 802.1p packet (not
	 * really a VLAN), so we will just netif_rx it later to the
	 * original interface, but with the skb->proto set to the
	 * wrapped proto: we do nothing here.
	 */

	if (!vlan_dev) {
#ifdef CONFIG_TCSUPPORT_PON_VLAN
Pon_Handle:
	if(pon_store_tag_hook)
	{
		ret = pon_store_tag_hook(skb, orig_dev);
		if(ret == 0)
		{
			netif_rx(skb);
			return 0;
		}
		else if(ret == -1)
		{
			kfree_skb(skb);
			return -1;
		}
		else
		{
			//HGU mode,do nothing
		}
	}
#endif
	#ifdef CONFIG_TCSUPPORT_VLAN_TAG
		if (check_vtag_hook && (check_vtag_hook() == 1)) {
			if (remove_vtag_hook) {
				 if (remove_vtag_hook(skb, orig_dev) == -1) {
				 	/* must free skb !! */
					kfree_skb(skb);
					rcu_read_unlock();
					return -1;
				 }
				 else {
				 	netif_rx(skb);
					rcu_read_unlock();
					return 0;
				 }
			}
			else {
				goto Normal_Handle;
			}
		}
		else {
Normal_Handle:
#if !defined(CONFIG_TCSUPPORT_CT) 
			if((orig_dev != NULL) && ((orig_dev->name[0] == 'b') || (orig_dev->name[0] == 'n'))) 
#endif
			{
				proto = vhdr->h_vlan_encapsulated_proto;
				skb->protocol = proto;
				/* Take off the VLAN header (4 bytes currently) */
				skb_pull_rcsum(skb, VLAN_HLEN);
				skb->dev = orig_dev;
				netif_rx(skb);
				rcu_read_unlock();
				return 0;
			}
			else {
				pr_debug("%s: ERROR: No net_device for VID: %u on dev: %s\n",
					 __func__, vlan_id, dev->name);
				kfree_skb(skb);
				rcu_read_unlock();
				return -1;

			}
		}
	#else
		if (vlan_id) {
			pr_debug("%s: ERROR: No net_device for VID: %u on dev: %s\n",
				 __func__, vlan_id, dev->name);
			goto err_unlock;
		}
		rx_stats = NULL;
	#endif
	} else {
		skb->dev = vlan_dev;

#if !defined(CONFIG_TCSUPPORT_CT) 
#ifdef CONFIG_PORT_BINDING
		if (skb->dev->name[0] == 'e') {
		//	skb->mark |= MASK_ORIGIN_DEV;
			skb->portbind_mark |= MASK_ORIGIN_DEV;
			memcpy(skb->orig_dev_name, skb->dev->name, IFNAMSIZ);
			//printk("vlan_skb_recv: begin orig_dev name is [%s], orig_dev name is [%s]\n", skb->orig_dev_name, orig_dev->name);
		}
#endif
#endif

		rx_stats = per_cpu_ptr(vlan_dev_info(skb->dev)->vlan_rx_stats,
					smp_processor_id());
		u64_stats_update_begin(&rx_stats->syncp);
		rx_stats->rx_packets++;
		rx_stats->rx_bytes += skb->len;

		skb->priority = vlan_get_ingress_priority(skb->dev, vlan_tci);

		pr_debug("%s: priority: %u for TCI: %hu\n",
			 __func__, skb->priority, vlan_tci);

		switch (skb->pkt_type) {
		case PACKET_BROADCAST:
			/* Yeah, stats collect these together.. */
			/* stats->broadcast ++; // no such counter :-( */
			break;

		case PACKET_MULTICAST:
			rx_stats->rx_multicast++;
			break;

		case PACKET_OTHERHOST:
			/* Our lower layer thinks this is not local, let's make
			 * sure.
			 * This allows the VLAN to have a different MAC than the
			 * underlying device, and still route correctly.
			 */
			if (!compare_ether_addr(eth_hdr(skb)->h_dest,
						skb->dev->dev_addr))
				skb->pkt_type = PACKET_HOST;
			break;
		default:
			break;
		}
		u64_stats_update_end(&rx_stats->syncp);
	}

	skb_pull_rcsum(skb, VLAN_HLEN);
	vlan_set_encap_proto(skb, vhdr);

	if (vlan_dev) {
		skb = vlan_check_reorder_header(skb);
		if (!skb) {
			rx_stats->rx_errors++;
			goto err_unlock;
		}
	}

	netif_rx(skb);
	rcu_read_unlock();
	return NET_RX_SUCCESS;

err_unlock:
	rcu_read_unlock();
err_free:
	kfree_skb(skb);
	return NET_RX_DROP;
}