163 |
struct ip_hdr *iphdr; |
struct ip_hdr *iphdr; |
164 |
u16_t src, dest; |
u16_t src, dest; |
165 |
|
|
166 |
|
#ifdef SO_REUSE |
167 |
|
struct udp_pcb *pcb_temp; |
168 |
|
int reuse = 0; |
169 |
|
int reuse_port_1 = 0; |
170 |
|
int reuse_port_2 = 0; |
171 |
|
#endif /* SO_REUSE */ |
172 |
|
|
173 |
PERF_START; |
PERF_START; |
174 |
|
|
175 |
#ifdef UDP_STATS |
#ifdef UDP_STATS |
207 |
ip4_addr3(&iphdr->dest), ip4_addr4(&iphdr->dest), ntohs(udphdr->dest), |
ip4_addr3(&iphdr->dest), ip4_addr4(&iphdr->dest), ntohs(udphdr->dest), |
208 |
ip4_addr1(&iphdr->src), ip4_addr2(&iphdr->src), |
ip4_addr1(&iphdr->src), ip4_addr2(&iphdr->src), |
209 |
ip4_addr3(&iphdr->src), ip4_addr4(&iphdr->src), ntohs(udphdr->src))); |
ip4_addr3(&iphdr->src), ip4_addr4(&iphdr->src), ntohs(udphdr->src))); |
210 |
|
|
211 |
|
#ifdef SO_REUSE |
212 |
|
pcb_temp = udp_pcbs; |
213 |
|
|
214 |
|
again_1: |
215 |
|
|
216 |
|
/* Iterate through the UDP pcb list for a fully matching pcb */ |
217 |
|
for(pcb = pcb_temp; pcb != NULL; pcb = pcb->next) { |
218 |
|
#else /* SO_REUSE */ |
219 |
/* Iterate through the UDP pcb list for a fully matching pcb */ |
/* Iterate through the UDP pcb list for a fully matching pcb */ |
220 |
for(pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) { |
for(pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) { |
221 |
|
#endif /* SO_REUSE */ |
222 |
/* print the PCB local and remote address */ |
/* print the PCB local and remote address */ |
223 |
LWIP_DEBUGF(UDP_DEBUG, ("pcb (%u.%u.%u.%u, %u) --- (%u.%u.%u.%u, %u)\n", |
LWIP_DEBUGF(UDP_DEBUG, ("pcb (%u.%u.%u.%u, %u) --- (%u.%u.%u.%u, %u)\n", |
224 |
ip4_addr1(&pcb->local_ip), ip4_addr2(&pcb->local_ip), |
ip4_addr1(&pcb->local_ip), ip4_addr2(&pcb->local_ip), |
238 |
(ip_addr_isany(&pcb->local_ip) || |
(ip_addr_isany(&pcb->local_ip) || |
239 |
/* PCB local IP address matches UDP destination IP address? */ |
/* PCB local IP address matches UDP destination IP address? */ |
240 |
ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)))) { |
ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)))) { |
241 |
|
#ifdef SO_REUSE |
242 |
|
if(pcb->so_options & SOF_REUSEPORT) { |
243 |
|
if(reuse) { |
244 |
|
/* We processed one PCB already */ |
245 |
|
LWIP_DEBUGF(UDP_DEBUG, ("udp_input: second or later PCB and SOF_REUSEPORT set.\n")); |
246 |
|
} else { |
247 |
|
/* First PCB with this address */ |
248 |
|
LWIP_DEBUGF(UDP_DEBUG, ("udp_input: first PCB and SOF_REUSEPORT set.\n")); |
249 |
|
reuse = 1; |
250 |
|
} |
251 |
|
|
252 |
|
reuse_port_1 = 1; |
253 |
|
p->ref++; |
254 |
|
LWIP_DEBUGF(UDP_DEBUG, ("udp_input: reference counter on PBUF set to %i\n", p->ref)); |
255 |
|
} else { |
256 |
|
if(reuse) { |
257 |
|
/* We processed one PCB already */ |
258 |
|
LWIP_DEBUGF(UDP_DEBUG, ("udp_input: second or later PCB but SOF_REUSEPORT not set !\n")); |
259 |
|
} |
260 |
|
} |
261 |
|
#endif /* SO_REUSE */ |
262 |
break; |
break; |
263 |
} |
} |
264 |
} |
} |
266 |
if (pcb == NULL) { |
if (pcb == NULL) { |
267 |
/* Iterate through the UDP PCB list for a pcb that matches |
/* Iterate through the UDP PCB list for a pcb that matches |
268 |
the local address. */ |
the local address. */ |
269 |
|
|
270 |
|
#ifdef SO_REUSE |
271 |
|
pcb_temp = udp_pcbs; |
272 |
|
|
273 |
|
again_2: |
274 |
|
|
275 |
|
for(pcb = pcb_temp; pcb != NULL; pcb = pcb->next) { |
276 |
|
#else /* SO_REUSE */ |
277 |
for(pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) { |
for(pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) { |
278 |
|
#endif /* SO_REUSE */ |
279 |
LWIP_DEBUGF(UDP_DEBUG, ("pcb (%u.%u.%u.%u, %u) --- (%u.%u.%u.%u, %u)\n", |
LWIP_DEBUGF(UDP_DEBUG, ("pcb (%u.%u.%u.%u, %u) --- (%u.%u.%u.%u, %u)\n", |
280 |
ip4_addr1(&pcb->local_ip), ip4_addr2(&pcb->local_ip), |
ip4_addr1(&pcb->local_ip), ip4_addr2(&pcb->local_ip), |
281 |
ip4_addr3(&pcb->local_ip), ip4_addr4(&pcb->local_ip), pcb->local_port, |
ip4_addr3(&pcb->local_ip), ip4_addr4(&pcb->local_ip), pcb->local_port, |
289 |
(ip_addr_isany(&pcb->local_ip) || |
(ip_addr_isany(&pcb->local_ip) || |
290 |
/* ...matching interface address? */ |
/* ...matching interface address? */ |
291 |
ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)))) { |
ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)))) { |
292 |
break; |
#ifdef SO_REUSE |
293 |
|
if(pcb->so_options & SOF_REUSEPORT) { |
294 |
|
if(reuse) { |
295 |
|
/* We processed one PCB already */ |
296 |
|
LWIP_DEBUGF(UDP_DEBUG, ("udp_input: second or later PCB and SOF_REUSEPORT set.\n")); |
297 |
|
} else { |
298 |
|
/* First PCB with this address */ |
299 |
|
LWIP_DEBUGF(UDP_DEBUG, ("udp_input: first PCB and SOF_REUSEPORT set.\n")); |
300 |
|
reuse = 1; |
301 |
|
} |
302 |
|
|
303 |
|
reuse_port_2 = 1; |
304 |
|
p->ref++; |
305 |
|
LWIP_DEBUGF(UDP_DEBUG, ("udp_input: reference counter on PBUF set to %i\n", p->ref)); |
306 |
|
} else { |
307 |
|
if(reuse) { |
308 |
|
/* We processed one PCB already */ |
309 |
|
LWIP_DEBUGF(UDP_DEBUG, ("udp_input: second or later PCB but SOF_REUSEPORT not set !\n")); |
310 |
|
} |
311 |
|
} |
312 |
|
#endif /* SO_REUSE */ |
313 |
|
break; |
314 |
} |
} |
315 |
} |
} |
316 |
} |
} |
359 |
if (pcb != NULL) { |
if (pcb != NULL) { |
360 |
snmp_inc_udpindatagrams(); |
snmp_inc_udpindatagrams(); |
361 |
pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src), src); |
pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src), src); |
362 |
|
#ifdef SO_REUSE |
363 |
|
/* First socket should receive now */ |
364 |
|
if(reuse_port_1 || reuse_port_2) { |
365 |
|
/* We want to search on next socket after receiving */ |
366 |
|
pcb_temp = pcb->next; |
367 |
|
|
368 |
|
if(reuse_port_1) { |
369 |
|
/* We are searching connected sockets */ |
370 |
|
reuse_port_1 = 0; |
371 |
|
reuse_port_2 = 0; |
372 |
|
goto again_1; |
373 |
|
} else { |
374 |
|
/* We are searching unconnected sockets */ |
375 |
|
reuse_port_1 = 0; |
376 |
|
reuse_port_2 = 0; |
377 |
|
goto again_2; |
378 |
|
} |
379 |
|
} |
380 |
|
#endif /* SO_REUSE */ |
381 |
} else { |
} else { |
382 |
|
#ifdef SO_REUSE |
383 |
|
if(reuse) { |
384 |
|
LWIP_DEBUGF(UDP_DEBUG, ("udp_input: freeing PBUF with reference counter set to %i\n", p->ref)); |
385 |
|
pbuf_free(p); |
386 |
|
goto end; |
387 |
|
} |
388 |
|
#endif /* SO_REUSE */ |
389 |
LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE, ("udp_input: not for us.\n")); |
LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE, ("udp_input: not for us.\n")); |
390 |
|
|
391 |
/* No match was found, send ICMP destination port unreachable unless |
/* No match was found, send ICMP destination port unreachable unless |
551 |
{ |
{ |
552 |
struct udp_pcb *ipcb; |
struct udp_pcb *ipcb; |
553 |
u8_t rebind; |
u8_t rebind; |
554 |
|
#ifdef SO_REUSE |
555 |
|
int reuse_port_all_set = 1; |
556 |
|
#endif /* SO_REUSE */ |
557 |
LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | 3, ("udp_bind(ipaddr = ")); |
LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | 3, ("udp_bind(ipaddr = ")); |
558 |
ip_addr_debug_print(UDP_DEBUG, ipaddr); |
ip_addr_debug_print(UDP_DEBUG, ipaddr); |
559 |
LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | 3, (", port = %u)\n", port)); |
LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | 3, (", port = %u)\n", port)); |
560 |
|
|
561 |
rebind = 0; |
rebind = 0; |
562 |
/* Check for double bind and rebind of the same pcb */ |
/* Check for double bind and rebind of the same pcb */ |
563 |
for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) { |
for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) { |
568 |
/* pcb already in list, just rebind */ |
/* pcb already in list, just rebind */ |
569 |
rebind = 1; |
rebind = 1; |
570 |
} |
} |
571 |
|
|
572 |
|
#ifndef SO_REUSE |
573 |
/* this code does not allow upper layer to share a UDP port for |
/* this code does not allow upper layer to share a UDP port for |
574 |
listening to broadcast or multicast traffic (See SO_REUSE_ADDR and |
listening to broadcast or multicast traffic (See SO_REUSE_ADDR and |
575 |
SO_REUSE_PORT under *BSD). TODO: See where it fits instead, OR |
SO_REUSE_PORT under *BSD). TODO: See where it fits instead, OR |
586 |
return ERR_USE; |
return ERR_USE; |
587 |
} |
} |
588 |
#endif |
#endif |
589 |
|
|
590 |
|
#else /* SO_REUSE */ |
591 |
|
/* Search through list of PCB's. |
592 |
|
|
593 |
|
If there is a PCB bound to specified port and IP_ADDR_ANY another PCB can be bound to the interface IP |
594 |
|
or to the loopback address on the same port if SOF_REUSEADDR is set. Any combination of PCB's bound to |
595 |
|
the same local port, but to one address out of {IP_ADDR_ANY, 127.0.0.1, interface IP} at a time is valid. |
596 |
|
But no two PCB's bound to same local port and same local address is valid. |
597 |
|
|
598 |
|
If SOF_REUSEPORT is set several PCB's can be bound to same local port and same local address also. But then |
599 |
|
all PCB's must have the SOF_REUSEPORT option set. |
600 |
|
|
601 |
|
When the two options aren't set and specified port is already bound, ERR_USE is returned saying that |
602 |
|
address is already in use. */ |
603 |
|
else if (ipcb->local_port == port) { |
604 |
|
if(ip_addr_cmp(&(ipcb->local_ip), ipaddr)) { |
605 |
|
if(pcb->so_options & SOF_REUSEPORT) { |
606 |
|
LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: in UDP PCB's SO_REUSEPORT set and same address.\n")); |
607 |
|
reuse_port_all_set = (reuse_port_all_set && (ipcb->so_options & SOF_REUSEPORT)); |
608 |
|
} |
609 |
|
else { |
610 |
|
LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: in UDP PCB's SO_REUSEPORT not set and same address.\n")); |
611 |
|
return ERR_USE; |
612 |
|
} |
613 |
|
} |
614 |
|
else if((ip_addr_isany(ipaddr) && !ip_addr_isany(&(ipcb->local_ip))) || |
615 |
|
(!ip_addr_isany(ipaddr) && ip_addr_isany(&(ipcb->local_ip)))) { |
616 |
|
if(!(pcb->so_options & SOF_REUSEADDR) && !(pcb->so_options & SOF_REUSEPORT)) { |
617 |
|
LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: in UDP PCB's SO_REUSEPORT or SO_REUSEADDR not set and not the same address.\n")); |
618 |
|
return ERR_USE; |
619 |
|
} |
620 |
|
} |
621 |
|
} |
622 |
|
#endif /* SO_REUSE */ |
623 |
|
|
624 |
|
} |
625 |
|
|
626 |
|
#ifdef SO_REUSE |
627 |
|
/* If SOF_REUSEPORT isn't set in all PCB's bound to specified port and local address specified then |
628 |
|
{IP, port} can't be reused. */ |
629 |
|
if(!reuse_port_all_set) { |
630 |
|
LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: not all sockets have SO_REUSEPORT set.\n")); |
631 |
|
return ERR_USE; |
632 |
} |
} |
633 |
/* bind local address */ |
#endif /* SO_REUSE */ |
634 |
|
|
635 |
ip_addr_set(&pcb->local_ip, ipaddr); |
ip_addr_set(&pcb->local_ip, ipaddr); |
636 |
/* no port specified? */ |
/* no port specified? */ |
637 |
if (port == 0) { |
if (port == 0) { |