【lwip】11-UDP协议&源码分析( 十 )

  • 如果UDP PCB 远端端口、IP和UDP报文源端口和IP匹配失败,则可以使用UDP PCB 本地端口、IP和UDP报文目的端口和IP匹配但是未连接的UDP PCBuncon_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

    推荐阅读