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