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