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