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