udp.c
Go to the documentation of this file.
1 /**
2  * @file udp.c
3  * @brief UDP (User Datagram Protocol)
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2019 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 1.9.6
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL UDP_TRACE_LEVEL
33 
34 //Dependencies
35 #include <string.h>
36 #include "core/net.h"
37 #include "core/ip.h"
38 #include "core/udp.h"
39 #include "core/socket.h"
40 #include "ipv4/ipv4.h"
41 #include "ipv4/ipv4_misc.h"
42 #include "ipv6/ipv6.h"
43 #include "ipv6/ipv6_misc.h"
44 #include "mibs/mib2_module.h"
45 #include "mibs/udp_mib_module.h"
46 #include "debug.h"
47 
48 //Check TCP/IP stack configuration
49 #if (UDP_SUPPORT == ENABLED)
50 
51 //Ephemeral ports are used for dynamic port assignment
52 static uint16_t udpDynamicPort;
53 //Mutex to prevent simultaneous access to the callback table
55 //Table that holds the registered user callbacks
57 
58 
59 /**
60  * @brief UDP related initialization
61  * @return Error code
62  **/
63 
65 {
66  //Reset ephemeral port number
67  udpDynamicPort = 0;
68 
69  //Create a mutex to prevent simultaneous access to the callback table
71  {
72  //Failed to create mutex
74  }
75 
76  //Initialize callback table
77  memset(udpCallbackTable, 0, sizeof(udpCallbackTable));
78 
79  //Successful initialization
80  return NO_ERROR;
81 }
82 
83 
84 /**
85  * @brief Get an ephemeral port number
86  * @return Ephemeral port
87  **/
88 
89 uint16_t udpGetDynamicPort(void)
90 {
91  uint_t port;
92 
93  //Retrieve current port number
94  port = udpDynamicPort;
95 
96  //Invalid port number?
97  if(port < SOCKET_EPHEMERAL_PORT_MIN || port > SOCKET_EPHEMERAL_PORT_MAX)
98  {
99  //Generate a random port number
102  }
103 
104  //Next dynamic port to use
106  {
107  //Increment port number
108  udpDynamicPort = port + 1;
109  }
110  else
111  {
112  //Wrap around if necessary
113  udpDynamicPort = SOCKET_EPHEMERAL_PORT_MIN;
114  }
115 
116  //Return an ephemeral port number
117  return port;
118 }
119 
120 
121 /**
122  * @brief Incoming UDP datagram processing
123  * @param[in] interface Underlying network interface
124  * @param[in] pseudoHeader UDP pseudo header
125  * @param[in] buffer Multi-part buffer containing the incoming UDP datagram
126  * @param[in] offset Offset to the first byte of the UDP header
127  * @return Error code
128  **/
129 
131  IpPseudoHeader *pseudoHeader, const NetBuffer *buffer, size_t offset)
132 {
133  error_t error;
134  uint_t i;
135  size_t length;
136  UdpHeader *header;
137  Socket *socket;
138  SocketQueueItem *queueItem;
139  NetBuffer *p;
140 
141  //Retrieve the length of the UDP datagram
142  length = netBufferGetLength(buffer) - offset;
143 
144  //Ensure the UDP header is valid
145  if(length < sizeof(UdpHeader))
146  {
147  //Number of received UDP datagrams that could not be delivered for
148  //reasons other than the lack of an application at the destination port
149  MIB2_INC_COUNTER32(udpGroup.udpInErrors, 1);
150  UDP_MIB_INC_COUNTER32(udpInErrors, 1);
151 
152  //Report an error
153  return ERROR_INVALID_HEADER;
154  }
155 
156  //Point to the UDP header
157  header = netBufferAt(buffer, offset);
158  //Sanity check
159  if(header == NULL)
160  return ERROR_FAILURE;
161 
162  //Debug message
163  TRACE_INFO("UDP datagram received (%" PRIuSIZE " bytes)...\r\n", length);
164  //Dump UDP header contents for debugging purpose
165  udpDumpHeader(header);
166 
167  //When UDP runs over IPv6, the checksum is mandatory
168  if(header->checksum != 0x0000 || pseudoHeader->length == sizeof(Ipv6PseudoHeader))
169  {
170  //Verify UDP checksum
171  if(ipCalcUpperLayerChecksumEx(pseudoHeader->data,
172  pseudoHeader->length, buffer, offset, length) != 0x0000)
173  {
174  //Debug message
175  TRACE_WARNING("Wrong UDP header checksum!\r\n");
176 
177  //Number of received UDP datagrams that could not be delivered for
178  //reasons other than the lack of an application at the destination port
179  MIB2_INC_COUNTER32(udpGroup.udpInErrors, 1);
180  UDP_MIB_INC_COUNTER32(udpInErrors, 1);
181 
182  //Report an error
183  return ERROR_WRONG_CHECKSUM;
184  }
185  }
186 
187  //Loop through opened sockets
188  for(i = 0; i < SOCKET_MAX_COUNT; i++)
189  {
190  //Point to the current socket
191  socket = socketTable + i;
192 
193  //UDP socket found?
194  if(socket->type != SOCKET_TYPE_DGRAM)
195  continue;
196  //Check whether the socket is bound to a particular interface
197  if(socket->interface && socket->interface != interface)
198  continue;
199  //Check destination port number
200  if(socket->localPort == 0 || socket->localPort != ntohs(header->destPort))
201  continue;
202  //Source port number filtering
203  if(socket->remotePort != 0 && socket->remotePort != ntohs(header->srcPort))
204  continue;
205 
206 #if (IPV4_SUPPORT == ENABLED)
207  //IPv4 packet received?
208  if(pseudoHeader->length == sizeof(Ipv4PseudoHeader))
209  {
210  //Destination IP address filtering
211  if(socket->localIpAddr.length != 0)
212  {
213  //An IPv4 address is expected
214  if(socket->localIpAddr.length != sizeof(Ipv4Addr))
215  continue;
216  //Filter out non-matching addresses
217  if(socket->localIpAddr.ipv4Addr != pseudoHeader->ipv4Data.destAddr)
218  continue;
219  }
220 
221  //Source IP address filtering
222  if(socket->remoteIpAddr.length != 0)
223  {
224  //An IPv4 address is expected
225  if(socket->remoteIpAddr.length != sizeof(Ipv4Addr))
226  continue;
227  //Filter out non-matching addresses
228  if(socket->remoteIpAddr.ipv4Addr != pseudoHeader->ipv4Data.srcAddr)
229  continue;
230  }
231  }
232  else
233 #endif
234 #if (IPV6_SUPPORT == ENABLED)
235  //IPv6 packet received?
236  if(pseudoHeader->length == sizeof(Ipv6PseudoHeader))
237  {
238  //Destination IP address filtering
239  if(socket->localIpAddr.length != 0)
240  {
241  //An IPv6 address is expected
242  if(socket->localIpAddr.length != sizeof(Ipv6Addr))
243  continue;
244  //Filter out non-matching addresses
245  if(!ipv6CompAddr(&socket->localIpAddr.ipv6Addr, &pseudoHeader->ipv6Data.destAddr))
246  continue;
247  }
248 
249  //Source IP address filtering
250  if(socket->remoteIpAddr.length != 0)
251  {
252  //An IPv6 address is expected
253  if(socket->remoteIpAddr.length != sizeof(Ipv6Addr))
254  continue;
255  //Filter out non-matching addresses
256  if(!ipv6CompAddr(&socket->remoteIpAddr.ipv6Addr, &pseudoHeader->ipv6Data.srcAddr))
257  continue;
258  }
259  }
260  else
261 #endif
262  //Invalid packet received?
263  {
264  //This should never occur...
265  continue;
266  }
267 
268  //The current socket meets all the criteria
269  break;
270  }
271 
272  //Point to the payload
273  offset += sizeof(UdpHeader);
274  length -= sizeof(UdpHeader);
275 
276  //No matching socket found?
277  if(i >= SOCKET_MAX_COUNT)
278  {
279  //Invoke user callback, if any
280  error = udpInvokeRxCallback(interface, pseudoHeader, header, buffer, offset);
281  //Return status code
282  return error;
283  }
284 
285  //Empty receive queue?
286  if(!socket->receiveQueue)
287  {
288  //Allocate a memory buffer to hold the data and the associated descriptor
289  p = netBufferAlloc(sizeof(SocketQueueItem) + length);
290 
291  //Successful memory allocation?
292  if(p != NULL)
293  {
294  //Point to the newly created item
295  queueItem = netBufferAt(p, 0);
296  queueItem->buffer = p;
297  //Add the newly created item to the queue
298  socket->receiveQueue = queueItem;
299  }
300  else
301  {
302  //Memory allocation failed
303  queueItem = NULL;
304  }
305  }
306  else
307  {
308  //Point to the very first item
309  queueItem = socket->receiveQueue;
310  //Reach the last item in the receive queue
311  for(i = 1; queueItem->next; i++)
312  queueItem = queueItem->next;
313 
314  //Make sure the receive queue is not full
315  if(i >= UDP_RX_QUEUE_SIZE)
317 
318  //Allocate a memory buffer to hold the data and the associated descriptor
319  p = netBufferAlloc(sizeof(SocketQueueItem) + length);
320 
321  //Successful memory allocation?
322  if(p != NULL)
323  {
324  //Add the newly created item to the queue
325  queueItem->next = netBufferAt(p, 0);
326  //Point to the newly created item
327  queueItem = queueItem->next;
328  queueItem->buffer = p;
329  }
330  else
331  {
332  //Memory allocation failed
333  queueItem = NULL;
334  }
335  }
336 
337  //Failed to allocate memory?
338  if(queueItem == NULL)
339  return ERROR_OUT_OF_MEMORY;
340 
341  //Initialize next field
342  queueItem->next = NULL;
343  //Record the source port number
344  queueItem->srcPort = ntohs(header->srcPort);
345 
346 #if (IPV4_SUPPORT == ENABLED)
347  //IPv4 remote address?
348  if(pseudoHeader->length == sizeof(Ipv4PseudoHeader))
349  {
350  //Save the source IPv4 address
351  queueItem->srcIpAddr.length = sizeof(Ipv4Addr);
352  queueItem->srcIpAddr.ipv4Addr = pseudoHeader->ipv4Data.srcAddr;
353  //Save the destination IPv4 address
354  queueItem->destIpAddr.length = sizeof(Ipv4Addr);
355  queueItem->destIpAddr.ipv4Addr = pseudoHeader->ipv4Data.destAddr;
356  }
357 #endif
358 #if (IPV6_SUPPORT == ENABLED)
359  //IPv6 remote address?
360  if(pseudoHeader->length == sizeof(Ipv6PseudoHeader))
361  {
362  //Save the source IPv6 address
363  queueItem->srcIpAddr.length = sizeof(Ipv6Addr);
364  queueItem->srcIpAddr.ipv6Addr = pseudoHeader->ipv6Data.srcAddr;
365  //Save the destination IPv6 address
366  queueItem->destIpAddr.length = sizeof(Ipv6Addr);
367  queueItem->destIpAddr.ipv6Addr = pseudoHeader->ipv6Data.destAddr;
368  }
369 #endif
370 
371  //Offset to the payload
372  queueItem->offset = sizeof(SocketQueueItem);
373  //Copy the payload
374  netBufferCopy(queueItem->buffer, queueItem->offset, buffer, offset, length);
375 
376  //Notify user that data is available
378 
379  //Total number of UDP datagrams delivered to UDP users
380  MIB2_INC_COUNTER32(udpGroup.udpInDatagrams, 1);
381  UDP_MIB_INC_COUNTER32(udpInDatagrams, 1);
382  UDP_MIB_INC_COUNTER64(udpHCInDatagrams, 1);
383 
384  //Successful processing
385  return NO_ERROR;
386 }
387 
388 
389 /**
390  * @brief Send a UDP datagram
391  * @param[in] socket Handle referencing the socket
392  * @param[in] destIpAddr IP address of the target host
393  * @param[in] destPort Target port number
394  * @param[in] data Pointer to data payload
395  * @param[in] length Length of the payload data
396  * @param[out] written Actual number of bytes written (optional parameter)
397  * @param[in] flags Set of flags that influences the behavior of this function
398  * @return Error code
399  **/
400 
402  uint16_t destPort, const void *data, size_t length, size_t *written,
403  uint_t flags)
404 {
405  error_t error;
406  size_t offset;
407  NetBuffer *buffer;
408 
409  //Ignore unused flags
411 
412  //Check whether the destination IP address is a multicast address
414  flags |= socket->multicastTtl;
415  else
416  flags |= socket->ttl;
417 
418  //Allocate a memory buffer to hold the UDP datagram
419  buffer = udpAllocBuffer(0, &offset);
420  //Failed to allocate buffer?
421  if(buffer == NULL)
422  return ERROR_OUT_OF_MEMORY;
423 
424  //Copy data payload
425  error = netBufferAppend(buffer, data, length);
426 
427  //Successful processing?
428  if(!error)
429  {
430  //Send UDP datagram
431  error = udpSendDatagramEx(socket->interface, NULL, socket->localPort,
432  destIpAddr, destPort, buffer, offset, flags);
433  }
434 
435  //Successful processing?
436  if(!error)
437  {
438  //Total number of data bytes successfully transmitted
439  if(written != NULL)
440  *written = length;
441  }
442 
443  //Free previously allocated memory
444  netBufferFree(buffer);
445  //Return status code
446  return error;
447 }
448 
449 
450 /**
451  * @brief Send a UDP datagram (raw interface)
452  * @param[in] interface Underlying network interface
453  * @param[in] srcIpAddr Source IP address (optional parameter)
454  * @param[in] srcPort Source port
455  * @param[in] destIpAddr IP address of the target host
456  * @param[in] destPort Target port number
457  * @param[in] buffer Multi-part buffer containing the payload
458  * @param[in] offset Offset to the first payload byte
459  * @param[in] flags Set of flags that influences the behavior of this function
460  * @return Error code
461  **/
462 
464  uint16_t srcPort, const IpAddr *destIpAddr, uint16_t destPort,
465  NetBuffer *buffer, size_t offset, uint_t flags)
466 {
467  error_t error;
468  size_t length;
469  UdpHeader *header;
470  IpPseudoHeader pseudoHeader;
471 
472  //Make room for the UDP header
473  offset -= sizeof(UdpHeader);
474  //Retrieve the length of the datagram
475  length = netBufferGetLength(buffer) - offset;
476 
477  //Point to the UDP header
478  header = netBufferAt(buffer, offset);
479  //Sanity check
480  if(header == NULL)
481  return ERROR_FAILURE;
482 
483  //Format UDP header
484  header->srcPort = htons(srcPort);
485  header->destPort = htons(destPort);
486  header->length = htons(length);
487  header->checksum = 0;
488 
489 #if (IPV4_SUPPORT == ENABLED)
490  //Destination address is an IPv4 address?
491  if(destIpAddr->length == sizeof(Ipv4Addr))
492  {
493  //Valid source IP address?
494  if(srcIpAddr != NULL && srcIpAddr->length == sizeof(Ipv4Addr))
495  {
496  //Copy the source IP address
497  pseudoHeader.ipv4Data.srcAddr = srcIpAddr->ipv4Addr;
498  }
499  else
500  {
502 
503  //Select the source IPv4 address and the relevant network interface
504  //to use when sending data to the specified destination host
505  error = ipv4SelectSourceAddr(&interface, destIpAddr->ipv4Addr,
506  &ipAddr);
507 
508  //Check status code
509  if(!error)
510  {
511  //Copy the resulting source IP address
512  pseudoHeader.ipv4Data.srcAddr = ipAddr;
513  }
514  else
515  {
516  //Handle the special case where the destination address is the
517  //broadcast address
518  if(destIpAddr->ipv4Addr == IPV4_BROADCAST_ADDR && interface != NULL)
519  {
520  //Use the unspecified address as source address
521  pseudoHeader.ipv4Data.srcAddr = IPV4_UNSPECIFIED_ADDR;
522  }
523  else
524  {
525  //Source address selection failed
526  return error;
527  }
528  }
529  }
530 
531  //Format IPv4 pseudo header
532  pseudoHeader.length = sizeof(Ipv4PseudoHeader);
533  pseudoHeader.ipv4Data.destAddr = destIpAddr->ipv4Addr;
534  pseudoHeader.ipv4Data.reserved = 0;
535  pseudoHeader.ipv4Data.protocol = IPV4_PROTOCOL_UDP;
536  pseudoHeader.ipv4Data.length = htons(length);
537 
538  //Calculate UDP header checksum
539  header->checksum = ipCalcUpperLayerChecksumEx(&pseudoHeader.ipv4Data,
540  sizeof(Ipv4PseudoHeader), buffer, offset, length);
541  }
542  else
543 #endif
544 #if (IPV6_SUPPORT == ENABLED)
545  //Destination address is an IPv6 address?
546  if(destIpAddr->length == sizeof(Ipv6Addr))
547  {
548  //Valid source IP address?
549  if(srcIpAddr != NULL && srcIpAddr->length == sizeof(Ipv6Addr))
550  {
551  //Copy the source IP address
552  pseudoHeader.ipv6Data.srcAddr = srcIpAddr->ipv6Addr;
553  }
554  else
555  {
556  //Select the source IPv6 address and the relevant network interface
557  //to use when sending data to the specified destination host
558  error = ipv6SelectSourceAddr(&interface, &destIpAddr->ipv6Addr,
559  &pseudoHeader.ipv6Data.srcAddr);
560  //Any error to report?
561  if(error)
562  return error;
563  }
564 
565  //Format IPv6 pseudo header
566  pseudoHeader.length = sizeof(Ipv6PseudoHeader);
567  pseudoHeader.ipv6Data.destAddr = destIpAddr->ipv6Addr;
568  pseudoHeader.ipv6Data.length = htonl(length);
569  pseudoHeader.ipv6Data.reserved = 0;
570  pseudoHeader.ipv6Data.nextHeader = IPV6_UDP_HEADER;
571 
572  //Calculate UDP header checksum
573  header->checksum = ipCalcUpperLayerChecksumEx(&pseudoHeader.ipv6Data,
574  sizeof(Ipv6PseudoHeader), buffer, offset, length);
575  }
576  else
577 #endif
578  //Invalid destination address?
579  {
580  //An internal error has occurred
581  return ERROR_FAILURE;
582  }
583 
584  //If the computed checksum is zero, it is transmitted as all ones. An all
585  //zero transmitted checksum value means that the transmitter generated no
586  //checksum
587  if(header->checksum == 0x0000)
588  {
589  header->checksum = 0xFFFF;
590  }
591 
592  //Total number of UDP datagrams sent from this entity
593  MIB2_INC_COUNTER32(udpGroup.udpOutDatagrams, 1);
594  UDP_MIB_INC_COUNTER32(udpOutDatagrams, 1);
595  UDP_MIB_INC_COUNTER64(udpHCOutDatagrams, 1);
596 
597  //Debug message
598  TRACE_INFO("Sending UDP datagram (%" PRIuSIZE " bytes)\r\n", length);
599  //Dump UDP header contents for debugging purpose
600  udpDumpHeader(header);
601 
602  //Send UDP datagram
603  error = ipSendDatagram(interface, &pseudoHeader, buffer, offset, flags);
604  //Return status code
605  return error;
606 }
607 
608 
609 /**
610  * @brief Receive data from a UDP socket
611  * @param[in] socket Handle referencing the socket
612  * @param[out] srcIpAddr Source IP address (optional)
613  * @param[out] srcPort Source port number (optional)
614  * @param[out] destIpAddr Destination IP address (optional)
615  * @param[out] data Buffer where to store the incoming data
616  * @param[in] size Maximum number of bytes that can be received
617  * @param[out] received Number of bytes that have been received
618  * @param[in] flags Set of flags that influences the behavior of this function
619  * @return Error code
620  **/
621 
623  IpAddr *destIpAddr, void *data, size_t size, size_t *received, uint_t flags)
624 {
625  SocketQueueItem *queueItem;
626 
627  //The SOCKET_FLAG_DONT_WAIT enables non-blocking operation
629  {
630  //The receive queue is empty?
631  if(!socket->receiveQueue)
632  {
633  //Set the events the application is interested in
634  socket->eventMask = SOCKET_EVENT_RX_READY;
635  //Reset the event object
636  osResetEvent(&socket->event);
637 
638  //Release exclusive access
640  //Wait until an event is triggered
641  osWaitForEvent(&socket->event, socket->timeout);
642  //Get exclusive access
644  }
645  }
646 
647  //Check whether the read operation timed out
648  if(!socket->receiveQueue)
649  {
650  //No data can be read
651  *received = 0;
652  //Report a timeout error
653  return ERROR_TIMEOUT;
654  }
655 
656  //Point to the first item in the receive queue
657  queueItem = socket->receiveQueue;
658  //Copy data to user buffer
659  *received = netBufferRead(data, queueItem->buffer, queueItem->offset, size);
660 
661  //Save the source IP address
662  if(srcIpAddr)
663  *srcIpAddr = queueItem->srcIpAddr;
664  //Save the source port number
665  if(srcPort)
666  *srcPort = queueItem->srcPort;
667  //Save the destination IP address
668  if(destIpAddr)
669  *destIpAddr = queueItem->destIpAddr;
670 
671  //If the SOCKET_FLAG_PEEK flag is set, the data is copied
672  //into the buffer but is not removed from the input queue
673  if(!(flags & SOCKET_FLAG_PEEK))
674  {
675  //Remove the item from the receive queue
676  socket->receiveQueue = queueItem->next;
677  //Deallocate memory buffer
678  netBufferFree(queueItem->buffer);
679  }
680 
681  //Update the state of events
683 
684  //Successful read operation
685  return NO_ERROR;
686 }
687 
688 
689 /**
690  * @brief Allocate a buffer to hold a UDP packet
691  * @param[in] length Desired payload length
692  * @param[out] offset Offset to the first byte of the payload
693  * @return The function returns a pointer to the newly allocated
694  * buffer. If the system is out of resources, NULL is returned
695  **/
696 
697 NetBuffer *udpAllocBuffer(size_t length, size_t *offset)
698 {
699  NetBuffer *buffer;
700 
701  //Allocate a buffer to hold the UDP header and the payload
702  buffer = ipAllocBuffer(length + sizeof(UdpHeader), offset);
703  //Failed to allocate buffer?
704  if(buffer == NULL)
705  return NULL;
706 
707  //Offset to the first byte of the payload
708  *offset += sizeof(UdpHeader);
709 
710  //Return a pointer to the freshly allocated buffer
711  return buffer;
712 }
713 
714 
715 /**
716  * @brief Update UDP related events
717  * @param[in] socket Handle referencing the socket
718  **/
719 
721 {
722  //Clear event flags
723  socket->eventFlags = 0;
724 
725  //The socket is marked as readable if a datagram is pending in the queue
726  if(socket->receiveQueue)
727  socket->eventFlags |= SOCKET_EVENT_RX_READY;
728 
729  //Check whether the socket is bound to a particular network interface
730  if(socket->interface != NULL)
731  {
732  //Handle link up and link down events
733  if(socket->interface->linkState)
734  socket->eventFlags |= SOCKET_EVENT_LINK_UP;
735  else
736  socket->eventFlags |= SOCKET_EVENT_LINK_DOWN;
737  }
738 
739  //Mask unused events
740  socket->eventFlags &= socket->eventMask;
741 
742  //Any event to signal?
743  if(socket->eventFlags)
744  {
745  //Unblock I/O operations currently in waiting state
746  osSetEvent(&socket->event);
747 
748  //Set user event to signaled state if necessary
749  if(socket->userEvent != NULL)
750  osSetEvent(socket->userEvent);
751  }
752 }
753 
754 
755 /**
756  * @brief Register user callback
757  * @param[in] interface Underlying network interface
758  * @param[in] port UDP port number
759  * @param[in] callback Callback function to be called when a datagram is received
760  * @param[in] param Callback function parameter (optional)
761  * @return Error code
762  **/
763 
765  uint16_t port, UdpRxCallback callback, void *param)
766 {
767  uint_t i;
768  UdpRxCallbackDesc *entry;
769 
770  //Acquire exclusive access to the callback table
772 
773  //Loop through the table
774  for(i = 0; i < UDP_CALLBACK_TABLE_SIZE; i++)
775  {
776  //Point to the current entry
777  entry = &udpCallbackTable[i];
778 
779  //Check whether the entry is currently in used
780  if(entry->callback == NULL)
781  {
782  //Create a new entry
783  entry->interface = interface;
784  entry->port = port;
785  entry->callback = callback;
786  entry->param = param;
787  //We are done
788  break;
789  }
790  }
791 
792  //Release exclusive access to the callback table
794 
795  //Failed to attach the specified user callback?
796  if(i >= UDP_CALLBACK_TABLE_SIZE)
797  return ERROR_OUT_OF_RESOURCES;
798 
799  //Successful processing
800  return NO_ERROR;
801 }
802 
803 
804 /**
805  * @brief Unregister user callback
806  * @param[in] interface Underlying network interface
807  * @param[in] port UDP port number
808  * @return Error code
809  **/
810 
812 {
813  error_t error;
814  uint_t i;
815  UdpRxCallbackDesc *entry;
816 
817  //Initialize status code
818  error = ERROR_FAILURE;
819 
820  //Acquire exclusive access to the callback table
822 
823  //Loop through the table
824  for(i = 0; i < UDP_CALLBACK_TABLE_SIZE; i++)
825  {
826  //Point to the current entry
827  entry = &udpCallbackTable[i];
828 
829  //Check whether the entry is currently in used
830  if(entry->callback != NULL)
831  {
832  //Does the specified port number match the current entry?
833  if(entry->port == port && entry->interface == interface)
834  {
835  //Unregister user callback
836  entry->callback = NULL;
837  //A matching entry has been found
838  error = NO_ERROR;
839  }
840  }
841  }
842 
843  //Release exclusive access to the callback table
845 
846  //Return status code
847  return error;
848 }
849 
850 
851 /**
852  * @brief Invoke user callback
853  * @param[in] interface Underlying network interface
854  * @param[in] pseudoHeader UDP pseudo header
855  * @param[in] header UDP header
856  * @param[in] buffer Multi-part buffer containing the payload
857  * @param[in] offset Offset to the first byte of the payload
858  * @return Error code
859  **/
860 
862  const UdpHeader *header, const NetBuffer *buffer, size_t offset)
863 {
864  error_t error;
865  uint_t i;
866  void *param;
867  UdpRxCallbackDesc *entry;
868 
869  //Initialize status code
870  error = ERROR_PORT_UNREACHABLE;
871 
872  //Acquire exclusive access to the callback table
874 
875  //Loop through the table
876  for(i = 0; i < UDP_CALLBACK_TABLE_SIZE; i++)
877  {
878  //Point to the current entry
879  entry = &udpCallbackTable[i];
880 
881  //Check whether the entry is currently in used
882  if(entry->callback != NULL)
883  {
884  //Bound to a particular interface?
885  if(entry->interface == NULL || entry->interface == interface)
886  {
887  //Does the specified port number match the current entry?
888  if(entry->port == ntohs(header->destPort))
889  {
890  //Retrieve callback parameter
891  param = entry->param;
892 
893  //Release mutex to prevent any deadlock
894  if(param == NULL)
896 
897  //Invoke user callback function
898  entry->callback(interface, pseudoHeader,
899  header, buffer, offset, param);
900 
901  //Acquire mutex
902  if(param == NULL)
904 
905  //A matching entry has been found
906  error = NO_ERROR;
907  }
908  }
909  }
910  }
911 
912  //Release exclusive access to the callback table
914 
915  //Check status code
916  if(error)
917  {
918  //Total number of received UDP datagrams for which there was
919  //no application at the destination port
920  MIB2_INC_COUNTER32(udpGroup.udpNoPorts, 1);
921  UDP_MIB_INC_COUNTER32(udpNoPorts, 1);
922  }
923  else
924  {
925  //Total number of UDP datagrams delivered to UDP users
926  MIB2_INC_COUNTER32(udpGroup.udpInDatagrams, 1);
927  UDP_MIB_INC_COUNTER32(udpInDatagrams, 1);
928  UDP_MIB_INC_COUNTER64(udpHCInDatagrams, 1);
929  }
930 
931  //Return status code
932  return error;
933 }
934 
935 
936 /**
937  * @brief Dump UDP header for debugging purpose
938  * @param[in] datagram Pointer to the UDP header
939  **/
940 
941 void udpDumpHeader(const UdpHeader *datagram)
942 {
943  //Dump UDP header contents
944  TRACE_DEBUG(" Source Port = %" PRIu16 "\r\n", ntohs(datagram->srcPort));
945  TRACE_DEBUG(" Destination Port = %" PRIu16 "\r\n", ntohs(datagram->destPort));
946  TRACE_DEBUG(" Length = %" PRIu16 "\r\n", ntohs(datagram->length));
947  TRACE_DEBUG(" Checksum = 0x%04" PRIX16 "\r\n", ntohs(datagram->checksum));
948 }
949 
950 #endif
error_t udpSendDatagramEx(NetInterface *interface, const IpAddr *srcIpAddr, uint16_t srcPort, const IpAddr *destIpAddr, uint16_t destPort, NetBuffer *buffer, size_t offset, uint_t flags)
Send a UDP datagram (raw interface)
Definition: udp.c:463
#define htons(value)
Definition: cpu_endian.h:392
IPv6 (Internet Protocol Version 6)
MIB-II module.
uint8_t length
Definition: dtls_misc.h:149
NetBuffer * ipAllocBuffer(size_t length, size_t *offset)
Allocate a buffer to hold an IP packet.
Definition: ip.c:637
Ipv6PseudoHeader ipv6Data
Definition: ip.h:99
bool_t osCreateMutex(OsMutex *mutex)
Create a mutex object.
struct _SocketQueueItem SocketQueueItem
Receive queue item.
void udpUpdateEvents(Socket *socket)
Update UDP related events.
Definition: udp.c:720
IP network address.
Definition: ip.h:71
size_t netBufferRead(void *dest, const NetBuffer *src, size_t srcOffset, size_t length)
Read data from a multi-part buffer.
Definition: net_mem.c:672
uint8_t p
Definition: ndp.h:298
@ SOCKET_FLAG_DONT_ROUTE
Definition: socket.h:119
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:88
@ ERROR_INVALID_HEADER
Definition: error.h:86
@ ERROR_OUT_OF_RESOURCES
Definition: error.h:64
uint16_t srcPort
Definition: socket.h:201
Entry describing a user callback.
Definition: udp.h:104
@ SOCKET_TYPE_DGRAM
Definition: socket.h:78
error_t ipv4SelectSourceAddr(NetInterface **interface, Ipv4Addr destAddr, Ipv4Addr *srcAddr)
IPv4 source address selection.
Definition: ipv4_misc.c:163
IpAddr srcIpAddr
Definition: socket.h:200
OsMutex udpCallbackMutex
Definition: udp.c:54
error_t udpReceiveDatagram(Socket *socket, IpAddr *srcIpAddr, uint16_t *srcPort, IpAddr *destIpAddr, void *data, size_t size, size_t *received, uint_t flags)
Receive data from a UDP socket.
Definition: udp.c:622
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
uint8_t data[4]
Definition: ip.h:101
#define ipv6CompAddr(ipAddr1, ipAddr2)
Definition: ipv6.h:121
error_t udpInvokeRxCallback(NetInterface *interface, const IpPseudoHeader *pseudoHeader, const UdpHeader *header, const NetBuffer *buffer, size_t offset)
Invoke user callback.
Definition: udp.c:861
uint16_t destPort
Definition: tcp.h:303
error_t ipSendDatagram(NetInterface *interface, IpPseudoHeader *pseudoHeader, NetBuffer *buffer, size_t offset, uint_t flags)
Send an IP datagram.
Definition: ip.c:59
#define UDP_MIB_INC_COUNTER64(name, value)
Ipv4Addr srcIpAddr
Definition: ipcp.h:77
struct _SocketQueueItem * next
Definition: socket.h:199
size_t length
Definition: ip.h:92
uint32_t Ipv4Addr
IPv4 network address.
Definition: ipv4.h:239
#define SOCKET_EPHEMERAL_PORT_MIN
Definition: socket.h:52
@ SOCKET_FLAG_PEEK
Definition: socket.h:118
IP pseudo header.
Definition: ip.h:90
#define UDP_MIB_INC_COUNTER32(name, value)
Helper functions for IPv4.
#define SOCKET_EPHEMERAL_PORT_MAX
Definition: socket.h:59
#define htonl(value)
Definition: cpu_endian.h:393
void osResetEvent(OsEvent *event)
Set the specified event object to the nonsignaled state.
UDP MIB module.
UdpRxCallbackDesc udpCallbackTable[UDP_CALLBACK_TABLE_SIZE]
Definition: udp.c:56
error_t
Error codes.
Definition: error.h:42
bool_t ipIsMulticastAddr(const IpAddr *ipAddr)
Determine whether an IP address is a multicast address.
Definition: ip.c:254
void * param
Definition: udp.h:109
#define Ipv6PseudoHeader
Definition: ipv6.h:42
error_t ipv6SelectSourceAddr(NetInterface **interface, const Ipv6Addr *destAddr, Ipv6Addr *srcAddr)
IPv6 source address selection.
Definition: ipv6_misc.c:882
void * netBufferAt(const NetBuffer *buffer, size_t offset)
Returns a pointer to the data at the specified position.
Definition: net_mem.c:413
int_t socket(int_t family, int_t type, int_t protocol)
Create a socket that is bound to a specific transport service provider.
Definition: bsd_socket.c:108
@ IPV6_UDP_HEADER
Definition: ipv6.h:186
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
@ SOCKET_EVENT_LINK_DOWN
Definition: socket.h:163
error_t udpDetachRxCallback(NetInterface *interface, uint16_t port)
Unregister user callback.
Definition: udp.c:811
error_t udpInit(void)
UDP related initialization.
Definition: udp.c:64
#define NetInterface
Definition: net.h:36
NetInterface * interface
Definition: tcp.h:375
error_t udpAttachRxCallback(NetInterface *interface, uint16_t port, UdpRxCallback callback, void *param)
Register user callback.
Definition: udp.c:764
void netBufferFree(NetBuffer *buffer)
Dispose a multi-part buffer.
Definition: net_mem.c:282
Helper functions for IPv6.
OsMutex netMutex
Definition: net.c:75
__start_packed struct @179 Ipv6Addr
IPv6 network address.
IpAddr destIpAddr
Definition: socket.h:202
__start_packed struct @122 UdpHeader
UDP header.
UdpRxCallback callback
Definition: udp.h:108
error_t netBufferCopy(NetBuffer *dest, size_t destOffset, const NetBuffer *src, size_t srcOffset, size_t length)
Copy data between multi-part buffers.
Definition: net_mem.c:504
#define Ipv4PseudoHeader
Definition: ipv4.h:39
#define TRACE_INFO(...)
Definition: debug.h:94
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
NetBuffer * udpAllocBuffer(size_t length, size_t *offset)
Allocate a buffer to hold a UDP packet.
Definition: udp.c:697
size_t length
Definition: ip.h:73
#define UDP_CALLBACK_TABLE_SIZE
Definition: udp.h:48
Socket socketTable[SOCKET_MAX_COUNT]
Definition: socket.c:49
#define IPV4_BROADCAST_ADDR
Definition: ipv4.h:106
uint32_t netGetRand(void)
Get a random value.
Definition: net.c:1810
@ SOCKET_EVENT_LINK_UP
Definition: socket.h:162
uint16_t udpGetDynamicPort(void)
Get an ephemeral port number.
Definition: udp.c:89
Mutex object.
NetBuffer * netBufferAlloc(size_t length)
Allocate a multi-part buffer.
Definition: net_mem.c:243
uint16_t port
Definition: dns_common.h:223
#define ntohs(value)
Definition: cpu_endian.h:398
Receive queue item.
Definition: socket.h:197
uint8_t flags
Definition: tcp.h:314
#define TRACE_WARNING(...)
Definition: debug.h:84
#define TRACE_DEBUG(...)
Definition: debug.h:106
@ ERROR_TIMEOUT
Definition: error.h:94
Ipv4Addr ipv4Addr
Definition: ip.h:77
uint16_t ipCalcUpperLayerChecksumEx(const void *pseudoHeader, size_t pseudoHeaderLen, const NetBuffer *buffer, size_t offset, size_t length)
Calculate IP upper-layer checksum over a multi-part buffer.
Definition: ip.c:612
uint16_t port
Definition: udp.h:107
#define UDP_RX_QUEUE_SIZE
Definition: udp.h:55
IPv4 and IPv6 common routines.
@ SOCKET_EVENT_RX_READY
Definition: socket.h:160
bool_t osWaitForEvent(OsEvent *event, systime_t timeout)
Wait until the specified event is in the signaled state.
@ IPV4_PROTOCOL_UDP
Definition: ipv4.h:217
error_t netBufferAppend(NetBuffer *dest, const void *src, size_t length)
Append data a multi-part buffer.
Definition: net_mem.c:586
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
#define MIB2_INC_COUNTER32(name, value)
Definition: mib2_module.h:156
UDP (User Datagram Protocol)
#define Socket
Definition: socket.h:36
Socket API.
NetInterface * interface
Definition: udp.h:106
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
@ ERROR_RECEIVE_QUEUE_FULL
Definition: error.h:93
@ ERROR_WRONG_CHECKSUM
Definition: error.h:87
IPv4 (Internet Protocol Version 4)
void(* UdpRxCallback)(NetInterface *interface, const IpPseudoHeader *pseudoHeader, const UdpHeader *header, const NetBuffer *buffer, size_t offset, void *param)
Data received callback.
Definition: udp.h:96
uint16_t srcPort
Definition: tcp.h:302
Ipv6Addr ipv6Addr
Definition: ip.h:80
#define PRIuSIZE
Definition: compiler_port.h:78
unsigned int uint_t
Definition: compiler_port.h:45
@ SOCKET_FLAG_DONT_WAIT
Definition: socket.h:121
@ ERROR_PORT_UNREACHABLE
Definition: error.h:84
void udpDumpHeader(const UdpHeader *datagram)
Dump UDP header for debugging purpose.
Definition: udp.c:941
TCP/IP stack core.
uint8_t data[]
Definition: dtls_misc.h:176
error_t udpSendDatagram(Socket *socket, const IpAddr *destIpAddr, uint16_t destPort, const void *data, size_t length, size_t *written, uint_t flags)
Send a UDP datagram.
Definition: udp.c:401
#define SOCKET_MAX_COUNT
Definition: socket.h:45
error_t udpProcessDatagram(NetInterface *interface, IpPseudoHeader *pseudoHeader, const NetBuffer *buffer, size_t offset)
Incoming UDP datagram processing.
Definition: udp.c:130
uint8_t ipAddr[4]
Definition: mib_common.h:187
Ipv4PseudoHeader ipv4Data
Definition: ip.h:96
NetBuffer * buffer
Definition: socket.h:203
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
size_t offset
Definition: socket.h:204
#define IPV4_UNSPECIFIED_ADDR
Definition: ipv4.h:104
Ipv4Addr destIpAddr
Definition: ipcp.h:78