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