EthernetNetIf Compatibility.
Dependents: XBeeWiFi_SPI_example
Fork of NetServicesSource by
Diff: lwip/core/udp.c
- Revision:
- 5:dd63a1e02b1b
- Parent:
- 0:632c9925f013
--- a/lwip/core/udp.c Fri Jul 09 14:46:47 2010 +0000 +++ b/lwip/core/udp.c Tue Jul 27 15:59:42 2010 +0000 @@ -113,7 +113,7 @@ udphdr = (struct udp_hdr *)p->payload; /* is broadcast packet ? */ - broadcast = ip_addr_isbroadcast(&(iphdr->dest), inp); + broadcast = ip_addr_isbroadcast(¤t_iphdr_dest, inp); LWIP_DEBUGF(UDP_DEBUG, ("udp_input: received datagram of length %"U16_F"\n", p->tot_len)); @@ -144,7 +144,7 @@ (- 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)))) { + ip_addr_cmp(&(inp->dhcp->pcb->remote_ip), ¤t_iphdr_src))) { pcb = inp->dhcp->pcb; } } @@ -173,9 +173,9 @@ /* compare PCB local addr+port to UDP destination addr+port */ if ((pcb->local_port == dest) && ((!broadcast && ip_addr_isany(&pcb->local_ip)) || - ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)) || + ip_addr_cmp(&(pcb->local_ip), ¤t_iphdr_dest) || #if LWIP_IGMP - ip_addr_ismulticast(&(iphdr->dest)) || + ip_addr_ismulticast(¤t_iphdr_dest) || #endif /* LWIP_IGMP */ #if IP_SOF_BROADCAST_RECV (broadcast && (pcb->so_options & SOF_BROADCAST)))) { @@ -193,7 +193,7 @@ if ((local_match != 0) && (pcb->remote_port == src) && (ip_addr_isany(&pcb->remote_ip) || - ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)))) { + 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 @@ -215,7 +215,7 @@ } /* 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)) { + 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) { @@ -237,7 +237,7 @@ goto end; } } - if (inet_chksum_pseudo_partial(p, &iphdr->src, &iphdr->dest, + 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")); @@ -253,7 +253,7 @@ { #if CHECKSUM_CHECK_UDP if (udphdr->chksum != 0) { - if (inet_chksum_pseudo(p, &iphdr->src, &iphdr->dest, + 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")); @@ -276,10 +276,58 @@ } if (pcb != NULL) { snmp_inc_udpindatagrams(); +#if SO_REUSE && SO_REUSE_RXTOALL + if ((broadcast || ip_addr_ismulticast(¤t_iphdr_dest)) && + ((pcb->so_options & SOF_REUSEADDR) != 0)) { + /* 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 && (mpcb->so_options & 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, &iphdr->src, src); + 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); @@ -292,7 +340,7 @@ /* No match was found, send ICMP destination port unreachable unless destination address was broadcast/multicast. */ if (!broadcast && - !ip_addr_ismulticast(&iphdr->dest)) { + !ip_addr_ismulticast(¤t_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)); @@ -336,6 +384,19 @@ return udp_sendto(pcb, p, &pcb->remote_ip, pcb->remote_port); } +#if LWIP_CHECKSUM_ON_COPY +/** Same as udp_send() but with checksum + */ +err_t +udp_send_chksum(struct udp_pcb *pcb, struct pbuf *p, + u8_t have_chksum, u16_t chksum) +{ + /* send to the packet using remote ip and port stored in the pcb */ + return udp_sendto_chksum(pcb, p, &pcb->remote_ip, pcb->remote_port, + have_chksum, chksum); +} +#endif /* LWIP_CHECKSUM_ON_COPY */ + /** * Send data to a specified address using UDP. * @@ -357,6 +418,16 @@ udp_sendto(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, u16_t dst_port) { +#if LWIP_CHECKSUM_ON_COPY + return udp_sendto_chksum(pcb, p, dst_ip, dst_port, 0, 0); +} + +/** Same as udp_sendto(), but with checksum */ +err_t +udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, + u16_t dst_port, u8_t have_chksum, u16_t chksum) +{ +#endif /* LWIP_CHECKSUM_ON_COPY */ struct netif *netif; LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send\n")); @@ -375,7 +446,11 @@ UDP_STATS_INC(udp.rterr); return ERR_RTE; } +#if LWIP_CHECKSUM_ON_COPY + return udp_sendto_if_chksum(pcb, p, dst_ip, dst_port, netif, have_chksum, chksum); +#else /* LWIP_CHECKSUM_ON_COPY */ return udp_sendto_if(pcb, p, dst_ip, dst_port, netif); +#endif /* LWIP_CHECKSUM_ON_COPY */ } /** @@ -401,6 +476,17 @@ udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif) { +#if LWIP_CHECKSUM_ON_COPY + return udp_sendto_if_chksum(pcb, p, dst_ip, dst_port, netif, 0, 0); +} + +/** Same as udp_sendto_if(), but with checksum */ +err_t +udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, + u16_t dst_port, struct netif *netif, u8_t have_chksum, + u16_t chksum) +{ +#endif /* LWIP_CHECKSUM_ON_COPY */ struct udp_hdr *udphdr; ip_addr_t *src_ip; err_t err; @@ -454,6 +540,14 @@ /* in UDP, 0 checksum means 'no checksum' */ udphdr->chksum = 0x0000; + /* Multicast Loop? */ +#if LWIP_IGMP + if (ip_addr_ismulticast(dst_ip) && ((pcb->flags & UDP_FLAGS_MULTICAST_LOOP) != 0)) { + q->flags |= PBUF_FLAG_MCASTLOOP; + } +#endif /* LWIP_IGMP */ + + /* PCB local address is IP_ANY_ADDR? */ if (ip_addr_isany(&pcb->local_ip)) { /* use outgoing network interface IP address as source address */ @@ -501,7 +595,18 @@ /* calculate checksum */ #if CHECKSUM_GEN_UDP udphdr->chksum = inet_chksum_pseudo_partial(q, src_ip, dst_ip, - IP_PROTO_UDPLITE, q->tot_len, chklen); + IP_PROTO_UDPLITE, q->tot_len, +#if !LWIP_CHECKSUM_ON_COPY + chklen); +#else /* !LWIP_CHECKSUM_ON_COPY */ + (have_chksum ? UDP_HLEN : chklen)); + if (have_chksum) { + u32_t acc; + acc = udphdr->chksum + (u16_t)~(chksum); + udphdr->chksum = FOLD_U32T(acc); + } +#endif /* !LWIP_CHECKSUM_ON_COPY */ + /* chksum zero must become 0xffff, as zero means 'no checksum' */ if (udphdr->chksum == 0x0000) { udphdr->chksum = 0xffff; @@ -524,11 +629,25 @@ /* 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); + u16_t udpchksum; +#if LWIP_CHECKSUM_ON_COPY + if (have_chksum) { + u32_t acc; + udpchksum = inet_chksum_pseudo_partial(q, src_ip, dst_ip, IP_PROTO_UDP, + q->tot_len, UDP_HLEN); + acc = udpchksum + (u16_t)~(chksum); + udpchksum = FOLD_U32T(acc); + } else +#endif /* LWIP_CHECKSUM_ON_COPY */ + { + udpchksum = 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; + if (udpchksum == 0x0000) { + udpchksum = 0xffff; } + udphdr->chksum = udpchksum; } #endif /* CHECKSUM_GEN_UDP */ LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP checksum 0x%04"X16_F"\n", udphdr->chksum)); @@ -597,13 +716,16 @@ rebind = 1; } - /* this code does not allow upper layer to share a UDP port for - listening to broadcast or multicast traffic (See SO_REUSEADDR and - SO_REUSEPORT under *BSD). TODO: See where it fits instead, OR - combine with implementation of UDP PCB flags. Leon Woestenberg. */ -#ifdef LWIP_UDP_TODO - /* port matches that of PCB in list? */ + /* By default, we don't allow to bind to a port that any other udp + PCB is alread bound to, unless *all* PCBs with that port have tha + REUSEADDR flag set. */ +#if SO_REUSE + else if (((pcb->so_options & SOF_REUSEADDR) == 0) && + ((ipcb->so_options & SOF_REUSEADDR) == 0)) { +#else /* SO_REUSE */ + /* port matches that of PCB in list and REUSEADDR not set -> reject */ else { +#endif /* SO_REUSE */ if ((ipcb->local_port == port) && /* IP address matches, or one is IP_ADDR_ANY? */ (ip_addr_isany(&(ipcb->local_ip)) || @@ -615,7 +737,6 @@ return ERR_USE; } } -#endif } ip_addr_set(&pcb->local_ip, ipaddr);