fix for corrupted graphics when manipulating config files
[open-ps2-loader.git] / modules / network / SMSTCPIP / udp.c
bloba52d31c18275ec58977a8a268b233349b3802c1f
1 /**
2 * @file
3 * User Datagram Protocol module
5 */
6 /*
7 * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
8 * All rights reserved.
10 * Redistribution and use in source and binary forms, with or without modification,
11 * are permitted provided that the following conditions are met:
13 * 1. Redistributions of source code must retain the above copyright notice,
14 * this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
18 * 3. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
22 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
24 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
26 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
29 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
30 * OF SUCH DAMAGE.
32 * This file is part of the lwIP TCP/IP stack.
34 * Author: Adam Dunkels <adam@sics.se>
39 /* udp.c
41 * The code for the User Datagram Protocol UDP.
45 #include "lwip/opt.h"
47 #include "lwip/def.h"
48 #include "lwip/memp.h"
49 #include "lwip/inet.h"
50 #include "lwip/netif.h"
51 #include "lwip/udp.h"
52 #include "lwip/icmp.h"
53 #include "lwip/ip_addr.h"
55 #include "lwip/stats.h"
57 #include "lwip/snmp.h"
59 #include "sysclib.h"
61 #include "smsutils.h"
63 /* The list of UDP PCBs */
64 #if LWIP_UDP
65 /* was static, but we may want to access this from a socket layer */
66 struct udp_pcb *udp_pcbs = NULL;
68 static struct udp_pcb *pcb_cache = NULL;
71 void
72 udp_init(void)
74 udp_pcbs = pcb_cache = NULL;
78 /* udp_lookup:
80 * An experimental feature that will be changed in future versions. Do
81 * not depend on it yet...
84 #ifdef LWIP_DEBUG
85 u8_t
86 udp_lookup(struct ip_hdr *iphdr, struct netif *inp)
88 struct udp_pcb *pcb;
89 struct udp_hdr *udphdr;
90 u16_t src, dest;
92 (void)inp;
94 udphdr = (struct udp_hdr *)(u8_t *)iphdr + IPH_HL(iphdr) * 4;
96 src = ntohs(udphdr->src);
97 dest = ntohs(udphdr->dest);
99 pcb = pcb_cache;
100 if (pcb != NULL &&
101 pcb->remote_port == src &&
102 pcb->local_port == dest &&
103 (ip_addr_isany(&pcb->remote_ip) ||
104 ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src))) &&
105 (ip_addr_isany(&pcb->local_ip) ||
106 ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)))) {
107 return 1;
109 else {
110 for(pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) {
111 if (pcb->remote_port == src &&
112 pcb->local_port == dest &&
113 (ip_addr_isany(&pcb->remote_ip) ||
114 ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src))) &&
115 (ip_addr_isany(&pcb->local_ip) ||
116 ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)))) {
117 pcb_cache = pcb;
118 break;
122 if (pcb == NULL) {
123 for(pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) {
124 if (pcb->remote_port == 0 &&
125 pcb->local_port == dest &&
126 (ip_addr_isany(&pcb->remote_ip) ||
127 ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src))) &&
128 (ip_addr_isany(&pcb->local_ip) ||
129 ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)))) {
130 break;
137 if (pcb != NULL) {
138 return 1;
140 else {
141 return 1;
144 #endif /* LWIP_DEBUG */
146 * Process an incoming UDP datagram.
148 * Given an incoming UDP datagram (as a chain of pbufs) this function
149 * finds a corresponding UDP PCB and
151 * @param pbuf pbuf to be demultiplexed to a UDP PCB.
152 * @param netif network interface on which the datagram was received.
155 void
156 udp_input(struct pbuf *p, struct netif *inp)
158 struct udp_hdr *udphdr;
159 struct udp_pcb *pcb;
160 struct ip_hdr *iphdr;
161 u16_t src, dest;
163 #ifdef SO_REUSE
164 struct udp_pcb *pcb_temp;
165 int reuse = 0;
166 int reuse_port_1 = 0;
167 int reuse_port_2 = 0;
168 #endif /* SO_REUSE */
170 UDP_STATS_INC(udp.recv);
172 iphdr = p->payload;
174 if (pbuf_header(p, -((s16_t)(UDP_HLEN + IPH_HL(iphdr) * 4)))) {
175 /* drop short packets */
176 LWIP_DEBUGF(UDP_DEBUG, ("udp_input: short UDP datagram (%u bytes) discarded\n", p->tot_len));
177 UDP_STATS_INC(udp.lenerr);
178 UDP_STATS_INC(udp.drop);
179 snmp_inc_udpinerrors();
180 pbuf_free(p);
181 goto end;
184 udphdr = (struct udp_hdr *)((u8_t *)p->payload - UDP_HLEN);
186 LWIP_DEBUGF(UDP_DEBUG, ("udp_input: received datagram of length %u\n", p->tot_len));
188 src = ntohs(udphdr->src);
189 dest = ntohs(udphdr->dest);
191 udp_debug_print(udphdr);
193 /* print the UDP source and destination */
194 LWIP_DEBUGF(UDP_DEBUG, ("udp (%u.%u.%u.%u, %u) <-- (%u.%u.%u.%u, %u)\n",
195 ip4_addr1(&iphdr->dest), ip4_addr2(&iphdr->dest),
196 ip4_addr3(&iphdr->dest), ip4_addr4(&iphdr->dest), ntohs(udphdr->dest),
197 ip4_addr1(&iphdr->src), ip4_addr2(&iphdr->src),
198 ip4_addr3(&iphdr->src), ip4_addr4(&iphdr->src), ntohs(udphdr->src)));
200 #ifdef SO_REUSE
201 pcb_temp = udp_pcbs;
203 again_1:
205 /* Iterate through the UDP pcb list for a fully matching pcb */
206 for(pcb = pcb_temp; pcb != NULL; pcb = pcb->next) {
207 #else /* SO_REUSE */
208 /* Iterate through the UDP pcb list for a fully matching pcb */
209 for(pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) {
210 #endif /* SO_REUSE */
211 /* print the PCB local and remote address */
212 LWIP_DEBUGF(UDP_DEBUG, ("pcb (%u.%u.%u.%u, %u) --- (%u.%u.%u.%u, %u)\n",
213 ip4_addr1(&pcb->local_ip), ip4_addr2(&pcb->local_ip),
214 ip4_addr3(&pcb->local_ip), ip4_addr4(&pcb->local_ip), pcb->local_port,
215 ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip),
216 ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip), pcb->remote_port));
218 /* PCB remote port matches UDP source port? */
219 if ((pcb->remote_port == src) &&
220 /* PCB local port matches UDP destination port? */
221 (pcb->local_port == dest) &&
222 /* accepting from any remote (source) IP address? or... */
223 (ip_addr_isany(&pcb->remote_ip) ||
224 /* PCB remote IP address matches UDP source IP address? */
225 ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src))) &&
226 /* accepting on any local (netif) IP address? or... */
227 (ip_addr_isany(&pcb->local_ip) ||
228 /* PCB local IP address matches UDP destination IP address? */
229 ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)))) {
230 #ifdef SO_REUSE
231 if(pcb->so_options & SOF_REUSEPORT) {
232 if(reuse) {
233 /* We processed one PCB already */
234 LWIP_DEBUGF(UDP_DEBUG, ("udp_input: second or later PCB and SOF_REUSEPORT set.\n"));
235 } else {
236 /* First PCB with this address */
237 LWIP_DEBUGF(UDP_DEBUG, ("udp_input: first PCB and SOF_REUSEPORT set.\n"));
238 reuse = 1;
241 reuse_port_1 = 1;
242 p->ref++;
243 LWIP_DEBUGF(UDP_DEBUG, ("udp_input: reference counter on PBUF set to %i\n", p->ref));
244 } else {
245 if(reuse) {
246 /* We processed one PCB already */
247 LWIP_DEBUGF(UDP_DEBUG, ("udp_input: second or later PCB but SOF_REUSEPORT not set !\n"));
250 #endif /* SO_REUSE */
251 break;
254 /* no fully matching pcb found? then look for an unconnected pcb */
255 if (pcb == NULL) {
256 /* Iterate through the UDP PCB list for a pcb that matches
257 the local address. */
259 #ifdef SO_REUSE
260 pcb_temp = udp_pcbs;
262 again_2:
264 for(pcb = pcb_temp; pcb != NULL; pcb = pcb->next) {
265 #else /* SO_REUSE */
266 for(pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) {
267 #endif /* SO_REUSE */
268 LWIP_DEBUGF(UDP_DEBUG, ("pcb (%u.%u.%u.%u, %u) --- (%u.%u.%u.%u, %u)\n",
269 ip4_addr1(&pcb->local_ip), ip4_addr2(&pcb->local_ip),
270 ip4_addr3(&pcb->local_ip), ip4_addr4(&pcb->local_ip), pcb->local_port,
271 ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip),
272 ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip), pcb->remote_port));
273 /* unconnected? */
274 if (((pcb->flags & UDP_FLAGS_CONNECTED) == 0) &&
275 /* destination port matches? */
276 (pcb->local_port == dest) &&
277 /* not bound to a specific (local) interface address? or... */
278 (ip_addr_isany(&pcb->local_ip) ||
279 /* ...matching interface address? */
280 ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)))) {
281 #ifdef SO_REUSE
282 if(pcb->so_options & SOF_REUSEPORT) {
283 if(reuse) {
284 /* We processed one PCB already */
285 LWIP_DEBUGF(UDP_DEBUG, ("udp_input: second or later PCB and SOF_REUSEPORT set.\n"));
286 } else {
287 /* First PCB with this address */
288 LWIP_DEBUGF(UDP_DEBUG, ("udp_input: first PCB and SOF_REUSEPORT set.\n"));
289 reuse = 1;
292 reuse_port_2 = 1;
293 p->ref++;
294 LWIP_DEBUGF(UDP_DEBUG, ("udp_input: reference counter on PBUF set to %i\n", p->ref));
295 } else {
296 if(reuse) {
297 /* We processed one PCB already */
298 LWIP_DEBUGF(UDP_DEBUG, ("udp_input: second or later PCB but SOF_REUSEPORT not set !\n"));
301 #endif /* SO_REUSE */
302 break;
307 /* Check checksum if this is a match or if it was directed at us. */
308 if (pcb != NULL || ip_addr_cmp(&inp->ip_addr, &iphdr->dest))
310 LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE, ("udp_input: calculating checksum\n"));
311 pbuf_header(p, UDP_HLEN);
312 #ifdef IPv6
313 if (iphdr->nexthdr == IP_PROTO_UDPLITE) {
314 #else
315 if (IPH_PROTO(iphdr) == IP_PROTO_UDPLITE) {
316 #endif /* IPv4 */
317 /* Do the UDP Lite checksum */
318 if (inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src),
319 (struct ip_addr *)&(iphdr->dest),
320 IP_PROTO_UDPLITE, ntohs(udphdr->len)) != 0) {
321 LWIP_DEBUGF(UDP_DEBUG | 2, ("udp_input: UDP Lite datagram discarded due to failing checksum\n"));
322 UDP_STATS_INC(udp.chkerr);
323 UDP_STATS_INC(udp.drop);
324 snmp_inc_udpinerrors();
325 pbuf_free(p);
326 goto end;
328 } else {
329 if (udphdr->chksum != 0) {
330 if (inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src),
331 (struct ip_addr *)&(iphdr->dest),
332 IP_PROTO_UDP, p->tot_len) != 0) {
333 LWIP_DEBUGF(UDP_DEBUG | 2, ("udp_input: UDP datagram discarded due to failing checksum\n"));
335 UDP_STATS_INC(udp.chkerr);
336 UDP_STATS_INC(udp.drop);
337 snmp_inc_udpinerrors();
338 pbuf_free(p);
339 goto end;
343 pbuf_header(p, -UDP_HLEN);
344 if (pcb != NULL) {
345 snmp_inc_udpindatagrams();
346 pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src), src);
347 #ifdef SO_REUSE
348 /* First socket should receive now */
349 if(reuse_port_1 || reuse_port_2) {
350 /* We want to search on next socket after receiving */
351 pcb_temp = pcb->next;
353 if(reuse_port_1) {
354 /* We are searching connected sockets */
355 reuse_port_1 = 0;
356 reuse_port_2 = 0;
357 goto again_1;
358 } else {
359 /* We are searching unconnected sockets */
360 reuse_port_1 = 0;
361 reuse_port_2 = 0;
362 goto again_2;
365 #endif /* SO_REUSE */
366 } else {
367 #ifdef SO_REUSE
368 if(reuse) {
369 LWIP_DEBUGF(UDP_DEBUG, ("udp_input: freeing PBUF with reference counter set to %i\n", p->ref));
370 pbuf_free(p);
371 goto end;
373 #endif /* SO_REUSE */
374 LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE, ("udp_input: not for us.\n"));
376 /* No match was found, send ICMP destination port unreachable unless
377 destination address was broadcast/multicast. */
379 if (!ip_addr_isbroadcast(&iphdr->dest, &inp->netmask) &&
380 !ip_addr_ismulticast(&iphdr->dest)) {
382 /* adjust pbuf pointer */
383 p->payload = iphdr;
384 icmp_dest_unreach(p, ICMP_DUR_PORT);
386 UDP_STATS_INC(udp.proterr);
387 UDP_STATS_INC(udp.drop);
388 snmp_inc_udpnoports();
389 pbuf_free(p);
391 } else {
392 pbuf_free(p);
394 end:
395 return;
399 * Send data using UDP.
401 * @param pcb UDP PCB used to send the data.
402 * @param pbuf chain of pbuf's to be sent.
404 * @return lwIP error code.
405 * - ERR_OK. Successful. No error occured.
406 * - ERR_MEM. Out of memory.
407 * - ERR_USE. The specified ipaddr and port are already bound to by
408 * another UDP PCB.
410 * @see udp_disconnect()
412 err_t
413 udp_send(struct udp_pcb *pcb, struct pbuf *p)
415 struct udp_hdr *udphdr;
416 struct netif *netif;
417 struct ip_addr *src_ip;
418 err_t err;
419 struct pbuf *q; /* q will be sent down the stack */
421 LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | 3, ("udp_send\n"));
423 /* if the PCB is not yet bound to a port, bind it here */
424 if (pcb->local_port == 0) {
425 LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | 2, ("udp_send: not yet bound to a port, binding now\n"));
426 err = udp_bind(pcb, &pcb->local_ip, pcb->local_port);
427 if (err != ERR_OK) {
428 LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | 2, ("udp_send: forced port bind failed\n"));
429 return err;
433 /* not enough space to add an UDP header to first pbuf in given p chain? */
434 if (pbuf_header(p, UDP_HLEN)) {
435 /* allocate header in new pbuf */
436 q = pbuf_alloc(PBUF_IP, UDP_HLEN, PBUF_RAM);
437 /* new header pbuf could not be allocated? */
438 if (q == NULL) {
439 LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | 2, ("udp_send: could not allocate header\n"));
440 return ERR_MEM;
442 /* chain header q in front of given pbuf p */
443 pbuf_chain(q, p);
444 /* { first pbuf q points to header pbuf } */
445 LWIP_DEBUGF(UDP_DEBUG, ("udp_send: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p));
446 /* adding a header within p succeeded */
447 } else {
448 /* first pbuf q equals given pbuf */
449 q = p;
450 LWIP_DEBUGF(UDP_DEBUG, ("udp_send: added header in given pbuf %p\n", (void *)p));
452 /* { q now represents the packet to be sent */
453 udphdr = q->payload;
454 udphdr->src = htons(pcb->local_port);
455 udphdr->dest = htons(pcb->remote_port);
456 udphdr->chksum = 0x0000;
458 if ((netif = ip_route(&(pcb->remote_ip))) == NULL) {
459 LWIP_DEBUGF(UDP_DEBUG | 1, ("udp_send: No route to 0x%lx\n", pcb->remote_ip.addr));
460 UDP_STATS_INC(udp.rterr);
461 return ERR_RTE;
463 /* using IP_ANY_ADDR? */
464 if (ip_addr_isany(&pcb->local_ip)) {
465 /* use outgoing network interface IP address as source address */
466 src_ip = &(netif->ip_addr);
467 } else {
468 /* use UDP PCB local IP address as source address */
469 src_ip = &(pcb->local_ip);
472 LWIP_DEBUGF(UDP_DEBUG, ("udp_send: sending datagram of length %u\n", q->tot_len));
474 /* UDP Lite protocol? */
475 if (pcb->flags & UDP_FLAGS_UDPLITE) {
476 LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP LITE packet length %u\n", q->tot_len));
477 /* set UDP message length in UDP header */
478 udphdr->len = htons(pcb->chksum_len);
479 /* calculate checksum */
480 udphdr->chksum = inet_chksum_pseudo(q, src_ip, &(pcb->remote_ip),
481 IP_PROTO_UDP, pcb->chksum_len);
482 /* chksum zero must become 0xffff, as zero means 'no checksum' */
483 if (udphdr->chksum == 0x0000) udphdr->chksum = 0xffff;
484 /* output to IP */
485 err = ip_output_if (q, src_ip, &pcb->remote_ip, pcb->ttl, pcb->tos, IP_PROTO_UDPLITE, netif);
486 snmp_inc_udpoutdatagrams();
487 } else {
488 LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP packet length %u\n", q->tot_len));
489 udphdr->len = htons(q->tot_len);
490 /* calculate checksum */
491 if ((pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) {
492 udphdr->chksum = inet_chksum_pseudo(q, src_ip, &pcb->remote_ip, IP_PROTO_UDP, q->tot_len);
493 /* chksum zero must become 0xffff, as zero means 'no checksum' */
494 if (udphdr->chksum == 0x0000) udphdr->chksum = 0xffff;
496 LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP checksum 0x%04x\n", udphdr->chksum));
497 snmp_inc_udpoutdatagrams();
498 LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDP,)\n"));
499 /* output to IP */
500 err = ip_output_if(q, src_ip, &pcb->remote_ip, pcb->ttl, pcb->tos, IP_PROTO_UDP, netif);
503 /* did we chain a header earlier? */
504 if (q != p) {
505 /* free the header */
506 /* p is also still referenced by the caller, and will live on */
507 pbuf_free(q);
510 UDP_STATS_INC(udp.xmit);
511 return err;
515 * Bind an UDP PCB.
517 * @param pcb UDP PCB to be bound with a local address ipaddr and port.
518 * @param ipaddr local IP address to bind with. Use IP_ADDR_ANY to
519 * bind to all local interfaces.
520 * @param port local UDP port to bind with.
522 * @return lwIP error code.
523 * - ERR_OK. Successful. No error occured.
524 * - ERR_USE. The specified ipaddr and port are already bound to by
525 * another UDP PCB.
527 * @see udp_disconnect()
529 err_t
530 udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
532 struct udp_pcb *ipcb;
533 u8_t rebind;
534 #ifdef SO_REUSE
535 int reuse_port_all_set = 1;
536 #endif /* SO_REUSE */
537 LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | 3, ("udp_bind(ipaddr = "));
538 ip_addr_debug_print(UDP_DEBUG, ipaddr);
539 LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | 3, (", port = %u)\n", port));
541 rebind = 0;
542 /* Check for double bind and rebind of the same pcb */
543 for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) {
544 /* is this UDP PCB already on active list? */
545 if (pcb == ipcb) {
546 /* pcb may occur at most once in active list */
547 LWIP_ASSERT("rebind == 0", rebind == 0);
548 /* pcb already in list, just rebind */
549 rebind = 1;
552 #ifndef SO_REUSE
553 /* this code does not allow upper layer to share a UDP port for
554 listening to broadcast or multicast traffic (See SO_REUSE_ADDR and
555 SO_REUSE_PORT under *BSD). TODO: See where it fits instead, OR
556 combine with implementation of UDP PCB flags. Leon Woestenberg. */
557 #ifdef LWIP_UDP_TODO
558 /* port matches that of PCB in list? */
559 else if ((ipcb->local_port == port) &&
560 /* IP address matches, or one is IP_ADDR_ANY? */
561 (ip_addr_isany(&(ipcb->local_ip)) ||
562 ip_addr_isany(ipaddr) ||
563 ip_addr_cmp(&(ipcb->local_ip), ipaddr))) {
564 /* other PCB already binds to this local IP and port */
565 LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: local port %u already bound by another pcb\n", port));
566 return ERR_USE;
568 #endif
570 #else /* SO_REUSE */
571 /* Search through list of PCB's.
573 If there is a PCB bound to specified port and IP_ADDR_ANY another PCB can be bound to the interface IP
574 or to the loopback address on the same port if SOF_REUSEADDR is set. Any combination of PCB's bound to
575 the same local port, but to one address out of {IP_ADDR_ANY, 127.0.0.1, interface IP} at a time is valid.
576 But no two PCB's bound to same local port and same local address is valid.
578 If SOF_REUSEPORT is set several PCB's can be bound to same local port and same local address also. But then
579 all PCB's must have the SOF_REUSEPORT option set.
581 When the two options aren't set and specified port is already bound, ERR_USE is returned saying that
582 address is already in use. */
583 else if (ipcb->local_port == port) {
584 if(ip_addr_cmp(&(ipcb->local_ip), ipaddr)) {
585 if(pcb->so_options & SOF_REUSEPORT) {
586 LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: in UDP PCB's SO_REUSEPORT set and same address.\n"));
587 reuse_port_all_set = (reuse_port_all_set && (ipcb->so_options & SOF_REUSEPORT));
589 else {
590 LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: in UDP PCB's SO_REUSEPORT not set and same address.\n"));
591 return ERR_USE;
594 else if((ip_addr_isany(ipaddr) && !ip_addr_isany(&(ipcb->local_ip))) ||
595 (!ip_addr_isany(ipaddr) && ip_addr_isany(&(ipcb->local_ip)))) {
596 if(!(pcb->so_options & SOF_REUSEADDR) && !(pcb->so_options & SOF_REUSEPORT)) {
597 LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: in UDP PCB's SO_REUSEPORT or SO_REUSEADDR not set and not the same address.\n"));
598 return ERR_USE;
602 #endif /* SO_REUSE */
606 #ifdef SO_REUSE
607 /* If SOF_REUSEPORT isn't set in all PCB's bound to specified port and local address specified then
608 {IP, port} can't be reused. */
609 if(!reuse_port_all_set) {
610 LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: not all sockets have SO_REUSEPORT set.\n"));
611 return ERR_USE;
613 #endif /* SO_REUSE */
615 ip_addr_set(&pcb->local_ip, ipaddr);
616 /* no port specified? */
617 if (port == 0) {
618 #ifndef UDP_LOCAL_PORT_RANGE_START
619 #define UDP_LOCAL_PORT_RANGE_START 4096
620 #define UDP_LOCAL_PORT_RANGE_END 0x7fff
621 #endif
622 port = UDP_LOCAL_PORT_RANGE_START;
623 ipcb = udp_pcbs;
624 while ((ipcb != NULL) && (port != UDP_LOCAL_PORT_RANGE_END)) {
625 if (ipcb->local_port == port) {
626 port++;
627 ipcb = udp_pcbs;
628 } else
629 ipcb = ipcb->next;
631 if (ipcb != NULL) {
632 /* no more ports available in local range */
633 LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: out of free UDP ports\n"));
634 return ERR_USE;
637 pcb->local_port = port;
638 /* pcb not active yet? */
639 if (rebind == 0) {
640 /* place the PCB on the active list if not already there */
641 pcb->next = udp_pcbs;
642 udp_pcbs = pcb;
644 LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | DBG_STATE, ("udp_bind: bound to %u.%u.%u.%u, port %u\n",
645 (unsigned int)(ntohl(pcb->local_ip.addr) >> 24 & 0xff),
646 (unsigned int)(ntohl(pcb->local_ip.addr) >> 16 & 0xff),
647 (unsigned int)(ntohl(pcb->local_ip.addr) >> 8 & 0xff),
648 (unsigned int)(ntohl(pcb->local_ip.addr) & 0xff), pcb->local_port));
649 return ERR_OK;
652 * Connect an UDP PCB.
654 * This will associate the UDP PCB with the remote address.
656 * @param pcb UDP PCB to be connected with remote address ipaddr and port.
657 * @param ipaddr remote IP address to connect with.
658 * @param port remote UDP port to connect with.
660 * @return lwIP error code
662 * @see udp_disconnect()
664 err_t
665 udp_connect(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
667 struct udp_pcb *ipcb;
669 if (pcb->local_port == 0) {
670 err_t err = udp_bind(pcb, &pcb->local_ip, pcb->local_port);
671 if (err != ERR_OK)
672 return err;
675 ip_addr_set(&pcb->remote_ip, ipaddr);
676 pcb->remote_port = port;
677 pcb->flags |= UDP_FLAGS_CONNECTED;
678 /** TODO: this functionality belongs in upper layers */
679 #ifdef LWIP_UDP_TODO
680 /* Nail down local IP for netconn_addr()/getsockname() */
681 if (ip_addr_isany(&pcb->local_ip) && !ip_addr_isany(&pcb->remote_ip)) {
682 struct netif *netif;
684 if ((netif = ip_route(&(pcb->remote_ip))) == NULL) {
685 LWIP_DEBUGF(UDP_DEBUG, ("udp_connect: No route to 0x%lx\n", pcb->remote_ip.addr));
686 UDP_STATS_INC(udp.rterr);
687 return ERR_RTE;
689 /** TODO: this will bind the udp pcb locally, to the interface which
690 is used to route output packets to the remote address. However, we
691 might want to accept incoming packets on any interface! */
692 pcb->local_ip = netif->ip_addr;
693 } else if (ip_addr_isany(&pcb->remote_ip)) {
694 pcb->local_ip.addr = 0;
696 #endif
697 LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | DBG_STATE, ("udp_connect: connected to %u.%u.%u.%u, port %u\n",
698 (unsigned int)(ntohl(pcb->remote_ip.addr) >> 24 & 0xff),
699 (unsigned int)(ntohl(pcb->remote_ip.addr) >> 16 & 0xff),
700 (unsigned int)(ntohl(pcb->remote_ip.addr) >> 8 & 0xff),
701 (unsigned int)(ntohl(pcb->remote_ip.addr) & 0xff), pcb->remote_port));
703 /* Insert UDP PCB into the list of active UDP PCBs. */
704 for(ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) {
705 if (pcb == ipcb) {
706 /* already on the list, just return */
707 return ERR_OK;
710 /* PCB not yet on the list, add PCB now */
711 pcb->next = udp_pcbs;
712 udp_pcbs = pcb;
713 return ERR_OK;
716 void
717 udp_disconnect(struct udp_pcb *pcb)
719 pcb->flags &= ~UDP_FLAGS_CONNECTED;
722 void
723 udp_recv(struct udp_pcb *pcb,
724 void (* recv)(void *arg, struct udp_pcb *upcb, struct pbuf *p,
725 struct ip_addr *addr, u16_t port),
726 void *recv_arg)
728 /* remember recv() callback and user data */
729 pcb->recv = recv;
730 pcb->recv_arg = recv_arg;
733 * Remove an UDP PCB.
735 * @param pcb UDP PCB to be removed. The PCB is removed from the list of
736 * UDP PCB's and the data structure is freed from memory.
738 * @see udp_new()
740 void
741 udp_remove(struct udp_pcb *pcb)
743 struct udp_pcb *pcb2;
744 /* pcb to be removed is first in list? */
745 if (udp_pcbs == pcb) {
746 /* make list start at 2nd pcb */
747 udp_pcbs = udp_pcbs->next;
748 /* pcb not 1st in list */
749 } else for(pcb2 = udp_pcbs; pcb2 != NULL; pcb2 = pcb2->next) {
750 /* find pcb in udp_pcbs list */
751 if (pcb2->next != NULL && pcb2->next == pcb) {
752 /* remove pcb from list */
753 pcb2->next = pcb->next;
756 memp_free(MEMP_UDP_PCB, pcb);
759 * Create a UDP PCB.
761 * @return The UDP PCB which was created. NULL if the PCB data structure
762 * could not be allocated.
764 * @see udp_remove()
766 struct udp_pcb *
767 udp_new(void) {
768 struct udp_pcb *pcb;
769 pcb = memp_malloc(MEMP_UDP_PCB);
770 /* could allocate UDP PCB? */
771 if (pcb != NULL) {
772 /* initialize PCB to all zeroes */
773 mips_memset(pcb, 0, sizeof(struct udp_pcb));
774 pcb->ttl = UDP_TTL;
778 return pcb;
781 #if UDP_DEBUG
783 udp_debug_print(struct udp_hdr *udphdr)
785 LWIP_DEBUGF(UDP_DEBUG, ("UDP header:\n"));
786 LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n"));
787 LWIP_DEBUGF(UDP_DEBUG, ("| %5u | %5u | (src port, dest port)\n",
788 ntohs(udphdr->src), ntohs(udphdr->dest)));
789 LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n"));
790 LWIP_DEBUGF(UDP_DEBUG, ("| %5u | 0x%04x | (len, chksum)\n",
791 ntohs(udphdr->len), ntohs(udphdr->chksum)));
792 LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n"));
793 return 0;
795 #endif /* UDP_DEBUG */
797 #endif /* LWIP_UDP */