/** * Send data to a specified address using UDP. * The netif used for sending can be specified. * * This function exists mainly for DHCP, to be able to send UDP packets * on a netif that is still down. * * @param pcb UDP PCB used to send the data. * @param p chain of pbuf's to be sent. * @param dst_ip Destination IP address. * @param dst_port Destination UDP port. * @param netif the netif used for sending. * * dst_ip & dst_port are expected to be in the same byte order as in the pcb. * * @return lwIP error code (@see udp_send for possible error codes) * * @see udp_disconnect() udp_send() */ err_t udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *dst_ip, u16_t dst_port, struct netif *netif) { struct udp_hdr *udphdr; struct ip_addr *src_ip; err_t err; struct pbuf *q; /* q will be sent down the stack */ #if IP_SOF_BROADCAST /* broadcast filter? */ if ( ((pcb->so_options & SOF_BROADCAST) == 0) && ip_addr_isbroadcast(dst_ip, netif) ) { LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("udp_sendto_if: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb)); return ERR_VAL; } #endif /* IP_SOF_BROADCAST */ /* if the PCB is not yet bound to a port, bind it here */ if (pcb->local_port == 0) { LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send: not yet bound to a port, binding now\n")); err = udp_bind(pcb, &pcb->local_ip, pcb->local_port); if (err != ERR_OK) { LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: forced port bind failed\n")); return err; } } /* not enough space to add an UDP header to first pbuf in given p chain? */ if (pbuf_header(p, UDP_HLEN)) { /* allocate header in a separate new pbuf */ q = pbuf_alloc(PBUF_IP, UDP_HLEN, PBUF_RAM); /* new header pbuf could not be allocated? */ if (q == NULL) { LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: could not allocate header\n")); return ERR_MEM; } /* chain header q in front of given pbuf p */ pbuf_chain(q, p); /* first pbuf q points to header pbuf */ LWIP_DEBUGF(UDP_DEBUG, ("udp_send: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p)); } else { /* adding space for header within p succeeded */ /* first pbuf q equals given pbuf */ q = p; LWIP_DEBUGF(UDP_DEBUG, ("udp_send: added header in given pbuf %p\n", (void *)p)); } LWIP_ASSERT("check that first pbuf can hold struct udp_hdr", (q->len >= sizeof(struct udp_hdr))); /* q now represents the packet to be sent */ udphdr = q->payload; udphdr->src = htons(pcb->local_port); udphdr->dest = htons(dst_port); /* in UDP, 0 checksum means 'no checksum' */ udphdr->chksum = 0x0000; /* PCB local address is IP_ANY_ADDR? */ if (ip_addr_isany(&pcb->local_ip)) { /* use outgoing network interface IP address as source address */ src_ip = &(netif->ip_addr); } else { /* check if UDP PCB local IP address is correct * this could be an old address if netif->ip_addr has changed */ if (!ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr))) { /* local_ip doesn't match, drop the packet */ if (q != p) { /* free the header pbuf */ pbuf_free(q); q = NULL; /* p is still referenced by the caller, and will live on */ } return ERR_VAL; } /* use UDP PCB local IP address as source address */ src_ip = &(pcb->local_ip); } LWIP_DEBUGF(UDP_DEBUG, ("udp_send: sending datagram of length %"U16_F"\n", q->tot_len)); #if LWIP_UDPLITE /* UDP Lite protocol? */ if (pcb->flags & UDP_FLAGS_UDPLITE) { u16_t chklen, chklen_hdr; LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP LITE packet length %"U16_F"\n", q->tot_len)); /* set UDP message length in UDP header */ chklen_hdr = chklen = pcb->chksum_len_tx; if ((chklen < sizeof(struct udp_hdr)) || (chklen > q->tot_len)) { if (chklen != 0) { LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP LITE pcb->chksum_len is illegal: %"U16_F"\n", chklen)); } /* For UDP-Lite, checksum length of 0 means checksum over the complete packet. (See RFC 3828 chap. 3.1) At least the UDP-Lite header must be covered by the checksum, therefore, if chksum_len has an illegal value, we generate the checksum over the complete packet to be safe. */ chklen_hdr = 0; chklen = q->tot_len; } udphdr->len = htons(chklen_hdr); /* calculate checksum */ #if CHECKSUM_GEN_UDP udphdr->chksum = inet_chksum_pseudo_partial(q, src_ip, dst_ip, IP_PROTO_UDPLITE, q->tot_len, chklen); /* chksum zero must become 0xffff, as zero means 'no checksum' */ if (udphdr->chksum == 0x0000) udphdr->chksum = 0xffff; #endif /* CHECKSUM_CHECK_UDP */ /* output to IP */ LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDPLITE,)\n")); #if LWIP_NETIF_HWADDRHINT netif->addr_hint = &(pcb->addr_hint); #endif /* LWIP_NETIF_HWADDRHINT*/ err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDPLITE, netif); #if LWIP_NETIF_HWADDRHINT netif->addr_hint = NULL; #endif /* LWIP_NETIF_HWADDRHINT*/ } else #endif /* LWIP_UDPLITE */ { /* UDP */ LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP packet length %"U16_F"\n", q->tot_len)); udphdr->len = htons(q->tot_len); /* calculate checksum */ #if CHECKSUM_GEN_UDP if ((pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) { udphdr->chksum = inet_chksum_pseudo(q, src_ip, dst_ip, IP_PROTO_UDP, q->tot_len); /* chksum zero must become 0xffff, as zero means 'no checksum' */ if (udphdr->chksum == 0x0000) udphdr->chksum = 0xffff; } #endif /* CHECKSUM_CHECK_UDP */ LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP checksum 0x%04"X16_F"\n", udphdr->chksum)); LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDP,)\n")); /* output to IP */ #if LWIP_NETIF_HWADDRHINT netif->addr_hint = &(pcb->addr_hint); #endif /* LWIP_NETIF_HWADDRHINT*/ err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDP, netif); #if LWIP_NETIF_HWADDRHINT netif->addr_hint = NULL; #endif /* LWIP_NETIF_HWADDRHINT*/ } /* TODO: must this be increased even if error occured? */ snmp_inc_udpoutdatagrams(); /* did we chain a separate header pbuf earlier? */ if (q != p) { /* free the header pbuf */ pbuf_free(q); q = NULL; /* p is still referenced by the caller, and will live on */ } UDP_STATS_INC(udp.xmit); return err; }
/** * 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. * @param inp network interface on which the datagram was received. * */ void udp_input(struct pbuf *p, struct netif *inp) { struct udp_hdr *udphdr; struct udp_pcb *pcb, *prev; struct udp_pcb *uncon_pcb; struct ip_hdr *iphdr; u16_t src, dest; u8_t local_match; u8_t broadcast; PERF_START; UDP_STATS_INC(udp.recv); iphdr = (struct ip_hdr *)p->payload; /* Check minimum length (IP header + UDP header) * and move payload pointer to UDP header */ if (p->tot_len < (IPH_HL(iphdr) * 4 + UDP_HLEN) || pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4))) { /* 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); snmp_inc_udpinerrors(); pbuf_free(p); goto end; } udphdr = (struct udp_hdr *)p->payload; /* is broadcast packet ? */ broadcast = ip_addr_isbroadcast(¤t_iphdr_dest, inp); LWIP_DEBUGF(UDP_DEBUG, ("udp_input: received datagram of length %"U16_F"\n", p->tot_len)); /* convert src and dest ports to host byte order */ src = ntohs(udphdr->src); dest = ntohs(udphdr->dest); udp_debug_print(udphdr); /* print the UDP source and destination */ LWIP_DEBUGF(UDP_DEBUG, ("udp (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") <-- " "(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n", ip4_addr1_16(&iphdr->dest), ip4_addr2_16(&iphdr->dest), ip4_addr3_16(&iphdr->dest), ip4_addr4_16(&iphdr->dest), ntohs(udphdr->dest), ip4_addr1_16(&iphdr->src), ip4_addr2_16(&iphdr->src), ip4_addr3_16(&iphdr->src), ip4_addr4_16(&iphdr->src), ntohs(udphdr->src))); #if LWIP_DHCP pcb = NULL; /* when LWIP_DHCP is active, packets to DHCP_CLIENT_PORT may only be processed by the dhcp module, no other UDP pcb may use the local UDP port DHCP_CLIENT_PORT */ if (dest == DHCP_CLIENT_PORT) { /* all packets for DHCP_CLIENT_PORT not coming from DHCP_SERVER_PORT are dropped! */ if (src == DHCP_SERVER_PORT) { if ((inp->dhcp != NULL) && (inp->dhcp->pcb != NULL)) { /* accept the packe if (- broadcast or directed to us) -> DHCP is link-layer-addressed, local ip is always ANY! - inp->dhcp->pcb->remote == ANY or iphdr->src */ if ((ip_addr_isany(&inp->dhcp->pcb->remote_ip) || ip_addr_cmp(&(inp->dhcp->pcb->remote_ip), ¤t_iphdr_src))) { pcb = inp->dhcp->pcb; } } } } else #endif /* LWIP_DHCP */ { prev = NULL; local_match = 0; uncon_pcb = NULL; /* Iterate through the UDP pcb list for a matching pcb. * 'Perfect match' pcbs (connected to the remote port & ip address) are * preferred. If no perfect match is found, the first unconnected pcb that * matches the local port and ip address gets the datagram. */ for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) { local_match = 0; /* print the PCB local and remote address */ LWIP_DEBUGF(UDP_DEBUG, ("pcb (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") --- " "(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n", ip4_addr1_16(&pcb->local_ip), ip4_addr2_16(&pcb->local_ip), ip4_addr3_16(&pcb->local_ip), ip4_addr4_16(&pcb->local_ip), pcb->local_port, ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip), ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip), pcb->remote_port)); /* compare PCB local addr+port to UDP destination addr+port */ if (pcb->local_port == dest) { if ( (!broadcast && ip_addr_isany(&pcb->local_ip)) || ip_addr_cmp(&(pcb->local_ip), ¤t_iphdr_dest) || #if LWIP_IGMP ip_addr_ismulticast(¤t_iphdr_dest) || #endif /* LWIP_IGMP */ #if IP_SOF_BROADCAST_RECV (broadcast && ip_get_option(pcb, SOF_BROADCAST) && (ip_addr_isany(&pcb->local_ip) || ip_addr_netcmp(&pcb->local_ip, ip_current_dest_addr(), &inp->netmask)))) { #else /* IP_SOF_BROADCAST_RECV */ (broadcast && (ip_addr_isany(&pcb->local_ip) || ip_addr_netcmp(&pcb->local_ip, ip_current_dest_addr(), &inp->netmask)))) { #endif /* IP_SOF_BROADCAST_RECV */ local_match = 1; if ((uncon_pcb == NULL) && ((pcb->flags & UDP_FLAGS_CONNECTED) == 0)) { /* the first unconnected matching PCB */ uncon_pcb = pcb; } } } /* compare PCB remote addr+port to UDP source addr+port */ if ((local_match != 0) && (pcb->remote_port == src) && (ip_addr_isany(&pcb->remote_ip) || ip_addr_cmp(&(pcb->remote_ip), ¤t_iphdr_src))) { /* the first fully matching PCB */ if (prev != NULL) { /* move the pcb to the front of udp_pcbs so that is found faster next time */ prev->next = pcb->next; pcb->next = udp_pcbs; udp_pcbs = pcb; } else { UDP_STATS_INC(udp.cachehit); } break; } prev = pcb; } /* no fully matching pcb found? then look for an unconnected pcb */ if (pcb == NULL) { pcb = uncon_pcb; } } /* Check checksum if this is a match or if it was directed at us. */ if (pcb != NULL || ip_addr_cmp(&inp->ip_addr, ¤t_iphdr_dest)) { LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: calculating checksum\n")); #if LWIP_UDPLITE if (IPH_PROTO(iphdr) == IP_PROTO_UDPLITE) { /* Do the UDP Lite checksum */ #if CHECKSUM_CHECK_UDP u16_t chklen = ntohs(udphdr->len); if (chklen < sizeof(struct udp_hdr)) { if (chklen == 0) { /* For UDP-Lite, checksum length of 0 means checksum over the complete packet (See RFC 3828 chap. 3.1) */ chklen = p->tot_len; } else { /* At least the UDP-Lite header must be covered by the checksum! (Again, see RFC 3828 chap. 3.1) */ UDP_STATS_INC(udp.chkerr); UDP_STATS_INC(udp.drop); snmp_inc_udpinerrors(); pbuf_free(p); goto end; } } if (inet_chksum_pseudo_partial(p, ¤t_iphdr_src, ¤t_iphdr_dest, IP_PROTO_UDPLITE, p->tot_len, chklen) != 0) { LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("udp_input: UDP Lite datagram discarded due to failing checksum\n")); UDP_STATS_INC(udp.chkerr); UDP_STATS_INC(udp.drop); snmp_inc_udpinerrors(); pbuf_free(p); goto end; } #endif /* CHECKSUM_CHECK_UDP */ } else #endif /* LWIP_UDPLITE */ { #if CHECKSUM_CHECK_UDP if (udphdr->chksum != 0) { if (inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(), IP_PROTO_UDP, p->tot_len) != 0) { LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("udp_input: UDP datagram discarded due to failing checksum\n")); UDP_STATS_INC(udp.chkerr); UDP_STATS_INC(udp.drop); snmp_inc_udpinerrors(); pbuf_free(p); goto end; } } #endif /* CHECKSUM_CHECK_UDP */ } if(pbuf_header(p, -UDP_HLEN)) { /* Can we cope with this failing? Just assert for now */ LWIP_ASSERT("pbuf_header failed\n", 0); UDP_STATS_INC(udp.drop); snmp_inc_udpinerrors(); pbuf_free(p); goto end; } if (pcb != NULL) { snmp_inc_udpindatagrams(); #if SO_REUSE && SO_REUSE_RXTOALL if ((broadcast || ip_addr_ismulticast(¤t_iphdr_dest)) && ip_get_option(pcb, SOF_REUSEADDR)) { /* pass broadcast- or multicast packets to all multicast pcbs if SOF_REUSEADDR is set on the first match */ struct udp_pcb *mpcb; u8_t p_header_changed = 0; for (mpcb = udp_pcbs; mpcb != NULL; mpcb = mpcb->next) { if (mpcb != pcb) { /* compare PCB local addr+port to UDP destination addr+port */ if ((mpcb->local_port == dest) && ((!broadcast && ip_addr_isany(&mpcb->local_ip)) || ip_addr_cmp(&(mpcb->local_ip), ¤t_iphdr_dest) || #if LWIP_IGMP ip_addr_ismulticast(¤t_iphdr_dest) || #endif /* LWIP_IGMP */ #if IP_SOF_BROADCAST_RECV (broadcast && ip_get_option(mpcb, SOF_BROADCAST)))) { #else /* IP_SOF_BROADCAST_RECV */ (broadcast))) { #endif /* IP_SOF_BROADCAST_RECV */ /* pass a copy of the packet to all local matches */ if (mpcb->recv != NULL) { struct pbuf *q; /* for that, move payload to IP header again */ if (p_header_changed == 0) { pbuf_header(p, (s16_t)((IPH_HL(iphdr) * 4) + UDP_HLEN)); p_header_changed = 1; } q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); if (q != NULL) { err_t err = pbuf_copy(q, p); if (err == ERR_OK) { /* move payload to UDP data */ pbuf_header(q, -(s16_t)((IPH_HL(iphdr) * 4) + UDP_HLEN)); mpcb->recv(mpcb->recv_arg, mpcb, q, ip_current_src_addr(), src); } } } } } } if (p_header_changed) { /* and move payload to UDP data again */ pbuf_header(p, -(s16_t)((IPH_HL(iphdr) * 4) + UDP_HLEN)); } } #endif /* SO_REUSE && SO_REUSE_RXTOALL */ /* callback */ if (pcb->recv != NULL) { /* now the recv function is responsible for freeing p */ pcb->recv(pcb->recv_arg, pcb, p, ip_current_src_addr(), src); } else { /* no recv function registered? then we have to free the pbuf! */ pbuf_free(p); goto end; } } else {
/** * 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. * @param inp network interface on which the datagram was received. * */ void udp_input(struct pbuf *p, struct netif *inp) { struct udp_hdr *udphdr; struct udp_pcb *pcb, *prev; struct udp_pcb *uncon_pcb; struct ip_hdr *iphdr; u16_t src, dest; u8_t local_match; PERF_START; UDP_STATS_INC(udp.recv); iphdr = (struct ip_hdr *)(p->payload); /* Check minimum length (IP header + UDP header) * and move payload pointer to UDP header */ if (p->tot_len < (IPH_HL(iphdr) * 4 + UDP_HLEN) || pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4))) { /* 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); snmp_inc_udpinerrors(); pbuf_free(p); goto end; } udphdr = (struct udp_hdr *)p->payload; LWIP_DEBUGF(UDP_DEBUG, ("udp_input: received datagram of length %"U16_F"\n", p->tot_len)); /* convert src and dest ports to host byte order */ src = ntohs(udphdr->src); dest = ntohs(udphdr->dest); udp_debug_print(udphdr); /* print the UDP source and destination */ LWIP_DEBUGF(UDP_DEBUG, ("udp (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") <-- " "(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n", ip4_addr1(&iphdr->dest), ip4_addr2(&iphdr->dest), ip4_addr3(&iphdr->dest), ip4_addr4(&iphdr->dest), ntohs(udphdr->dest), ip4_addr1(&iphdr->src), ip4_addr2(&iphdr->src), ip4_addr3(&iphdr->src), ip4_addr4(&iphdr->src), ntohs(udphdr->src))); #if LWIP_DHCP pcb = NULL; /* when LWIP_DHCP is active, packets to DHCP_CLIENT_PORT may only be processed by the dhcp module, no other UDP pcb may use the local UDP port DHCP_CLIENT_PORT */ if (dest == DHCP_CLIENT_PORT) { /* all packets for DHCP_CLIENT_PORT not coming from DHCP_SERVER_PORT are dropped! */ if (src == DHCP_SERVER_PORT) { if ((inp->dhcp != NULL) && (inp->dhcp->pcb != NULL)) { /* accept the packe if (- broadcast or directed to us) -> DHCP is link-layer-addressed, local ip is always ANY! - inp->dhcp->pcb->remote == ANY or iphdr->src */ if ((ip_addr_isany(&inp->dhcp->pcb->remote_ip) || ip_addr_cmp(&(inp->dhcp->pcb->remote_ip), &(iphdr->src)))) { pcb = inp->dhcp->pcb; } } } } else #endif /* LWIP_DHCP */ { prev = NULL; local_match = 0; uncon_pcb = NULL; /* Iterate through the UDP pcb list for a matching pcb. * 'Perfect match' pcbs (connected to the remote port & ip address) are * preferred. If no perfect match is found, the first unconnected pcb that * matches the local port and ip address gets the datagram. */ for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) { local_match = 0; /* print the PCB local and remote address */ LWIP_DEBUGF(UDP_DEBUG, ("pcb (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") --- " "(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n", ip4_addr1(&pcb->local_ip), ip4_addr2(&pcb->local_ip), ip4_addr3(&pcb->local_ip), ip4_addr4(&pcb->local_ip), pcb->local_port, ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip), ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip), pcb->remote_port)); /* compare PCB local addr+port to UDP destination addr+port */ if ((pcb->local_port == dest) && (ip_addr_isany(&pcb->local_ip) || ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)) || #if LWIP_IGMP ip_addr_ismulticast(&(iphdr->dest)) || #endif /* LWIP_IGMP */ ip_addr_isbroadcast(&(iphdr->dest), inp))) { local_match = 1; if ((uncon_pcb == NULL) && ((pcb->flags & UDP_FLAGS_CONNECTED) == 0)) { /* the first unconnected matching PCB */ uncon_pcb = pcb; } } /* compare PCB remote addr+port to UDP source addr+port */ if ((local_match != 0) && (pcb->remote_port == src) && (ip_addr_isany(&pcb->remote_ip) || ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)))) { /* the first fully matching PCB */ if (prev != NULL) { /* move the pcb to the front of udp_pcbs so that is found faster next time */ prev->next = pcb->next; pcb->next = udp_pcbs; udp_pcbs = pcb; } else { UDP_STATS_INC(udp.cachehit); } break; } prev = pcb; } /* no fully matching pcb found? then look for an unconnected pcb */ if (pcb == NULL) { pcb = uncon_pcb; } } /* Check checksum if this is a match or if it was directed at us. */ if (pcb != NULL || ip_addr_cmp(&inp->ip_addr, &iphdr->dest)) { LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: calculating checksum\n")); #if LWIP_UDPLITE if (IPH_PROTO(iphdr) == IP_PROTO_UDPLITE) { /* Do the UDP Lite checksum */ #if CHECKSUM_CHECK_UDP u16_t chklen = ntohs(udphdr->len); if (chklen < sizeof(struct udp_hdr)) { if (chklen == 0) { /* For UDP-Lite, checksum length of 0 means checksum over the complete packet (See RFC 3828 chap. 3.1) */ chklen = p->tot_len; } else { /* At least the UDP-Lite header must be covered by the checksum! (Again, see RFC 3828 chap. 3.1) */ UDP_STATS_INC(udp.chkerr); UDP_STATS_INC(udp.drop); snmp_inc_udpinerrors(); pbuf_free(p); goto end; } } if (inet_chksum_pseudo_partial(p, (struct ip_addr *)&(iphdr->src), (struct ip_addr *)&(iphdr->dest), IP_PROTO_UDPLITE, p->tot_len, chklen) != 0) { LWIP_DEBUGF(UDP_DEBUG | 2, ("udp_input: UDP Lite datagram discarded due to failing checksum\n")); UDP_STATS_INC(udp.chkerr); UDP_STATS_INC(udp.drop); snmp_inc_udpinerrors(); pbuf_free(p); goto end; } #endif /* CHECKSUM_CHECK_UDP */ } else #endif /* LWIP_UDPLITE */ { #if CHECKSUM_CHECK_UDP if (udphdr->chksum != 0) { if (inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src), (struct ip_addr *)&(iphdr->dest), IP_PROTO_UDP, p->tot_len) != 0) { LWIP_DEBUGF(UDP_DEBUG | 2, ("udp_input: UDP datagram discarded due to failing checksum\n")); UDP_STATS_INC(udp.chkerr); UDP_STATS_INC(udp.drop); snmp_inc_udpinerrors(); pbuf_free(p); goto end; } } #endif /* CHECKSUM_CHECK_UDP */ } if(pbuf_header(p, -UDP_HLEN)) { /* Can we cope with this failing? Just assert for now */ LWIP_ASSERT("pbuf_header failed\n", 0); UDP_STATS_INC(udp.drop); snmp_inc_udpinerrors(); pbuf_free(p); goto end; } if (pcb != NULL) { snmp_inc_udpindatagrams(); /* callback */ if (pcb->recv != NULL) { /* now the recv function is responsible for freeing p */ struct ip_addr iphdrsrc; // __packed hack iphdrsrc.addr = iphdr->src.addr; pcb->recv(pcb->recv_arg, pcb, p, &iphdrsrc, src); } else { /* no recv function registered? then we have to free the pbuf! */ pbuf_free(p); goto end; } } else { LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: not for us.\n")); #if LWIP_ICMP /* No match was found, send ICMP destination port unreachable unless destination address was broadcast/multicast. */ if (!ip_addr_isbroadcast(&(iphdr->dest), inp) && !ip_addr_ismulticast(&iphdr->dest)) { /* move payload pointer back to ip header */ pbuf_header(p, (IPH_HL(iphdr) * 4) + UDP_HLEN); LWIP_ASSERT("p->payload == iphdr", (p->payload == iphdr)); icmp_dest_unreach(p, ICMP_DUR_PORT); } #endif /* LWIP_ICMP */ UDP_STATS_INC(udp.proterr); UDP_STATS_INC(udp.drop); snmp_inc_udpnoports(); pbuf_free(p); } } else { pbuf_free(p); } end: PERF_STOP("udp_input"); }