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