ethernet.c
Go to the documentation of this file.
1 /**
2  * @file ethernet.c
3  * @brief Ethernet
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  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 1.9.6
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL ETH_TRACE_LEVEL
33 
34 //Dependencies
35 #include <stdlib.h>
36 #include <string.h>
37 #include <ctype.h>
38 #include "core/net.h"
39 #include "core/nic.h"
40 #include "core/ethernet.h"
41 #include "core/ethernet_misc.h"
42 #include "core/socket.h"
43 #include "core/raw_socket.h"
44 #include "core/tcp_timer.h"
45 #include "ipv4/arp.h"
46 #include "ipv4/ipv4.h"
47 #include "ipv6/ipv6.h"
48 #include "mibs/mib2_module.h"
49 #include "mibs/if_mib_module.h"
50 #include "debug.h"
51 
52 //Check TCP/IP stack configuration
53 #if (ETH_SUPPORT == ENABLED)
54 
55 //Unspecified MAC address
56 const MacAddr MAC_UNSPECIFIED_ADDR = {{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}};
57 //Broadcast MAC address
58 const MacAddr MAC_BROADCAST_ADDR = {{{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}}};
59 
60 
61 /**
62  * @brief Ethernet related initialization
63  * @param[in] interface Underlying network interface
64  * @return Error code
65  **/
66 
68 {
69  //Clear the MAC filter table contents
70  memset(interface->macAddrFilter, 0,
71  sizeof(interface->macAddrFilter));
72 
73  //Successful initialization
74  return NO_ERROR;
75 }
76 
77 
78 /**
79  * @brief Process an incoming Ethernet frame
80  * @param[in] interface Underlying network interface
81  * @param[in] frame Incoming Ethernet frame to process
82  * @param[in] length Total frame length
83  **/
84 
85 void ethProcessFrame(NetInterface *interface, uint8_t *frame, size_t length)
86 {
87  error_t error;
88  uint_t i;
89  uint16_t type;
90  uint8_t *data;
91  EthHeader *header;
92  NetInterface *virtualInterface;
93 
94 #if (IPV6_SUPPORT == ENABLED)
95  NetBuffer1 buffer;
96 #endif
97 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
98  uint8_t port = 0;
99 #endif
100 #if (ETH_VLAN_SUPPORT == ENABLED)
101  uint16_t vlanId = 0;
102 #endif
103 #if (ETH_VMAN_SUPPORT == ENABLED)
104  uint16_t vmanId = 0;
105 #endif
106 
107  //Initialize status code
108  error = NO_ERROR;
109 
110  //Initialize variables
111  type = 0;
112  data = NULL;
113  header = NULL;
114 
115  //Start of exception handling block
116  do
117  {
118  //Check whether the CRC is included in the received frame
119  if(!interface->nicDriver->autoCrcStrip)
120  {
121  //Perform CRC verification
122  error = ethCheckCrc(interface, frame, length);
123  //CRC error?
124  if(error)
125  break;
126 
127  //Strip CRC field from Ethernet frame
128  length -= ETH_CRC_SIZE;
129  }
130 
131 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
132  //Ethernet port multiplication using VLAN or tail tagging?
133  if(interface->port != 0 &&
134  interface->phyDriver != NULL &&
135  interface->phyDriver->untagFrame != NULL)
136  {
137  //Decode VLAN tag (SMSC switches) or tail tag (Micrel switches)
138  error = interface->phyDriver->untagFrame(interface, &frame,
139  &length, &port);
140  //Any error to report?
141  if(error)
142  break;
143  }
144 #endif
145 
146  //Point to the beginning of the frame
147  header = (EthHeader *) frame;
148 
149  //Total number of octets received on the interface
150  MIB2_INC_COUNTER32(ifGroup.ifTable[interface->index].ifInOctets, length);
151  IF_MIB_INC_COUNTER32(ifTable[interface->index].ifInOctets, length);
152  IF_MIB_INC_COUNTER64(ifXTable[interface->index].ifHCInOctets, length);
153 
154  //Malformed Ethernet frame?
155  if(length < sizeof(EthHeader))
156  {
157  //Drop the received frame
158  error = ERROR_INVALID_LENGTH;
159  break;
160  }
161 
162  //Debug message
163  TRACE_DEBUG("Ethernet frame received (%" PRIuSIZE " bytes)...\r\n", length);
164  //Dump Ethernet header contents for debugging purpose
165  ethDumpHeader(header);
166 
167 #if defined(ETH_FRAME_FORWARD_HOOK)
168  ETH_FRAME_FORWARD_HOOK(interface, header, length);
169 #endif
170 
171  //Retrieve the value of the EtherType field
172  type = ntohs(header->type);
173 
174  //Point to the data payload
175  data = header->data;
176  //Calculate the length of the data payload
177  length -= sizeof(EthHeader);
178 
179 #if (ETH_VMAN_SUPPORT == ENABLED)
180  //VMAN tag found?
181  if(type == ETH_TYPE_VMAN)
182  {
183  //Decode VMAN tag
184  error = ethDecodeVlanTag(data, length, &vmanId, &type);
185  //Any error to report?
186  if(error)
187  break;
188 
189  //Advance data pointer over the VMAN tag
190  data += sizeof(VlanTag);
191  length -= sizeof(VlanTag);
192  }
193 #endif
194 
195 #if (ETH_VLAN_SUPPORT == ENABLED)
196  //VLAN tag found?
197  if(type == ETH_TYPE_VLAN)
198  {
199  //Decode VLAN tag
200  error = ethDecodeVlanTag(data, length, &vlanId, &type);
201  //Any error to report?
202  if(error)
203  break;
204 
205  //Advance data pointer over the VLAN tag
206  data += sizeof(VlanTag);
207  length -= sizeof(VlanTag);
208  }
209 #endif
210 
211  //End of exception handling block
212  } while(0);
213 
214  //Invalid frame received?
215  if(error)
216  {
217  //Update Ethernet statistics
218  ethUpdateErrorStats(interface, error);
219  //Drop the received frame
220  return;
221  }
222 
223 #if (ETH_VLAN_SUPPORT == ENABLED)
224  //Dump VLAN identifier
225  if(vlanId != 0)
226  {
227  TRACE_DEBUG(" VLAN Id = %" PRIu16 "\r\n", vlanId);
228  }
229 #endif
230 #if (ETH_VMAN_SUPPORT == ENABLED)
231  //Dump VMAN identifier
232  if(vmanId != 0)
233  {
234  TRACE_DEBUG(" VMAN Id = %" PRIu16 "\r\n", vmanId);
235  }
236 #endif
237 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
238  //Dump switch port identifier
239  if(port != 0)
240  {
241  TRACE_DEBUG(" Switch Port = %" PRIu8 "\r\n", port);
242  }
243 #endif
244 
245  //802.1q allows a single physical interface to be bound to multiple
246  //virtual interfaces
247  for(i = 0; i < NET_INTERFACE_COUNT; i++)
248  {
249  //Point to the current interface
250  virtualInterface = &netInterface[i];
251 
252  //Check whether the current virtual interface is attached to the
253  //physical interface where the packet was received
254  if(nicGetPhysicalInterface(virtualInterface) != interface)
255  continue;
256 
257 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
258  //Check switch port identifier
259  if(nicGetSwitchPort(virtualInterface) != port)
260  continue;
261 #endif
262 #if (ETH_VLAN_SUPPORT == ENABLED)
263  //Check VLAN identifier
264  if((nicGetVlanId(virtualInterface) & VLAN_VID_MASK) != vlanId)
265  continue;
266 #endif
267 #if (ETH_VMAN_SUPPORT == ENABLED)
268  //Check VMAN identifier
269  if((nicGetVmanId(virtualInterface) & VLAN_VID_MASK) != vmanId)
270  continue;
271 #endif
272 
273  //The host must silently discards an incoming frame whose destination
274  //address does not correspond to the physical interface through which
275  //it was received
276  error = ethCheckDestAddr(virtualInterface, &header->destAddr);
277 
278  //Valid destination address?
279  if(!error)
280  {
281  //Update Ethernet statistics
282  ethUpdateInStats(virtualInterface, &header->destAddr);
283 
284 #if (RAW_SOCKET_SUPPORT == ENABLED)
285  //Allow raw sockets to process Ethernet packets
286  rawSocketProcessEthPacket(virtualInterface, header, data, length);
287 #endif
288  //Check Ethernet type field
289  switch(type)
290  {
291 #if (IPV4_SUPPORT == ENABLED)
292  //ARP packet received?
293  case ETH_TYPE_ARP:
294  //Process incoming ARP packet
295  arpProcessPacket(virtualInterface, (ArpPacket *) data, length);
296  break;
297  //IPv4 packet received?
298  case ETH_TYPE_IPV4:
299  //Process incoming IPv4 packet
300  ipv4ProcessPacket(virtualInterface, (Ipv4Header *) data, length);
301  break;
302 #endif
303 #if (IPV6_SUPPORT == ENABLED)
304  //IPv6 packet received?
305  case ETH_TYPE_IPV6:
306  //The incoming Ethernet frame fits in a single chunk
307  buffer.chunkCount = 1;
308  buffer.maxChunkCount = 1;
309  buffer.chunk[0].address = data;
310  buffer.chunk[0].length = (uint16_t) length;
311  buffer.chunk[0].size = 0;
312 
313  //Process incoming IPv6 packet
314  ipv6ProcessPacket(virtualInterface, (NetBuffer *) &buffer, 0);
315  break;
316 #endif
317  //Unknown packet received?
318  default:
319  //Drop the received frame
320  error = ERROR_INVALID_PROTOCOL;
321  break;
322  }
323  }
324 
325  //Invalid frame received?
326  if(error)
327  {
328  //Update Ethernet statistics
329  ethUpdateErrorStats(virtualInterface, error);
330  }
331  }
332 }
333 
334 
335 /**
336  * @brief Send an Ethernet frame
337  * @param[in] interface Underlying network interface
338  * @param[in] destAddr MAC address of the destination host
339  * @param[in] buffer Multi-part buffer containing the payload
340  * @param[in] offset Offset to the first payload byte
341  * @param[in] type Ethernet type
342  * @return Error code
343  **/
344 
346  NetBuffer *buffer, size_t offset, uint16_t type)
347 {
348  error_t error;
349  uint32_t crc;
350  size_t length;
351  MacAddr *srcAddr;
352  EthHeader *header;
353  NetInterface *logicalInterface;
354  NetInterface *physicalInterface;
355 
356 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
357  //Get the switch port identifier assigned to the interface
358  uint8_t port = nicGetSwitchPort(interface);
359 #endif
360 #if (ETH_VLAN_SUPPORT == ENABLED)
361  //Get the VLAN identifier assigned to the interface
362  uint16_t vlanId = nicGetVlanId(interface);
363 #endif
364 #if (ETH_VMAN_SUPPORT == ENABLED)
365  //Get the VMAN identifier assigned to the interface
366  uint16_t vmanId = nicGetVmanId(interface);
367 #endif
368 
369 #if (ETH_VLAN_SUPPORT == ENABLED)
370  //Valid VLAN identifier?
371  if(vlanId != 0)
372  {
373  //The VLAN tag is inserted in the Ethernet frame
374  error = ethEncodeVlanTag(buffer, &offset, vlanId, type);
375  //Any error to report?
376  if(error)
377  return error;
378 
379  //A distinct EtherType has been allocated for use in the TPID field
381  }
382 #endif
383 
384 #if (ETH_VMAN_SUPPORT == ENABLED)
385  //Valid VMAN identifier?
386  if(vmanId != 0)
387  {
388  //The VMAN tag is inserted in the Ethernet frame
389  error = ethEncodeVlanTag(buffer, &offset, vmanId, type);
390  //Any error to report?
391  if(error)
392  return error;
393 
394  //A distinct EtherType has been allocated for use in the TPID field
396  }
397 #endif
398 
399  //Point to the logical interface
400  logicalInterface = nicGetLogicalInterface(interface);
401  //Get the appropriate MAC address to be used as source address
402  srcAddr = &logicalInterface->macAddr;
403 
404  //Forward the frame to the physical interface
405  physicalInterface = nicGetPhysicalInterface(interface);
406 
407 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
408  //Ethernet port multiplication using VLAN or tail tagging?
409  if(physicalInterface->port != 0 &&
410  physicalInterface->phyDriver != NULL &&
411  physicalInterface->phyDriver->tagFrame != NULL)
412  {
413  //Add VLAN tag (SMSC switches) or tail tag (Micrel switches)
414  error = physicalInterface->phyDriver->tagFrame(physicalInterface,
415  buffer, &offset, port, &type);
416  //Any error to report?
417  if(error)
418  return error;
419  }
420 #endif
421 
422  //Sanity check
423  if(offset < sizeof(EthHeader))
425 
426  //Make room for the Ethernet header
427  offset -= sizeof(EthHeader);
428  //Retrieve the length of the frame
429  length = netBufferGetLength(buffer) - offset;
430 
431  //Position to the beginning of the frame
432  header = netBufferAt(buffer, offset);
433 
434  //Format Ethernet header
435  header->destAddr = *destAddr;
436  header->srcAddr = *srcAddr;
437  header->type = htons(type);
438 
439  //Valid NIC driver?
440  if(physicalInterface->nicDriver != NULL)
441  {
442  //Automatic padding not supported by hardware?
443  if(!physicalInterface->nicDriver->autoPadding)
444  {
445  //The host controller should manually add padding to the packet before
446  //transmitting it
447  error = ethPadFrame(buffer, &length);
448  //Any error to report?
449  if(error)
450  return error;
451  }
452 
453  //CRC calculation not supported by hardware?
454  if(!physicalInterface->nicDriver->autoCrcCalc)
455  {
456  //Compute CRC over the header and payload
457  crc = ethCalcCrcEx(buffer, offset, length);
458  //Convert from host byte order to little-endian byte order
459  crc = htole32(crc);
460 
461  //Append the calculated CRC value
462  error = netBufferAppend(buffer, &crc, sizeof(crc));
463  //Any error to report?
464  if(error)
465  return error;
466 
467  //Adjust frame length
468  length += sizeof(crc);
469  }
470  }
471 
472  //Update Ethernet statistics
473  ethUpdateOutStats(interface, &header->destAddr, length);
474 
475  //Debug message
476  TRACE_DEBUG("Sending Ethernet frame (%" PRIuSIZE " bytes)...\r\n", length);
477  //Dump Ethernet header contents for debugging purpose
478  ethDumpHeader(header);
479 
480 #if (ETH_VLAN_SUPPORT == ENABLED)
481  //Dump VLAN identifier
482  if(vlanId != 0)
483  {
484  TRACE_DEBUG(" VLAN Id = %" PRIu16 "\r\n", vlanId);
485  }
486 #endif
487 #if (ETH_VMAN_SUPPORT == ENABLED)
488  //Dump VMAN identifier
489  if(vmanId != 0)
490  {
491  TRACE_DEBUG(" VMAN Id = %" PRIu16 "\r\n", vmanId);
492  }
493 #endif
494 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
495  //Dump switch port identifier
496  if(port != 0)
497  {
498  TRACE_DEBUG(" Switch Port = %" PRIu8 "\r\n", port);
499  }
500 #endif
501 
502  //Forward the frame to the physical interface
503  error = nicSendPacket(physicalInterface, buffer, offset);
504  //Return status code
505  return error;
506 }
507 
508 
509 /**
510  * @brief Add a unicast/multicast address to the MAC filter table
511  * @param[in] interface Underlying network interface
512  * @param[in] macAddr MAC address to accept
513  * @return Error code
514  **/
515 
516 error_t ethAcceptMacAddr(NetInterface *interface, const MacAddr *macAddr)
517 {
518  uint_t i;
519  MacFilterEntry *entry;
520  MacFilterEntry *firstFreeEntry;
521 
522  //Keep track of the first free entry
523  firstFreeEntry = NULL;
524 
525  //Go through the MAC filter table
526  for(i = 0; i < MAC_ADDR_FILTER_SIZE; i++)
527  {
528  //Point to the current entry
529  entry = &interface->macAddrFilter[i];
530 
531  //Valid entry?
532  if(entry->refCount > 0)
533  {
534  //Check whether the table already contains the specified MAC address
535  if(macCompAddr(&entry->addr, macAddr))
536  {
537  //Increment the reference count
538  entry->refCount++;
539  //No error to report
540  return NO_ERROR;
541  }
542  }
543  else
544  {
545  //Keep track of the first free entry
546  if(firstFreeEntry == NULL)
547  firstFreeEntry = entry;
548  }
549  }
550 
551  //Check whether the multicast filter table is full
552  if(firstFreeEntry == NULL)
553  {
554  //A new entry cannot be added
555  return ERROR_FAILURE;
556  }
557 
558  //Add a new entry to the table
559  firstFreeEntry->addr = *macAddr;
560  //Initialize the reference count
561  firstFreeEntry->refCount = 1;
562 
563  //Force the network interface controller to add the current
564  //entry to its MAC filter table
565  firstFreeEntry->addFlag = TRUE;
566  firstFreeEntry->deleteFlag = FALSE;
567 
568  //Update the MAC filter table
569  nicUpdateMacAddrFilter(interface);
570 
571  //Clear the flag
572  firstFreeEntry->addFlag = FALSE;
573 
574  //No error to report
575  return NO_ERROR;
576 }
577 
578 
579 /**
580  * @brief Remove a unicast/multicast address from the MAC filter table
581  * @param[in] interface Underlying network interface
582  * @param[in] macAddr MAC address to drop
583  * @return Error code
584  **/
585 
586 error_t ethDropMacAddr(NetInterface *interface, const MacAddr *macAddr)
587 {
588  uint_t i;
589  MacFilterEntry *entry;
590 
591  //Go through the MAC filter table
592  for(i = 0; i < MAC_ADDR_FILTER_SIZE; i++)
593  {
594  //Point to the current entry
595  entry = &interface->macAddrFilter[i];
596 
597  //Valid entry?
598  if(entry->refCount > 0)
599  {
600  //Specified MAC address found?
601  if(macCompAddr(&entry->addr, macAddr))
602  {
603  //Decrement the reference count
604  entry->refCount--;
605 
606  //Remove the entry if the reference count drops to zero
607  if(entry->refCount == 0)
608  {
609  //Force the network interface controller to remove the current
610  //entry from its MAC filter table
611  entry->deleteFlag = TRUE;
612 
613  //Update the MAC filter table
614  nicUpdateMacAddrFilter(interface);
615 
616  //Clear the flag
617  entry->deleteFlag = FALSE;
618  //Remove the multicast address from the list
619  entry->addr = MAC_UNSPECIFIED_ADDR;
620  }
621 
622  //No error to report
623  return NO_ERROR;
624  }
625  }
626  }
627 
628  //The specified MAC address does not exist
630 }
631 
632 
633 /**
634  * @brief Allocate a buffer to hold an Ethernet frame
635  * @param[in] length Desired payload length
636  * @param[out] offset Offset to the first byte of the payload
637  * @return The function returns a pointer to the newly allocated
638  * buffer. If the system is out of resources, NULL is returned
639  **/
640 
641 NetBuffer *ethAllocBuffer(size_t length, size_t *offset)
642 {
643  size_t n;
644  NetBuffer *buffer;
645 
646  //Ethernet frame overhead
647  n = sizeof(EthHeader);
648 
649 #if (ETH_VLAN_SUPPORT == ENABLED)
650  //VLAN tagging overhead (802.1q)
651  n += sizeof(VlanTag);
652 #endif
653 
654 #if (ETH_VMAN_SUPPORT == ENABLED)
655  //VMAN tagging overhead (802.1ad)
656  n += sizeof(VlanTag);
657 #endif
658 
659 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
660  //Special VLAN tagging overhead
661  n += sizeof(VlanTag);
662 #endif
663 
664  //Allocate a buffer to hold the Ethernet header and the payload
665  buffer = netBufferAlloc(length + n);
666  //Failed to allocate buffer?
667  if(buffer == NULL)
668  return NULL;
669 
670  //Offset to the first byte of the payload
671  *offset = n;
672 
673  //Return a pointer to the freshly allocated buffer
674  return buffer;
675 }
676 
677 
678 /**
679  * @brief Convert a string representation of a MAC address to a binary MAC address
680  * @param[in] str NULL-terminated string representing the MAC address
681  * @param[out] macAddr Binary representation of the MAC address
682  * @return Error code
683  **/
684 
685 error_t macStringToAddr(const char_t *str, MacAddr *macAddr)
686 {
687  error_t error;
688  int_t i = 0;
689  int_t value = -1;
690 
691  //Parse input string
692  while(1)
693  {
694  //Hexadecimal digit found?
695  if(isxdigit((uint8_t) *str))
696  {
697  //First digit to be decoded?
698  if(value < 0)
699  value = 0;
700 
701  //Update the value of the current byte
702  if(isdigit((uint8_t) *str))
703  value = (value * 16) + (*str - '0');
704  else if(isupper((uint8_t) *str))
705  value = (value * 16) + (*str - 'A' + 10);
706  else
707  value = (value * 16) + (*str - 'a' + 10);
708 
709  //Check resulting value
710  if(value > 0xFF)
711  {
712  //The conversion failed
713  error = ERROR_INVALID_SYNTAX;
714  break;
715  }
716  }
717  //Dash or colon separator found?
718  else if((*str == '-' || *str == ':') && i < 6)
719  {
720  //Each separator must be preceded by a valid number
721  if(value < 0)
722  {
723  //The conversion failed
724  error = ERROR_INVALID_SYNTAX;
725  break;
726  }
727 
728  //Save the current byte
729  macAddr->b[i++] = value;
730  //Prepare to decode the next byte
731  value = -1;
732  }
733  //End of string detected?
734  else if(*str == '\0' && i == 5)
735  {
736  //The NULL character must be preceded by a valid number
737  if(value < 0)
738  {
739  //The conversion failed
740  error = ERROR_INVALID_SYNTAX;
741  }
742  else
743  {
744  //Save the last byte of the MAC address
745  macAddr->b[i] = value;
746  //The conversion succeeded
747  error = NO_ERROR;
748  }
749 
750  //We are done
751  break;
752  }
753  //Invalid character...
754  else
755  {
756  //The conversion failed
757  error = ERROR_INVALID_SYNTAX;
758  break;
759  }
760 
761  //Point to the next character
762  str++;
763  }
764 
765  //Return status code
766  return error;
767 }
768 
769 
770 /**
771  * @brief Convert a MAC address to a dash delimited string
772  * @param[in] macAddr Pointer to the MAC address
773  * @param[out] str NULL-terminated string representing the MAC address
774  * @return Pointer to the formatted string
775  **/
776 
777 char_t *macAddrToString(const MacAddr *macAddr, char_t *str)
778 {
779  static char_t buffer[18];
780 
781  //The str parameter is optional
782  if(str == NULL)
783  str = buffer;
784 
785  //Format MAC address
786  sprintf(str, "%02" PRIX8 "-%02" PRIX8 "-%02" PRIX8 "-%02" PRIX8 "-%02" PRIX8 "-%02" PRIX8,
787  macAddr->b[0], macAddr->b[1], macAddr->b[2], macAddr->b[3], macAddr->b[4], macAddr->b[5]);
788 
789  //Return a pointer to the formatted string
790  return str;
791 }
792 
793 
794 /**
795  * @brief Map a MAC address to the IPv6 modified EUI-64 identifier
796  * @param[in] macAddr Host MAC address
797  * @param[out] interfaceId IPv6 modified EUI-64 identifier
798  **/
799 
800 void macAddrToEui64(const MacAddr *macAddr, Eui64 *interfaceId)
801 {
802  //Copy the Organization Unique Identifier (OUI)
803  interfaceId->b[0] = macAddr->b[0];
804  interfaceId->b[1] = macAddr->b[1];
805  interfaceId->b[2] = macAddr->b[2];
806 
807  //The middle 16 bits are given the value 0xFFFE
808  interfaceId->b[3] = 0xFF;
809  interfaceId->b[4] = 0xFE;
810 
811  //Copy the right-most 24 bits of the MAC address
812  interfaceId->b[5] = macAddr->b[3];
813  interfaceId->b[6] = macAddr->b[4];
814  interfaceId->b[7] = macAddr->b[5];
815 
816  //Modified EUI-64 format interface identifiers are
817  //formed by inverting the Universal/Local bit
819 }
820 
821 
822 /**
823  * @brief Dump Ethernet header for debugging purpose
824  * @param[in] ethHeader Pointer to the Ethernet header
825  **/
826 
827 void ethDumpHeader(const EthHeader *ethHeader)
828 {
829  //Dump Ethernet header contents
830  TRACE_DEBUG(" Dest Addr = %s\r\n", macAddrToString(&ethHeader->destAddr, NULL));
831  TRACE_DEBUG(" Src Addr = %s\r\n", macAddrToString(&ethHeader->srcAddr, NULL));
832  TRACE_DEBUG(" Type = 0x%04" PRIX16 "\r\n", ntohs(ethHeader->type));
833 }
834 
835 #endif
836 #if (ETH_SUPPORT == ENABLED || IPV6_SUPPORT == ENABLED)
837 
838 //Unspecified EUI-64 address
839 const Eui64 EUI64_UNSPECIFIED_ADDR = {{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}};
840 
841 
842 /**
843  * @brief Convert a string representation of an EUI-64 address to a binary EUI-64 address
844  * @param[in] str NULL-terminated string representing the EUI-64 address
845  * @param[out] eui64 Binary representation of the EUI-64 address
846  * @return Error code
847  **/
848 
850 {
851  error_t error;
852  int_t i = 0;
853  int_t value = -1;
854 
855  //Parse input string
856  while(1)
857  {
858  //Hexadecimal digit found?
859  if(isxdigit((uint8_t) *str))
860  {
861  //First digit to be decoded?
862  if(value < 0)
863  value = 0;
864 
865  //Update the value of the current byte
866  if(isdigit((uint8_t) *str))
867  value = (value * 16) + (*str - '0');
868  else if(isupper((uint8_t) *str))
869  value = (value * 16) + (*str - 'A' + 10);
870  else
871  value = (value * 16) + (*str - 'a' + 10);
872 
873  //Check resulting value
874  if(value > 0xFF)
875  {
876  //The conversion failed
877  error = ERROR_INVALID_SYNTAX;
878  break;
879  }
880  }
881  //Dash or colon separator found?
882  else if((*str == '-' || *str == ':') && i < 8)
883  {
884  //Each separator must be preceded by a valid number
885  if(value < 0)
886  {
887  //The conversion failed
888  error = ERROR_INVALID_SYNTAX;
889  break;
890  }
891 
892  //Save the current byte
893  eui64->b[i++] = value;
894  //Prepare to decode the next byte
895  value = -1;
896  }
897  //End of string detected?
898  else if(*str == '\0' && i == 7)
899  {
900  //The NULL character must be preceded by a valid number
901  if(value < 0)
902  {
903  //The conversion failed
904  error = ERROR_INVALID_SYNTAX;
905  }
906  else
907  {
908  //Save the last byte of the EUI-64 address
909  eui64->b[i] = value;
910  //The conversion succeeded
911  error = NO_ERROR;
912  }
913 
914  //We are done
915  break;
916  }
917  //Invalid character...
918  else
919  {
920  //The conversion failed
921  error = ERROR_INVALID_SYNTAX;
922  break;
923  }
924 
925  //Point to the next character
926  str++;
927  }
928 
929  //Return status code
930  return error;
931 }
932 
933 
934 /**
935  * @brief Convert an EUI-64 address to a dash delimited string
936  * @param[in] eui64 Pointer to the EUI-64 address
937  * @param[out] str NULL-terminated string representing the EUI-64 address
938  * @return Pointer to the formatted string
939  **/
940 
941 char_t *eui64AddrToString(const Eui64 *eui64, char_t *str)
942 {
943  static char_t buffer[24];
944 
945  //The str parameter is optional
946  if(str == NULL)
947  str = buffer;
948 
949  //Format EUI-64 identifier
950  sprintf(str, "%02" PRIX8 "-%02" PRIX8 "-%02" PRIX8 "-%02" PRIX8
951  "-%02" PRIX8 "-%02" PRIX8 "-%02" PRIX8 "-%02" PRIX8,
952  eui64->b[0], eui64->b[1], eui64->b[2], eui64->b[3],
953  eui64->b[4], eui64->b[5], eui64->b[6], eui64->b[7]);
954 
955  //Return a pointer to the formatted string
956  return str;
957 }
958 
959 #endif
char_t * eui64AddrToString(const Eui64 *eui64, char_t *str)
Convert an EUI-64 address to a dash delimited string.
Definition: ethernet.c:941
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
IPv6 (Internet Protocol Version 6)
MIB-II module.
error_t eui64StringToAddr(const char_t *str, Eui64 *eui64)
Convert a string representation of an EUI-64 address to a binary EUI-64 address.
Definition: ethernet.c:849
uint8_t length
Definition: dtls_misc.h:149
#define Ipv4Header
Definition: ipv4.h:36
void ethUpdateInStats(NetInterface *interface, const MacAddr *destMacAddr)
Update Ethernet input statistics.
MacAddr srcAddr
Definition: ethernet.h:193
void ipv6ProcessPacket(NetInterface *interface, NetBuffer *ipPacket, size_t ipPacketOffset)
Incoming IPv6 packet processing.
Definition: ipv6.c:887
__start_packed struct @109 Eui64
EUI-64 identifier.
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
void macAddrToEui64(const MacAddr *macAddr, Eui64 *interfaceId)
Map a MAC address to the IPv6 modified EUI-64 identifier.
Definition: ethernet.c:800
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:88
#define MAC_ADDR_FILTER_SIZE
Definition: ethernet.h:74
#define TRUE
Definition: os_port.h:50
@ MAC_ADDR_FLAG_LOCAL
Definition: ethernet.h:131
bool_t addFlag
Definition: ethernet.h:224
uint_t refCount
Reference count for the current entry.
Definition: ethernet.h:223
error_t ethCheckCrc(NetInterface *interface, const uint8_t *frame, size_t length)
Ethernet CRC verification.
error_t nicSendPacket(NetInterface *interface, const NetBuffer *buffer, size_t offset)
Send a packet to the network controller.
Definition: nic.c:278
#define NET_INTERFACE_COUNT
Definition: net.h:109
@ ETH_TYPE_IPV4
Definition: ethernet.h:141
void rawSocketProcessEthPacket(NetInterface *interface, EthHeader *header, const uint8_t *data, size_t length)
Process incoming Ethernet packet.
Definition: raw_socket.c:274
#define VLAN_VID_MASK
Definition: ethernet.h:101
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
#define IF_MIB_INC_COUNTER64(name, value)
Definition: if_mib_module.h:48
Ethernet.
error_t ethDropMacAddr(NetInterface *interface, const MacAddr *macAddr)
Remove a unicast/multicast address from the MAC filter table.
Definition: ethernet.c:586
uint32_t ethCalcCrcEx(const NetBuffer *buffer, size_t offset, size_t length)
Calculate CRC over a multi-part buffer.
MacAddr destAddr
Definition: ethernet.h:192
uint16_t length
Definition: net_mem.h:79
#define FALSE
Definition: os_port.h:46
NetInterface netInterface[NET_INTERFACE_COUNT]
Definition: net.c:79
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
void ethUpdateErrorStats(NetInterface *interface, error_t error)
Update Ethernet error statistics.
NetInterface * nicGetPhysicalInterface(NetInterface *interface)
Retrieve physical interface.
Definition: nic.c:84
char_t type
error_t
Error codes.
Definition: error.h:42
#define htole32(value)
Definition: cpu_endian.h:406
void ethDumpHeader(const EthHeader *ethHeader)
Dump Ethernet header for debugging purpose.
Definition: ethernet.c:827
error_t ethDecodeVlanTag(const uint8_t *frame, size_t length, uint16_t *vlanId, uint16_t *type)
VLAN tag deccoding.
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_FAILURE
Generic error code.
Definition: error.h:45
char_t * macAddrToString(const MacAddr *macAddr, char_t *str)
Convert a MAC address to a dash delimited string.
Definition: ethernet.c:777
const Eui64 EUI64_UNSPECIFIED_ADDR
Definition: ethernet.c:839
uint_t maxChunkCount
Definition: net_mem.h:99
#define NetInterface
Definition: net.h:36
MacAddr addr
MAC address.
Definition: ethernet.h:222
@ ERROR_INVALID_LENGTH
Definition: error.h:109
@ ETH_TYPE_ARP
Definition: ethernet.h:142
error_t ethPadFrame(NetBuffer *buffer, size_t *length)
Ethernet frame padding.
error_t macStringToAddr(const char_t *str, MacAddr *macAddr)
Convert a string representation of a MAC address to a binary MAC address.
Definition: ethernet.c:685
Eui64 interfaceId
Definition: ipv6cp.h:69
void arpProcessPacket(NetInterface *interface, ArpPacket *arpPacket, size_t length)
Incoming ARP packet processing.
Definition: arp.c:537
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
Interfaces Group MIB module.
@ ERROR_INVALID_PROTOCOL
Definition: error.h:100
__start_packed struct @162 ArpPacket
ARP packet.
error_t nicUpdateMacAddrFilter(NetInterface *interface)
Configure MAC address filtering.
Definition: nic.c:346
TCP/IP raw sockets.
NetBuffer * netBufferAlloc(size_t length)
Allocate a multi-part buffer.
Definition: net_mem.c:243
uint16_t port
Definition: dns_common.h:223
#define ntohs(value)
Definition: cpu_endian.h:398
@ ETH_TYPE_VLAN
Definition: ethernet.h:144
#define TRACE_DEBUG(...)
Definition: debug.h:106
error_t ethCheckDestAddr(NetInterface *interface, const MacAddr *macAddr)
Destination MAC address filtering.
char char_t
Definition: compiler_port.h:43
void ethProcessFrame(NetInterface *interface, uint8_t *frame, size_t length)
Process an incoming Ethernet frame.
Definition: ethernet.c:85
#define ETH_CRC_SIZE
Definition: ethernet.h:93
__start_packed struct @111 VlanTag
VLAN tag.
uint8_t n
MAC filter table entry.
Definition: ethernet.h:220
error_t netBufferAppend(NetBuffer *dest, const void *src, size_t length)
Append data a multi-part buffer.
Definition: net_mem.c:586
@ ETH_TYPE_IPV6
Definition: ethernet.h:145
#define IF_MIB_INC_COUNTER32(name, value)
Definition: if_mib_module.h:47
#define MIB2_INC_COUNTER32(name, value)
Definition: mib2_module.h:156
Network interface controller abstraction layer.
@ ETH_TYPE_VMAN
Definition: ethernet.h:147
#define macCompAddr(macAddr1, macAddr2)
Definition: ethernet.h:107
Socket API.
error_t ethInit(NetInterface *interface)
Ethernet related initialization.
Definition: ethernet.c:67
@ ERROR_ADDRESS_NOT_FOUND
Definition: error.h:252
@ ERROR_INVALID_SYNTAX
Definition: error.h:68
void ethUpdateOutStats(NetInterface *interface, const MacAddr *destMacAddr, size_t length)
Update Ethernet output statistics.
error_t ethEncodeVlanTag(NetBuffer *buffer, size_t *offset, uint16_t vlanId, uint16_t type)
VLAN tag encoding.
IPv4 (Internet Protocol Version 4)
bool_t deleteFlag
Definition: ethernet.h:225
TCP timer management.
uint8_t value[]
Definition: dtls_misc.h:150
NetBuffer * ethAllocBuffer(size_t length, size_t *offset)
Allocate a buffer to hold an Ethernet frame.
Definition: ethernet.c:641
#define PRIuSIZE
Definition: compiler_port.h:78
unsigned int uint_t
Definition: compiler_port.h:45
__start_packed struct @110 EthHeader
Ethernet frame header.
TCP/IP stack core.
uint8_t data[]
Definition: dtls_misc.h:176
NetInterface * nicGetLogicalInterface(NetInterface *interface)
Retrieve logical interface.
Definition: nic.c:52
uint16_t nicGetVmanId(NetInterface *interface)
Retrieve VMAN identifier.
Definition: nic.c:175
uint16_t size
Definition: net_mem.h:80
uint16_t nicGetVlanId(NetInterface *interface)
Retrieve VLAN identifier.
Definition: nic.c:144
ARP (Address Resolution Protocol)
Helper functions for Ethernet.
uint8_t nicGetSwitchPort(NetInterface *interface)
Retrieve switch port identifier.
Definition: nic.c:113
const MacAddr MAC_UNSPECIFIED_ADDR
Definition: ethernet.c:56
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
const MacAddr MAC_BROADCAST_ADDR
Definition: ethernet.c:58
__start_packed struct @108 MacAddr
MAC address.