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