ipv4.c
Go to the documentation of this file.
1 /**
2  * @file ipv4.c
3  * @brief IPv4 (Internet Protocol Version 4)
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2023 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @section Description
28  *
29  * The Internet Protocol (IP) provides the functions necessary to deliver a
30  * datagram from a source to a destination over an interconnected system of
31  * networks. Refer to RFC 791 for complete details
32  *
33  * @author Oryx Embedded SARL (www.oryx-embedded.com)
34  * @version 2.2.4
35  **/
36 
37 //Switch to the appropriate trace level
38 #define TRACE_LEVEL IPV4_TRACE_LEVEL
39 
40 //Dependencies
41 #include <string.h>
42 #include "core/net.h"
43 #include "core/ethernet.h"
44 #include "core/ip.h"
45 #include "core/udp.h"
46 #include "core/tcp_fsm.h"
47 #include "core/raw_socket.h"
48 #include "ipv4/arp.h"
49 #include "ipv4/ipv4.h"
50 #include "ipv4/ipv4_misc.h"
51 #include "ipv4/ipv4_routing.h"
52 #include "ipv4/icmp.h"
53 #include "ipv4/auto_ip_misc.h"
54 #include "igmp/igmp_host.h"
55 #include "dhcp/dhcp_client_misc.h"
56 #include "mdns/mdns_responder.h"
57 #include "mibs/mib2_module.h"
58 #include "mibs/ip_mib_module.h"
59 #include "debug.h"
60 
61 //IPsec supported?
62 #if (IPV4_IPSEC_SUPPORT == ENABLED)
63  #include "ipsec/ipsec.h"
64  #include "ipsec/ipsec_inbound.h"
65  #include "ipsec/ipsec_outbound.h"
66  #include "ah/ah.h"
67  #include "esp/esp.h"
68 #endif
69 
70 //Check TCP/IP stack configuration
71 #if (IPV4_SUPPORT == ENABLED)
72 
73 
74 /**
75  * @brief IPv4 related initialization
76  * @param[in] interface Underlying network interface
77  * @return Error code
78  **/
79 
81 {
82  Ipv4Context *context;
83  NetInterface *physicalInterface;
84 
85  //Point to the physical interface
86  physicalInterface = nicGetPhysicalInterface(interface);
87 
88  //Point to the IPv4 context
89  context = &interface->ipv4Context;
90 
91  //Clear the IPv4 context
92  osMemset(context, 0, sizeof(Ipv4Context));
93 
94  //Initialize interface specific variables
95  context->linkMtu = physicalInterface->nicDriver->mtu;
96  context->isRouter = FALSE;
97 
98  //ICMP Echo Request messages are allowed by default
99  context->enableEchoReq = TRUE;
100  context->enableBroadcastEchoReq = TRUE;
101 
102  //Identification field is primarily used to identify
103  //fragments of an original IP datagram
104  context->identification = 0;
105 
106  //Initialize the list of DNS servers
107  osMemset(context->dnsServerList, 0, sizeof(context->dnsServerList));
108  //Initialize the multicast filter table
109  osMemset(context->multicastFilter, 0, sizeof(context->multicastFilter));
110 
111 #if (IPV4_FRAG_SUPPORT == ENABLED)
112  //Initialize the reassembly queue
113  osMemset(context->fragQueue, 0, sizeof(context->fragQueue));
114 #endif
115 
116  //Successful initialization
117  return NO_ERROR;
118 }
119 
120 
121 /**
122  * @brief Assign host address
123  * @param[in] interface Pointer to the desired network interface
124  * @param[in] addr IPv4 host address
125  * @return Error code
126  **/
127 
129 {
130  //Set IPv4 host address
131  return ipv4SetHostAddrEx(interface, 0, addr);
132 }
133 
134 
135 /**
136  * @brief Assign host address
137  * @param[in] interface Pointer to the desired network interface
138  * @param[in] index Zero-based index
139  * @param[in] addr IPv4 host address
140  * @return Error code
141  **/
142 
144 {
145  Ipv4AddrEntry *entry;
146 
147  //Check parameters
148  if(interface == NULL)
150 
151  //Make sure that the index is valid
152  if(index >= IPV4_ADDR_LIST_SIZE)
153  return ERROR_OUT_OF_RANGE;
154 
155  //The IPv4 address must be a valid unicast address
157  return ERROR_INVALID_ADDRESS;
158 
159  //Get exclusive access
161 
162  //Point to the corresponding entry
163  entry = &interface->ipv4Context.addrList[index];
164 
165  //Set up host address
166  entry->addr = addr;
167  //Clear conflict flag
168  entry->conflict = FALSE;
169 
170  //Check whether the new host address is valid
172  {
173  //The use of the IPv4 address is now unrestricted
174  entry->state = IPV4_ADDR_STATE_VALID;
175  }
176  else
177  {
178  //The IPv4 address is no longer valid
180  }
181 
182 #if (MDNS_RESPONDER_SUPPORT == ENABLED)
183  //Restart mDNS probing process
184  mdnsResponderStartProbing(interface->mdnsResponderContext);
185 #endif
186 
187  //Release exclusive access
189 
190  //Successful processing
191  return NO_ERROR;
192 }
193 
194 
195 /**
196  * @brief Retrieve host address
197  * @param[in] interface Pointer to the desired network interface
198  * @param[out] addr IPv4 host address
199  * @return Error code
200  **/
201 
203 {
204  //Get IPv4 host address
205  return ipv4GetHostAddrEx(interface, 0, addr);
206 }
207 
208 
209 /**
210  * @brief Retrieve host address
211  * @param[in] interface Pointer to the desired network interface
212  * @param[in] index Zero-based index
213  * @param[out] addr IPv4 host address
214  * @return Error code
215  **/
216 
218 {
219  Ipv4AddrEntry *entry;
220 
221  //Check parameters
222  if(interface == NULL || addr == NULL)
224 
225  //Make sure that the index is valid
226  if(index >= IPV4_ADDR_LIST_SIZE)
227  {
228  //Return the unspecified address when the index is out of range
230  //Report an error
231  return ERROR_OUT_OF_RANGE;
232  }
233 
234  //Get exclusive access
236 
237  //Point to the corresponding entry
238  entry = &interface->ipv4Context.addrList[index];
239 
240  //Check whether the host address is valid
241  if(entry->state == IPV4_ADDR_STATE_VALID)
242  {
243  //Get IPv4 address
244  *addr = entry->addr;
245  }
246  else
247  {
248  //Return the unspecified address when no address has been assigned
250  }
251 
252  //Release exclusive access
254 
255  //Successful processing
256  return NO_ERROR;
257 }
258 
259 
260 /**
261  * @brief Configure subnet mask
262  * @param[in] interface Pointer to the desired network interface
263  * @param[in] mask Subnet mask
264  * @return Error code
265  **/
266 
268 {
269  //Set subnet mask
270  return ipv4SetSubnetMaskEx(interface, 0, mask);
271 }
272 
273 
274 /**
275  * @brief Configure subnet mask
276  * @param[in] interface Pointer to the desired network interface
277  * @param[in] index Zero-based index
278  * @param[in] mask Subnet mask
279  * @return Error code
280  **/
281 
283 {
284  //Check parameters
285  if(interface == NULL)
287 
288  //Make sure that the index is valid
289  if(index >= IPV4_ADDR_LIST_SIZE)
290  return ERROR_OUT_OF_RANGE;
291 
292  //Get exclusive access
294  //Set up subnet mask
295  interface->ipv4Context.addrList[index].subnetMask = mask;
296  //Release exclusive access
298 
299  //Successful processing
300  return NO_ERROR;
301 }
302 
303 
304 /**
305  * @brief Retrieve subnet mask
306  * @param[in] interface Pointer to the desired network interface
307  * @param[out] mask Subnet mask
308  * @return Error code
309  **/
310 
312 {
313  //Get subnet mask
314  return ipv4GetSubnetMaskEx(interface, 0, mask);
315 }
316 
317 
318 /**
319  * @brief Retrieve subnet mask
320  * @param[in] interface Pointer to the desired network interface
321  * @param[in] index Zero-based index
322  * @param[out] mask Subnet mask
323  * @return Error code
324  **/
325 
327 {
328  //Check parameters
329  if(interface == NULL || mask == NULL)
331 
332  //Make sure that the index is valid
333  if(index >= IPV4_ADDR_LIST_SIZE)
334  {
335  //Return the default mask when the index is out of range
337  //Report an error
338  return ERROR_OUT_OF_RANGE;
339  }
340 
341  //Get exclusive access
343  //Get subnet mask
344  *mask = interface->ipv4Context.addrList[index].subnetMask;
345  //Release exclusive access
347 
348  //Successful processing
349  return NO_ERROR;
350 }
351 
352 
353 /**
354  * @brief Configure default gateway
355  * @param[in] interface Pointer to the desired network interface
356  * @param[in] addr Default gateway address
357  * @return Error code
358  **/
359 
361 {
362  //Set default gateway
363  return ipv4SetDefaultGatewayEx(interface, 0, addr);
364 }
365 
366 
367 /**
368  * @brief Configure default gateway
369  * @param[in] interface Pointer to the desired network interface
370  * @param[in] index Zero-based index
371  * @param[in] addr Default gateway address
372  * @return Error code
373  **/
374 
376  Ipv4Addr addr)
377 {
378  //Check parameters
379  if(interface == NULL)
381 
382  //Make sure that the index is valid
383  if(index >= IPV4_ADDR_LIST_SIZE)
384  return ERROR_OUT_OF_RANGE;
385 
386  //The IPv4 address must be a valid unicast address
388  return ERROR_INVALID_ADDRESS;
389 
390  //Get exclusive access
392  //Set up default gateway address
393  interface->ipv4Context.addrList[index].defaultGateway = addr;
394  //Release exclusive access
396 
397  //Successful processing
398  return NO_ERROR;
399 }
400 
401 
402 /**
403  * @brief Retrieve default gateway
404  * @param[in] interface Pointer to the desired network interface
405  * @param[out] addr Default gateway address
406  * @return Error code
407  **/
408 
410 {
411  //Get default gateway
412  return ipv4GetDefaultGatewayEx(interface, 0, addr);
413 }
414 
415 
416 /**
417  * @brief Retrieve default gateway
418  * @param[in] interface Pointer to the desired network interface
419  * @param[in] index Zero-based index
420  * @param[out] addr Default gateway address
421  * @return Error code
422  **/
423 
425  Ipv4Addr *addr)
426 {
427  //Check parameters
428  if(interface == NULL || addr == NULL)
430 
431  //Make sure that the index is valid
432  if(index >= IPV4_ADDR_LIST_SIZE)
433  {
434  //Return the unspecified address when the index is out of range
436  //Report an error
437  return ERROR_OUT_OF_RANGE;
438  }
439 
440  //Get exclusive access
442  //Get default gateway address
443  *addr = interface->ipv4Context.addrList[index].defaultGateway;
444  //Release exclusive access
446 
447  //Successful processing
448  return NO_ERROR;
449 }
450 
451 
452 /**
453  * @brief Configure DNS server
454  * @param[in] interface Pointer to the desired network interface
455  * @param[in] index This parameter selects between the primary and secondary DNS server
456  * @param[in] addr DNS server address
457  * @return Error code
458  **/
459 
461 {
462  //Check parameters
463  if(interface == NULL)
465 
466  //Make sure that the index is valid
467  if(index >= IPV4_DNS_SERVER_LIST_SIZE)
468  return ERROR_OUT_OF_RANGE;
469 
470  //The IPv4 address must be a valid unicast address
472  return ERROR_INVALID_ADDRESS;
473 
474  //Get exclusive access
476  //Set up DNS server address
477  interface->ipv4Context.dnsServerList[index] = addr;
478  //Release exclusive access
480 
481  //Successful processing
482  return NO_ERROR;
483 }
484 
485 
486 /**
487  * @brief Retrieve DNS server
488  * @param[in] interface Pointer to the desired network interface
489  * @param[in] index This parameter selects between the primary and secondary DNS server
490  * @param[out] addr DNS server address
491  * @return Error code
492  **/
493 
495 {
496  //Check parameters
497  if(interface == NULL || addr == NULL)
499 
500  //Make sure that the index is valid
501  if(index >= IPV4_DNS_SERVER_LIST_SIZE)
502  {
503  //Return the unspecified address when the index is out of range
505  //Report an error
506  return ERROR_OUT_OF_RANGE;
507  }
508 
509  //Get exclusive access
511  //Get DNS server address
512  *addr = interface->ipv4Context.dnsServerList[index];
513  //Release exclusive access
515 
516  //Successful processing
517  return NO_ERROR;
518 }
519 
520 
521 /**
522  * @brief Callback function for link change event
523  * @param[in] interface Underlying network interface
524  **/
525 
527 {
528  Ipv4Context *context;
529  NetInterface *physicalInterface;
530 
531  //Point to the physical interface
532  physicalInterface = nicGetPhysicalInterface(interface);
533 
534  //Point to the IPv4 context
535  context = &interface->ipv4Context;
536 
537  //Restore default MTU
538  context->linkMtu = physicalInterface->nicDriver->mtu;
539 
540 #if (ETH_SUPPORT == ENABLED)
541  //Flush ARP cache contents
542  arpFlushCache(interface);
543 #endif
544 
545 #if (IPV4_FRAG_SUPPORT == ENABLED)
546  //Flush the reassembly queue
547  ipv4FlushFragQueue(interface);
548 #endif
549 
550 #if (IGMP_HOST_SUPPORT == ENABLED || IGMP_ROUTER_SUPPORT == ENABLED || \
551  IGMP_SNOOPING_SUPPORT == ENABLED)
552  //Notify IGMP of link state changes
553  igmpLinkChangeEvent(interface);
554 #endif
555 
556 #if (AUTO_IP_SUPPORT == ENABLED)
557  //Notify Auto-IP of link state changes
558  autoIpLinkChangeEvent(interface->autoIpContext);
559 #endif
560 
561 #if (DHCP_CLIENT_SUPPORT == ENABLED)
562  //Notify the DHCP client of link state changes
563  dhcpClientLinkChangeEvent(interface->dhcpClientContext);
564 #endif
565 }
566 
567 
568 /**
569  * @brief Incoming IPv4 packet processing
570  * @param[in] interface Underlying network interface
571  * @param[in] packet Incoming IPv4 packet
572  * @param[in] length Packet length including header and payload
573  * @param[in] ancillary Additional options passed to the stack along with
574  * the packet
575  **/
576 
577 void ipv4ProcessPacket(NetInterface *interface, Ipv4Header *packet,
578  size_t length, NetRxAncillary *ancillary)
579 {
580  error_t error;
581 
582  //Initialize status code
583  error = NO_ERROR;
584 
585  //Total number of input datagrams received, including those received in error
586  MIB2_IP_INC_COUNTER32(ipInReceives, 1);
587  IP_MIB_INC_COUNTER32(ipv4SystemStats.ipSystemStatsInReceives, 1);
588  IP_MIB_INC_COUNTER64(ipv4SystemStats.ipSystemStatsHCInReceives, 1);
589  IP_MIB_INC_COUNTER32(ipv4IfStatsTable[interface->index].ipIfStatsInReceives, 1);
590  IP_MIB_INC_COUNTER64(ipv4IfStatsTable[interface->index].ipIfStatsHCInReceives, 1);
591 
592  //Total number of octets received in input IP datagrams
593  IP_MIB_INC_COUNTER32(ipv4SystemStats.ipSystemStatsInOctets, length);
594  IP_MIB_INC_COUNTER64(ipv4SystemStats.ipSystemStatsHCInOctets, length);
595  IP_MIB_INC_COUNTER32(ipv4IfStatsTable[interface->index].ipIfStatsInOctets, length);
596  IP_MIB_INC_COUNTER64(ipv4IfStatsTable[interface->index].ipIfStatsHCInOctets, length);
597 
598  //Start of exception handling block
599  do
600  {
601  //Ensure the packet length is greater than 20 bytes
602  if(length < sizeof(Ipv4Header))
603  {
604  //Discard the received packet
605  error = ERROR_INVALID_LENGTH;
606  break;
607  }
608 
609  //Debug message
610  TRACE_INFO("IPv4 packet received (%" PRIuSIZE " bytes)...\r\n", length);
611  //Dump IP header contents for debugging purpose
612  ipv4DumpHeader(packet);
613 
614  //A packet whose version number is not 4 must be silently discarded
615  if(packet->version != IPV4_VERSION)
616  {
617  //Discard the received packet
618  error = ERROR_INVALID_HEADER;
619  break;
620  }
621 
622  //Valid IPv4 header shall contains more than five 32-bit words
623  if(packet->headerLength < 5)
624  {
625  //Discard the received packet
626  error = ERROR_INVALID_HEADER;
627  break;
628  }
629 
630  //Ensure the total length is correct before processing the packet
631  if(ntohs(packet->totalLength) < (packet->headerLength * 4))
632  {
633  //Discard the received packet
634  error = ERROR_INVALID_HEADER;
635  break;
636  }
637 
638  //Truncated packet?
639  if(length < ntohs(packet->totalLength))
640  {
641  //Discard the received packet
642  error = ERROR_INVALID_LENGTH;
643  break;
644  }
645 
646  //Source address filtering
647  if(ipv4CheckSourceAddr(interface, packet->srcAddr))
648  {
649  //Discard the received packet
650  error = ERROR_INVALID_HEADER;
651  break;
652  }
653 
654 #if (IGMP_ROUTER_SUPPORT == ENABLED)
655  //Trap IGMP packets when IGMP router is enabled
656  if(interface->igmpRouterContext != NULL && ipv4TrapIgmpPacket(packet))
657  {
658  //Forward the packet to the IGMP router
659  error = NO_ERROR;
660  }
661  else
662 #endif
663 #if (IGMP_SNOOPING_SUPPORT == ENABLED)
664  //Trap IGMP packets when IGMP snooping is enabled
665  if(interface->igmpSnoopingContext != NULL && ipv4TrapIgmpPacket(packet))
666  {
667  //Forward the packet to the IGMP snooping switch
668  error = NO_ERROR;
669  }
670  else
671 #endif
672 #if (IGMP_ROUTER_SUPPORT == ENABLED && IPV4_ROUTING_SUPPORT == ENABLED)
673  //Trap multicast packets
674  if(ipv4IsMulticastAddr(packet->destAddr))
675  {
676  NetBuffer1 buffer;
677 
678  //Unfragmented datagrams fit in a single chunk
679  buffer.chunkCount = 1;
680  buffer.maxChunkCount = 1;
681  buffer.chunk[0].address = packet;
682  buffer.chunk[0].length = length;
683 
684  //Forward the multicast packet
685  ipv4ForwardPacket(interface, (NetBuffer *) &buffer, 0);
686 
687  //Destination address filtering
688  error = ipv4CheckDestAddr(interface, packet->destAddr);
689  }
690  else
691 #endif
692  {
693  //Destination address filtering
694  error = ipv4CheckDestAddr(interface, packet->destAddr);
695 
696 #if defined(IPV4_PACKET_FORWARD_HOOK)
697  IPV4_PACKET_FORWARD_HOOK(interface, packet, length);
698 #elif (IPV4_ROUTING_SUPPORT == ENABLED)
699  //Invalid destination address?
700  if(error)
701  {
702  NetBuffer1 buffer;
703 
704  //Unfragmented datagrams fit in a single chunk
705  buffer.chunkCount = 1;
706  buffer.maxChunkCount = 1;
707  buffer.chunk[0].address = packet;
708  buffer.chunk[0].length = length;
709 
710  //Forward the packet according to the routing table
711  ipv4ForwardPacket(interface, (NetBuffer *) &buffer, 0);
712  }
713 #endif
714  }
715 
716  //Invalid destination address?
717  if(error)
718  {
719  //Discard the received packet
720  error = ERROR_INVALID_ADDRESS;
721  break;
722  }
723 
724  //Packets addressed to a tentative address should be silently discarded
725  if(ipv4IsTentativeAddr(interface, packet->destAddr))
726  {
727  //Discard the received packet
728  error = ERROR_INVALID_ADDRESS;
729  break;
730  }
731 
732  //The host must verify the IP header checksum on every received datagram
733  //and silently discard every datagram that has a bad checksum (refer to
734  //RFC 1122, section 3.2.1.2)
735  if(ipCalcChecksum(packet, packet->headerLength * 4) != 0x0000)
736  {
737  //Debug message
738  TRACE_WARNING("Wrong IP header checksum!\r\n");
739 
740  //Discard incoming packet
741  error = ERROR_INVALID_HEADER;
742  break;
743  }
744 
745  //Update IP statistics
746  ipv4UpdateInStats(interface, packet->destAddr, length);
747 
748  //Convert the total length from network byte order
749  length = ntohs(packet->totalLength);
750 
751  //A fragmented packet was received?
752  if((ntohs(packet->fragmentOffset) & (IPV4_FLAG_MF | IPV4_OFFSET_MASK)) != 0)
753  {
754 #if (IPV4_FRAG_SUPPORT == ENABLED)
755  //Reassemble the original datagram
756  ipv4ReassembleDatagram(interface, packet, length, ancillary);
757 #endif
758  }
759  else
760  {
761  NetBuffer1 buffer;
762 
763  //Unfragmented datagrams fit in a single chunk
764  buffer.chunkCount = 1;
765  buffer.maxChunkCount = 1;
766  buffer.chunk[0].address = packet;
767  buffer.chunk[0].length = (uint16_t) length;
768 
769  //Pass the IPv4 datagram to the higher protocol layer
770  ipv4ProcessDatagram(interface, (NetBuffer *) &buffer, 0, ancillary);
771  }
772 
773  //End of exception handling block
774  } while(0);
775 
776  //Invalid IPv4 packet received?
777  if(error)
778  {
779  //Update IP statistics
780  ipv4UpdateErrorStats(interface, error);
781  }
782 }
783 
784 
785 /**
786  * @brief Incoming IPv4 datagram processing
787  * @param[in] interface Underlying network interface
788  * @param[in] buffer Multi-part buffer that holds the incoming IPv4 datagram
789  * @param[in] offset Offset from the beginning of the buffer
790  * @param[in] ancillary Additional options passed to the stack along with
791  * the packet
792  **/
793 
794 void ipv4ProcessDatagram(NetInterface *interface, const NetBuffer *buffer,
795  size_t offset, NetRxAncillary *ancillary)
796 {
797  error_t error;
798  size_t length;
799  Ipv4Header *header;
800  IpPseudoHeader pseudoHeader;
801 
802  //Retrieve the length of the IPv4 datagram
803  length = netBufferGetLength(buffer) - offset;
804 
805  //Point to the IPv4 header
806  header = netBufferAt(buffer, offset);
807  //Sanity check
808  if(header == NULL)
809  return;
810 
811  //Debug message
812  TRACE_INFO("IPv4 datagram received (%" PRIuSIZE " bytes)...\r\n", length);
813  //Dump IP header contents for debugging purpose
814  ipv4DumpHeader(header);
815 
816  //Get the offset to the payload
817  offset += header->headerLength * 4;
818  //Compute the length of the payload
819  length -= header->headerLength * 4;
820 
821  //Form the IPv4 pseudo header
822  pseudoHeader.length = sizeof(Ipv4PseudoHeader);
823  pseudoHeader.ipv4Data.srcAddr = header->srcAddr;
824  pseudoHeader.ipv4Data.destAddr = header->destAddr;
825  pseudoHeader.ipv4Data.reserved = 0;
826  pseudoHeader.ipv4Data.protocol = header->protocol;
827  pseudoHeader.ipv4Data.length = htons(length);
828 
829  //Save TTL value
830  ancillary->ttl = header->timeToLive;
831 
832 #if defined(IPV4_DATAGRAM_FORWARD_HOOK)
833  IPV4_DATAGRAM_FORWARD_HOOK(interface, &pseudoHeader, buffer, offset);
834 #endif
835 
836  //Initialize status code
837  error = NO_ERROR;
838 
839 #if (IPV4_IPSEC_SUPPORT == ENABLED)
840  //Process inbound IP traffic (unprotected-to-protected)
841  error = ipsecProcessInboundIpv4Packet(interface, header, buffer, offset);
842  //Any error to report?
843  if(error)
844  return;
845 #endif
846 
847  //Check the protocol field
848  switch(header->protocol)
849  {
850  //ICMP protocol?
851  case IPV4_PROTOCOL_ICMP:
852  //Process incoming ICMP message
853  icmpProcessMessage(interface, &pseudoHeader.ipv4Data, buffer, offset);
854 
855 #if (RAW_SOCKET_SUPPORT == ENABLED)
856  //Allow raw sockets to process ICMP messages
857  rawSocketProcessIpPacket(interface, &pseudoHeader, buffer, offset,
858  ancillary);
859 #endif
860 
861  //Continue processing
862  break;
863 
864 #if (IGMP_HOST_SUPPORT == ENABLED || IGMP_ROUTER_SUPPORT == ENABLED || \
865  IGMP_SNOOPING_SUPPORT == ENABLED)
866  //IGMP protocol?
867  case IPV4_PROTOCOL_IGMP:
868  //Process incoming IGMP message
869  igmpProcessMessage(interface, &pseudoHeader.ipv4Data, buffer, offset,
870  ancillary);
871 
872 #if (RAW_SOCKET_SUPPORT == ENABLED)
873  //Allow raw sockets to process IGMP messages
874  rawSocketProcessIpPacket(interface, &pseudoHeader, buffer, offset,
875  ancillary);
876 #endif
877 
878  //Continue processing
879  break;
880 #endif
881 
882 #if (TCP_SUPPORT == ENABLED)
883  //TCP protocol?
884  case IPV4_PROTOCOL_TCP:
885  //Process incoming TCP segment
886  tcpProcessSegment(interface, &pseudoHeader, buffer, offset, ancillary);
887  //Continue processing
888  break;
889 #endif
890 
891 #if (UDP_SUPPORT == ENABLED)
892  //UDP protocol?
893  case IPV4_PROTOCOL_UDP:
894  //Process incoming UDP datagram
895  error = udpProcessDatagram(interface, &pseudoHeader, buffer, offset,
896  ancillary);
897  //Continue processing
898  break;
899 #endif
900 
901 #if (IPV4_IPSEC_SUPPORT == ENABLED && AH_SUPPORT == ENABLED)
902  //AH header?
903  case IPV4_PROTOCOL_AH:
904  //Process AH header
905  error = ipv4ProcessAhHeader(interface, header, buffer, offset,
906  ancillary);
907  //Continue processing
908  break;
909 #endif
910 
911 #if (IPV4_IPSEC_SUPPORT == ENABLED && ESP_SUPPORT == ENABLED)
912  //ESP header?
913  case IPV4_PROTOCOL_ESP:
914  //Process ESP header
915  error = ipv4ProcessEspHeader(interface, header, buffer, offset,
916  ancillary);
917  //Continue processing
918  break;
919 #endif
920 
921  //Unknown protocol?
922  default:
923 #if (RAW_SOCKET_SUPPORT == ENABLED)
924  //Allow raw sockets to process IPv4 packets
925  error = rawSocketProcessIpPacket(interface, &pseudoHeader, buffer, offset,
926  ancillary);
927 #else
928  //Report an error
930 #endif
931  //Continue processing
932  break;
933  }
934 
935  //Unreachable protocol?
936  if(error == ERROR_PROTOCOL_UNREACHABLE)
937  {
938  //Update IP statistics
939  ipv4UpdateErrorStats(interface, error);
940 
941  //Send a Destination Unreachable message
943  ICMP_CODE_PROTOCOL_UNREACHABLE, 0, buffer, 0);
944  }
945  else
946  {
947  //Total number of input datagrams successfully delivered to IP
948  //user-protocols
949  MIB2_IP_INC_COUNTER32(ipInDelivers, 1);
950  IP_MIB_INC_COUNTER32(ipv4SystemStats.ipSystemStatsInDelivers, 1);
951  IP_MIB_INC_COUNTER64(ipv4SystemStats.ipSystemStatsHCInDelivers, 1);
952  IP_MIB_INC_COUNTER32(ipv4IfStatsTable[interface->index].ipIfStatsInDelivers, 1);
953  IP_MIB_INC_COUNTER64(ipv4IfStatsTable[interface->index].ipIfStatsHCInDelivers, 1);
954  }
955 
956  //Unreachable port?
957  if(error == ERROR_PORT_UNREACHABLE)
958  {
959  //Send a Destination Unreachable message
961  ICMP_CODE_PORT_UNREACHABLE, 0, buffer, 0);
962  }
963 }
964 
965 
966 /**
967  * @brief Send an IPv4 datagram
968  * @param[in] interface Underlying network interface
969  * @param[in] pseudoHeader IPv4 pseudo header
970  * @param[in] buffer Multi-part buffer containing the payload
971  * @param[in] offset Offset to the first byte of the payload
972  * @param[in] ancillary Additional options passed to the stack along with
973  * the packet
974  * @return Error code
975  **/
976 
978  NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
979 {
980  error_t error;
981  size_t length;
982  uint16_t id;
983 
984  //Total number of IP datagrams which local IP user-protocols supplied to IP
985  //in requests for transmission
986  MIB2_IP_INC_COUNTER32(ipOutRequests, 1);
987  IP_MIB_INC_COUNTER32(ipv4SystemStats.ipSystemStatsOutRequests, 1);
988  IP_MIB_INC_COUNTER64(ipv4SystemStats.ipSystemStatsHCOutRequests, 1);
989  IP_MIB_INC_COUNTER32(ipv4IfStatsTable[interface->index].ipIfStatsOutRequests, 1);
990  IP_MIB_INC_COUNTER64(ipv4IfStatsTable[interface->index].ipIfStatsHCOutRequests, 1);
991 
992  //Identification field is primarily used to identify fragments of an
993  //original IP datagram
994  id = interface->ipv4Context.identification++;
995 
996 #if (IPV4_IPSEC_SUPPORT == ENABLED)
997  //Process outbound IP traffic (protected-to-unprotected)
998  error = ipsecProcessOutboundIpv4Packet(interface, pseudoHeader, id, buffer,
999  &offset, ancillary);
1000 #else
1001  //Initialize status code
1002  error = NO_ERROR;
1003 #endif
1004 
1005  //Check status code
1006  if(!error)
1007  {
1008  //Retrieve the length of payload
1009  length = netBufferGetLength(buffer) - offset;
1010 
1011  //Check the length of the payload
1012  if((length + sizeof(Ipv4Header)) <= interface->ipv4Context.linkMtu)
1013  {
1014  //If the payload length is smaller than the network interface MTU
1015  //then no fragmentation is needed
1016  error = ipv4SendPacket(interface, pseudoHeader, id, 0, buffer,
1017  offset, ancillary);
1018  }
1019  else
1020  {
1021 #if (IPV4_FRAG_SUPPORT == ENABLED)
1022  //If the payload length exceeds the network interface MTU then the
1023  //device must fragment the data
1024  error = ipv4FragmentDatagram(interface, pseudoHeader, id, buffer,
1025  offset, ancillary);
1026 #else
1027  //Fragmentation is not supported
1028  error = ERROR_MESSAGE_TOO_LONG;
1029 #endif
1030  }
1031  }
1032 
1033  //Return status code
1034  return error;
1035 }
1036 
1037 
1038 /**
1039  * @brief Send an IPv4 packet
1040  * @param[in] interface Underlying network interface
1041  * @param[in] pseudoHeader IPv4 pseudo header
1042  * @param[in] fragId Fragment identification field
1043  * @param[in] fragOffset Fragment offset field
1044  * @param[in] buffer Multi-part buffer containing the payload
1045  * @param[in] offset Offset to the first byte of the payload
1046  * @param[in] ancillary Additional options passed to the stack along with
1047  * the packet
1048  * @return Error code
1049  **/
1050 
1052  uint16_t fragId, size_t fragOffset, NetBuffer *buffer, size_t offset,
1053  NetTxAncillary *ancillary)
1054 {
1055  error_t error;
1056  size_t length;
1057  Ipv4Header *packet;
1058 #if (ETH_SUPPORT == ENABLED)
1059  NetInterface *physicalInterface;
1060 #endif
1061 
1062  //Check whether an IP Router Alert option should be added
1063  if(ancillary->routerAlert)
1064  {
1065  //Add an IP Router Alert option
1066  error = ipv4AddRouterAlertOption(buffer, &offset);
1067  //Any error to report?
1068  if(error)
1069  return error;
1070  }
1071 
1072  //Sanity check
1073  if(offset < sizeof(Ipv4Header))
1074  return ERROR_INVALID_PARAMETER;
1075 
1076  //Make room for the header
1077  offset -= sizeof(Ipv4Header);
1078  //Calculate the size of the entire packet, including header and data
1079  length = netBufferGetLength(buffer) - offset;
1080 
1081  //Point to the IPv4 header
1082  packet = netBufferAt(buffer, offset);
1083 
1084  //Format IPv4 header
1085  packet->version = IPV4_VERSION;
1086  packet->headerLength = 5;
1087  packet->typeOfService = 0;
1088  packet->totalLength = htons(length);
1089  packet->identification = htons(fragId);
1090  packet->fragmentOffset = htons(fragOffset);
1091  packet->timeToLive = ancillary->ttl;
1092  packet->protocol = pseudoHeader->protocol;
1093  packet->headerChecksum = 0;
1094  packet->srcAddr = pseudoHeader->srcAddr;
1095  packet->destAddr = pseudoHeader->destAddr;
1096 
1097  //The IHL field is the length of the IP packet header in 32-bit words, and
1098  //thus points to the beginning of the data. Note that the minimum value for
1099  //a correct header is 5 (refer to RFC 791, section 3.1)
1100  if(ancillary->routerAlert)
1101  {
1102  packet->headerLength = 6;
1103  }
1104 
1105  //Check whether the TTL value is zero
1106  if(packet->timeToLive == 0)
1107  {
1108  //Use default Time-To-Live value
1109  packet->timeToLive = IPV4_DEFAULT_TTL;
1110  }
1111 
1112 #if (IP_DIFF_SERV_SUPPORT == ENABLED)
1113  //Set DSCP field
1114  packet->typeOfService = (ancillary->dscp << 2) & 0xFC;
1115 #endif
1116 
1117  //Calculate IP header checksum
1118  packet->headerChecksum = ipCalcChecksumEx(buffer, offset,
1119  packet->headerLength * 4);
1120 
1121  //Ensure the source address is valid
1122  error = ipv4CheckSourceAddr(interface, pseudoHeader->srcAddr);
1123  //Invalid source address?
1124  if(error)
1125  return error;
1126 
1127  //Check destination address
1128  if(pseudoHeader->destAddr == IPV4_UNSPECIFIED_ADDR)
1129  {
1130  //The unspecified address must not appear on the public Internet
1131  error = ERROR_INVALID_ADDRESS;
1132  }
1133  else if(ipv4IsLocalHostAddr(pseudoHeader->destAddr))
1134  {
1135 #if (NET_LOOPBACK_IF_SUPPORT == ENABLED)
1136  uint_t i;
1137 
1138  //Initialize status code
1139  error = ERROR_NO_ROUTE;
1140 
1141  //Loop through network interfaces
1142  for(i = 0; i < NET_INTERFACE_COUNT; i++)
1143  {
1144  //Point to the current interface
1145  interface = &netInterface[i];
1146 
1147  //Loopback interface?
1148  if(interface->nicDriver != NULL &&
1149  interface->nicDriver->type == NIC_TYPE_LOOPBACK)
1150  {
1151  //Forward the packet to the loopback interface
1152  error = nicSendPacket(interface, buffer, offset, ancillary);
1153  break;
1154  }
1155  }
1156 #else
1157  //Addresses within the entire 127.0.0.0/8 block do not legitimately
1158  //appear on any network anywhere
1159  error = ERROR_NO_ROUTE;
1160 #endif
1161  }
1162  else
1163  {
1164 #if (ETH_SUPPORT == ENABLED)
1165  //Point to the physical interface
1166  physicalInterface = nicGetPhysicalInterface(interface);
1167 
1168  //Ethernet interface?
1169  if(physicalInterface->nicDriver != NULL &&
1170  physicalInterface->nicDriver->type == NIC_TYPE_ETHERNET)
1171  {
1173 
1174  //Get the destination IPv4 address
1175  destIpAddr = pseudoHeader->destAddr;
1176 
1177  //Perform address resolution
1178  if(!macCompAddr(&ancillary->destMacAddr, &MAC_UNSPECIFIED_ADDR))
1179  {
1180  //The destination address is already resolved
1181  error = NO_ERROR;
1182  }
1183  else if(ipv4IsBroadcastAddr(interface, destIpAddr))
1184  {
1185  //Use of the broadcast MAC address to send the packet
1186  ancillary->destMacAddr = MAC_BROADCAST_ADDR;
1187  //Successful address resolution
1188  error = NO_ERROR;
1189  }
1191  {
1192  //Map IPv4 multicast address to MAC-layer multicast address
1193  error = ipv4MapMulticastAddrToMac(destIpAddr, &ancillary->destMacAddr);
1194  }
1195  else if(ipv4IsLinkLocalAddr(pseudoHeader->srcAddr) ||
1197  {
1198  //Packets with a link-local source or destination address are not
1199  //routable off the link
1200  error = arpResolve(interface, destIpAddr, &ancillary->destMacAddr);
1201  }
1202  else if(ipv4IsOnLink(interface, destIpAddr))
1203  {
1204  //Resolve destination address before sending the packet
1205  error = arpResolve(interface, destIpAddr, &ancillary->destMacAddr);
1206  }
1207  else if(ancillary->dontRoute)
1208  {
1209  //Do not send the packet via a gateway
1210  error = arpResolve(interface, destIpAddr, &ancillary->destMacAddr);
1211  }
1212  else
1213  {
1214  //Default gateway selection
1215  error = ipv4SelectDefaultGateway(interface, pseudoHeader->srcAddr,
1216  &destIpAddr);
1217 
1218  //Check status code
1219  if(!error)
1220  {
1221  //Use the selected gateway to forward the packet
1222  error = arpResolve(interface, destIpAddr, &ancillary->destMacAddr);
1223  }
1224  else
1225  {
1226  //Number of IP datagrams discarded because no route could be found
1227  //to transmit them to their destination
1228  MIB2_IP_INC_COUNTER32(ipOutNoRoutes, 1);
1229  IP_MIB_INC_COUNTER32(ipv4SystemStats.ipSystemStatsOutNoRoutes, 1);
1230  }
1231  }
1232 
1233  //Successful address resolution?
1234  if(error == NO_ERROR)
1235  {
1236  //Update IP statistics
1237  ipv4UpdateOutStats(interface, destIpAddr, length);
1238 
1239  //Debug message
1240  TRACE_INFO("Sending IPv4 packet (%" PRIuSIZE " bytes)...\r\n", length);
1241  //Dump IP header contents for debugging purpose
1242  ipv4DumpHeader(packet);
1243 
1244  //Send Ethernet frame
1245  error = ethSendFrame(interface, &ancillary->destMacAddr,
1246  ETH_TYPE_IPV4, buffer, offset, ancillary);
1247  }
1248  else if(error == ERROR_IN_PROGRESS)
1249  {
1250  //Debug message
1251  TRACE_INFO("Enqueuing IPv4 packet (%" PRIuSIZE " bytes)...\r\n", length);
1252  //Dump IP header contents for debugging purpose
1253  ipv4DumpHeader(packet);
1254 
1255  //Enqueue packets waiting for address resolution
1256  error = arpEnqueuePacket(interface, destIpAddr, buffer, offset,
1257  ancillary);
1258  }
1259  else
1260  {
1261  //Debug message
1262  TRACE_WARNING("Cannot map IPv4 address to Ethernet address!\r\n");
1263  }
1264  }
1265  else
1266 #endif
1267 #if (PPP_SUPPORT == ENABLED)
1268  //PPP interface?
1269  if(interface->nicDriver != NULL &&
1270  interface->nicDriver->type == NIC_TYPE_PPP)
1271  {
1272  //Update IP statistics
1273  ipv4UpdateOutStats(interface, pseudoHeader->destAddr, length);
1274 
1275  //Debug message
1276  TRACE_INFO("Sending IPv4 packet (%" PRIuSIZE " bytes)...\r\n", length);
1277  //Dump IP header contents for debugging purpose
1278  ipv4DumpHeader(packet);
1279 
1280  //Send PPP frame
1281  error = pppSendFrame(interface, buffer, offset, PPP_PROTOCOL_IP);
1282  }
1283  else
1284 #endif
1285  //IPv4 interface?
1286  if(interface->nicDriver != NULL &&
1287  interface->nicDriver->type == NIC_TYPE_IPV4)
1288  {
1289  //Update IP statistics
1290  ipv4UpdateOutStats(interface, pseudoHeader->destAddr, length);
1291 
1292  //Debug message
1293  TRACE_INFO("Sending IPv4 packet (%" PRIuSIZE " bytes)...\r\n", length);
1294  //Dump IP header contents for debugging purpose
1295  ipv4DumpHeader(packet);
1296 
1297  //Send the packet over the specified link
1298  error = nicSendPacket(interface, buffer, offset, ancillary);
1299  }
1300  //Unknown interface type?
1301  else
1302  {
1303  //Report an error
1304  error = ERROR_INVALID_INTERFACE;
1305  }
1306  }
1307 
1308  //Return status code
1309  return error;
1310 }
1311 
1312 
1313 /**
1314  * @brief Join the specified host group
1315  * @param[in] interface Underlying network interface
1316  * @param[in] groupAddr IPv4 address identifying the host group to join
1317  * @return Error code
1318  **/
1319 
1321 {
1322  error_t error;
1323  uint_t i;
1324  Ipv4FilterEntry *entry;
1325  Ipv4FilterEntry *firstFreeEntry;
1326 #if (ETH_SUPPORT == ENABLED)
1327  NetInterface *physicalInterface;
1328  MacAddr macAddr;
1329 #endif
1330 
1331  //The IPv4 address must be a valid multicast address
1333  return ERROR_INVALID_ADDRESS;
1334 
1335 #if (ETH_SUPPORT == ENABLED)
1336  //Point to the physical interface
1337  physicalInterface = nicGetPhysicalInterface(interface);
1338 #endif
1339 
1340  //Initialize error code
1341  error = NO_ERROR;
1342  //Keep track of the first free entry
1343  firstFreeEntry = NULL;
1344 
1345  //Go through the multicast filter table
1346  for(i = 0; i < IPV4_MULTICAST_FILTER_SIZE; i++)
1347  {
1348  //Point to the current entry
1349  entry = &interface->ipv4Context.multicastFilter[i];
1350 
1351  //Valid entry?
1352  if(entry->refCount > 0)
1353  {
1354  //Check whether the table already contains the specified IPv4 address
1355  if(entry->addr == groupAddr)
1356  {
1357  //Increment the reference count
1358  entry->refCount++;
1359  //Successful processing
1360  return NO_ERROR;
1361  }
1362  }
1363  else
1364  {
1365  //Keep track of the first free entry
1366  if(firstFreeEntry == NULL)
1367  firstFreeEntry = entry;
1368  }
1369  }
1370 
1371  //Check whether the multicast filter table is full
1372  if(firstFreeEntry == NULL)
1373  {
1374  //A new entry cannot be added
1375  return ERROR_FAILURE;
1376  }
1377 
1378 #if (ETH_SUPPORT == ENABLED)
1379  //Map the IPv4 multicast address to a MAC-layer address
1381  //Add the corresponding address to the MAC filter table
1382  error = ethAcceptMacAddr(interface, &macAddr);
1383 
1384  //Check status code
1385  if(!error)
1386  {
1387  //Virtual interface?
1388  if(interface != physicalInterface)
1389  {
1390  //Configure the physical interface to accept the MAC address
1391  error = ethAcceptMacAddr(physicalInterface, &macAddr);
1392 
1393  //Any error to report?
1394  if(error)
1395  {
1396  //Clean up side effects
1397  ethDropMacAddr(interface, &macAddr);
1398  }
1399  }
1400  }
1401 #endif
1402 
1403  //MAC filter table successfully updated?
1404  if(!error)
1405  {
1406  //Now we can safely add a new entry to the table
1407  firstFreeEntry->addr = groupAddr;
1408  //Initialize the reference count
1409  firstFreeEntry->refCount = 1;
1410 
1411 #if (IGMP_HOST_SUPPORT == ENABLED)
1412  //Report multicast group membership to the router
1413  igmpHostJoinGroup(interface, firstFreeEntry);
1414 #endif
1415  }
1416 
1417  //Return status code
1418  return error;
1419 }
1420 
1421 
1422 /**
1423  * @brief Leave the specified host group
1424  * @param[in] interface Underlying network interface
1425  * @param[in] groupAddr IPv4 address identifying the host group to leave
1426  * @return Error code
1427  **/
1428 
1430 {
1431  uint_t i;
1432  Ipv4FilterEntry *entry;
1433 #if (ETH_SUPPORT == ENABLED)
1434  NetInterface *physicalInterface;
1435  MacAddr macAddr;
1436 #endif
1437 
1438  //The IPv4 address must be a valid multicast address
1440  return ERROR_INVALID_ADDRESS;
1441 
1442 #if (ETH_SUPPORT == ENABLED)
1443  //Point to the physical interface
1444  physicalInterface = nicGetPhysicalInterface(interface);
1445 #endif
1446 
1447  //Go through the multicast filter table
1448  for(i = 0; i < IPV4_MULTICAST_FILTER_SIZE; i++)
1449  {
1450  //Point to the current entry
1451  entry = &interface->ipv4Context.multicastFilter[i];
1452 
1453  //Valid entry?
1454  if(entry->refCount > 0)
1455  {
1456  //Specified IPv4 address found?
1457  if(entry->addr == groupAddr)
1458  {
1459  //Decrement the reference count
1460  entry->refCount--;
1461 
1462  //Remove the entry if the reference count drops to zero
1463  if(entry->refCount == 0)
1464  {
1465 #if (IGMP_HOST_SUPPORT == ENABLED)
1466  //Report group membership termination
1467  igmpHostLeaveGroup(interface, entry);
1468 #endif
1469 #if (ETH_SUPPORT == ENABLED)
1470  //Map the IPv4 multicast address to a MAC-layer address
1472  //Drop the corresponding address from the MAC filter table
1473  ethDropMacAddr(interface, &macAddr);
1474 
1475  //Virtual interface?
1476  if(interface != physicalInterface)
1477  {
1478  //Drop the corresponding address from the MAC filter table of
1479  //the physical interface
1480  ethDropMacAddr(physicalInterface, &macAddr);
1481  }
1482 #endif
1483  //Remove the multicast address from the list
1484  entry->addr = IPV4_UNSPECIFIED_ADDR;
1485  }
1486 
1487  //Successful processing
1488  return NO_ERROR;
1489  }
1490  }
1491  }
1492 
1493  //The specified IPv4 address does not exist
1494  return ERROR_ADDRESS_NOT_FOUND;
1495 }
1496 
1497 
1498 /**
1499  * @brief Convert a dot-decimal string to a binary IPv4 address
1500  * @param[in] str NULL-terminated string representing the IPv4 address
1501  * @param[out] ipAddr Binary representation of the IPv4 address
1502  * @return Error code
1503  **/
1504 
1506 {
1507  error_t error;
1508  int_t i = 0;
1509  int_t value = -1;
1510 
1511  //Parse input string
1512  while(1)
1513  {
1514  //Decimal digit found?
1515  if(osIsdigit(*str))
1516  {
1517  //First digit to be decoded?
1518  if(value < 0)
1519  value = 0;
1520 
1521  //Update the value of the current byte
1522  value = (value * 10) + (*str - '0');
1523 
1524  //The resulting value shall be in range 0 to 255
1525  if(value > 255)
1526  {
1527  //The conversion failed
1528  error = ERROR_INVALID_SYNTAX;
1529  break;
1530  }
1531  }
1532  //Dot separator found?
1533  else if(*str == '.' && i < 4)
1534  {
1535  //Each dot must be preceded by a valid number
1536  if(value < 0)
1537  {
1538  //The conversion failed
1539  error = ERROR_INVALID_SYNTAX;
1540  break;
1541  }
1542 
1543  //Save the current byte
1544  ((uint8_t *) ipAddr)[i++] = value;
1545  //Prepare to decode the next byte
1546  value = -1;
1547  }
1548  //End of string detected?
1549  else if(*str == '\0' && i == 3)
1550  {
1551  //The NULL character must be preceded by a valid number
1552  if(value < 0)
1553  {
1554  //The conversion failed
1555  error = ERROR_INVALID_SYNTAX;
1556  }
1557  else
1558  {
1559  //Save the last byte of the IPv4 address
1560  ((uint8_t *) ipAddr)[i] = value;
1561  //The conversion succeeded
1562  error = NO_ERROR;
1563  }
1564 
1565  //We are done
1566  break;
1567  }
1568  //Invalid character...
1569  else
1570  {
1571  //The conversion failed
1572  error = ERROR_INVALID_SYNTAX;
1573  break;
1574  }
1575 
1576  //Point to the next character
1577  str++;
1578  }
1579 
1580  //Return status code
1581  return error;
1582 }
1583 
1584 
1585 /**
1586  * @brief Convert a binary IPv4 address to dot-decimal notation
1587  * @param[in] ipAddr Binary representation of the IPv4 address
1588  * @param[out] str NULL-terminated string representing the IPv4 address
1589  * @return Pointer to the formatted string
1590  **/
1591 
1593 {
1594  uint8_t *p;
1595  static char_t buffer[16];
1596 
1597  //If the NULL pointer is given as parameter, then the internal buffer is used
1598  if(str == NULL)
1599  str = buffer;
1600 
1601  //Cast the address to byte array
1602  p = (uint8_t *) &ipAddr;
1603  //Format IPv4 address
1604  osSprintf(str, "%" PRIu8 ".%" PRIu8 ".%" PRIu8 ".%" PRIu8 "", p[0], p[1], p[2], p[3]);
1605 
1606  //Return a pointer to the formatted string
1607  return str;
1608 }
1609 
1610 
1611 /**
1612  * @brief Dump IPv4 header for debugging purpose
1613  * @param[in] ipHeader Pointer to the IPv4 header
1614  **/
1615 
1616 void ipv4DumpHeader(const Ipv4Header *ipHeader)
1617 {
1618  //Dump IP header contents
1619  TRACE_DEBUG(" Version = %" PRIu8 "\r\n", ipHeader->version);
1620  TRACE_DEBUG(" Header Length = %" PRIu8 "\r\n", ipHeader->headerLength);
1621  TRACE_DEBUG(" Type Of Service = %" PRIu8 "\r\n", ipHeader->typeOfService);
1622  TRACE_DEBUG(" Total Length = %" PRIu16 "\r\n", ntohs(ipHeader->totalLength));
1623  TRACE_DEBUG(" Identification = %" PRIu16 "\r\n", ntohs(ipHeader->identification));
1624  TRACE_DEBUG(" Flags = 0x%01X\r\n", ntohs(ipHeader->fragmentOffset) >> 13);
1625  TRACE_DEBUG(" Fragment Offset = %" PRIu16 "\r\n", ntohs(ipHeader->fragmentOffset) & 0x1FFF);
1626  TRACE_DEBUG(" Time To Live = %" PRIu8 "\r\n", ipHeader->timeToLive);
1627  TRACE_DEBUG(" Protocol = %" PRIu8 "\r\n", ipHeader->protocol);
1628  TRACE_DEBUG(" Header Checksum = 0x%04" PRIX16 "\r\n", ntohs(ipHeader->headerChecksum));
1629  TRACE_DEBUG(" Src Addr = %s\r\n", ipv4AddrToString(ipHeader->srcAddr, NULL));
1630  TRACE_DEBUG(" Dest Addr = %s\r\n", ipv4AddrToString(ipHeader->destAddr, NULL));
1631 }
1632 
1633 #endif
#define ipv4IsMulticastAddr(ipAddr)
Definition: ipv4.h:169
error_t ipv4SelectDefaultGateway(NetInterface *interface, Ipv4Addr srcAddr, Ipv4Addr *defaultGatewayAddr)
Default gateway selection.
Definition: ipv4_misc.c:392
error_t ethAcceptMacAddr(NetInterface *interface, const MacAddr *macAddr)
Add a unicast/multicast address to the MAC filter table.
Definition: ethernet.c:596
uint8_t length
Definition: coap_common.h:193
#define htons(value)
Definition: cpu_endian.h:413
MIB-II module.
@ ERROR_OUT_OF_RANGE
Definition: error.h:137
#define Ipv4Header
Definition: ipv4.h:36
Ipv4Addr addr
IPv4 address.
Definition: ipv4.h:341
@ IPV4_PROTOCOL_ICMP
Definition: ipv4.h:221
uint16_t ipCalcChecksumEx(const NetBuffer *buffer, size_t offset, size_t length)
Calculate IP checksum over a multi-part buffer.
Definition: ip.c:599
@ IPV4_OFFSET_MASK
Definition: ipv4.h:211
error_t ipv4GetDnsServer(NetInterface *interface, uint_t index, Ipv4Addr *addr)
Retrieve DNS server.
Definition: ipv4.c:494
error_t ipv4SetSubnetMaskEx(NetInterface *interface, uint_t index, Ipv4Addr mask)
Configure subnet mask.
Definition: ipv4.c:282
signed int int_t
Definition: compiler_port.h:49
uint_t chunkCount
Definition: net_mem.h:98
error_t ipv4SetDnsServer(NetInterface *interface, uint_t index, Ipv4Addr addr)
Configure DNS server.
Definition: ipv4.c:460
#define netMutex
Definition: net_legacy.h:195
void ipv4FlushFragQueue(NetInterface *interface)
Flush IPv4 reassembly queue.
Definition: ipv4_frag.c:646
Ipv4Addr dnsServerList[IPV4_DNS_SERVER_LIST_SIZE]
DNS servers.
Definition: ipv4.h:375
error_t ipv4GetSubnetMaskEx(NetInterface *interface, uint_t index, Ipv4Addr *mask)
Retrieve subnet mask.
Definition: ipv4.c:326
#define IP_MIB_INC_COUNTER32(name, value)
Definition: ip_mib_module.h:46
@ ERROR_INVALID_INTERFACE
Invalid interface.
Definition: error.h:53
uint8_t p
Definition: ndp.h:298
error_t nicSendPacket(NetInterface *interface, const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send a packet to the network controller.
Definition: nic.c:280
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
bool_t ipv4IsBroadcastAddr(NetInterface *interface, Ipv4Addr ipAddr)
Check whether an IPv4 address is a broadcast address.
Definition: ipv4_misc.c:469
#define TRUE
Definition: os_port.h:52
error_t ipv4SetDefaultGatewayEx(NetInterface *interface, uint_t index, Ipv4Addr addr)
Configure default gateway.
Definition: ipv4.c:375
void tcpProcessSegment(NetInterface *interface, IpPseudoHeader *pseudoHeader, const NetBuffer *buffer, size_t offset, NetRxAncillary *ancillary)
Incoming TCP segment processing.
Definition: tcp_fsm.c:75
@ ERROR_INVALID_HEADER
Definition: error.h:87
void ipv4ProcessPacket(NetInterface *interface, Ipv4Header *packet, size_t length, NetRxAncillary *ancillary)
Incoming IPv4 packet processing.
Definition: ipv4.c:577
error_t ethSendFrame(NetInterface *interface, const MacAddr *destAddr, uint16_t type, NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send an Ethernet frame.
Definition: ethernet.c:401
@ ICMP_CODE_PROTOCOL_UNREACHABLE
Definition: icmp.h:77
error_t arpEnqueuePacket(NetInterface *interface, Ipv4Addr ipAddr, NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Enqueue an IPv4 packet waiting for address resolution.
Definition: arp.c:484
void ipv4LinkChangeEvent(NetInterface *interface)
Callback function for link change event.
Definition: ipv4.c:526
void arpFlushCache(NetInterface *interface)
Flush ARP cache.
Definition: arp.c:190
error_t ipv4SetHostAddrEx(NetInterface *interface, uint_t index, Ipv4Addr addr)
Assign host address.
Definition: ipv4.c:143
#define NET_INTERFACE_COUNT
Definition: net.h:113
Ipv4AddrState state
IPv4 address state.
Definition: ipv4.h:342
#define ipv4IsLinkLocalAddr(ipAddr)
Definition: ipv4.h:165
Ipv4FilterEntry multicastFilter[IPV4_MULTICAST_FILTER_SIZE]
Multicast filter table.
Definition: ipv4.h:376
void autoIpLinkChangeEvent(AutoIpContext *context)
Callback function for link change event.
Definition: auto_ip_misc.c:270
@ ETH_TYPE_IPV4
Definition: ethernet.h:164
size_t length
Definition: ip.h:99
void ipv4ProcessDatagram(NetInterface *interface, const NetBuffer *buffer, size_t offset, NetRxAncillary *ancillary)
Incoming IPv4 datagram processing.
Definition: ipv4.c:794
error_t udpProcessDatagram(NetInterface *interface, IpPseudoHeader *pseudoHeader, const NetBuffer *buffer, size_t offset, NetRxAncillary *ancillary)
Incoming UDP datagram processing.
Definition: udp.c:124
ChunkDesc chunk[1]
Definition: net_mem.h:100
uint32_t Ipv4Addr
IPv4 network address.
Definition: ipv4.h:268
Helper functions for DHCP client.
error_t ipv4GetDefaultGateway(NetInterface *interface, Ipv4Addr *addr)
Retrieve default gateway.
Definition: ipv4.c:409
void igmpLinkChangeEvent(NetInterface *interface)
Callback function for link change event.
Definition: igmp_common.c:123
IPv4 context.
Definition: ipv4.h:368
Ethernet.
bool_t isRouter
A flag indicating whether routing is enabled on this interface.
Definition: ipv4.h:370
error_t ethDropMacAddr(NetInterface *interface, const MacAddr *macAddr)
Remove a unicast/multicast address from the MAC filter table.
Definition: ethernet.c:666
IP pseudo header.
Definition: ip.h:98
@ NIC_TYPE_LOOPBACK
Loopback interface.
Definition: nic.h:88
error_t ipv4CheckDestAddr(NetInterface *interface, Ipv4Addr ipAddr)
Destination IPv4 address filtering.
Definition: ipv4_misc.c:118
@ IPV4_PROTOCOL_TCP
Definition: ipv4.h:223
@ ERROR_IN_PROGRESS
Definition: error.h:213
Helper functions for IPv4.
void ipv4DumpHeader(const Ipv4Header *ipHeader)
Dump IPv4 header for debugging purpose.
Definition: ipv4.c:1616
error_t ipv4GetSubnetMask(NetInterface *interface, Ipv4Addr *mask)
Retrieve subnet mask.
Definition: ipv4.c:311
uint16_t length
Definition: net_mem.h:79
#define FALSE
Definition: os_port.h:48
__start_packed struct @0 MacAddr
MAC address.
@ IPV4_PROTOCOL_AH
Definition: ipv4.h:226
void ipv4UpdateErrorStats(NetInterface *interface, error_t error)
Update Ethernet error statistics.
Definition: ipv4_misc.c:905
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
ICMP (Internet Control Message Protocol)
NetInterface * nicGetPhysicalInterface(NetInterface *interface)
Retrieve physical interface.
Definition: nic.c:84
size_t linkMtu
Maximum transmission unit.
Definition: ipv4.h:369
error_t
Error codes.
Definition: error.h:43
#define netInterface
Definition: net_legacy.h:199
@ ERROR_PROTOCOL_UNREACHABLE
Definition: error.h:84
#define osSprintf(dest,...)
Definition: os_port.h:230
void ipv4UpdateInStats(NetInterface *interface, Ipv4Addr destIpAddr, size_t length)
Update IPv4 input statistics.
Definition: ipv4_misc.c:820
#define IP_MIB_INC_COUNTER64(name, value)
Definition: ip_mib_module.h:47
error_t ipv4GetDefaultGatewayEx(NetInterface *interface, uint_t index, Ipv4Addr *addr)
Retrieve default gateway.
Definition: ipv4.c:424
TCP finite state machine.
bool_t enableEchoReq
Support for ICMP Echo Request messages.
Definition: ipv4.h:371
void * netBufferAt(const NetBuffer *buffer, size_t offset)
Returns a pointer to the data at the specified position.
Definition: net_mem.c:413
void * address
Definition: net_mem.h:78
uint8_t value[]
Definition: tcp.h:367
@ ERROR_INVALID_ADDRESS
Definition: error.h:103
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
@ IPV4_FLAG_MF
Definition: ipv4.h:210
void ipv4ReassembleDatagram(NetInterface *interface, const Ipv4Header *packet, size_t length, NetRxAncillary *ancillary)
IPv4 datagram reassembly algorithm.
Definition: ipv4_frag.c:184
uint_t maxChunkCount
Definition: net_mem.h:99
#define IPV4_DNS_SERVER_LIST_SIZE
Definition: ipv4.h:77
#define NetRxAncillary
Definition: net_misc.h:40
#define NetInterface
Definition: net.h:36
@ ERROR_INVALID_LENGTH
Definition: error.h:111
error_t ipv4GetHostAddr(NetInterface *interface, Ipv4Addr *addr)
Retrieve host address.
Definition: ipv4.c:202
uint16_t identification
IPv4 fragment identification field.
Definition: ipv4.h:373
#define MIB2_IP_INC_COUNTER32(name, value)
Definition: mib2_module.h:164
bool_t ipv4IsTentativeAddr(NetInterface *interface, Ipv4Addr ipAddr)
Check whether an IPv4 address is a tentative address.
Definition: ipv4_misc.c:515
IPv4 multicast filter entry.
Definition: ipv4.h:354
#define NetTxAncillary
Definition: net_misc.h:36
uint8_t mask
Definition: web_socket.h:317
uint8_t fragOffset[3]
Definition: dtls_misc.h:190
void igmpProcessMessage(NetInterface *interface, Ipv4PseudoHeader *pseudoHeader, const NetBuffer *buffer, size_t offset, NetRxAncillary *ancillary)
Process incoming IGMP message.
Definition: igmp_common.c:259
void ipv4UpdateOutStats(NetInterface *interface, Ipv4Addr destIpAddr, size_t length)
Update IPv4 output statistics.
Definition: ipv4_misc.c:856
#define osIsdigit(c)
Definition: os_port.h:278
#define Ipv4PseudoHeader
Definition: ipv4.h:39
#define TRACE_INFO(...)
Definition: debug.h:95
#define IPV4_ADDR_LIST_SIZE
Definition: ipv4.h:70
IGMP host.
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
@ ERROR_MESSAGE_TOO_LONG
Definition: error.h:136
error_t ipv4SendPacket(NetInterface *interface, Ipv4PseudoHeader *pseudoHeader, uint16_t fragId, size_t fragOffset, NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send an IPv4 packet.
Definition: ipv4.c:1051
bool_t ipv4IsOnLink(NetInterface *interface, Ipv4Addr ipAddr)
Check whether an IPv4 address is on-link.
Definition: ipv4_misc.c:434
IPv4 address entry.
Definition: ipv4.h:340
error_t ipv4ForwardPacket(NetInterface *srcInterface, const NetBuffer *ipPacket, size_t ipPacketOffset)
bool_t ipv4TrapIgmpPacket(Ipv4Header *header)
Trap IGMP packets.
Definition: ipv4_misc.c:790
@ ERROR_NO_ROUTE
Definition: error.h:219
TCP/IP raw sockets.
#define IPV4_DEFAULT_TTL
Definition: ipv4.h:63
@ IPV4_PROTOCOL_IGMP
Definition: ipv4.h:222
#define ntohs(value)
Definition: cpu_endian.h:421
@ NIC_TYPE_PPP
PPP interface.
Definition: nic.h:84
#define TRACE_WARNING(...)
Definition: debug.h:85
#define TRACE_DEBUG(...)
Definition: debug.h:107
char char_t
Definition: compiler_port.h:48
@ ICMP_TYPE_DEST_UNREACHABLE
Definition: icmp.h:54
Ipv4Addr addr
Multicast address.
Definition: ipv4.h:355
error_t rawSocketProcessIpPacket(NetInterface *interface, IpPseudoHeader *pseudoHeader, const NetBuffer *buffer, size_t offset, NetRxAncillary *ancillary)
Process incoming IP packet.
Definition: raw_socket.c:68
error_t pppSendFrame(NetInterface *interface, NetBuffer *buffer, size_t offset, uint16_t protocol)
Send a PPP frame.
Definition: ppp.c:1022
bool_t ipv4IsLocalHostAddr(Ipv4Addr ipAddr)
Check whether the specified IPv4 is assigned to the host.
Definition: ipv4_misc.c:551
IPv4 and IPv6 common routines.
@ IPV4_PROTOCOL_UDP
Definition: ipv4.h:224
IP MIB module.
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
@ IPV4_ADDR_STATE_INVALID
An address that is not assigned to any interface.
Definition: ipv4.h:196
Ipv4Addr groupAddr
Definition: igmp_common.h:169
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
@ IPV4_PROTOCOL_ESP
Definition: ipv4.h:225
error_t ipv4SetDefaultGateway(NetInterface *interface, Ipv4Addr addr)
Configure default gateway.
Definition: ipv4.c:360
error_t ipv4MapMulticastAddrToMac(Ipv4Addr ipAddr, MacAddr *macAddr)
Map an host group address to a MAC-layer multicast address.
Definition: ipv4_misc.c:757
UDP (User Datagram Protocol)
#define IPV4_VERSION
Definition: ipv4.h:90
error_t ipv4GetHostAddrEx(NetInterface *interface, uint_t index, Ipv4Addr *addr)
Retrieve host address.
Definition: ipv4.c:217
Ipv4FragDesc fragQueue[IPV4_MAX_FRAG_DATAGRAMS]
IPv4 fragment reassembly queue.
Definition: ipv4.h:378
#define macCompAddr(macAddr1, macAddr2)
Definition: ethernet.h:130
error_t igmpHostJoinGroup(NetInterface *interface, Ipv4FilterEntry *entry)
Join the specified host group.
Definition: igmp_host.c:87
error_t ipv4SendDatagram(NetInterface *interface, Ipv4PseudoHeader *pseudoHeader, NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send an IPv4 datagram.
Definition: ipv4.c:977
IPv4 routing.
uint16_t id
Definition: dns_common.h:158
@ ICMP_CODE_PORT_UNREACHABLE
Definition: icmp.h:78
error_t ipv4FragmentDatagram(NetInterface *interface, Ipv4PseudoHeader *pseudoHeader, uint16_t id, const NetBuffer *payload, size_t payloadOffset, NetTxAncillary *ancillary)
Fragment an IPv4 datagram into smaller packets.
Definition: ipv4_frag.c:72
@ ERROR_ADDRESS_NOT_FOUND
Definition: error.h:257
@ ERROR_INVALID_SYNTAX
Definition: error.h:68
error_t ipv4SetHostAddr(NetInterface *interface, Ipv4Addr addr)
Assign host address.
Definition: ipv4.c:128
Helper functions for Auto-IP.
error_t ipv4StringToAddr(const char_t *str, Ipv4Addr *ipAddr)
Convert a dot-decimal string to a binary IPv4 address.
Definition: ipv4.c:1505
uint_t refCount
Reference count for the current entry.
Definition: ipv4.h:356
error_t ipv4CheckSourceAddr(NetInterface *interface, Ipv4Addr ipAddr)
Source IPv4 address filtering.
Definition: ipv4_misc.c:94
error_t arpResolve(NetInterface *interface, Ipv4Addr ipAddr, MacAddr *macAddr)
Address resolution using ARP protocol.
Definition: arp.c:391
void icmpProcessMessage(NetInterface *interface, Ipv4PseudoHeader *requestPseudoHeader, const NetBuffer *buffer, size_t offset)
Incoming ICMP message processing.
Definition: icmp.c:111
@ IPV4_ADDR_STATE_VALID
An address assigned to an interface whose use is unrestricted.
Definition: ipv4.h:198
Ipv4Addr addr
Definition: nbns_common.h:121
@ NIC_TYPE_IPV4
IPv4 interface.
Definition: nic.h:85
bool_t conflict
Address conflict detected.
Definition: ipv4.h:343
error_t ipv4JoinMulticastGroup(NetInterface *interface, Ipv4Addr groupAddr)
Join the specified host group.
Definition: ipv4.c:1320
IPv4 (Internet Protocol Version 4)
error_t ipv4LeaveMulticastGroup(NetInterface *interface, Ipv4Addr groupAddr)
Leave the specified host group.
Definition: ipv4.c:1429
void dhcpClientLinkChangeEvent(DhcpClientContext *context)
Callback function for link change event.
@ PPP_PROTOCOL_IP
Internet Protocol.
Definition: ppp.h:199
#define PRIuSIZE
unsigned int uint_t
Definition: compiler_port.h:50
error_t ipv4AddRouterAlertOption(NetBuffer *buffer, size_t *offset)
Append a Router Alert option to an IPv4 packet.
Definition: ipv4_misc.c:54
@ ERROR_PORT_UNREACHABLE
Definition: error.h:85
#define osMemset(p, value, length)
Definition: os_port.h:134
TCP/IP stack core.
char_t * ipv4AddrToString(Ipv4Addr ipAddr, char_t *str)
Convert a binary IPv4 address to dot-decimal notation.
Definition: ipv4.c:1592
bool_t enableBroadcastEchoReq
Support for broadcast ICMP Echo Request messages.
Definition: ipv4.h:372
ARP (Address Resolution Protocol)
error_t ipv4Init(NetInterface *interface)
IPv4 related initialization.
Definition: ipv4.c:80
uint8_t ipAddr[4]
Definition: mib_common.h:187
Ipv4PseudoHeader ipv4Data
Definition: ip.h:103
error_t mdnsResponderStartProbing(MdnsResponderContext *context)
Restart probing process.
error_t icmpSendErrorMessage(NetInterface *interface, uint8_t type, uint8_t code, uint8_t parameter, const NetBuffer *ipPacket, size_t ipPacketOffset)
Send an ICMP Error message.
Definition: icmp.c:337
const MacAddr MAC_UNSPECIFIED_ADDR
Definition: ethernet.c:55
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
const MacAddr MAC_BROADCAST_ADDR
Definition: ethernet.c:57
error_t igmpHostLeaveGroup(NetInterface *interface, Ipv4FilterEntry *entry)
Leave the specified host group.
Definition: igmp_host.c:137
#define IPV4_UNSPECIFIED_ADDR
Definition: ipv4.h:111
uint16_t ipCalcChecksum(const void *data, size_t length)
IP checksum calculation.
Definition: ip.c:479
mDNS responder (Multicast DNS)
@ NIC_TYPE_ETHERNET
Ethernet interface.
Definition: nic.h:83
#define IPV4_MULTICAST_FILTER_SIZE
Definition: ipv4.h:84
Ipv4Addr destIpAddr
Definition: ipcp.h:78
error_t ipv4SetSubnetMask(NetInterface *interface, Ipv4Addr mask)
Configure subnet mask.
Definition: ipv4.c:267