Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Diff: lwip/core/udp.c
- Revision:
- 1:3a7c15057192
- Parent:
- 0:b802fc31f1db
diff -r b802fc31f1db -r 3a7c15057192 lwip/core/udp.c
--- a/lwip/core/udp.c Fri Jul 09 15:37:23 2010 +0000
+++ b/lwip/core/udp.c Fri Aug 06 10:23:41 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);