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