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.1.6
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, 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] ancillary Additional options passed to the stack along with
780  * the packet
781  **/
782 
783 void ipv4ProcessDatagram(NetInterface *interface, const NetBuffer *buffer,
784  NetRxAncillary *ancillary)
785 {
786  error_t error;
787  size_t offset;
788  size_t length;
789  Ipv4Header *header;
790  IpPseudoHeader pseudoHeader;
791 
792  //Retrieve the length of the IPv4 datagram
793  length = netBufferGetLength(buffer);
794 
795  //Point to the IPv4 header
796  header = netBufferAt(buffer, 0);
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  //Check the protocol field
827  switch(header->protocol)
828  {
829  //ICMP protocol?
830  case IPV4_PROTOCOL_ICMP:
831  //Process incoming ICMP message
832  icmpProcessMessage(interface, &pseudoHeader.ipv4Data, buffer, offset);
833 
834 #if (RAW_SOCKET_SUPPORT == ENABLED)
835  //Allow raw sockets to process ICMP messages
836  rawSocketProcessIpPacket(interface, &pseudoHeader, buffer, offset,
837  ancillary);
838 #endif
839 
840  //No error to report
841  error = NO_ERROR;
842  //Continue processing
843  break;
844 
845 #if (IGMP_HOST_SUPPORT == ENABLED || IGMP_ROUTER_SUPPORT == ENABLED || \
846  IGMP_SNOOPING_SUPPORT == ENABLED)
847  //IGMP protocol?
848  case IPV4_PROTOCOL_IGMP:
849  //Process incoming IGMP message
850  igmpProcessMessage(interface, &pseudoHeader.ipv4Data, buffer, offset,
851  ancillary);
852 
853 #if (RAW_SOCKET_SUPPORT == ENABLED)
854  //Allow raw sockets to process IGMP messages
855  rawSocketProcessIpPacket(interface, &pseudoHeader, buffer, offset,
856  ancillary);
857 #endif
858 
859  //No error to report
860  error = NO_ERROR;
861  //Continue processing
862  break;
863 #endif
864 
865 #if (TCP_SUPPORT == ENABLED)
866  //TCP protocol?
867  case IPV4_PROTOCOL_TCP:
868  //Process incoming TCP segment
869  tcpProcessSegment(interface, &pseudoHeader, buffer, offset, ancillary);
870  //No error to report
871  error = NO_ERROR;
872  //Continue processing
873  break;
874 #endif
875 
876 #if (UDP_SUPPORT == ENABLED)
877  //UDP protocol?
878  case IPV4_PROTOCOL_UDP:
879  //Process incoming UDP datagram
880  error = udpProcessDatagram(interface, &pseudoHeader, buffer, offset,
881  ancillary);
882  //Continue processing
883  break;
884 #endif
885 
886  //Unknown protocol?
887  default:
888 #if (RAW_SOCKET_SUPPORT == ENABLED)
889  //Allow raw sockets to process IPv4 packets
890  error = rawSocketProcessIpPacket(interface, &pseudoHeader, buffer, offset,
891  ancillary);
892 #else
893  //Report an error
895 #endif
896  //Continue processing
897  break;
898  }
899 
900  //Unreachable protocol?
901  if(error == ERROR_PROTOCOL_UNREACHABLE)
902  {
903  //Update IP statistics
904  ipv4UpdateErrorStats(interface, error);
905 
906  //Send a Destination Unreachable message
908  ICMP_CODE_PROTOCOL_UNREACHABLE, 0, buffer, 0);
909  }
910  else
911  {
912  //Total number of input datagrams successfully delivered to IP
913  //user-protocols
914  MIB2_IP_INC_COUNTER32(ipInDelivers, 1);
915  IP_MIB_INC_COUNTER32(ipv4SystemStats.ipSystemStatsInDelivers, 1);
916  IP_MIB_INC_COUNTER64(ipv4SystemStats.ipSystemStatsHCInDelivers, 1);
917  IP_MIB_INC_COUNTER32(ipv4IfStatsTable[interface->index].ipIfStatsInDelivers, 1);
918  IP_MIB_INC_COUNTER64(ipv4IfStatsTable[interface->index].ipIfStatsHCInDelivers, 1);
919  }
920 
921  //Unreachable port?
922  if(error == ERROR_PORT_UNREACHABLE)
923  {
924  //Send a Destination Unreachable message
926  ICMP_CODE_PORT_UNREACHABLE, 0, buffer, 0);
927  }
928 }
929 
930 
931 /**
932  * @brief Send an IPv4 datagram
933  * @param[in] interface Underlying network interface
934  * @param[in] pseudoHeader IPv4 pseudo header
935  * @param[in] buffer Multi-part buffer containing the payload
936  * @param[in] offset Offset to the first byte of the payload
937  * @param[in] ancillary Additional options passed to the stack along with
938  * the packet
939  * @return Error code
940  **/
941 
943  NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
944 {
945  error_t error;
946  size_t length;
947  uint16_t id;
948 
949  //Total number of IP datagrams which local IP user-protocols supplied to IP
950  //in requests for transmission
951  MIB2_IP_INC_COUNTER32(ipOutRequests, 1);
952  IP_MIB_INC_COUNTER32(ipv4SystemStats.ipSystemStatsOutRequests, 1);
953  IP_MIB_INC_COUNTER64(ipv4SystemStats.ipSystemStatsHCOutRequests, 1);
954  IP_MIB_INC_COUNTER32(ipv4IfStatsTable[interface->index].ipIfStatsOutRequests, 1);
955  IP_MIB_INC_COUNTER64(ipv4IfStatsTable[interface->index].ipIfStatsHCOutRequests, 1);
956 
957  //Retrieve the length of payload
958  length = netBufferGetLength(buffer) - offset;
959 
960  //Identification field is primarily used to identify fragments of an
961  //original IP datagram
962  id = interface->ipv4Context.identification++;
963 
964  //If the payload length is smaller than the network interface MTU then no
965  //fragmentation is needed
966  if((length + sizeof(Ipv4Header)) <= interface->ipv4Context.linkMtu)
967  {
968  //Send data as is
969  error = ipv4SendPacket(interface, pseudoHeader, id, 0, buffer, offset,
970  ancillary);
971  }
972  //If the payload length exceeds the network interface MTU then the device
973  //must fragment the data
974  else
975  {
976 #if (IPV4_FRAG_SUPPORT == ENABLED)
977  //Fragment IP datagram into smaller packets
978  error = ipv4FragmentDatagram(interface, pseudoHeader, id, buffer, offset,
979  ancillary);
980 #else
981  //Fragmentation is not supported
982  error = ERROR_MESSAGE_TOO_LONG;
983 #endif
984  }
985 
986  //Return status code
987  return error;
988 }
989 
990 
991 /**
992  * @brief Send an IPv4 packet
993  * @param[in] interface Underlying network interface
994  * @param[in] pseudoHeader IPv4 pseudo header
995  * @param[in] fragId Fragment identification field
996  * @param[in] fragOffset Fragment offset field
997  * @param[in] buffer Multi-part buffer containing the payload
998  * @param[in] offset Offset to the first byte of the payload
999  * @param[in] ancillary Additional options passed to the stack along with
1000  * the packet
1001  * @return Error code
1002  **/
1003 
1005  uint16_t fragId, size_t fragOffset, NetBuffer *buffer, size_t offset,
1006  NetTxAncillary *ancillary)
1007 {
1008  error_t error;
1009  size_t length;
1010  Ipv4Header *packet;
1011 #if (ETH_SUPPORT == ENABLED)
1012  NetInterface *physicalInterface;
1013 #endif
1014 
1015  //Check whether an IP Router Alert option should be added
1016  if(ancillary->routerAlert)
1017  {
1018  //Add an IP Router Alert option
1019  error = ipv4AddRouterAlertOption(buffer, &offset);
1020  //Any error to report?
1021  if(error)
1022  return error;
1023  }
1024 
1025  //Is there enough space for the IPv4 header?
1026  if(offset < sizeof(Ipv4Header))
1027  return ERROR_INVALID_PARAMETER;
1028 
1029  //Make room for the header
1030  offset -= sizeof(Ipv4Header);
1031  //Calculate the size of the entire packet, including header and data
1032  length = netBufferGetLength(buffer) - offset;
1033 
1034  //Point to the IPv4 header
1035  packet = netBufferAt(buffer, offset);
1036 
1037  //Format IPv4 header
1038  packet->version = IPV4_VERSION;
1039  packet->headerLength = 5;
1040  packet->typeOfService = 0;
1041  packet->totalLength = htons(length);
1042  packet->identification = htons(fragId);
1043  packet->fragmentOffset = htons(fragOffset);
1044  packet->timeToLive = ancillary->ttl;
1045  packet->protocol = pseudoHeader->protocol;
1046  packet->headerChecksum = 0;
1047  packet->srcAddr = pseudoHeader->srcAddr;
1048  packet->destAddr = pseudoHeader->destAddr;
1049 
1050  //The IHL field is the length of the IP packet header in 32-bit words, and
1051  //thus points to the beginning of the data. Note that the minimum value for
1052  //a correct header is 5 (refer to RFC 791, section 3.1)
1053  if(ancillary->routerAlert)
1054  {
1055  packet->headerLength = 6;
1056  }
1057 
1058  //Check whether the TTL value is zero
1059  if(packet->timeToLive == 0)
1060  {
1061  //Use default Time-To-Live value
1062  packet->timeToLive = IPV4_DEFAULT_TTL;
1063  }
1064 
1065 #if (IP_DIFF_SERV_SUPPORT == ENABLED)
1066  //Set DSCP field
1067  packet->typeOfService = (ancillary->dscp << 2) & 0xFC;
1068 #endif
1069 
1070  //Calculate IP header checksum
1071  packet->headerChecksum = ipCalcChecksumEx(buffer, offset,
1072  packet->headerLength * 4);
1073 
1074  //Ensure the source address is valid
1075  error = ipv4CheckSourceAddr(interface, pseudoHeader->srcAddr);
1076  //Invalid source address?
1077  if(error)
1078  return error;
1079 
1080  //Check destination address
1081  if(pseudoHeader->destAddr == IPV4_UNSPECIFIED_ADDR)
1082  {
1083  //The unspecified address must not appear on the public Internet
1084  error = ERROR_INVALID_ADDRESS;
1085  }
1086  else if(ipv4IsLocalHostAddr(pseudoHeader->destAddr))
1087  {
1088 #if (NET_LOOPBACK_IF_SUPPORT == ENABLED)
1089  uint_t i;
1090 
1091  //Initialize status code
1092  error = ERROR_NO_ROUTE;
1093 
1094  //Loop through network interfaces
1095  for(i = 0; i < NET_INTERFACE_COUNT; i++)
1096  {
1097  //Point to the current interface
1098  interface = &netInterface[i];
1099 
1100  //Loopback interface?
1101  if(interface->nicDriver != NULL &&
1102  interface->nicDriver->type == NIC_TYPE_LOOPBACK)
1103  {
1104  //Forward the packet to the loopback interface
1105  error = nicSendPacket(interface, buffer, offset, ancillary);
1106  break;
1107  }
1108  }
1109 #else
1110  //Addresses within the entire 127.0.0.0/8 block do not legitimately
1111  //appear on any network anywhere
1112  error = ERROR_NO_ROUTE;
1113 #endif
1114  }
1115  else
1116  {
1117 #if (ETH_SUPPORT == ENABLED)
1118  //Point to the physical interface
1119  physicalInterface = nicGetPhysicalInterface(interface);
1120 
1121  //Ethernet interface?
1122  if(physicalInterface->nicDriver != NULL &&
1123  physicalInterface->nicDriver->type == NIC_TYPE_ETHERNET)
1124  {
1126 
1127  //Get the destination IPv4 address
1128  destIpAddr = pseudoHeader->destAddr;
1129 
1130  //Perform address resolution
1131  if(!macCompAddr(&ancillary->destMacAddr, &MAC_UNSPECIFIED_ADDR))
1132  {
1133  //The destination address is already resolved
1134  error = NO_ERROR;
1135  }
1136  else if(ipv4IsBroadcastAddr(interface, destIpAddr))
1137  {
1138  //Use of the broadcast MAC address to send the packet
1139  ancillary->destMacAddr = MAC_BROADCAST_ADDR;
1140  //Successful address resolution
1141  error = NO_ERROR;
1142  }
1144  {
1145  //Map IPv4 multicast address to MAC-layer multicast address
1146  error = ipv4MapMulticastAddrToMac(destIpAddr, &ancillary->destMacAddr);
1147  }
1148  else if(ipv4IsLinkLocalAddr(pseudoHeader->srcAddr) ||
1150  {
1151  //Packets with a link-local source or destination address are not
1152  //routable off the link
1153  error = arpResolve(interface, destIpAddr, &ancillary->destMacAddr);
1154  }
1155  else if(ipv4IsOnLink(interface, destIpAddr))
1156  {
1157  //Resolve destination address before sending the packet
1158  error = arpResolve(interface, destIpAddr, &ancillary->destMacAddr);
1159  }
1160  else if(ancillary->dontRoute)
1161  {
1162  //Do not send the packet via a gateway
1163  error = arpResolve(interface, destIpAddr, &ancillary->destMacAddr);
1164  }
1165  else
1166  {
1167  //Default gateway selection
1168  error = ipv4SelectDefaultGateway(interface, pseudoHeader->srcAddr,
1169  &destIpAddr);
1170 
1171  //Check status code
1172  if(!error)
1173  {
1174  //Use the selected gateway to forward the packet
1175  error = arpResolve(interface, destIpAddr, &ancillary->destMacAddr);
1176  }
1177  else
1178  {
1179  //Number of IP datagrams discarded because no route could be found
1180  //to transmit them to their destination
1181  MIB2_IP_INC_COUNTER32(ipOutNoRoutes, 1);
1182  IP_MIB_INC_COUNTER32(ipv4SystemStats.ipSystemStatsOutNoRoutes, 1);
1183  }
1184  }
1185 
1186  //Successful address resolution?
1187  if(error == NO_ERROR)
1188  {
1189  //Update IP statistics
1190  ipv4UpdateOutStats(interface, destIpAddr, length);
1191 
1192  //Debug message
1193  TRACE_INFO("Sending IPv4 packet (%" PRIuSIZE " bytes)...\r\n", length);
1194  //Dump IP header contents for debugging purpose
1195  ipv4DumpHeader(packet);
1196 
1197  //Send Ethernet frame
1198  error = ethSendFrame(interface, &ancillary->destMacAddr,
1199  ETH_TYPE_IPV4, buffer, offset, ancillary);
1200  }
1201  else if(error == ERROR_IN_PROGRESS)
1202  {
1203  //Debug message
1204  TRACE_INFO("Enqueuing IPv4 packet (%" PRIuSIZE " bytes)...\r\n", length);
1205  //Dump IP header contents for debugging purpose
1206  ipv4DumpHeader(packet);
1207 
1208  //Enqueue packets waiting for address resolution
1209  error = arpEnqueuePacket(interface, destIpAddr, buffer, offset,
1210  ancillary);
1211  }
1212  else
1213  {
1214  //Debug message
1215  TRACE_WARNING("Cannot map IPv4 address to Ethernet address!\r\n");
1216  }
1217  }
1218  else
1219 #endif
1220 #if (PPP_SUPPORT == ENABLED)
1221  //PPP interface?
1222  if(interface->nicDriver != NULL &&
1223  interface->nicDriver->type == NIC_TYPE_PPP)
1224  {
1225  //Update IP statistics
1226  ipv4UpdateOutStats(interface, pseudoHeader->destAddr, length);
1227 
1228  //Debug message
1229  TRACE_INFO("Sending IPv4 packet (%" PRIuSIZE " bytes)...\r\n", length);
1230  //Dump IP header contents for debugging purpose
1231  ipv4DumpHeader(packet);
1232 
1233  //Send PPP frame
1234  error = pppSendFrame(interface, buffer, offset, PPP_PROTOCOL_IP);
1235  }
1236  else
1237 #endif
1238  //Unknown interface type?
1239  {
1240  //Report an error
1241  error = ERROR_INVALID_INTERFACE;
1242  }
1243  }
1244 
1245  //Return status code
1246  return error;
1247 }
1248 
1249 
1250 /**
1251  * @brief Join the specified host group
1252  * @param[in] interface Underlying network interface
1253  * @param[in] groupAddr IPv4 address identifying the host group to join
1254  * @return Error code
1255  **/
1256 
1258 {
1259  error_t error;
1260  uint_t i;
1261  Ipv4FilterEntry *entry;
1262  Ipv4FilterEntry *firstFreeEntry;
1263 #if (ETH_SUPPORT == ENABLED)
1264  NetInterface *physicalInterface;
1265  MacAddr macAddr;
1266 #endif
1267 
1268  //The IPv4 address must be a valid multicast address
1270  return ERROR_INVALID_ADDRESS;
1271 
1272 #if (ETH_SUPPORT == ENABLED)
1273  //Point to the physical interface
1274  physicalInterface = nicGetPhysicalInterface(interface);
1275 #endif
1276 
1277  //Initialize error code
1278  error = NO_ERROR;
1279  //Keep track of the first free entry
1280  firstFreeEntry = NULL;
1281 
1282  //Go through the multicast filter table
1283  for(i = 0; i < IPV4_MULTICAST_FILTER_SIZE; i++)
1284  {
1285  //Point to the current entry
1286  entry = &interface->ipv4Context.multicastFilter[i];
1287 
1288  //Valid entry?
1289  if(entry->refCount > 0)
1290  {
1291  //Check whether the table already contains the specified IPv4 address
1292  if(entry->addr == groupAddr)
1293  {
1294  //Increment the reference count
1295  entry->refCount++;
1296  //Successful processing
1297  return NO_ERROR;
1298  }
1299  }
1300  else
1301  {
1302  //Keep track of the first free entry
1303  if(firstFreeEntry == NULL)
1304  firstFreeEntry = entry;
1305  }
1306  }
1307 
1308  //Check whether the multicast filter table is full
1309  if(firstFreeEntry == NULL)
1310  {
1311  //A new entry cannot be added
1312  return ERROR_FAILURE;
1313  }
1314 
1315 #if (ETH_SUPPORT == ENABLED)
1316  //Map the IPv4 multicast address to a MAC-layer address
1318  //Add the corresponding address to the MAC filter table
1319  error = ethAcceptMacAddr(interface, &macAddr);
1320 
1321  //Check status code
1322  if(!error)
1323  {
1324  //Virtual interface?
1325  if(interface != physicalInterface)
1326  {
1327  //Configure the physical interface to accept the MAC address
1328  error = ethAcceptMacAddr(physicalInterface, &macAddr);
1329 
1330  //Any error to report?
1331  if(error)
1332  {
1333  //Clean up side effects
1334  ethDropMacAddr(interface, &macAddr);
1335  }
1336  }
1337  }
1338 #endif
1339 
1340  //MAC filter table successfully updated?
1341  if(!error)
1342  {
1343  //Now we can safely add a new entry to the table
1344  firstFreeEntry->addr = groupAddr;
1345  //Initialize the reference count
1346  firstFreeEntry->refCount = 1;
1347 
1348 #if (IGMP_HOST_SUPPORT == ENABLED)
1349  //Report multicast group membership to the router
1350  igmpHostJoinGroup(interface, firstFreeEntry);
1351 #endif
1352  }
1353 
1354  //Return status code
1355  return error;
1356 }
1357 
1358 
1359 /**
1360  * @brief Leave the specified host group
1361  * @param[in] interface Underlying network interface
1362  * @param[in] groupAddr IPv4 address identifying the host group to leave
1363  * @return Error code
1364  **/
1365 
1367 {
1368  uint_t i;
1369  Ipv4FilterEntry *entry;
1370 #if (ETH_SUPPORT == ENABLED)
1371  NetInterface *physicalInterface;
1372  MacAddr macAddr;
1373 #endif
1374 
1375  //The IPv4 address must be a valid multicast address
1377  return ERROR_INVALID_ADDRESS;
1378 
1379 #if (ETH_SUPPORT == ENABLED)
1380  //Point to the physical interface
1381  physicalInterface = nicGetPhysicalInterface(interface);
1382 #endif
1383 
1384  //Go through the multicast filter table
1385  for(i = 0; i < IPV4_MULTICAST_FILTER_SIZE; i++)
1386  {
1387  //Point to the current entry
1388  entry = &interface->ipv4Context.multicastFilter[i];
1389 
1390  //Valid entry?
1391  if(entry->refCount > 0)
1392  {
1393  //Specified IPv4 address found?
1394  if(entry->addr == groupAddr)
1395  {
1396  //Decrement the reference count
1397  entry->refCount--;
1398 
1399  //Remove the entry if the reference count drops to zero
1400  if(entry->refCount == 0)
1401  {
1402 #if (IGMP_HOST_SUPPORT == ENABLED)
1403  //Report group membership termination
1404  igmpHostLeaveGroup(interface, entry);
1405 #endif
1406 #if (ETH_SUPPORT == ENABLED)
1407  //Map the IPv4 multicast address to a MAC-layer address
1409  //Drop the corresponding address from the MAC filter table
1410  ethDropMacAddr(interface, &macAddr);
1411 
1412  //Virtual interface?
1413  if(interface != physicalInterface)
1414  {
1415  //Drop the corresponding address from the MAC filter table of
1416  //the physical interface
1417  ethDropMacAddr(physicalInterface, &macAddr);
1418  }
1419 #endif
1420  //Remove the multicast address from the list
1421  entry->addr = IPV4_UNSPECIFIED_ADDR;
1422  }
1423 
1424  //Successful processing
1425  return NO_ERROR;
1426  }
1427  }
1428  }
1429 
1430  //The specified IPv4 address does not exist
1431  return ERROR_ADDRESS_NOT_FOUND;
1432 }
1433 
1434 
1435 /**
1436  * @brief Convert a dot-decimal string to a binary IPv4 address
1437  * @param[in] str NULL-terminated string representing the IPv4 address
1438  * @param[out] ipAddr Binary representation of the IPv4 address
1439  * @return Error code
1440  **/
1441 
1443 {
1444  error_t error;
1445  int_t i = 0;
1446  int_t value = -1;
1447 
1448  //Parse input string
1449  while(1)
1450  {
1451  //Decimal digit found?
1452  if(osIsdigit(*str))
1453  {
1454  //First digit to be decoded?
1455  if(value < 0)
1456  value = 0;
1457 
1458  //Update the value of the current byte
1459  value = (value * 10) + (*str - '0');
1460 
1461  //The resulting value shall be in range 0 to 255
1462  if(value > 255)
1463  {
1464  //The conversion failed
1465  error = ERROR_INVALID_SYNTAX;
1466  break;
1467  }
1468  }
1469  //Dot separator found?
1470  else if(*str == '.' && i < 4)
1471  {
1472  //Each dot must be preceded by a valid number
1473  if(value < 0)
1474  {
1475  //The conversion failed
1476  error = ERROR_INVALID_SYNTAX;
1477  break;
1478  }
1479 
1480  //Save the current byte
1481  ((uint8_t *) ipAddr)[i++] = value;
1482  //Prepare to decode the next byte
1483  value = -1;
1484  }
1485  //End of string detected?
1486  else if(*str == '\0' && i == 3)
1487  {
1488  //The NULL character must be preceded by a valid number
1489  if(value < 0)
1490  {
1491  //The conversion failed
1492  error = ERROR_INVALID_SYNTAX;
1493  }
1494  else
1495  {
1496  //Save the last byte of the IPv4 address
1497  ((uint8_t *) ipAddr)[i] = value;
1498  //The conversion succeeded
1499  error = NO_ERROR;
1500  }
1501 
1502  //We are done
1503  break;
1504  }
1505  //Invalid character...
1506  else
1507  {
1508  //The conversion failed
1509  error = ERROR_INVALID_SYNTAX;
1510  break;
1511  }
1512 
1513  //Point to the next character
1514  str++;
1515  }
1516 
1517  //Return status code
1518  return error;
1519 }
1520 
1521 
1522 /**
1523  * @brief Convert a binary IPv4 address to dot-decimal notation
1524  * @param[in] ipAddr Binary representation of the IPv4 address
1525  * @param[out] str NULL-terminated string representing the IPv4 address
1526  * @return Pointer to the formatted string
1527  **/
1528 
1530 {
1531  uint8_t *p;
1532  static char_t buffer[16];
1533 
1534  //If the NULL pointer is given as parameter, then the internal buffer is used
1535  if(str == NULL)
1536  str = buffer;
1537 
1538  //Cast the address to byte array
1539  p = (uint8_t *) &ipAddr;
1540  //Format IPv4 address
1541  osSprintf(str, "%" PRIu8 ".%" PRIu8 ".%" PRIu8 ".%" PRIu8 "", p[0], p[1], p[2], p[3]);
1542 
1543  //Return a pointer to the formatted string
1544  return str;
1545 }
1546 
1547 
1548 /**
1549  * @brief Dump IPv4 header for debugging purpose
1550  * @param[in] ipHeader Pointer to the IPv4 header
1551  **/
1552 
1553 void ipv4DumpHeader(const Ipv4Header *ipHeader)
1554 {
1555  //Dump IP header contents
1556  TRACE_DEBUG(" Version = %" PRIu8 "\r\n", ipHeader->version);
1557  TRACE_DEBUG(" Header Length = %" PRIu8 "\r\n", ipHeader->headerLength);
1558  TRACE_DEBUG(" Type Of Service = %" PRIu8 "\r\n", ipHeader->typeOfService);
1559  TRACE_DEBUG(" Total Length = %" PRIu16 "\r\n", ntohs(ipHeader->totalLength));
1560  TRACE_DEBUG(" Identification = %" PRIu16 "\r\n", ntohs(ipHeader->identification));
1561  TRACE_DEBUG(" Flags = 0x%01X\r\n", ntohs(ipHeader->fragmentOffset) >> 13);
1562  TRACE_DEBUG(" Fragment Offset = %" PRIu16 "\r\n", ntohs(ipHeader->fragmentOffset) & 0x1FFF);
1563  TRACE_DEBUG(" Time To Live = %" PRIu8 "\r\n", ipHeader->timeToLive);
1564  TRACE_DEBUG(" Protocol = %" PRIu8 "\r\n", ipHeader->protocol);
1565  TRACE_DEBUG(" Header Checksum = 0x%04" PRIX16 "\r\n", ntohs(ipHeader->headerChecksum));
1566  TRACE_DEBUG(" Src Addr = %s\r\n", ipv4AddrToString(ipHeader->srcAddr, NULL));
1567  TRACE_DEBUG(" Dest Addr = %s\r\n", ipv4AddrToString(ipHeader->destAddr, NULL));
1568 }
1569 
1570 #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:191
#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:312
@ 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:627
Ipv4Addr dnsServerList[IPV4_DNS_SERVER_LIST_SIZE]
DNS servers.
Definition: ipv4.h:345
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:313
#define ipv4IsLinkLocalAddr(ipAddr)
Definition: ipv4.h:158
Ipv4FilterEntry multicastFilter[IPV4_MULTICAST_FILTER_SIZE]
Multicast filter table.
Definition: ipv4.h:346
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
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:239
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:339
Ethernet.
bool_t isRouter
A flag indicating whether routing is enabled on this interface.
Definition: ipv4.h:341
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:1553
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:340
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
void ipv4ProcessDatagram(NetInterface *interface, const NetBuffer *buffer, NetRxAncillary *ancillary)
Incoming IPv4 datagram processing.
Definition: ipv4.c:783
@ 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:343
#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:325
#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:1004
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:311
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:326
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:348
#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:942
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:1442
uint_t refCount
Reference count for the current entry.
Definition: ipv4.h:327
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:314
error_t ipv4JoinMulticastGroup(NetInterface *interface, Ipv4Addr groupAddr)
Join the specified host group.
Definition: ipv4.c:1257
IPv4 (Internet Protocol Version 4)
error_t ipv4LeaveMulticastGroup(NetInterface *interface, Ipv4Addr groupAddr)
Leave the specified host group.
Definition: ipv4.c:1366
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:1529
bool_t enableBroadcastEchoReq
Support for broadcast ICMP Echo Request messages.
Definition: ipv4.h:342
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:269
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