UDP报文的处理入口是udp_rcv函数,该函数是在ip_local_deliver_finish函数中被调用的。
1、udp_rcv函数
int udp_rcv(struct sk_buff *skb)
{
return __udp4_lib_rcv(skb, &udp_table, IPPROTO_UDP);
}
2、__udp4_lib_rcv函数
int __udp4_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
int proto)
{
struct sock *sk;
struct udphdr *uh;
unsigned short ulen;
struct rtable *rt = skb_rtable(skb); //得到路由表项信息
__be32 saddr, daddr;
struct net *net = dev_net(skb->dev);
/*
* Validate the packet.
*/
if (!pskb_may_pull(skb, sizeof(struct udphdr))) //检测报文长度
goto drop; /* No space for header. */
uh = udp_hdr(skb);
ulen = ntohs(uh->len);
saddr = ip_hdr(skb)->saddr;
daddr = ip_hdr(skb)->daddr;
if (ulen > skb->len) //skb报文长度必须UDP头设定的长度,skb可能存在pad
goto short_packet;
if (proto == IPPROTO_UDP) {
/* UDP validates ulen. */
if (ulen < sizeof(*uh) || pskb_trim_rcsum(skb, ulen)) //裁剪skb报文
goto short_packet;
uh = udp_hdr(skb);
}
if (udp4_csum_init(skb, uh, proto)) //csum值校验,如果非零则表示csum错误
goto csum_error;
sk = skb_steal_sock(skb); //IP层调用UDP的early_demux函数设置的sk
if (sk) {
struct dst_entry *dst = skb_dst(skb);
int ret;
if (unlikely(sk->sk_rx_dst != dst))
udp_sk_rx_dst_set(sk, dst);
ret = udp_queue_rcv_skb(sk, skb); //sock处理skb报文
sock_put(sk);
/* a return value > 0 means to resubmit the input, b