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.4
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/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 IpPseudoHeader *pseudoHeader, const NetBuffer *buffer, size_t offset,
126  const NetRxAncillary *ancillary)
127 {
128  error_t error;
129  uint_t i;
130  size_t length;
131  UdpHeader *header;
132  Socket *socket;
133  SocketQueueItem *queueItem;
134  NetBuffer *p;
135 
136  //Retrieve the length of the UDP datagram
137  length = netBufferGetLength(buffer) - offset;
138 
139  //Ensure the UDP header is valid
140  if(length < sizeof(UdpHeader))
141  {
142  //Number of received UDP datagrams that could not be delivered for
143  //reasons other than the lack of an application at the destination port
144  MIB2_UDP_INC_COUNTER32(udpInErrors, 1);
145  UDP_MIB_INC_COUNTER32(udpInErrors, 1);
146 
147  //Report an error
148  return ERROR_INVALID_HEADER;
149  }
150 
151  //Point to the UDP header
152  header = netBufferAt(buffer, offset, sizeof(UdpHeader));
153  //Sanity check
154  if(header == NULL)
155  return ERROR_FAILURE;
156 
157  //Debug message
158  TRACE_INFO("UDP datagram received (%" PRIuSIZE " bytes)...\r\n", length);
159  //Dump UDP header contents for debugging purpose
160  udpDumpHeader(header);
161 
162  //Make sure the length field is correct
163  if(ntohs(header->length) < sizeof(UdpHeader) ||
164  ntohs(header->length) > length)
165  {
166  //Number of received UDP datagrams that could not be delivered for
167  //reasons other than the lack of an application at the destination port
168  MIB2_UDP_INC_COUNTER32(udpInErrors, 1);
169  UDP_MIB_INC_COUNTER32(udpInErrors, 1);
170 
171  //Report an error
172  return ERROR_INVALID_HEADER;
173  }
174 
175  //Convert the length field from network byte order
176  length = ntohs(header->length);
177 
178  //When UDP runs over IPv6, the checksum is mandatory
179  if(header->checksum != 0x0000 ||
180  pseudoHeader->length == sizeof(Ipv6PseudoHeader))
181  {
182  //Verify UDP checksum
183  if(ipCalcUpperLayerChecksumEx(pseudoHeader->data,
184  pseudoHeader->length, buffer, offset, length) != 0x0000)
185  {
186  //Debug message
187  TRACE_WARNING("Wrong UDP header checksum!\r\n");
188 
189  //Number of received UDP datagrams that could not be delivered for
190  //reasons other than the lack of an application at the destination port
191  MIB2_UDP_INC_COUNTER32(udpInErrors, 1);
192  UDP_MIB_INC_COUNTER32(udpInErrors, 1);
193 
194  //Report an error
195  return ERROR_WRONG_CHECKSUM;
196  }
197  }
198 
199  //Loop through opened sockets
200  for(i = 0; i < SOCKET_MAX_COUNT; i++)
201  {
202  //Point to the current socket
203  socket = &socketTable[i];
204 
205  //UDP socket found?
206  if(socket->type != SOCKET_TYPE_DGRAM)
207  continue;
208 
209  //Check whether the socket is bound to a particular interface
210  if(socket->interface != NULL && socket->interface != interface)
211  continue;
212 
213  //Check destination port number
214  if(socket->localPort == 0 || socket->localPort != ntohs(header->destPort))
215  continue;
216 
217  //Source port number filtering
218  if(socket->remotePort != 0 && socket->remotePort != ntohs(header->srcPort))
219  continue;
220 
221 #if (IPV4_SUPPORT == ENABLED)
222  //IPv4 packet received?
223  if(pseudoHeader->length == sizeof(Ipv4PseudoHeader))
224  {
225  //Check whether the socket is restricted to IPv6 communications only
226  if((socket->options & SOCKET_OPTION_IPV6_ONLY) != 0)
227  continue;
228 
229  //Check whether the destination address is a unicast, broadcast or
230  //multicast address
231  if(ipv4IsBroadcastAddr(interface, pseudoHeader->ipv4Data.destAddr))
232  {
233  //Check whether broadcast datagrams are accepted or not
234  if((socket->options & SOCKET_OPTION_BROADCAST) == 0)
235  continue;
236  }
237  else if(ipv4IsMulticastAddr(pseudoHeader->ipv4Data.destAddr))
238  {
239  IpAddr srcAddr;
241 
242  //Get source IPv4 address
243  srcAddr.length = sizeof(Ipv4Addr);
244  srcAddr.ipv4Addr = pseudoHeader->ipv4Data.srcAddr;
245 
246  //Get destination IPv4 address
247  destAddr.length = sizeof(Ipv4Addr);
248  destAddr.ipv4Addr = pseudoHeader->ipv4Data.destAddr;
249 
250  //Multicast address filtering
252  {
253  continue;
254  }
255  }
256  else
257  {
258  //Destination IP address filtering
259  if(socket->localIpAddr.length != 0)
260  {
261  //An IPv4 address is expected
262  if(socket->localIpAddr.length != sizeof(Ipv4Addr))
263  continue;
264 
265  //Filter out non-matching addresses
266  if(socket->localIpAddr.ipv4Addr != IPV4_UNSPECIFIED_ADDR &&
267  socket->localIpAddr.ipv4Addr != pseudoHeader->ipv4Data.destAddr)
268  {
269  continue;
270  }
271  }
272  }
273 
274  //Source IP address filtering
275  if(socket->remoteIpAddr.length != 0)
276  {
277  //An IPv4 address is expected
278  if(socket->remoteIpAddr.length != sizeof(Ipv4Addr))
279  continue;
280 
281  //Filter out non-matching addresses
282  if(socket->remoteIpAddr.ipv4Addr != IPV4_UNSPECIFIED_ADDR &&
283  socket->remoteIpAddr.ipv4Addr != pseudoHeader->ipv4Data.srcAddr)
284  {
285  continue;
286  }
287  }
288  }
289  else
290 #endif
291 #if (IPV6_SUPPORT == ENABLED)
292  //IPv6 packet received?
293  if(pseudoHeader->length == sizeof(Ipv6PseudoHeader))
294  {
295  //Check whether the destination address is a unicast or multicast
296  //address
297  if(ipv6IsMulticastAddr(&pseudoHeader->ipv6Data.destAddr))
298  {
299  IpAddr srcAddr;
301 
302  //Get source IPv6 address
303  srcAddr.length = sizeof(Ipv6Addr);
304  srcAddr.ipv6Addr = pseudoHeader->ipv6Data.srcAddr;
305 
306  //Get destination IPv6 address
307  destAddr.length = sizeof(Ipv6Addr);
308  destAddr.ipv6Addr = pseudoHeader->ipv6Data.destAddr;
309 
310  //Multicast address filtering
312  {
313  continue;
314  }
315  }
316  else
317  {
318  //Destination IP address filtering
319  if(socket->localIpAddr.length != 0)
320  {
321  //An IPv6 address is expected
322  if(socket->localIpAddr.length != sizeof(Ipv6Addr))
323  continue;
324 
325  //Filter out non-matching addresses
326  if(!ipv6CompAddr(&socket->localIpAddr.ipv6Addr,
328  !ipv6CompAddr(&socket->localIpAddr.ipv6Addr,
329  &pseudoHeader->ipv6Data.destAddr))
330  {
331  continue;
332  }
333  }
334  }
335 
336  //Source IP address filtering
337  if(socket->remoteIpAddr.length != 0)
338  {
339  //An IPv6 address is expected
340  if(socket->remoteIpAddr.length != sizeof(Ipv6Addr))
341  continue;
342 
343  //Filter out non-matching addresses
344  if(!ipv6CompAddr(&socket->remoteIpAddr.ipv6Addr,
346  !ipv6CompAddr(&socket->remoteIpAddr.ipv6Addr,
347  &pseudoHeader->ipv6Data.srcAddr))
348  {
349  continue;
350  }
351  }
352  }
353  else
354 #endif
355  //Invalid packet received?
356  {
357  //This should never occur...
358  continue;
359  }
360 
361  //The current socket meets all the criteria
362  break;
363  }
364 
365  //Point to the payload
366  offset += sizeof(UdpHeader);
367  length -= sizeof(UdpHeader);
368 
369  //No matching socket found?
370  if(i >= SOCKET_MAX_COUNT)
371  {
372  //Invoke user callback, if any
373  error = udpInvokeRxCallback(interface, pseudoHeader, header, buffer,
374  offset, ancillary);
375  //Return status code
376  return error;
377  }
378 
379  //Empty receive queue?
380  if(socket->receiveQueue == NULL)
381  {
382  //Allocate a memory buffer to hold the data and the associated descriptor
383  p = netBufferAlloc(sizeof(SocketQueueItem) + length);
384 
385  //Successful memory allocation?
386  if(p != NULL)
387  {
388  //Point to the newly created item
389  queueItem = netBufferAt(p, 0, 0);
390  queueItem->buffer = p;
391  //Add the newly created item to the queue
392  socket->receiveQueue = queueItem;
393  }
394  else
395  {
396  //Memory allocation failed
397  queueItem = NULL;
398  }
399  }
400  else
401  {
402  //Point to the very first item
403  queueItem = socket->receiveQueue;
404 
405  //Reach the last item in the receive queue
406  for(i = 1; queueItem->next; i++)
407  {
408  queueItem = queueItem->next;
409  }
410 
411  //Check whether the receive queue is full
412  if(i >= UDP_RX_QUEUE_SIZE)
413  {
414  //Number of inbound packets which were chosen to be discarded even
415  //though no errors had been detected
416  MIB2_IF_INC_COUNTER32(ifTable[interface->index].ifInDiscards, 1);
417  IF_MIB_INC_COUNTER32(ifTable[interface->index].ifInDiscards, 1);
418 
419  //Report an error
421  }
422 
423  //Allocate a memory buffer to hold the data and the associated descriptor
424  p = netBufferAlloc(sizeof(SocketQueueItem) + length);
425 
426  //Successful memory allocation?
427  if(p != NULL)
428  {
429  //Add the newly created item to the queue
430  queueItem->next = netBufferAt(p, 0, 0);
431  //Point to the newly created item
432  queueItem = queueItem->next;
433  queueItem->buffer = p;
434  }
435  else
436  {
437  //Memory allocation failed
438  queueItem = NULL;
439  }
440  }
441 
442  //Not enough resources to properly handle the packet?
443  if(queueItem == NULL)
444  {
445  //Number of inbound packets which were chosen to be discarded even
446  //though no errors had been detected
447  MIB2_IF_INC_COUNTER32(ifTable[interface->index].ifInDiscards, 1);
448  IF_MIB_INC_COUNTER32(ifTable[interface->index].ifInDiscards, 1);
449 
450  //Report an error
451  return ERROR_OUT_OF_MEMORY;
452  }
453 
454  //Initialize next field
455  queueItem->next = NULL;
456  //Network interface where the packet was received
457  queueItem->interface = interface;
458  //Record the source port number
459  queueItem->srcPort = ntohs(header->srcPort);
460 
461 #if (IPV4_SUPPORT == ENABLED)
462  //IPv4 remote address?
463  if(pseudoHeader->length == sizeof(Ipv4PseudoHeader))
464  {
465  //Save the source IPv4 address
466  queueItem->srcIpAddr.length = sizeof(Ipv4Addr);
467  queueItem->srcIpAddr.ipv4Addr = pseudoHeader->ipv4Data.srcAddr;
468 
469  //Save the destination IPv4 address
470  queueItem->destIpAddr.length = sizeof(Ipv4Addr);
471  queueItem->destIpAddr.ipv4Addr = pseudoHeader->ipv4Data.destAddr;
472  }
473 #endif
474 #if (IPV6_SUPPORT == ENABLED)
475  //IPv6 remote address?
476  if(pseudoHeader->length == sizeof(Ipv6PseudoHeader))
477  {
478  //Save the source IPv6 address
479  queueItem->srcIpAddr.length = sizeof(Ipv6Addr);
480  queueItem->srcIpAddr.ipv6Addr = pseudoHeader->ipv6Data.srcAddr;
481 
482  //Save the destination IPv6 address
483  queueItem->destIpAddr.length = sizeof(Ipv6Addr);
484  queueItem->destIpAddr.ipv6Addr = pseudoHeader->ipv6Data.destAddr;
485  }
486 #endif
487 
488  //Offset to the payload
489  queueItem->offset = sizeof(SocketQueueItem);
490  //Copy the payload
491  netBufferCopy(queueItem->buffer, queueItem->offset, buffer, offset, length);
492 
493  //Additional options can be passed to the stack along with the packet
494  queueItem->ancillary = *ancillary;
495 
496  //Notify user that data is available
498 
499  //Total number of UDP datagrams delivered to UDP users
500  MIB2_UDP_INC_COUNTER32(udpInDatagrams, 1);
501  UDP_MIB_INC_COUNTER32(udpInDatagrams, 1);
502  UDP_MIB_INC_COUNTER64(udpHCInDatagrams, 1);
503 
504  //Successful processing
505  return NO_ERROR;
506 }
507 
508 
509 /**
510  * @brief Send a UDP datagram
511  * @param[in] socket Handle referencing the socket
512  * @param[in] message Pointer to the structure describing the datagram
513  * @param[in] flags Set of flags that influences the behavior of this function
514  * @return Error code
515  **/
516 
518 {
519  error_t error;
520  size_t offset;
521  NetBuffer *buffer;
523  NetTxAncillary ancillary;
524 
525  //Select the relevant network interface
526  if(message->interface != NULL)
527  {
528  interface = message->interface;
529  }
530  else
531  {
532  interface = socket->interface;
533  }
534 
535  //Allocate a memory buffer to hold the UDP datagram
536  buffer = udpAllocBuffer(0, &offset);
537  //Failed to allocate buffer?
538  if(buffer == NULL)
539  return ERROR_OUT_OF_MEMORY;
540 
541  //Copy data payload
542  error = netBufferAppend(buffer, message->data, message->length);
543 
544  //Successful processing?
545  if(!error)
546  {
547  //Additional options can be passed to the stack along with the packet
548  ancillary = NET_DEFAULT_TX_ANCILLARY;
549 
550  //This option allows UDP checksum generation to be bypassed
551  if((socket->options & SOCKET_OPTION_UDP_NO_CHECKSUM) != 0)
552  {
553  ancillary.noChecksum = TRUE;
554  }
555 
556  //Set the TTL value to be used
557  if(message->ttl != 0)
558  {
559  ancillary.ttl = message->ttl;
560  }
561  else if(ipIsMulticastAddr(&message->destIpAddr))
562  {
563  ancillary.ttl = socket->multicastTtl;
564  }
565  else
566  {
567  ancillary.ttl = socket->ttl;
568  }
569 
570  //Set ToS field
571  if(message->tos != 0)
572  {
573  ancillary.tos = message->tos;
574  }
575  else
576  {
577  ancillary.tos = socket->tos;
578  }
579 
580  //This flag can be used to send IP packets without fragmentation
581  if(message->destIpAddr.length == sizeof(Ipv4Addr) &&
582  (socket->options & SOCKET_OPTION_IPV4_DONT_FRAG) != 0)
583  {
584  ancillary.dontFrag = TRUE;
585  }
586  else if(message->destIpAddr.length == sizeof(Ipv6Addr) &&
587  (socket->options & SOCKET_OPTION_IPV6_DONT_FRAG) != 0)
588  {
589  ancillary.dontFrag = TRUE;
590  }
591  else
592  {
593  ancillary.dontFrag = message->dontFrag;
594  }
595 
596  //This flag tells the stack that the destination is on a locally attached
597  //network and not to perform a lookup of the routing table
598  if((flags & SOCKET_FLAG_DONT_ROUTE) != 0)
599  {
600  ancillary.dontRoute = TRUE;
601  }
602 
603 #if (ETH_SUPPORT == ENABLED)
604  //Set source and destination MAC addresses
605  ancillary.srcMacAddr = message->srcMacAddr;
606  ancillary.destMacAddr = message->destMacAddr;
607 #endif
608 
609 #if (ETH_VLAN_SUPPORT == ENABLED)
610  //Set VLAN PCP and DEI fields
611  ancillary.vlanPcp = socket->vlanPcp;
612  ancillary.vlanDei = socket->vlanDei;
613 #endif
614 
615 #if (ETH_VMAN_SUPPORT == ENABLED)
616  //Set VMAN PCP and DEI fields
617  ancillary.vmanPcp = socket->vmanPcp;
618  ancillary.vmanDei = socket->vmanDei;
619 #endif
620 
621 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
622  //Set switch port identifier
623  ancillary.port = message->switchPort;
624 #endif
625 
626 #if (ETH_TIMESTAMP_SUPPORT == ENABLED)
627  //Unique identifier for hardware time stamping
628  ancillary.timestampId = message->timestampId;
629 #endif
630 
631  //Send UDP datagram
632  error = udpSendBuffer(interface, &message->srcIpAddr, socket->localPort,
633  &message->destIpAddr, message->destPort, buffer, offset, &ancillary);
634  }
635 
636  //Free previously allocated memory
637  netBufferFree(buffer);
638 
639  //Return status code
640  return error;
641 }
642 
643 
644 /**
645  * @brief Send a UDP datagram
646  * @param[in] interface Underlying network interface
647  * @param[in] srcIpAddr Source IP address (optional parameter)
648  * @param[in] srcPort Source port
649  * @param[in] destIpAddr IP address of the target host
650  * @param[in] destPort Target port number
651  * @param[in] buffer Multi-part buffer containing the payload
652  * @param[in] offset Offset to the first payload byte
653  * @param[in] ancillary Additional options passed to the stack along with
654  * the packet
655  * @return Error code
656  **/
657 
659  uint16_t srcPort, const IpAddr *destIpAddr, uint16_t destPort,
660  NetBuffer *buffer, size_t offset, 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();
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(&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();
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(&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
862  //Wait until an event is triggered
863  osWaitForEvent(&socket->event, socket->timeout);
864  //Get exclusive access
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:175
#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:711
Ipv6PseudoHeader ipv6Data
Definition: ip.h:118
Ipv4Addr destAddr
Definition: ipv4.h:329
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: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:476
#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:260
uint16_t port
Definition: udp.h:113
@ SOCKET_TYPE_DGRAM
Definition: socket.h:93
error_t ipv4SelectSourceAddr(NetInterface **interface, Ipv4Addr destAddr, Ipv4Addr *srcAddr)
IPv4 source address selection.
Definition: ipv4_misc.c:174
@ 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:127
uint16_t destPort
Definition: tcp.h:340
error_t udpProcessDatagram(NetInterface *interface, const IpPseudoHeader *pseudoHeader, const NetBuffer *buffer, size_t offset, const NetRxAncillary *ancillary)
Incoming UDP datagram processing.
Definition: udp.c:124
#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:297
#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:185
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:139
#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.
uint32_t netGenerateRandRange(uint32_t min, uint32_t max)
Generate a random value in the specified range.
Definition: net_misc.c:948
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:250
#define Ipv6PseudoHeader
Definition: ipv6.h:42
UdpRxCallback callback
Definition: udp.h:114
error_t ipv6SelectSourceAddr(NetInterface **interface, const Ipv6Addr *destAddr, Ipv6Addr *srcAddr)
IPv6 source address selection.
Definition: ipv6_misc.c:870
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
#define MIB2_IF_INC_COUNTER32(name, value)
Definition: mib2_module.h:156
@ IPV6_UDP_HEADER
Definition: ipv6.h:188
@ 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 udpDetachRxCallback(NetInterface *interface, uint16_t port)
Unregister user callback.
Definition: udp.c:1062
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:402
error_t udpAttachRxCallback(NetInterface *interface, uint16_t port, UdpRxCallback callback, void *param)
Register user callback.
Definition: udp.c:1021
void netBufferFree(NetBuffer *buffer)
Dispose a multi-part buffer.
Definition: net_mem.c:282
@ ERROR_INVALID_LENGTH
Definition: error.h:111
NetInterface * netGetDefaultInterface(void)
Get default network interface.
Definition: net.c:467
@ SOCKET_OPTION_IPV4_DONT_FRAG
Definition: socket.h:195
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:658
@ SOCKET_OPTION_BROADCAST
Definition: socket.h:193
#define NetTxAncillary
Definition: net_misc.h:36
const Ipv6Addr IPV6_UNSPECIFIED_ADDR
Definition: ipv6.c:66
IpAddr destIpAddr
Definition: socket.h:293
error_t udpSendDatagram(Socket *socket, const SocketMsg *message, uint_t flags)
Send a UDP datagram.
Definition: udp.c:517
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:95
uint8_t length
Definition: tcp.h:368
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: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:119
@ SOCKET_EVENT_LINK_UP
Definition: socket.h:181
uint16_t udpGetDynamicPort(void)
Get an ephemeral port number.
Definition: udp.c:81
UdpHeader
Definition: udp.h:85
NetBuffer * netBufferAlloc(size_t length)
Allocate a multi-part buffer.
Definition: net_mem.c:243
uint16_t port
Definition: dns_common.h:267
#define ntohs(value)
Definition: cpu_endian.h:421
Receive queue item.
Definition: socket.h:288
uint8_t flags
Definition: tcp.h:351
#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: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:686
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.
@ IPV4_PROTOCOL_UDP
Definition: ipv4.h:253
error_t netBufferAppend(NetBuffer *dest, const void *src, size_t length)
Append data a multi-part buffer.
Definition: net_mem.c:604
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
MacAddr srcAddr
Definition: ethernet.h:220
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: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:308
IPv4 (Internet Protocol Version 4)
Ipv6Addr ipv6Addr
Definition: ip.h:98
#define PRIuSIZE
unsigned int uint_t
Definition: compiler_port.h:50
@ 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:135
TCP/IP stack core.
#define SOCKET_MAX_COUNT
Definition: socket.h:46
Ipv4PseudoHeader ipv4Data
Definition: ip.h:115
NetBuffer * buffer
Definition: socket.h:294
@ 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:117
Ipv4Addr destIpAddr
Definition: ipcp.h:80