linux 内核 UDP层csum校验

本人内核小菜,最近工作需要在内核模块做udp的recv checksum 校验,整理了相关资料并把关键的函数列出来。

参考4.9内核及相关博客

http://blog.csdn.net/one_clouder/article/details/53177992

http://wenx05124561.blog.163.com/blog/static/124000805201242032041268/

//recv udp packet check
static bool checksumError(struct sk_buff* skb, struct udphdr* uh)
{
    unsigned int psum = 0;
    //needn't check if below:
    //1. ip_summed is CHECKSUM_UNNECESSARY hardware check
    if(skb->ip_summed == CHECKSUM_UNNECESSARY)
    {
        return false;
    }
    //2. udp header check is 0,mean needn't check
    if(uh->check == 0)
    {
        incCounter64(&recvChecksumStat_g.checkZero);
        return false;
    }
    //otherwise, we must calculate csum
    //skb->data must move to udphr
    if(skb_pull(skb, ip_hdrlen (skb)) == NULL) //注意:勾包是L3 skb->data 指向ip头
    {
        return true;
    }
    //calculate pseudo header csum
    psum = csum_tcpudp_nofold(ip_hdr(skb)->saddr, ip_hdr(skb)->daddr, skb->len, ip_hdr(skb)->protocol, 0);
    if(skb->ip_summed == CHECKSUM_COMPLETE)
    {
        //payload csum has calculated by hardware, and set it to skb->csum
        if(!csum_fold(csum_add(psum, skb->csum)))
        {
            skb->ip_summed = CHECKSUM_UNNECESSARY;//避免处理不了时,返回协议栈处理还要再算一次
            return false;
        }

    }

    //calculate payload csum and fold pseudo header csum
    skb->csum = skb_checksum(skb, 0, skb->len, 0);
    if(!csum_fold(csum_add(psum, skb->csum)))
    {
        skb->ip_summed = CHECKSUM_UNNECESSARY;
        return false;
    }
    return true;

}

//call

    if(checksumError(skb, udph)) //check csum
    {
        if (net_ratelimit())
        {
            log(Error, "handlePacket: checksum error!src %u:%u dst %u:%u\n", iph->saddr, ntohs(udph->source), iph->daddr, ntohs(udph->dest));
        }
        //discard packet if csum error
        return NF_DROP;  //直接返回 不需要 kfree_skb(skb);  nf_hook_slow函数中free掉,否则crash

    }

你可能感兴趣的:(linux内核)