- /* 额...直接就来函数调用... */
- int udp_rcv(struct sk_buff *skb)
- {
- return __udp4_lib_rcv(skb, udp_hash, IPPROTO_UDP);
- }
- /*
- * All we need to do is get the socket, and then do a checksum.
- */
- int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[],
- int proto)
- {
- struct sock *sk;
- struct udphdr *uh = udp_hdr(skb);
- unsigned short ulen;
- struct rtable *rt = (struct rtable*)skb->dst;
- __be32 saddr = ip_hdr(skb)->saddr;
- __be32 daddr = ip_hdr(skb)->daddr;
- /*
- * Validate the packet.
- */
- /* 确保udp头部在线性数据缓冲区中 */
- if (!pskb_may_pull(skb, sizeof(struct udphdr)))
- goto drop; /* No space for header. */
- ulen = ntohs(uh->len);
- /* udp头部指定该upd长度比skb总数据长度还大,显然是一个错误 */
- if (ulen > skb->len)
- goto short_packet;
- /* UDP-Lite协议不必进行len validate。因为其头部的len字段表示的校验的长度 */
- if (proto == IPPROTO_UDP) {
- /* UDP validates ulen. */
- /* 该包的长度至少是一个UDP头部长度,将该包trim到ulen长度 */
- if (ulen < sizeof(*uh) || pskb_trim_rcsum(skb, ulen))
- goto short_packet;
- uh = udp_hdr(skb);
- }
- /* 校验和初始化,若udp头部的校验和字段为0,则设置不必校验标志位,若校验由硬
- * 完成,且伪首部通过校验,则同样设置不必校验标志,若以上都不满足,则将伪首
- * 部的校验和给skb->csum,之后还需要对数据部分进行校验,但这不是该函数的工
- * 作,错误只可能发生在对UDP-Lite协议的包进行校验,暂不考虑。 */
- if (udp4_csum_init(skb, uh, proto))
- goto csum_error;
- /* 广播包或者是多播包...暂不考虑 */
- if (rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST))
- return __udp4_lib_mcast_deliver(skb, uh, saddr, daddr, udptable);
- /* 接收udp包的上层应用对应的sock都组织在udptable这个以注册端口为关键字的
- * 哈希表中,该函数遍历哈希槽找最满足匹配条件的sock并返回它,匹配的字段包括
- * 地址域是否是PF_INET,源、目的地址是否匹配,端口是否匹配,绑定的外出接口
- * 设备是否匹配。匹配项最多的获胜。 */
- sk = __udp4_lib_lookup(saddr, uh->source, daddr, uh->dest,
- inet_iif(skb), udptable);
- /* 这表明有上层应用需要接收这个包, */
- if (sk != NULL) {
- /* 将该包挂入到套接字的等待队列,并唤醒等待该套接字中的数据的进程 */
- int ret = udp_queue_rcv_skb(sk, skb);
- sock_put(sk);
- /* a return value > 0 means to resubmit the input, but
- * it wants the return to be -protocol, or 0
- */
- if (ret > 0)
- return -ret;
- return 0;
- }
- /* 下面的就暂不操心了...*/
- if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
- goto drop;
- nf_reset(skb);
- /* No socket. Drop packet silently, if checksum is wrong */
- if (udp_lib_checksum_complete(skb))
- goto csum_error;
- UDP_INC_STATS_BH(UDP_MIB_NOPORTS, proto == IPPROTO_UDPLITE);
- icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
- /*
- * Hmm. We got an UDP packet to a port to which we
- * don't wanna listen. Ignore it.
- */
- kfree_skb(skb);
- return 0;
- short_packet:
- LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: short packet: From %u.%u.%u.%u:%u %d/%d to %u.%u.%u.%u:%u\n",
- proto == IPPROTO_UDPLITE ? "-Lite" : "",
- NIPQUAD(saddr),
- ntohs(uh->source),
- ulen,
- skb->len,
- NIPQUAD(daddr),
- ntohs(uh->dest));
- goto drop;
- csum_error:
- /*
- * RFC1122: OK. Discards the bad packet silently (as far as
- * the network is concerned, anyway) as per 4.1.3.4 (MUST).
- */
- LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: bad checksum. From %d.%d.%d.%d:%d to %d.%d.%d.%d:%d ulen %d\n",
- proto == IPPROTO_UDPLITE ? "-Lite" : "",
- NIPQUAD(saddr),
- ntohs(uh->source),
- NIPQUAD(daddr),
- ntohs(uh->dest),
- ulen);
- drop:
- UDP_INC_STATS_BH(UDP_MIB_INERRORS, proto == IPPROTO_UDPLITE);
- kfree_skb(skb);
- return 0;
- }
阅读(2333) | 评论(0) | 转发(0) |