- 首页 > 生活 > >
【lwip】11-UDP协议&源码分析(11)
参数校验 。
报文校验 。
匹配UDP PCB:通过IP和端口号确保该UDP报文得到某个应用程序 。遍历UDP PCB udp_pcbs
:
- UDP PCB 本地端口、IP和UDP报文目的端口和IP匹配:端口一致且IP匹配:
- 当前UDP PCB没有指定本地IP , 或UDP报文的目的IP就是指向当前UDP PCB的IP 。本地可以匹配成功 。
- 如果UDP报文对应的目的IP是一个广播地址 , 且当前UDP设置了
SOF_BROADCAST
选项 。这个IP是全广播地址或者和当前UDP PCB IP处于同一个子网 。本地可以匹配成功 。 - 如果UDP PCB 本地端口、IP和UDP报文目的端口和IP匹配成功后 , 但是该UDP PCB还没有处于连接状态 , 则可以记录到
uncon_pcb
变量中 , 有更适合且未连接的UDP PCB适配本次UDP报文的 , 更新到uncon_pcb
中 。
- UDP PCB 远端端口、IP和UDP报文源端口和IP匹配:端口一致且IP匹配:
- UDP PCB远端IP随意或者就是当前UDP报文的源IP 。远端匹配成功 。
- 如果UDP PCB 远端端口、IP和UDP报文源端口和IP匹配失败 , 则可以使用UDP PCB 本地端口、IP和UDP报文目的端口和IP匹配但是未连接的UDP PCB
uncon_pcb
。
- 上述都匹配成功后 , UDP PCB即可匹配成功 , 当前 UDP 报文是给我们的 。
校验和校验:
- UDP协议:校验和字段为0 , 不用校验 。校验和字段不为0 , 则全部校验 。
- UDP LITE协议:UDP报文的总长度字段值即为需要进行校验和计算的数据长度 。注意:长度字段为0表示整个报文校验 。(参考RFC 3828章3.1)
pbuf偏移头部 , 指向UDP数据区 。即是用户数据 。
如果开启了SOF_REUSEADDR
选项:则把当前UDP PCB包复制转发到所有能匹配成功的UDP PCB 。
- 如果没有开启该选项 , 当前UDP报文就只递交给第一个匹配成功的DUP PCB了 。
把数据回调到上层应用:pcb->recv()
/** * Process an incoming UDP datagram. * * Given an incoming UDP datagram (as a chain of pbufs) this function * finds a corresponding UDP PCB and hands over the pbuf to the pcbs * recv function. If no pcb is found or the datagram is incorrect, the * pbuf is freed. * * @param p pbuf to be demultiplexed to a UDP PCB (p->payload pointing to the UDP header) * @param inp network interface on which the datagram was received. * */voidudp_input(struct pbuf *p, struct netif *inp){struct udp_hdr *udphdr;struct udp_pcb *pcb, *prev;struct udp_pcb *uncon_pcb;u16_t src, dest;u8_t broadcast;u8_t for_us = 0;LWIP_UNUSED_ARG(inp);LWIP_ASSERT_CORE_LOCKED(); /* 确保在内核锁内 *//* 参数校验 */LWIP_ASSERT("udp_input: invalid pbuf", p != NULL);LWIP_ASSERT("udp_input: invalid netif", inp != NULL);PERF_START;UDP_STATS_INC(udp.recv);/* 检查最小长度(UDP首部) */if (p->len < UDP_HLEN) {/* drop short packets */LWIP_DEBUGF(UDP_DEBUG,("udp_input: short UDP datagram (%"U16_F" bytes) discarded\n", p->tot_len));UDP_STATS_INC(udp.lenerr);UDP_STATS_INC(udp.drop);MIB2_STATS_INC(mib2.udpinerrors);pbuf_free(p);goto end;}/* 提取UDP首部 */udphdr = (struct udp_hdr *)p->payload;/* 检查是否是广播包 */broadcast = ip_addr_isbroadcast(ip_current_dest_addr(), ip_current_netif());LWIP_DEBUGF(UDP_DEBUG, ("udp_input: received datagram of length %"U16_F"\n", p->tot_len));src = https://www.huyubaike.com/biancheng/lwip_ntohs(udphdr->src); /* UDP报文的源端口号 */dest = lwip_ntohs(udphdr->dest); /* UDP报文的目的端口号 */udp_debug_print(udphdr);/* 打印相关信息 */LWIP_DEBUGF(UDP_DEBUG, ("udp ("));ip_addr_debug_print_val(UDP_DEBUG, *ip_current_dest_addr());LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F") <-- (", lwip_ntohs(udphdr->dest)));ip_addr_debug_print_val(UDP_DEBUG, *ip_current_src_addr());LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F")\n", lwip_ntohs(udphdr->src)));pcb = NULL;prev = NULL;uncon_pcb = NULL;/* 遍历UDP PCB列表以找到匹配的PCB 。匹配pcb:连接到远程端口和ip地址优先 。如果没有找到完全匹配的 , 那么与本地端口和ip地址匹配的第一个未连接的pcb将获得数据报 */for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) {/* 每次遍历都打印PCB本地和远端IP地址和端口号 */LWIP_DEBUGF(UDP_DEBUG, ("pcb ("));ip_addr_debug_print_val(UDP_DEBUG, pcb->local_ip);LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F") <-- (", pcb->local_port));ip_addr_debug_print_val(UDP_DEBUG, pcb->remote_ip);LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F")\n", pcb->remote_port));/* 匹配UDP PCB 本地端口、IP和UDP报文目的端口和IP */if ((pcb->local_port == dest) &&(udp_input_local_match(pcb, inp, broadcast) != 0)) {if ((pcb->flags & UDP_FLAGS_CONNECTED) == 0) {if (uncon_pcb == NULL) {/* 第一个未连接的匹配PCB */uncon_pcb = pcb;#if LWIP_IPV4} else if (broadcast && ip4_current_dest_addr()->addr == IPADDR_BROADCAST) {/* 全局广播地址(仅对IPv4有效;之前检查过匹配) */if (!IP_IS_V4_VAL(uncon_pcb->local_ip) || !ip4_addr_cmp(ip_2_ip4(&uncon_pcb->local_ip), netif_ip4_addr(inp))) {/* uncon_pcb 与收到数据netif不匹配 , 则需要重新检查此PCB */if (IP_IS_V4_VAL(pcb->local_ip) && ip4_addr_cmp(ip_2_ip4(&pcb->local_ip), netif_ip4_addr(inp))) {/* 更新uncon_pcb */uncon_pcb = pcb;}}#endif /* LWIP_IPV4 */}/* 支持SOF_REUSEADDR选项功能 。因为如果没有开启这个功能 , 那前面两个if的匹配逻辑就能找到唯一一个符合要求的uncon_pcb 。如果支持SOF_REUSEADDR功能 , UDP PCB中就可能存在多个匹配成功未连接的PCB , 这样选第一个即可(靠近链表尾 , 即是老的) */#if SO_REUSEelse if (!ip_addr_isany(&pcb->local_ip)) {/* 更加倾向于有指定本地IP未连接的PCB */uncon_pcb = pcb;}#endif /* SO_REUSE */}/* 匹配UDP PCB 远端端口、IP和UDP报文源端口和IP */if ((pcb->remote_port == src) &&(ip_addr_isany_val(pcb->remote_ip) ||ip_addr_cmp(&pcb->remote_ip, ip_current_src_addr()))) {/* 第一个完全匹配的PCB */if (prev != NULL) {/* 将PCB移动到udp_pcbs的前面 , 以便下次更快地找到它 */prev->next = pcb->next;pcb->next = udp_pcbs;udp_pcbs = pcb;} else {UDP_STATS_INC(udp.cachehit);}break;}}prev = pcb; /* 遍历下一个UDP PCB */}/* 没有找到完全匹配的PCB , 就使用未连接的匹配PCB */if (pcb == NULL) {pcb = uncon_pcb;}/* 最终检查当前UDP报文是不是给我们的 */if (pcb != NULL) {for_us = 1; /* UDP PCB匹配成功 , 是给我们的 */} else { /* UDP PCB匹配不成功 */#if LWIP_IPV6if (ip_current_is_v6()) {/* 检查下当前UDP报文的目的IP是不是给我们的 */for_us = netif_get_ip6_addr_match(inp, ip6_c
经验总结扩展阅读
-
2022年农历腊月初九搬新家吉日 2022年12月31日搬新家好不好
-
8月底,痛定思痛,爱恨清空,展望未来,高傲离去,真爱就在眼前
-
-
-
-
总有人在问 太多婚后的真爱,不过只是一时的激情,根本就当不得真
-
怎么开心怎么过 致35岁的女人:往后你要怎么开心怎么过
-
-
热水器不出热水怎么回事,电热水器不出热水怎么回事?
-
-
涂抹 “一款三用”的平价口红,不挑肤色巨显白,素颜涂也能彰显高级感
-
喝不完的奶粉可以放到下次喝吗,喝剩的奶粉可以下顿喝吗
-
-
相思梧叶影视情感说|《北辙南辕》:中年夫妻应该如何经营婚姻?不妨学学杜世均和司梦
-
2022年农历九月十六修坟吉日 2022年10月11日适合修坟吗
-
-
因为走丢了的哈士奇被送进了派出所,结果把派出所拆了,不愧为拆家王
-
葡萄干配一物,每天喝一杯,不贫血了,眼睛亮了,女人常喝不显老
-
-