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-2023 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 2.2.2
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/if_mib_module.h"
46 #include "mibs/udp_mib_module.h"
47 #include "debug.h"
48 
49 //Check TCP/IP stack configuration
50 #if (UDP_SUPPORT == ENABLED)
51 
52 //Ephemeral ports are used for dynamic port assignment
53 static uint16_t udpDynamicPort;
54 //Table that holds the registered user callbacks
56 
57 
58 /**
59  * @brief UDP related initialization
60  * @return Error code
61  **/
62 
64 {
65  //Reset ephemeral port number
66  udpDynamicPort = 0;
67 
68  //Initialize callback table
70 
71  //Successful initialization
72  return NO_ERROR;
73 }
74 
75 
76 /**
77  * @brief Get an ephemeral port number
78  * @return Ephemeral port
79  **/
80 
81 uint16_t udpGetDynamicPort(void)
82 {
83  uint_t port;
84 
85  //Retrieve current port number
86  port = udpDynamicPort;
87 
88  //Invalid port number?
89  if(port < SOCKET_EPHEMERAL_PORT_MIN || port > SOCKET_EPHEMERAL_PORT_MAX)
90  {
91  //Generate a random port number
94  }
95 
96  //Next dynamic port to use
98  {
99  //Increment port number
100  udpDynamicPort = port + 1;
101  }
102  else
103  {
104  //Wrap around if necessary
105  udpDynamicPort = SOCKET_EPHEMERAL_PORT_MIN;
106  }
107 
108  //Return an ephemeral port number
109  return port;
110 }
111 
112 
113 /**
114  * @brief Incoming UDP datagram processing
115  * @param[in] interface Underlying network interface
116  * @param[in] pseudoHeader UDP pseudo header
117  * @param[in] buffer Multi-part buffer containing the incoming UDP datagram
118  * @param[in] offset Offset to the first byte of the UDP header
119  * @param[in] ancillary Additional options passed to the stack along with
120  * the packet
121  * @return Error code
122  **/
123 
125  const NetBuffer *buffer, size_t offset, NetRxAncillary *ancillary)
126 {
127  error_t error;
128  uint_t i;
129  size_t length;
130  UdpHeader *header;
131  Socket *socket;
132  SocketQueueItem *queueItem;
133  NetBuffer *p;
134 
135  //Retrieve the length of the UDP datagram
136  length = netBufferGetLength(buffer) - offset;
137 
138  //Ensure the UDP header is valid
139  if(length < sizeof(UdpHeader))
140  {
141  //Number of received UDP datagrams that could not be delivered for
142  //reasons other than the lack of an application at the destination port
143  MIB2_UDP_INC_COUNTER32(udpInErrors, 1);
144  UDP_MIB_INC_COUNTER32(udpInErrors, 1);
145 
146  //Report an error
147  return ERROR_INVALID_HEADER;
148  }
149 
150  //Point to the UDP header
151  header = netBufferAt(buffer, offset);
152  //Sanity check
153  if(header == NULL)
154  return ERROR_FAILURE;
155 
156  //Debug message
157  TRACE_INFO("UDP datagram received (%" PRIuSIZE " bytes)...\r\n", length);
158  //Dump UDP header contents for debugging purpose
159  udpDumpHeader(header);
160 
161  //When UDP runs over IPv6, the checksum is mandatory
162  if(header->checksum != 0x0000 || pseudoHeader->length == sizeof(Ipv6PseudoHeader))
163  {
164  //Verify UDP checksum
165  if(ipCalcUpperLayerChecksumEx(pseudoHeader->data,
166  pseudoHeader->length, buffer, offset, length) != 0x0000)
167  {
168  //Debug message
169  TRACE_WARNING("Wrong UDP header checksum!\r\n");
170 
171  //Number of received UDP datagrams that could not be delivered for
172  //reasons other than the lack of an application at the destination port
173  MIB2_UDP_INC_COUNTER32(udpInErrors, 1);
174  UDP_MIB_INC_COUNTER32(udpInErrors, 1);
175 
176  //Report an error
177  return ERROR_WRONG_CHECKSUM;
178  }
179  }
180 
181  //Loop through opened sockets
182  for(i = 0; i < SOCKET_MAX_COUNT; i++)
183  {
184  //Point to the current socket
185  socket = socketTable + i;
186 
187  //UDP socket found?
188  if(socket->type != SOCKET_TYPE_DGRAM)
189  continue;
190  //Check whether the socket is bound to a particular interface
191  if(socket->interface && socket->interface != interface)
192  continue;
193  //Check destination port number
194  if(socket->localPort == 0 || socket->localPort != ntohs(header->destPort))
195  continue;
196  //Source port number filtering
197  if(socket->remotePort != 0 && socket->remotePort != ntohs(header->srcPort))
198  continue;
199 
200 #if (IPV4_SUPPORT == ENABLED)
201  //IPv4 packet received?
202  if(pseudoHeader->length == sizeof(Ipv4PseudoHeader))
203  {
204  //Destination IP address filtering
205  if(socket->localIpAddr.length != 0)
206  {
207  //An IPv4 address is expected
208  if(socket->localIpAddr.length != sizeof(Ipv4Addr))
209  continue;
210 
211  //Filter out non-matching addresses
212  if(socket->localIpAddr.ipv4Addr != IPV4_UNSPECIFIED_ADDR &&
213  socket->localIpAddr.ipv4Addr != pseudoHeader->ipv4Data.destAddr)
214  {
215  continue;
216  }
217  }
218 
219  //Source IP address filtering
220  if(socket->remoteIpAddr.length != 0)
221  {
222  //An IPv4 address is expected
223  if(socket->remoteIpAddr.length != sizeof(Ipv4Addr))
224  continue;
225 
226  //Filter out non-matching addresses
227  if(socket->remoteIpAddr.ipv4Addr != IPV4_UNSPECIFIED_ADDR &&
228  socket->remoteIpAddr.ipv4Addr != pseudoHeader->ipv4Data.srcAddr)
229  {
230  continue;
231  }
232  }
233  }
234  else
235 #endif
236 #if (IPV6_SUPPORT == ENABLED)
237  //IPv6 packet received?
238  if(pseudoHeader->length == sizeof(Ipv6PseudoHeader))
239  {
240  //Destination IP address filtering
241  if(socket->localIpAddr.length != 0)
242  {
243  //An IPv6 address is expected
244  if(socket->localIpAddr.length != sizeof(Ipv6Addr))
245  continue;
246 
247  //Filter out non-matching addresses
248  if(!ipv6CompAddr(&socket->localIpAddr.ipv6Addr, &IPV6_UNSPECIFIED_ADDR) &&
249  !ipv6CompAddr(&socket->localIpAddr.ipv6Addr, &pseudoHeader->ipv6Data.destAddr))
250  {
251  continue;
252  }
253  }
254 
255  //Source IP address filtering
256  if(socket->remoteIpAddr.length != 0)
257  {
258  //An IPv6 address is expected
259  if(socket->remoteIpAddr.length != sizeof(Ipv6Addr))
260  continue;
261 
262  //Filter out non-matching addresses
263  if(!ipv6CompAddr(&socket->remoteIpAddr.ipv6Addr, &IPV6_UNSPECIFIED_ADDR) &&
264  !ipv6CompAddr(&socket->remoteIpAddr.ipv6Addr, &pseudoHeader->ipv6Data.srcAddr))
265  {
266  continue;
267  }
268  }
269  }
270  else
271 #endif
272  //Invalid packet received?
273  {
274  //This should never occur...
275  continue;
276  }
277 
278  //The current socket meets all the criteria
279  break;
280  }
281 
282  //Point to the payload
283  offset += sizeof(UdpHeader);
284  length -= sizeof(UdpHeader);
285 
286  //No matching socket found?
287  if(i >= SOCKET_MAX_COUNT)
288  {
289  //Invoke user callback, if any
290  error = udpInvokeRxCallback(interface, pseudoHeader, header, buffer,
291  offset, ancillary);
292  //Return status code
293  return error;
294  }
295 
296  //Empty receive queue?
297  if(socket->receiveQueue == NULL)
298  {
299  //Allocate a memory buffer to hold the data and the associated descriptor
300  p = netBufferAlloc(sizeof(SocketQueueItem) + length);
301 
302  //Successful memory allocation?
303  if(p != NULL)
304  {
305  //Point to the newly created item
306  queueItem = netBufferAt(p, 0);
307  queueItem->buffer = p;
308  //Add the newly created item to the queue
309  socket->receiveQueue = queueItem;
310  }
311  else
312  {
313  //Memory allocation failed
314  queueItem = NULL;
315  }
316  }
317  else
318  {
319  //Point to the very first item
320  queueItem = socket->receiveQueue;
321 
322  //Reach the last item in the receive queue
323  for(i = 1; queueItem->next; i++)
324  {
325  queueItem = queueItem->next;
326  }
327 
328  //Check whether the receive queue is full
329  if(i >= UDP_RX_QUEUE_SIZE)
330  {
331  //Number of inbound packets which were chosen to be discarded even
332  //though no errors had been detected
333  MIB2_IF_INC_COUNTER32(ifTable[interface->index].ifInDiscards, 1);
334  IF_MIB_INC_COUNTER32(ifTable[interface->index].ifInDiscards, 1);
335 
336  //Report an error
338  }
339 
340  //Allocate a memory buffer to hold the data and the associated descriptor
341  p = netBufferAlloc(sizeof(SocketQueueItem) + length);
342 
343  //Successful memory allocation?
344  if(p != NULL)
345  {
346  //Add the newly created item to the queue
347  queueItem->next = netBufferAt(p, 0);
348  //Point to the newly created item
349  queueItem = queueItem->next;
350  queueItem->buffer = p;
351  }
352  else
353  {
354  //Memory allocation failed
355  queueItem = NULL;
356  }
357  }
358 
359  //Not enough resources to properly handle the packet?
360  if(queueItem == NULL)
361  {
362  //Number of inbound packets which were chosen to be discarded even
363  //though no errors had been detected
364  MIB2_IF_INC_COUNTER32(ifTable[interface->index].ifInDiscards, 1);
365  IF_MIB_INC_COUNTER32(ifTable[interface->index].ifInDiscards, 1);
366 
367  //Report an error
368  return ERROR_OUT_OF_MEMORY;
369  }
370 
371  //Initialize next field
372  queueItem->next = NULL;
373  //Network interface where the packet was received
374  queueItem->interface = interface;
375  //Record the source port number
376  queueItem->srcPort = ntohs(header->srcPort);
377 
378 #if (IPV4_SUPPORT == ENABLED)
379  //IPv4 remote address?
380  if(pseudoHeader->length == sizeof(Ipv4PseudoHeader))
381  {
382  //Save the source IPv4 address
383  queueItem->srcIpAddr.length = sizeof(Ipv4Addr);
384  queueItem->srcIpAddr.ipv4Addr = pseudoHeader->ipv4Data.srcAddr;
385 
386  //Save the destination IPv4 address
387  queueItem->destIpAddr.length = sizeof(Ipv4Addr);
388  queueItem->destIpAddr.ipv4Addr = pseudoHeader->ipv4Data.destAddr;
389  }
390 #endif
391 #if (IPV6_SUPPORT == ENABLED)
392  //IPv6 remote address?
393  if(pseudoHeader->length == sizeof(Ipv6PseudoHeader))
394  {
395  //Save the source IPv6 address
396  queueItem->srcIpAddr.length = sizeof(Ipv6Addr);
397  queueItem->srcIpAddr.ipv6Addr = pseudoHeader->ipv6Data.srcAddr;
398 
399  //Save the destination IPv6 address
400  queueItem->destIpAddr.length = sizeof(Ipv6Addr);
401  queueItem->destIpAddr.ipv6Addr = pseudoHeader->ipv6Data.destAddr;
402  }
403 #endif
404 
405  //Offset to the payload
406  queueItem->offset = sizeof(SocketQueueItem);
407  //Copy the payload
408  netBufferCopy(queueItem->buffer, queueItem->offset, buffer, offset, length);
409 
410  //Additional options can be passed to the stack along with the packet
411  queueItem->ancillary = *ancillary;
412 
413  //Notify user that data is available
415 
416  //Total number of UDP datagrams delivered to UDP users
417  MIB2_UDP_INC_COUNTER32(udpInDatagrams, 1);
418  UDP_MIB_INC_COUNTER32(udpInDatagrams, 1);
419  UDP_MIB_INC_COUNTER64(udpHCInDatagrams, 1);
420 
421  //Successful processing
422  return NO_ERROR;
423 }
424 
425 
426 /**
427  * @brief Send a UDP datagram
428  * @param[in] socket Handle referencing the socket
429  * @param[in] message Pointer to the structure describing the datagram
430  * @param[in] flags Set of flags that influences the behavior of this function
431  * @return Error code
432  **/
433 
435 {
436  error_t error;
437  size_t offset;
438  NetBuffer *buffer;
440  NetTxAncillary ancillary;
441 
442  //Select the relevant network interface
443  if(message->interface != NULL)
444  {
445  interface = message->interface;
446  }
447  else
448  {
449  interface = socket->interface;
450  }
451 
452  //Allocate a memory buffer to hold the UDP datagram
453  buffer = udpAllocBuffer(0, &offset);
454  //Failed to allocate buffer?
455  if(buffer == NULL)
456  return ERROR_OUT_OF_MEMORY;
457 
458  //Copy data payload
459  error = netBufferAppend(buffer, message->data, message->length);
460 
461  //Successful processing?
462  if(!error)
463  {
464  //Additional options can be passed to the stack along with the packet
465  ancillary = NET_DEFAULT_TX_ANCILLARY;
466 
467  //Set the TTL value to be used
468  if(message->ttl != 0)
469  {
470  ancillary.ttl = message->ttl;
471  }
472  else if(ipIsMulticastAddr(&message->destIpAddr))
473  {
474  ancillary.ttl = socket->multicastTtl;
475  }
476  else
477  {
478  ancillary.ttl = socket->ttl;
479  }
480 
481  //This flag tells the stack that the destination is on a locally attached
482  //network and not to perform a lookup of the routing table
483  if((flags & SOCKET_FLAG_DONT_ROUTE) != 0)
484  {
485  ancillary.dontRoute = TRUE;
486  }
487 
488 #if (IP_DIFF_SERV_SUPPORT == ENABLED)
489  //Set DSCP field
490  ancillary.dscp = socket->dscp;
491 #endif
492 
493 #if (ETH_SUPPORT == ENABLED)
494  //Set source and destination MAC addresses
495  ancillary.srcMacAddr = message->srcMacAddr;
496  ancillary.destMacAddr = message->destMacAddr;
497 #endif
498 
499 #if (ETH_VLAN_SUPPORT == ENABLED)
500  //Set VLAN PCP and DEI fields
501  ancillary.vlanPcp = socket->vlanPcp;
502  ancillary.vlanDei = socket->vlanDei;
503 #endif
504 
505 #if (ETH_VMAN_SUPPORT == ENABLED)
506  //Set VMAN PCP and DEI fields
507  ancillary.vmanPcp = socket->vmanPcp;
508  ancillary.vmanDei = socket->vmanDei;
509 #endif
510 
511 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
512  //Set switch port identifier
513  ancillary.port = message->switchPort;
514 #endif
515 
516 #if (ETH_TIMESTAMP_SUPPORT == ENABLED)
517  //Unique identifier for hardware time stamping
518  ancillary.timestampId = message->timestampId;
519 #endif
520 
521  //Send UDP datagram
522  error = udpSendBuffer(interface, &message->srcIpAddr, socket->localPort,
523  &message->destIpAddr, message->destPort, buffer, offset, &ancillary);
524  }
525 
526  //Free previously allocated memory
527  netBufferFree(buffer);
528 
529  //Return status code
530  return error;
531 }
532 
533 
534 /**
535  * @brief Send a UDP datagram
536  * @param[in] interface Underlying network interface
537  * @param[in] srcIpAddr Source IP address (optional parameter)
538  * @param[in] srcPort Source port
539  * @param[in] destIpAddr IP address of the target host
540  * @param[in] destPort Target port number
541  * @param[in] buffer Multi-part buffer containing the payload
542  * @param[in] offset Offset to the first payload byte
543  * @param[in] ancillary Additional options passed to the stack along with
544  * the packet
545  * @return Error code
546  **/
547 
549  uint16_t srcPort, const IpAddr *destIpAddr, uint16_t destPort,
550  NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
551 {
552  error_t error;
553  size_t length;
554  UdpHeader *header;
555  IpPseudoHeader pseudoHeader;
556 
557  //Make room for the UDP header
558  offset -= sizeof(UdpHeader);
559  //Retrieve the length of the datagram
560  length = netBufferGetLength(buffer) - offset;
561 
562  //Point to the UDP header
563  header = netBufferAt(buffer, offset);
564  //Sanity check
565  if(header == NULL)
566  return ERROR_FAILURE;
567 
568  //Format UDP header
569  header->srcPort = htons(srcPort);
570  header->destPort = htons(destPort);
571  header->length = htons(length);
572  header->checksum = 0;
573 
574 #if (IPV4_SUPPORT == ENABLED)
575  //Destination address is an IPv4 address?
576  if(destIpAddr->length == sizeof(Ipv4Addr))
577  {
578  //Valid source IP address?
579  if(srcIpAddr != NULL && srcIpAddr->length == sizeof(Ipv4Addr))
580  {
581  //Copy the source IP address
582  pseudoHeader.ipv4Data.srcAddr = srcIpAddr->ipv4Addr;
583  }
584  else
585  {
587 
588  //Select the source IPv4 address and the relevant network interface
589  //to use when sending data to the specified destination host
590  error = ipv4SelectSourceAddr(&interface, destIpAddr->ipv4Addr,
591  &ipAddr);
592 
593  //Check status code
594  if(!error)
595  {
596  //Copy the resulting source IP address
597  pseudoHeader.ipv4Data.srcAddr = ipAddr;
598  }
599  else
600  {
601  //Handle the special case where the destination address is the
602  //broadcast address
603  if(destIpAddr->ipv4Addr == IPV4_BROADCAST_ADDR && interface != NULL)
604  {
605  //Use the unspecified address as source address
606  pseudoHeader.ipv4Data.srcAddr = IPV4_UNSPECIFIED_ADDR;
607  }
608  else
609  {
610  //Source address selection failed
611  return error;
612  }
613  }
614  }
615 
616  //Format IPv4 pseudo header
617  pseudoHeader.length = sizeof(Ipv4PseudoHeader);
618  pseudoHeader.ipv4Data.destAddr = destIpAddr->ipv4Addr;
619  pseudoHeader.ipv4Data.reserved = 0;
620  pseudoHeader.ipv4Data.protocol = IPV4_PROTOCOL_UDP;
621  pseudoHeader.ipv4Data.length = htons(length);
622 
623  //Calculate UDP header checksum
624  header->checksum = ipCalcUpperLayerChecksumEx(&pseudoHeader.ipv4Data,
625  sizeof(Ipv4PseudoHeader), buffer, offset, length);
626  }
627  else
628 #endif
629 #if (IPV6_SUPPORT == ENABLED)
630  //Destination address is an IPv6 address?
631  if(destIpAddr->length == sizeof(Ipv6Addr))
632  {
633  //Valid source IP address?
634  if(srcIpAddr != NULL && srcIpAddr->length == sizeof(Ipv6Addr))
635  {
636  //Copy the source IP address
637  pseudoHeader.ipv6Data.srcAddr = srcIpAddr->ipv6Addr;
638  }
639  else
640  {
641  //Select the source IPv6 address and the relevant network interface
642  //to use when sending data to the specified destination host
643  error = ipv6SelectSourceAddr(&interface, &destIpAddr->ipv6Addr,
644  &pseudoHeader.ipv6Data.srcAddr);
645  //Any error to report?
646  if(error)
647  return error;
648  }
649 
650  //Format IPv6 pseudo header
651  pseudoHeader.length = sizeof(Ipv6PseudoHeader);
652  pseudoHeader.ipv6Data.destAddr = destIpAddr->ipv6Addr;
653  pseudoHeader.ipv6Data.length = htonl(length);
654  pseudoHeader.ipv6Data.reserved[0] = 0;
655  pseudoHeader.ipv6Data.reserved[1] = 0;
656  pseudoHeader.ipv6Data.reserved[2] = 0;
657  pseudoHeader.ipv6Data.nextHeader = IPV6_UDP_HEADER;
658 
659  //Calculate UDP header checksum
660  header->checksum = ipCalcUpperLayerChecksumEx(&pseudoHeader.ipv6Data,
661  sizeof(Ipv6PseudoHeader), buffer, offset, length);
662  }
663  else
664 #endif
665  //Invalid destination address?
666  {
667  //An internal error has occurred
668  return ERROR_FAILURE;
669  }
670 
671  //If the computed checksum is zero, it is transmitted as all ones. An all
672  //zero transmitted checksum value means that the transmitter generated no
673  //checksum
674  if(header->checksum == 0x0000)
675  {
676  header->checksum = 0xFFFF;
677  }
678 
679  //Total number of UDP datagrams sent from this entity
680  MIB2_UDP_INC_COUNTER32(udpOutDatagrams, 1);
681  UDP_MIB_INC_COUNTER32(udpOutDatagrams, 1);
682  UDP_MIB_INC_COUNTER64(udpHCOutDatagrams, 1);
683 
684  //Debug message
685  TRACE_INFO("Sending UDP datagram (%" PRIuSIZE " bytes)\r\n", length);
686  //Dump UDP header contents for debugging purpose
687  udpDumpHeader(header);
688 
689  //Send UDP datagram
690  error = ipSendDatagram(interface, &pseudoHeader, buffer, offset, ancillary);
691 
692  //Return status code
693  return error;
694 }
695 
696 
697 /**
698  * @brief Receive data from a UDP socket
699  * @param[in] socket Handle referencing the socket
700  * @param[out] message Received UDP datagram and ancillary data
701  * @param[in] flags Set of flags that influences the behavior of this function
702  * @return Error code
703  **/
704 
706 {
707  error_t error;
708  SocketQueueItem *queueItem;
709 
710  //The SOCKET_FLAG_DONT_WAIT enables non-blocking operation
711  if((flags & SOCKET_FLAG_DONT_WAIT) == 0)
712  {
713  //Check whether the receive queue is empty
714  if(socket->receiveQueue == NULL)
715  {
716  //Set the events the application is interested in
717  socket->eventMask = SOCKET_EVENT_RX_READY;
718 
719  //Reset the event object
720  osResetEvent(&socket->event);
721 
722  //Release exclusive access
724  //Wait until an event is triggered
725  osWaitForEvent(&socket->event, socket->timeout);
726  //Get exclusive access
728  }
729  }
730 
731  //Any datagram received?
732  if(socket->receiveQueue != NULL)
733  {
734  //Point to the first item in the receive queue
735  queueItem = socket->receiveQueue;
736 
737  //Copy data to user buffer
738  message->length = netBufferRead(message->data, queueItem->buffer,
739  queueItem->offset, message->size);
740 
741  //Network interface where the packet was received
742  message->interface = queueItem->interface;
743  //Save the source IP address
744  message->srcIpAddr = queueItem->srcIpAddr;
745  //Save the source port number
746  message->srcPort = queueItem->srcPort;
747  //Save the destination IP address
748  message->destIpAddr = queueItem->destIpAddr;
749 
750  //Save TTL value
751  message->ttl = queueItem->ancillary.ttl;
752 
753 #if (ETH_SUPPORT == ENABLED)
754  //Save source and destination MAC addresses
755  message->srcMacAddr = queueItem->ancillary.srcMacAddr;
756  message->destMacAddr = queueItem->ancillary.destMacAddr;
757 #endif
758 
759 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
760  //Save switch port identifier
761  message->switchPort = queueItem->ancillary.port;
762 #endif
763 
764 #if (ETH_TIMESTAMP_SUPPORT == ENABLED)
765  //Save captured time stamp
766  message->timestamp = queueItem->ancillary.timestamp;
767 #endif
768 
769  //If the SOCKET_FLAG_PEEK flag is set, the data is copied into the
770  //buffer but is not removed from the input queue
771  if((flags & SOCKET_FLAG_PEEK) == 0)
772  {
773  //Remove the item from the receive queue
774  socket->receiveQueue = queueItem->next;
775 
776  //Deallocate memory buffer
777  netBufferFree(queueItem->buffer);
778  }
779 
780  //Update the state of events
782 
783  //Successful read operation
784  error = NO_ERROR;
785  }
786  else
787  {
788  //Total number of data that have been received
789  message->length = 0;
790 
791  //Report a timeout error
792  error = ERROR_TIMEOUT;
793  }
794 
795  //Return status code
796  return error;
797 }
798 
799 
800 /**
801  * @brief Allocate a buffer to hold a UDP packet
802  * @param[in] length Desired payload length
803  * @param[out] offset Offset to the first byte of the payload
804  * @return The function returns a pointer to the newly allocated
805  * buffer. If the system is out of resources, NULL is returned
806  **/
807 
808 NetBuffer *udpAllocBuffer(size_t length, size_t *offset)
809 {
810  NetBuffer *buffer;
811 
812  //Allocate a buffer to hold the UDP header and the payload
813  buffer = ipAllocBuffer(length + sizeof(UdpHeader), offset);
814  //Failed to allocate buffer?
815  if(buffer == NULL)
816  return NULL;
817 
818  //Offset to the first byte of the payload
819  *offset += sizeof(UdpHeader);
820 
821  //Return a pointer to the freshly allocated buffer
822  return buffer;
823 }
824 
825 
826 /**
827  * @brief Update UDP related events
828  * @param[in] socket Handle referencing the socket
829  **/
830 
832 {
833  //Clear event flags
834  socket->eventFlags = 0;
835 
836  //The socket is marked as readable if a datagram is pending in the queue
837  if(socket->receiveQueue)
838  socket->eventFlags |= SOCKET_EVENT_RX_READY;
839 
840  //Check whether the socket is bound to a particular network interface
841  if(socket->interface != NULL)
842  {
843  //Handle link up and link down events
844  if(socket->interface->linkState)
845  socket->eventFlags |= SOCKET_EVENT_LINK_UP;
846  else
847  socket->eventFlags |= SOCKET_EVENT_LINK_DOWN;
848  }
849 
850  //Mask unused events
851  socket->eventFlags &= socket->eventMask;
852 
853  //Any event to signal?
854  if(socket->eventFlags)
855  {
856  //Unblock I/O operations currently in waiting state
857  osSetEvent(&socket->event);
858 
859  //Set user event to signaled state if necessary
860  if(socket->userEvent != NULL)
861  {
862  osSetEvent(socket->userEvent);
863  }
864  }
865 }
866 
867 
868 /**
869  * @brief Register user callback
870  * @param[in] interface Underlying network interface
871  * @param[in] port UDP port number
872  * @param[in] callback Callback function to be called when a datagram is received
873  * @param[in] param Callback function parameter (optional)
874  * @return Error code
875  **/
876 
878  UdpRxCallback callback, void *param)
879 {
880  uint_t i;
881  UdpRxCallbackEntry *entry;
882 
883  //Loop through the table
884  for(i = 0; i < UDP_CALLBACK_TABLE_SIZE; i++)
885  {
886  //Point to the current entry
887  entry = &udpCallbackTable[i];
888 
889  //Check whether the entry is currently in use
890  if(entry->callback == NULL)
891  {
892  //Create a new entry
893  entry->interface = interface;
894  entry->port = port;
895  entry->callback = callback;
896  entry->param = param;
897  //We are done
898  break;
899  }
900  }
901 
902  //Failed to attach the specified user callback?
903  if(i >= UDP_CALLBACK_TABLE_SIZE)
904  return ERROR_OUT_OF_RESOURCES;
905 
906  //Successful processing
907  return NO_ERROR;
908 }
909 
910 
911 /**
912  * @brief Unregister user callback
913  * @param[in] interface Underlying network interface
914  * @param[in] port UDP port number
915  * @return Error code
916  **/
917 
919 {
920  error_t error;
921  uint_t i;
922  UdpRxCallbackEntry *entry;
923 
924  //Initialize status code
925  error = ERROR_FAILURE;
926 
927  //Loop through the table
928  for(i = 0; i < UDP_CALLBACK_TABLE_SIZE; i++)
929  {
930  //Point to the current entry
931  entry = &udpCallbackTable[i];
932 
933  //Check whether the entry is currently in use
934  if(entry->callback != NULL)
935  {
936  //Does the specified port number match the current entry?
937  if(entry->port == port && entry->interface == interface)
938  {
939  //Unregister user callback
940  entry->callback = NULL;
941  //A matching entry has been found
942  error = NO_ERROR;
943  }
944  }
945  }
946 
947  //Return status code
948  return error;
949 }
950 
951 
952 /**
953  * @brief Invoke user callback
954  * @param[in] interface Underlying network interface
955  * @param[in] pseudoHeader UDP pseudo header
956  * @param[in] header UDP header
957  * @param[in] buffer Multi-part buffer containing the payload
958  * @param[in] offset Offset to the first byte of the payload
959  * @param[in] ancillary Additional options passed to the stack along with
960  * the packet
961  * @return Error code
962  **/
963 
965  const IpPseudoHeader *pseudoHeader, const UdpHeader *header,
966  const NetBuffer *buffer, size_t offset, NetRxAncillary *ancillary)
967 {
968  error_t error;
969  uint_t i;
970  UdpRxCallbackEntry *entry;
971 
972  //Initialize status code
973  error = ERROR_PORT_UNREACHABLE;
974 
975  //Loop through the table
976  for(i = 0; i < UDP_CALLBACK_TABLE_SIZE; i++)
977  {
978  //Point to the current entry
979  entry = &udpCallbackTable[i];
980 
981  //Check whether the entry is currently in use
982  if(entry->callback != NULL)
983  {
984  //Bound to a particular interface?
985  if(entry->interface == NULL || entry->interface == interface)
986  {
987  //Does the specified port number match the current entry?
988  if(entry->port == ntohs(header->destPort))
989  {
990  //Invoke user callback function
991  entry->callback(interface, pseudoHeader, header, buffer, offset,
992  ancillary, entry->param);
993 
994  //A matching entry has been found
995  error = NO_ERROR;
996  }
997  }
998  }
999  }
1000 
1001  //Check status code
1002  if(error)
1003  {
1004  //Total number of received UDP datagrams for which there was
1005  //no application at the destination port
1006  MIB2_UDP_INC_COUNTER32(udpNoPorts, 1);
1007  UDP_MIB_INC_COUNTER32(udpNoPorts, 1);
1008  }
1009  else
1010  {
1011  //Total number of UDP datagrams delivered to UDP users
1012  MIB2_UDP_INC_COUNTER32(udpInDatagrams, 1);
1013  UDP_MIB_INC_COUNTER32(udpInDatagrams, 1);
1014  UDP_MIB_INC_COUNTER64(udpHCInDatagrams, 1);
1015  }
1016 
1017  //Return status code
1018  return error;
1019 }
1020 
1021 
1022 /**
1023  * @brief Dump UDP header for debugging purpose
1024  * @param[in] datagram Pointer to the UDP header
1025  **/
1026 
1027 void udpDumpHeader(const UdpHeader *datagram)
1028 {
1029  //Dump UDP header contents
1030  TRACE_DEBUG(" Source Port = %" PRIu16 "\r\n", ntohs(datagram->srcPort));
1031  TRACE_DEBUG(" Destination Port = %" PRIu16 "\r\n", ntohs(datagram->destPort));
1032  TRACE_DEBUG(" Length = %" PRIu16 "\r\n", ntohs(datagram->length));
1033  TRACE_DEBUG(" Checksum = 0x%04" PRIX16 "\r\n", ntohs(datagram->checksum));
1034 }
1035 
1036 #endif
uint8_t length
Definition: coap_common.h:193
#define htons(value)
Definition: cpu_endian.h:413
IPv6 (Internet Protocol Version 6)
MIB-II module.
NetBuffer * ipAllocBuffer(size_t length, size_t *offset)
Allocate a buffer to hold an IP packet.
Definition: ip.c:717
Ipv6PseudoHeader ipv6Data
Definition: ip.h:106
struct _SocketQueueItem SocketQueueItem
Receive queue item.
const NetTxAncillary NET_DEFAULT_TX_ANCILLARY
Definition: net_misc.c:71
#define netMutex
Definition: net_legacy.h:195
void udpUpdateEvents(Socket *socket)
Update UDP related events.
Definition: udp.c:831
IP network address.
Definition: ip.h:79
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
__start_packed struct @0 UdpHeader
UDP header.
uint8_t p
Definition: ndp.h:298
@ SOCKET_FLAG_DONT_ROUTE
Definition: socket.h:120
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
#define TRUE
Definition: os_port.h:50
Message and ancillary data.
Definition: socket.h:200
@ ERROR_INVALID_HEADER
Definition: error.h:87
@ ERROR_OUT_OF_RESOURCES
Definition: error.h:64
uint16_t srcPort
Definition: socket.h:234
uint16_t port
Definition: udp.h:109
@ SOCKET_TYPE_DGRAM
Definition: socket.h:79
error_t ipSendDatagram(NetInterface *interface, IpPseudoHeader *pseudoHeader, NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send an IP datagram.
Definition: ip.c:60
error_t ipv4SelectSourceAddr(NetInterface **interface, Ipv4Addr destAddr, Ipv4Addr *srcAddr)
IPv4 source address selection.
Definition: ipv4_misc.c:203
IpAddr srcIpAddr
Definition: socket.h:233
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
uint8_t data[4]
Definition: ip.h:108
#define ipv6CompAddr(ipAddr1, ipAddr2)
Definition: ipv6.h:121
uint16_t destPort
Definition: tcp.h:338
#define UDP_MIB_INC_COUNTER64(name, value)
Ipv4Addr srcIpAddr
Definition: ipcp.h:77
struct _SocketQueueItem * next
Definition: socket.h:231
size_t length
Definition: ip.h:99
error_t udpProcessDatagram(NetInterface *interface, IpPseudoHeader *pseudoHeader, const NetBuffer *buffer, size_t offset, NetRxAncillary *ancillary)
Incoming UDP datagram processing.
Definition: udp.c:124
error_t udpInvokeRxCallback(NetInterface *interface, const IpPseudoHeader *pseudoHeader, const UdpHeader *header, const NetBuffer *buffer, size_t offset, NetRxAncillary *ancillary)
Invoke user callback.
Definition: udp.c:964
uint32_t Ipv4Addr
IPv4 network address.
Definition: ipv4.h:261
#define SOCKET_EPHEMERAL_PORT_MIN
Definition: socket.h:53
error_t udpReceiveDatagram(Socket *socket, SocketMsg *message, uint_t flags)
Receive data from a UDP socket.
Definition: udp.c:705
@ SOCKET_FLAG_PEEK
Definition: socket.h:119
#define MIB2_UDP_INC_COUNTER32(name, value)
Definition: mib2_module.h:185
IP pseudo header.
Definition: ip.h:98
#define UDP_MIB_INC_COUNTER32(name, value)
NetRxAncillary ancillary
Definition: socket.h:238
Helper functions for IPv4.
#define SOCKET_EPHEMERAL_PORT_MAX
Definition: socket.h:60
#define htonl(value)
Definition: cpu_endian.h:414
void osResetEvent(OsEvent *event)
Set the specified event object to the nonsignaled state.
uint32_t netGenerateRandRange(uint32_t min, uint32_t max)
Generate a random value in the specified range.
Definition: net_misc.c:900
void * param
Definition: udp.h:111
void(* UdpRxCallback)(NetInterface *interface, const IpPseudoHeader *pseudoHeader, const UdpHeader *header, const NetBuffer *buffer, size_t offset, const NetRxAncillary *ancillary, void *param)
UDP receive callback.
Definition: udp.h:96
UDP MIB module.
error_t
Error codes.
Definition: error.h:43
bool_t ipIsMulticastAddr(const IpAddr *ipAddr)
Determine whether an IP address is a multicast address.
Definition: ip.c:241
#define Ipv6PseudoHeader
Definition: ipv6.h:42
UdpRxCallback callback
Definition: udp.h:110
error_t ipv6SelectSourceAddr(NetInterface **interface, const Ipv6Addr *destAddr, Ipv6Addr *srcAddr)
IPv6 source address selection.
Definition: ipv6_misc.c:879
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:63
UDP receive callback entry.
Definition: udp.h:107
#define MIB2_IF_INC_COUNTER32(name, value)
Definition: mib2_module.h:156
@ IPV6_UDP_HEADER
Definition: ipv6.h:182
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
NetInterface * interface
Definition: udp.h:108
@ SOCKET_EVENT_LINK_DOWN
Definition: socket.h:165
error_t udpDetachRxCallback(NetInterface *interface, uint16_t port)
Unregister user callback.
Definition: udp.c:918
error_t udpInit(void)
UDP related initialization.
Definition: udp.c:63
#define NetRxAncillary
Definition: net_misc.h:40
#define NetInterface
Definition: net.h:36
NetInterface * interface
Definition: tcp.h:398
error_t udpAttachRxCallback(NetInterface *interface, uint16_t port, UdpRxCallback callback, void *param)
Register user callback.
Definition: udp.c:877
void netBufferFree(NetBuffer *buffer)
Dispose a multi-part buffer.
Definition: net_mem.c:282
Helper functions for IPv6.
error_t udpSendBuffer(NetInterface *interface, const IpAddr *srcIpAddr, uint16_t srcPort, const IpAddr *destIpAddr, uint16_t destPort, NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send a UDP datagram.
Definition: udp.c:548
#define NetTxAncillary
Definition: net_misc.h:36
const Ipv6Addr IPV6_UNSPECIFIED_ADDR
Definition: ipv6.c:66
IpAddr destIpAddr
Definition: socket.h:235
error_t udpSendDatagram(Socket *socket, const SocketMsg *message, uint_t flags)
Send a UDP datagram.
Definition: udp.c:434
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:95
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
Interfaces Group MIB module.
NetBuffer * udpAllocBuffer(size_t length, size_t *offset)
Allocate a buffer to hold a UDP packet.
Definition: udp.c:808
size_t length
Definition: ip.h:80
#define UDP_CALLBACK_TABLE_SIZE
Definition: udp.h:48
Socket socketTable[SOCKET_MAX_COUNT]
Definition: socket.c:50
#define IPV4_BROADCAST_ADDR
Definition: ipv4.h:106
@ SOCKET_EVENT_LINK_UP
Definition: socket.h:164
uint16_t udpGetDynamicPort(void)
Get an ephemeral port number.
Definition: udp.c:81
NetBuffer * netBufferAlloc(size_t length)
Allocate a multi-part buffer.
Definition: net_mem.c:243
uint16_t port
Definition: dns_common.h:251
#define ntohs(value)
Definition: cpu_endian.h:421
Receive queue item.
Definition: socket.h:230
uint8_t flags
Definition: tcp.h:349
#define TRACE_WARNING(...)
Definition: debug.h:85
#define TRACE_DEBUG(...)
Definition: debug.h:107
@ ERROR_TIMEOUT
Definition: error.h:95
Ipv4Addr ipv4Addr
Definition: ip.h:84
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:692
#define UDP_RX_QUEUE_SIZE
Definition: udp.h:55
IPv4 and IPv6 common routines.
@ SOCKET_EVENT_RX_READY
Definition: socket.h:162
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.
#define IF_MIB_INC_COUNTER32(name, value)
Definition: if_mib_module.h:47
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
UDP (User Datagram Protocol)
#define Socket
Definition: socket.h:36
uint8_t message[]
Definition: chap.h:152
Socket API.
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
@ ERROR_RECEIVE_QUEUE_FULL
Definition: error.h:94
UdpRxCallbackEntry udpCallbackTable[UDP_CALLBACK_TABLE_SIZE]
Definition: udp.c:55
NetInterface * interface
Definition: socket.h:232
@ ERROR_WRONG_CHECKSUM
Definition: error.h:88
IPv4 (Internet Protocol Version 4)
uint16_t srcPort
Definition: tcp.h:337
Ipv6Addr ipv6Addr
Definition: ip.h:87
#define PRIuSIZE
unsigned int uint_t
Definition: compiler_port.h:50
@ SOCKET_FLAG_DONT_WAIT
Definition: socket.h:122
@ ERROR_PORT_UNREACHABLE
Definition: error.h:85
void udpDumpHeader(const UdpHeader *datagram)
Dump UDP header for debugging purpose.
Definition: udp.c:1027
#define osMemset(p, value, length)
Definition: os_port.h:131
TCP/IP stack core.
#define SOCKET_MAX_COUNT
Definition: socket.h:46
__start_packed struct @0 Ipv6Addr
IPv6 network address.
uint8_t ipAddr[4]
Definition: mib_common.h:187
Ipv4PseudoHeader ipv4Data
Definition: ip.h:103
NetBuffer * buffer
Definition: socket.h:236
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
size_t offset
Definition: socket.h:237
#define IPV4_UNSPECIFIED_ADDR
Definition: ipv4.h:104
Ipv4Addr destIpAddr
Definition: ipcp.h:78