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