kernel ipv4/ip_output.c

static inline int ip_finish_output2(struct sk_buff *skb)
{
    struct dst_entry *dst = skb->dst;
    struct rtable *rt = (struct rtable *)dst;
    struct hh_cache *hh = dst->hh;
    struct net_device *dev = dst->dev;
    int hh_len = LL_RESERVED_SPACE(dev);

    if (rt->rt_type == RTN_MULTICAST)
        IP_INC_STATS(IPSTATS_MIB_OUTMCASTPKTS);
    else if (rt->rt_type == RTN_BROADCAST)
        IP_INC_STATS(IPSTATS_MIB_OUTBCASTPKTS);

    /* Be paranoid, rather than too clever. */
    if (unlikely(skb_headroom(skb) < hh_len && dev->hard_header)) {
        struct sk_buff *skb2;

        skb2 = skb_realloc_headroom(skb, LL_RESERVED_SPACE(dev));
        if (skb2 == NULL) {
            kfree_skb(skb);
            return -ENOMEM;
        }
        if (skb->sk)
            skb_set_owner_w(skb2, skb->sk);
        kfree_skb(skb);
        skb = skb2;
    }

    if (hh) {
        int hh_alen;

        read_lock_bh(&hh->hh_lock);
        hh_alen = HH_DATA_ALIGN(hh->hh_len);
          memcpy(skb->data - hh_alen, hh->hh_data, hh_alen);
        read_unlock_bh(&hh->hh_lock);
            skb_push(skb, hh->hh_len);
        return hh->hh_output(skb);
    } else if (dst->neighbour)
        return dst->neighbour->output(skb);

    if (net_ratelimit())
        printk(KERN_DEBUG "ip_finish_output2: No header cache and no neighbour!\n");
    kfree_skb(skb);
    return -EINVAL;
}
原文地址:https://www.cnblogs.com/phoenix13suns/p/2547758.html