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-2023 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.2.4
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, data, length, ancillary);
335 #endif
336  //Check Ethernet type field
337  switch(type)
338  {
339 #if (IPV4_SUPPORT == ENABLED)
340  //ARP packet received?
341  case ETH_TYPE_ARP:
342  //Process incoming ARP packet
343  arpProcessPacket(virtualInterface, (ArpPacket *) data, length);
344  //Continue processing
345  break;
346 
347  //IPv4 packet received?
348  case ETH_TYPE_IPV4:
349  //Process incoming IPv4 packet
350  ipv4ProcessPacket(virtualInterface, (Ipv4Header *) data, length,
351  ancillary);
352  //Continue processing
353  break;
354 #endif
355 #if (IPV6_SUPPORT == ENABLED)
356  //IPv6 packet received?
357  case ETH_TYPE_IPV6:
358  //The incoming Ethernet frame fits in a single chunk
359  buffer.chunkCount = 1;
360  buffer.maxChunkCount = 1;
361  buffer.chunk[0].address = data;
362  buffer.chunk[0].length = (uint16_t) length;
363  buffer.chunk[0].size = 0;
364 
365  //Process incoming IPv6 packet
366  ipv6ProcessPacket(virtualInterface, (NetBuffer *) &buffer, 0,
367  ancillary);
368  //Continue processing
369  break;
370 #endif
371  //Unknown packet received?
372  default:
373  //Drop the received frame
374  error = ERROR_INVALID_PROTOCOL;
375  break;
376  }
377  }
378 
379  //Invalid frame received?
380  if(error)
381  {
382  //Update Ethernet statistics
383  ethUpdateErrorStats(virtualInterface, error);
384  }
385  }
386 }
387 
388 
389 /**
390  * @brief Send an Ethernet frame
391  * @param[in] interface Underlying network interface
392  * @param[in] destAddr MAC address of the destination host
393  * @param[in] type Ethernet type
394  * @param[in] buffer Multi-part buffer containing the payload
395  * @param[in] offset Offset to the first payload byte
396  * @param[in] ancillary Additional options passed to the stack along with
397  * the packet
398  * @return Error code
399  **/
400 
402  uint16_t type, NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
403 {
404  error_t error;
405  uint32_t crc;
406  size_t length;
407  EthHeader *header;
408  NetInterface *physicalInterface;
409 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
410  uint8_t port;
411 #endif
412 #if (ETH_VLAN_SUPPORT == ENABLED)
413  uint16_t vlanId;
414 #endif
415 #if (ETH_VMAN_SUPPORT == ENABLED)
416  uint16_t vmanId;
417 #endif
418 
419 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
420  //Get the switch port identifier assigned to the interface
421  port = nicGetSwitchPort(interface);
422 
423  //Port separation mode?
424  if(port != 0)
425  {
426  //Force the destination port
427  ancillary->port = port;
428  }
429 #endif
430 
431 #if (ETH_VLAN_SUPPORT == ENABLED)
432  //Get the VLAN identifier assigned to the interface
433  vlanId = nicGetVlanId(interface);
434 
435  //Valid VLAN identifier?
436  if(vlanId != 0)
437  {
438  //The VLAN tag is inserted in the Ethernet frame
439  error = ethEncodeVlanTag(buffer, &offset, vlanId, ancillary->vlanPcp,
440  ancillary->vlanDei, type);
441  //Any error to report?
442  if(error)
443  return error;
444 
445  //A distinct EtherType has been allocated for use in the TPID field
447  }
448 #endif
449 
450 #if (ETH_VMAN_SUPPORT == ENABLED)
451  //Get the VMAN identifier assigned to the interface
452  vmanId = nicGetVmanId(interface);
453 
454  //Valid VMAN identifier?
455  if(vmanId != 0)
456  {
457  //The VMAN tag is inserted in the Ethernet frame
458  error = ethEncodeVlanTag(buffer, &offset, vmanId, ancillary->vmanPcp,
459  ancillary->vmanDei, type);
460  //Any error to report?
461  if(error)
462  return error;
463 
464  //A distinct EtherType has been allocated for use in the TPID field
466  }
467 #endif
468 
469  //If the source address is not specified, then use the MAC address of the
470  //interface as source address
471  if(macCompAddr(&ancillary->srcMacAddr, &MAC_UNSPECIFIED_ADDR))
472  {
473  NetInterface *logicalInterface;
474 
475  //Point to the logical interface
476  logicalInterface = nicGetLogicalInterface(interface);
477  //Get the MAC address of the interface
478  ancillary->srcMacAddr = logicalInterface->macAddr;
479  }
480 
481  //Sanity check
482  if(offset < sizeof(EthHeader))
484 
485  //Make room for the Ethernet header
486  offset -= sizeof(EthHeader);
487  //Calculate the length of the frame
488  length = netBufferGetLength(buffer) - offset;
489 
490  //Point to the beginning of the frame
491  header = netBufferAt(buffer, offset);
492 
493  //Format Ethernet header
494  header->destAddr = *destAddr;
495  header->srcAddr = ancillary->srcMacAddr;
496  header->type = htons(type);
497 
498  //Update Ethernet statistics
499  ethUpdateOutStats(interface, &header->destAddr, length);
500 
501  //Debug message
502  TRACE_DEBUG("Sending Ethernet frame (%" PRIuSIZE " bytes)...\r\n", length);
503  //Dump Ethernet header contents for debugging purpose
504  ethDumpHeader(header);
505 
506 #if (ETH_VLAN_SUPPORT == ENABLED)
507  //Dump VLAN identifier
508  if(vlanId != 0)
509  {
510  TRACE_DEBUG(" VLAN Id = %" PRIu16 "\r\n", vlanId);
511  }
512 #endif
513 #if (ETH_VMAN_SUPPORT == ENABLED)
514  //Dump VMAN identifier
515  if(vmanId != 0)
516  {
517  TRACE_DEBUG(" VMAN Id = %" PRIu16 "\r\n", vmanId);
518  }
519 #endif
520 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
521  //Dump switch port identifier
522  if(ancillary->port != 0)
523  {
524  TRACE_DEBUG(" Switch Port = %" PRIu8 "\r\n", ancillary->port);
525  }
526 #endif
527 
528  //Point to the physical interface
529  physicalInterface = nicGetPhysicalInterface(interface);
530 
531 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
532  //Check whether port tagging is supported by the switch
533  if(physicalInterface->switchDriver != NULL &&
534  physicalInterface->switchDriver->tagFrame != NULL)
535  {
536  //Add VLAN tag (SMSC switches) or tail tag (Micrel switches)
537  error = physicalInterface->switchDriver->tagFrame(physicalInterface,
538  buffer, &offset, ancillary);
539  //Any error to report?
540  if(error)
541  return error;
542 
543  //Recalculate the length of the frame
544  length = netBufferGetLength(buffer) - offset;
545  }
546 #endif
547 
548  //Valid NIC driver?
549  if(physicalInterface->nicDriver != NULL)
550  {
551  //Automatic padding not supported by hardware?
552  if(!physicalInterface->nicDriver->autoPadding)
553  {
554  //The host controller should manually add padding to the packet before
555  //transmitting it
556  error = ethPadFrame(buffer, &length);
557  //Any error to report?
558  if(error)
559  return error;
560  }
561 
562  //CRC calculation not supported by hardware?
563  if(!physicalInterface->nicDriver->autoCrcCalc)
564  {
565  //Compute CRC over the header and payload
566  crc = ethCalcCrcEx(buffer, offset, length);
567  //Convert from host byte order to little-endian byte order
568  crc = htole32(crc);
569 
570  //Append the calculated CRC value
571  error = netBufferAppend(buffer, &crc, sizeof(crc));
572  //Any error to report?
573  if(error)
574  return error;
575 
576  //Adjust the length of the frame
577  length += sizeof(crc);
578  }
579  }
580 
581  //Forward the frame to the physical interface
582  error = nicSendPacket(physicalInterface, buffer, offset, ancillary);
583 
584  //Return status code
585  return error;
586 }
587 
588 
589 /**
590  * @brief Add a unicast/multicast address to the MAC filter table
591  * @param[in] interface Underlying network interface
592  * @param[in] macAddr MAC address to accept
593  * @return Error code
594  **/
595 
596 error_t ethAcceptMacAddr(NetInterface *interface, const MacAddr *macAddr)
597 {
598  uint_t i;
599  MacFilterEntry *entry;
600  MacFilterEntry *firstFreeEntry;
601 
602  //Keep track of the first free entry
603  firstFreeEntry = NULL;
604 
605  //Go through the MAC filter table
606  for(i = 0; i < MAC_ADDR_FILTER_SIZE; i++)
607  {
608  //Point to the current entry
609  entry = &interface->macAddrFilter[i];
610 
611  //Valid entry?
612  if(entry->refCount > 0)
613  {
614  //Check whether the table already contains the specified MAC address
615  if(macCompAddr(&entry->addr, macAddr))
616  {
617  //Increment the reference count
618  entry->refCount++;
619  //No error to report
620  return NO_ERROR;
621  }
622  }
623  else
624  {
625  //Keep track of the first free entry
626  if(firstFreeEntry == NULL)
627  firstFreeEntry = entry;
628  }
629  }
630 
631  //Check whether the multicast filter table is full
632  if(firstFreeEntry == NULL)
633  {
634  //A new entry cannot be added
635  return ERROR_FAILURE;
636  }
637 
638  //Add a new entry to the table
639  firstFreeEntry->addr = *macAddr;
640  //Initialize the reference count
641  firstFreeEntry->refCount = 1;
642 
643  //Force the network interface controller to add the current
644  //entry to its MAC filter table
645  firstFreeEntry->addFlag = TRUE;
646  firstFreeEntry->deleteFlag = FALSE;
647 
648  //Update the MAC filter table
649  nicUpdateMacAddrFilter(interface);
650 
651  //Clear the flag
652  firstFreeEntry->addFlag = FALSE;
653 
654  //No error to report
655  return NO_ERROR;
656 }
657 
658 
659 /**
660  * @brief Remove a unicast/multicast address from the MAC filter table
661  * @param[in] interface Underlying network interface
662  * @param[in] macAddr MAC address to drop
663  * @return Error code
664  **/
665 
666 error_t ethDropMacAddr(NetInterface *interface, const MacAddr *macAddr)
667 {
668  uint_t i;
669  MacFilterEntry *entry;
670 
671  //Go through the MAC filter table
672  for(i = 0; i < MAC_ADDR_FILTER_SIZE; i++)
673  {
674  //Point to the current entry
675  entry = &interface->macAddrFilter[i];
676 
677  //Valid entry?
678  if(entry->refCount > 0)
679  {
680  //Specified MAC address found?
681  if(macCompAddr(&entry->addr, macAddr))
682  {
683  //Decrement the reference count
684  entry->refCount--;
685 
686  //Remove the entry if the reference count drops to zero
687  if(entry->refCount == 0)
688  {
689  //Force the network interface controller to remove the current
690  //entry from its MAC filter table
691  entry->deleteFlag = TRUE;
692 
693  //Update the MAC filter table
694  nicUpdateMacAddrFilter(interface);
695 
696  //Clear the flag
697  entry->deleteFlag = FALSE;
698  //Remove the multicast address from the list
699  entry->addr = MAC_UNSPECIFIED_ADDR;
700  }
701 
702  //No error to report
703  return NO_ERROR;
704  }
705  }
706  }
707 
708  //The specified MAC address does not exist
710 }
711 
712 
713 /**
714  * @brief Register LLC frame received callback
715  * @param[in] interface Underlying network interface
716  * @param[in] callback Callback function to be called when a LLC frame is received
717  * @param[in] param Callback function parameter (optional)
718  * @return Error code
719  **/
720 
722  void *param)
723 {
724 #if (ETH_LLC_SUPPORT == ENABLED)
725  //Check parameters
726  if(interface == NULL)
728 
729  //Register LLC frame received callback
730  interface->llcRxCallback = callback;
731  //This opaque pointer will be directly passed to the callback function
732  interface->llcRxParam = param;
733 
734  //Successful processing
735  return NO_ERROR;
736 #else
737  //Not implemented
738  return ERROR_NOT_IMPLEMENTED;
739 #endif
740 }
741 
742 
743 /**
744  * @brief Unregister LLC frame received callback
745  * @param[in] interface Underlying network interface
746  * @return Error code
747  **/
748 
750 {
751 #if (ETH_LLC_SUPPORT == ENABLED)
752  //Check parameters
753  if(interface == NULL)
755 
756  //Unregister LLC frame received callback
757  interface->llcRxCallback = NULL;
758  interface->llcRxParam = 0;
759 
760  //Successful processing
761  return NO_ERROR;
762 #else
763  //Not implemented
764  return ERROR_NOT_IMPLEMENTED;
765 #endif
766 }
767 
768 
769 /**
770  * @brief Allocate a buffer to hold an Ethernet frame
771  * @param[in] length Desired payload length
772  * @param[out] offset Offset to the first byte of the payload
773  * @return The function returns a pointer to the newly allocated
774  * buffer. If the system is out of resources, NULL is returned
775  **/
776 
777 NetBuffer *ethAllocBuffer(size_t length, size_t *offset)
778 {
779  size_t n;
780  NetBuffer *buffer;
781 
782  //Ethernet frame overhead
783  n = sizeof(EthHeader);
784 
785 #if (ETH_VLAN_SUPPORT == ENABLED)
786  //VLAN tagging overhead (802.1Q)
787  n += sizeof(VlanTag);
788 #endif
789 
790 #if (ETH_VMAN_SUPPORT == ENABLED)
791  //VMAN tagging overhead (802.1ad)
792  n += sizeof(VlanTag);
793 #endif
794 
795 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
796  //Switch port tagging overhead
797  n += ETH_PORT_TAG_SIZE;
798 #endif
799 
800  //Allocate a buffer to hold the Ethernet header and the payload
801  buffer = netBufferAlloc(length + n);
802  //Failed to allocate buffer?
803  if(buffer == NULL)
804  return NULL;
805 
806  //Offset to the first byte of the payload
807  *offset = n;
808 
809  //Return a pointer to the freshly allocated buffer
810  return buffer;
811 }
812 
813 
814 /**
815  * @brief Convert a string representation of a MAC address to a binary MAC address
816  * @param[in] str NULL-terminated string representing the MAC address
817  * @param[out] macAddr Binary representation of the MAC address
818  * @return Error code
819  **/
820 
821 error_t macStringToAddr(const char_t *str, MacAddr *macAddr)
822 {
823  error_t error;
824  int_t i = 0;
825  int_t value = -1;
826 
827  //Parse input string
828  while(1)
829  {
830  //Hexadecimal digit found?
831  if(isxdigit((uint8_t) *str))
832  {
833  //First digit to be decoded?
834  if(value < 0)
835  value = 0;
836 
837  //Update the value of the current byte
838  if(osIsdigit(*str))
839  {
840  value = (value * 16) + (*str - '0');
841  }
842  else if(osIsupper(*str))
843  {
844  value = (value * 16) + (*str - 'A' + 10);
845  }
846  else
847  {
848  value = (value * 16) + (*str - 'a' + 10);
849  }
850 
851  //Check resulting value
852  if(value > 0xFF)
853  {
854  //The conversion failed
855  error = ERROR_INVALID_SYNTAX;
856  break;
857  }
858  }
859  //Dash or colon separator found?
860  else if((*str == '-' || *str == ':') && i < 6)
861  {
862  //Each separator must be preceded by a valid number
863  if(value < 0)
864  {
865  //The conversion failed
866  error = ERROR_INVALID_SYNTAX;
867  break;
868  }
869 
870  //Save the current byte
871  macAddr->b[i++] = value;
872  //Prepare to decode the next byte
873  value = -1;
874  }
875  //End of string detected?
876  else if(*str == '\0' && i == 5)
877  {
878  //The NULL character must be preceded by a valid number
879  if(value < 0)
880  {
881  //The conversion failed
882  error = ERROR_INVALID_SYNTAX;
883  }
884  else
885  {
886  //Save the last byte of the MAC address
887  macAddr->b[i] = value;
888  //The conversion succeeded
889  error = NO_ERROR;
890  }
891 
892  //We are done
893  break;
894  }
895  //Invalid character...
896  else
897  {
898  //The conversion failed
899  error = ERROR_INVALID_SYNTAX;
900  break;
901  }
902 
903  //Point to the next character
904  str++;
905  }
906 
907  //Return status code
908  return error;
909 }
910 
911 
912 /**
913  * @brief Convert a MAC address to a dash delimited string
914  * @param[in] macAddr Pointer to the MAC address
915  * @param[out] str NULL-terminated string representing the MAC address
916  * @return Pointer to the formatted string
917  **/
918 
919 char_t *macAddrToString(const MacAddr *macAddr, char_t *str)
920 {
921  static char_t buffer[24];
922 
923  //The str parameter is optional
924  if(str == NULL)
925  {
926  str = buffer;
927  }
928 
929  //Format MAC address
930  osSprintf(str, "%02" PRIX8 "-%02" PRIX8 "-%02" PRIX8
931  "-%02" PRIX8 "-%02" PRIX8 "-%02" PRIX8,
932  macAddr->b[0], macAddr->b[1], macAddr->b[2],
933  macAddr->b[3], macAddr->b[4], macAddr->b[5]);
934 
935  //Return a pointer to the formatted string
936  return str;
937 }
938 
939 
940 /**
941  * @brief Map a MAC address to the IPv6 modified EUI-64 identifier
942  * @param[in] macAddr Host MAC address
943  * @param[out] interfaceId IPv6 modified EUI-64 identifier
944  **/
945 
946 void macAddrToEui64(const MacAddr *macAddr, Eui64 *interfaceId)
947 {
948  //Copy the Organization Unique Identifier (OUI)
949  interfaceId->b[0] = macAddr->b[0];
950  interfaceId->b[1] = macAddr->b[1];
951  interfaceId->b[2] = macAddr->b[2];
952 
953  //The middle 16 bits are given the value 0xFFFE
954  interfaceId->b[3] = 0xFF;
955  interfaceId->b[4] = 0xFE;
956 
957  //Copy the right-most 24 bits of the MAC address
958  interfaceId->b[5] = macAddr->b[3];
959  interfaceId->b[6] = macAddr->b[4];
960  interfaceId->b[7] = macAddr->b[5];
961 
962  //Modified EUI-64 format interface identifiers are
963  //formed by inverting the Universal/Local bit
965 }
966 
967 
968 /**
969  * @brief Dump Ethernet header for debugging purpose
970  * @param[in] ethHeader Pointer to the Ethernet header
971  **/
972 
973 void ethDumpHeader(const EthHeader *ethHeader)
974 {
975  //Dump Ethernet header contents
976  TRACE_DEBUG(" Dest Addr = %s\r\n", macAddrToString(&ethHeader->destAddr, NULL));
977  TRACE_DEBUG(" Src Addr = %s\r\n", macAddrToString(&ethHeader->srcAddr, NULL));
978  TRACE_DEBUG(" Type = 0x%04" PRIX16 "\r\n", ntohs(ethHeader->type));
979 }
980 
981 #endif
982 #if (ETH_SUPPORT == ENABLED || IPV6_SUPPORT == ENABLED)
983 
984 //Unspecified EUI-64 address
985 const Eui64 EUI64_UNSPECIFIED_ADDR = {{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}};
986 
987 
988 /**
989  * @brief Convert a string representation of an EUI-64 address to a binary EUI-64 address
990  * @param[in] str NULL-terminated string representing the EUI-64 address
991  * @param[out] eui64 Binary representation of the EUI-64 address
992  * @return Error code
993  **/
994 
996 {
997  error_t error;
998  int_t i = 0;
999  int_t value = -1;
1000 
1001  //Parse input string
1002  while(1)
1003  {
1004  //Hexadecimal digit found?
1005  if(isxdigit((uint8_t) *str))
1006  {
1007  //First digit to be decoded?
1008  if(value < 0)
1009  {
1010  value = 0;
1011  }
1012 
1013  //Update the value of the current byte
1014  if(osIsdigit(*str))
1015  {
1016  value = (value * 16) + (*str - '0');
1017  }
1018  else if(osIsupper(*str))
1019  {
1020  value = (value * 16) + (*str - 'A' + 10);
1021  }
1022  else
1023  {
1024  value = (value * 16) + (*str - 'a' + 10);
1025  }
1026 
1027  //Check resulting value
1028  if(value > 0xFF)
1029  {
1030  //The conversion failed
1031  error = ERROR_INVALID_SYNTAX;
1032  break;
1033  }
1034  }
1035  //Dash or colon separator found?
1036  else if((*str == '-' || *str == ':') && i < 8)
1037  {
1038  //Each separator must be preceded by a valid number
1039  if(value < 0)
1040  {
1041  //The conversion failed
1042  error = ERROR_INVALID_SYNTAX;
1043  break;
1044  }
1045 
1046  //Save the current byte
1047  eui64->b[i++] = value;
1048  //Prepare to decode the next byte
1049  value = -1;
1050  }
1051  //End of string detected?
1052  else if(*str == '\0' && i == 7)
1053  {
1054  //The NULL character must be preceded by a valid number
1055  if(value < 0)
1056  {
1057  //The conversion failed
1058  error = ERROR_INVALID_SYNTAX;
1059  }
1060  else
1061  {
1062  //Save the last byte of the EUI-64 address
1063  eui64->b[i] = value;
1064  //The conversion succeeded
1065  error = NO_ERROR;
1066  }
1067 
1068  //We are done
1069  break;
1070  }
1071  //Invalid character...
1072  else
1073  {
1074  //The conversion failed
1075  error = ERROR_INVALID_SYNTAX;
1076  break;
1077  }
1078 
1079  //Point to the next character
1080  str++;
1081  }
1082 
1083  //Return status code
1084  return error;
1085 }
1086 
1087 
1088 /**
1089  * @brief Convert an EUI-64 address to a dash delimited string
1090  * @param[in] eui64 Pointer to the EUI-64 address
1091  * @param[out] str NULL-terminated string representing the EUI-64 address
1092  * @return Pointer to the formatted string
1093  **/
1094 
1095 char_t *eui64AddrToString(const Eui64 *eui64, char_t *str)
1096 {
1097  static char_t buffer[32];
1098 
1099  //The str parameter is optional
1100  if(str == NULL)
1101  {
1102  str = buffer;
1103  }
1104 
1105  //Format EUI-64 identifier
1106  osSprintf(str, "%02" PRIX8 "-%02" PRIX8 "-%02" PRIX8 "-%02" PRIX8
1107  "-%02" PRIX8 "-%02" PRIX8 "-%02" PRIX8 "-%02" PRIX8,
1108  eui64->b[0], eui64->b[1], eui64->b[2], eui64->b[3],
1109  eui64->b[4], eui64->b[5], eui64->b[6], eui64->b[7]);
1110 
1111  //Return a pointer to the formatted string
1112  return str;
1113 }
1114 
1115 #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:1095
error_t ethAcceptMacAddr(NetInterface *interface, const MacAddr *macAddr)
Add a unicast/multicast address to the MAC filter table.
Definition: ethernet.c:596
uint8_t length
Definition: coap_common.h:193
#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:995
#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:49
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:946
@ 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:52
void ipv4ProcessPacket(NetInterface *interface, Ipv4Header *packet, size_t length, NetRxAncillary *ancillary)
Incoming IPv4 packet processing.
Definition: ipv4.c:577
@ 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:401
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 rawSocketProcessEthPacket(NetInterface *interface, const uint8_t *data, size_t length, NetRxAncillary *ancillary)
Process incoming Ethernet packet.
Definition: raw_socket.c:322
void ipv6ProcessPacket(NetInterface *interface, NetBuffer *ipPacket, size_t ipPacketOffset, NetRxAncillary *ancillary)
Incoming IPv6 packet processing.
Definition: ipv6.c:940
@ ETH_TYPE_IPV4
Definition: ethernet.h:164
#define VLAN_VID_MASK
Definition: ethernet.h:124
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:666
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:48
__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:199
#define htole32(value)
Definition: cpu_endian.h:430
#define osSprintf(dest,...)
Definition: os_port.h:230
void ethDumpHeader(const EthHeader *ethHeader)
Dump Ethernet header for debugging purpose.
Definition: ethernet.c:973
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:919
const Eui64 EUI64_UNSPECIFIED_ADDR
Definition: ethernet.c:985
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:111
@ 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:821
#define osIsdigit(c)
Definition: os_port.h:278
Eui64 interfaceId
Definition: ipv6cp.h:69
void arpProcessPacket(NetInterface *interface, ArpPacket *arpPacket, size_t length)
Incoming ARP packet processing.
Definition: arp.c:689
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:101
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:48
#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:721
@ 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:257
@ 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:749
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:777
#define PRIuSIZE
unsigned int uint_t
Definition: compiler_port.h:50
#define osMemset(p, value, length)
Definition: os_port.h:134
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:272
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