struct sk_buff *vlan_untag(struct sk_buff *skb)
{
struct vlan_hdr *vhdr;
u16 vlan_tci;
// 检查VLAN_TAG_PRESENT标志
// 如果已经设置,说明VLAN已被处理
// 本函数最后也会设置此标志
if (unlikely(vlan_tx_tag_present(skb))) {
/* vlan_tci is already set-up so leave this for another time */
return skb;
}
// 检查skb是否被共享,如果是,克隆一份
skb = skb_share_check(skb, GFP_ATOMIC);
if (unlikely(!skb))
goto err_free;
// 长度检查
if (unlikely(!pskb_may_pull(skb, VLAN_HLEN)))
goto err_free;
// vhdr赋值
vhdr = (struct vlan_hdr *)skb->data;
vlan_tci = ntohs(vhdr->h_vlan_TCI);
// 设置VLAN_TAG_PRESENT标志及skb->vlan_tci
__vlan_hwaccel_put_tag(skb, vlan_tci);
// 提取vlan头部并更新接收校验和
skb_pull_rcsum(skb, VLAN_HLEN);
// 将skb的协议字段设置为h_vlan_encapsulated_proto
vlan_set_encap_proto(skb, vhdr);
// 修改skb->data/mac_header/mac_header_len,移除vlan
skb = vlan_reorder_header(skb);
if (unlikely(!skb))
goto err_free;
// network_header = skb->data
skb_reset_network_header(skb);
skb_reset_transport_header(skb);
return skb;
err_free:
kfree_skb(skb);
return NULL;
}