vlan处理


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;
}

 

你可能感兴趣的:(linux协议栈)