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-2024 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.4.4
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 "mibs/mib2_module.h"
46 #include "mibs/if_mib_module.h"
47 #include "debug.h"
48 
49 //Check TCP/IP stack configuration
50 #if (ETH_SUPPORT == ENABLED)
51 
52 //Unspecified MAC address
53 const MacAddr MAC_UNSPECIFIED_ADDR = {{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}};
54 //Broadcast MAC address
55 const MacAddr MAC_BROADCAST_ADDR = {{{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}}};
56 
57 
58 /**
59  * @brief Ethernet related initialization
60  * @param[in] interface Underlying network interface
61  * @return Error code
62  **/
63 
65 {
66  //Clear the MAC filter table contents
67  osMemset(interface->macAddrFilter, 0,
68  sizeof(interface->macAddrFilter));
69 
70  //Successful initialization
71  return NO_ERROR;
72 }
73 
74 
75 /**
76  * @brief Process an incoming Ethernet frame
77  * @param[in] interface Underlying network interface
78  * @param[in] frame Incoming Ethernet frame to process
79  * @param[in] length Total frame length
80  * @param[in] ancillary Additional options passed to the stack along with
81  * the packet
82  **/
83 
84 void ethProcessFrame(NetInterface *interface, uint8_t *frame, size_t length,
85  NetRxAncillary *ancillary)
86 {
87  error_t error;
88  uint_t i;
89  uint16_t type;
90  uint8_t *data;
91  EthHeader *header;
92  NetInterface *virtualInterface;
93 
94 #if (IPV6_SUPPORT == ENABLED)
95  NetBuffer1 buffer;
96 #endif
97 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
98  uint8_t port = 0;
99 #endif
100 #if (ETH_VLAN_SUPPORT == ENABLED)
101  uint16_t vlanId = 0;
102 #endif
103 #if (ETH_VMAN_SUPPORT == ENABLED)
104  uint16_t vmanId = 0;
105 #endif
106 
107  //Initialize status code
108  error = NO_ERROR;
109 
110  //Initialize variables
111  type = 0;
112  data = NULL;
113  header = NULL;
114 
115  //Start of exception handling block
116  do
117  {
118  //Check whether the CRC is included in the received frame
119  if(!interface->nicDriver->autoCrcStrip)
120  {
121  //Perform CRC verification
122  error = ethCheckCrc(interface, frame, length);
123  //CRC error?
124  if(error)
125  break;
126 
127  //Strip CRC field from Ethernet frame
128  length -= ETH_CRC_SIZE;
129  }
130 
131 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
132  //Check whether port tagging is supported by the switch
133  if(interface->switchDriver != NULL &&
134  interface->switchDriver->untagFrame != NULL)
135  {
136  //Decode VLAN tag (SMSC switches) or tail tag (Micrel switches)
137  error = interface->switchDriver->untagFrame(interface, &frame,
138  &length, ancillary);
139  //Any error to report?
140  if(error)
141  break;
142  }
143 #endif
144 
145  //Point to the beginning of the frame
146  header = (EthHeader *) frame;
147 
148  //Total number of octets received on the interface
149  MIB2_IF_INC_COUNTER32(ifTable[interface->index].ifInOctets, length);
150  IF_MIB_INC_COUNTER32(ifTable[interface->index].ifInOctets, length);
151  IF_MIB_INC_COUNTER64(ifXTable[interface->index].ifHCInOctets, length);
152 
153  //Malformed Ethernet frame?
154  if(length < sizeof(EthHeader))
155  {
156  //Drop the received frame
157  error = ERROR_INVALID_LENGTH;
158  break;
159  }
160 
161  //Debug message
162  TRACE_DEBUG("Ethernet frame received (%" PRIuSIZE " bytes)...\r\n", length);
163  //Dump Ethernet header contents for debugging purpose
164  ethDumpHeader(header);
165 
166 #if defined(ETH_FRAME_FORWARD_HOOK)
167  ETH_FRAME_FORWARD_HOOK(interface, header, length);
168 #endif
169 
170  //Retrieve the value of the EtherType field
171  type = ntohs(header->type);
172 
173  //Point to the data payload
174  data = header->data;
175  //Calculate the length of the data payload
176  length -= sizeof(EthHeader);
177 
178 #if (ETH_VMAN_SUPPORT == ENABLED)
179  //VMAN tag found?
180  if(type == ETH_TYPE_VMAN)
181  {
182  //Decode VMAN tag
183  error = ethDecodeVlanTag(data, length, &vmanId, &type);
184  //Any error to report?
185  if(error)
186  break;
187 
188  //Advance data pointer over the VMAN tag
189  data += sizeof(VlanTag);
190  length -= sizeof(VlanTag);
191  }
192 #endif
193 
194 #if (ETH_VLAN_SUPPORT == ENABLED)
195  //VLAN tag found?
196  if(type == ETH_TYPE_VLAN)
197  {
198  //Decode VLAN tag
199  error = ethDecodeVlanTag(data, length, &vlanId, &type);
200  //Any error to report?
201  if(error)
202  break;
203 
204  //Advance data pointer over the VLAN tag
205  data += sizeof(VlanTag);
206  length -= sizeof(VlanTag);
207  }
208 #endif
209 
210  //End of exception handling block
211  } while(0);
212 
213  //Invalid frame received?
214  if(error)
215  {
216  //Update Ethernet statistics
217  ethUpdateErrorStats(interface, error);
218  //Drop the received frame
219  return;
220  }
221 
222 #if (ETH_VLAN_SUPPORT == ENABLED)
223  //Dump VLAN identifier
224  if(vlanId != 0)
225  {
226  TRACE_DEBUG(" VLAN Id = %" PRIu16 "\r\n", vlanId);
227  }
228 #endif
229 #if (ETH_VMAN_SUPPORT == ENABLED)
230  //Dump VMAN identifier
231  if(vmanId != 0)
232  {
233  TRACE_DEBUG(" VMAN Id = %" PRIu16 "\r\n", vmanId);
234  }
235 #endif
236 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
237  //Dump switch port identifier
238  if(ancillary->port != 0)
239  {
240  TRACE_DEBUG(" Switch Port = %" PRIu8 "\r\n", ancillary->port);
241  }
242 #endif
243 
244  //802.1Q allows a single physical interface to be bound to multiple
245  //virtual interfaces
246  for(i = 0; i < NET_INTERFACE_COUNT; i++)
247  {
248  //Point to the current interface
249  virtualInterface = &netInterface[i];
250 
251  //Check whether the current virtual interface is attached to the
252  //physical interface where the packet was received
253  if(nicGetPhysicalInterface(virtualInterface) != interface)
254  continue;
255 
256 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
257  //Retrieve switch port identifier
258  port = nicGetSwitchPort(virtualInterface);
259 
260  //Check switch port identifier
261  if(port != 0 && port != ancillary->port)
262  continue;
263 #endif
264 #if (ETH_VLAN_SUPPORT == ENABLED)
265  //Check VLAN identifier
266  if((nicGetVlanId(virtualInterface) & VLAN_VID_MASK) != vlanId)
267  continue;
268 #endif
269 #if (ETH_VMAN_SUPPORT == ENABLED)
270  //Check VMAN identifier
271  if((nicGetVmanId(virtualInterface) & VLAN_VID_MASK) != vmanId)
272  continue;
273 #endif
274 
275 #if (IPV4_SUPPORT == ENABLED && IGMP_ROUTER_SUPPORT == ENABLED)
276  //Trap IGMP packets when IGMP router is enabled
277  if(virtualInterface->igmpRouterContext != NULL &&
278  ethTrapIgmpPacket(header, data, length))
279  {
280  //Forward the packet to the IGMP router
281  error = NO_ERROR;
282  }
283  else
284 #endif
285 #if (IPV4_SUPPORT == ENABLED && IGMP_SNOOPING_SUPPORT == ENABLED)
286  //Trap IGMP packets when IGMP snooping is enabled
287  if(virtualInterface->igmpSnoopingContext != NULL &&
288  ethTrapIgmpPacket(header, data, length))
289  {
290  //Forward the packet to the IGMP snooping switch
291  error = NO_ERROR;
292  }
293  else
294 #endif
295  {
296  //The host must silently discards an incoming frame whose destination
297  //address does not correspond to the physical interface through which
298  //it was received
299  error = ethCheckDestAddr(virtualInterface, &header->destAddr);
300  }
301 
302  //Valid destination address?
303  if(!error)
304  {
305  //Save source and destination MAC addresses
306  ancillary->srcMacAddr = header->srcAddr;
307  ancillary->destMacAddr = header->destAddr;
308 
309  //Save the value of the EtherType field
310  ancillary->ethType = type;
311 
312  //Update Ethernet statistics
313  ethUpdateInStats(virtualInterface, &header->destAddr);
314 
315 #if (ETH_LLC_SUPPORT == ENABLED)
316  //Values of 1500 and below mean that it is used to indicate the size
317  //of the payload in octets
318  if(type <= ETH_MTU && type <= length)
319  {
320  //Any registered callback?
321  if(virtualInterface->llcRxCallback != NULL)
322  {
323  //Process incoming LLC frame
324  virtualInterface->llcRxCallback(virtualInterface, header, data,
325  type, ancillary, virtualInterface->llcRxParam);
326  }
327  }
328 #endif
329 
330 #if (RAW_SOCKET_SUPPORT == ENABLED)
331  //Allow raw sockets to process Ethernet packets
332  rawSocketProcessEthPacket(virtualInterface, data, length, ancillary);
333 #endif
334  //Check Ethernet type field
335  switch(type)
336  {
337 #if (IPV4_SUPPORT == ENABLED)
338  //ARP packet received?
339  case ETH_TYPE_ARP:
340  //Process incoming ARP packet
341  arpProcessPacket(virtualInterface, (ArpPacket *) data, length);
342  //Continue processing
343  break;
344 
345  //IPv4 packet received?
346  case ETH_TYPE_IPV4:
347  //Process incoming IPv4 packet
348  ipv4ProcessPacket(virtualInterface, (Ipv4Header *) data, length,
349  ancillary);
350  //Continue processing
351  break;
352 #endif
353 #if (IPV6_SUPPORT == ENABLED)
354  //IPv6 packet received?
355  case ETH_TYPE_IPV6:
356  //The incoming Ethernet frame fits in a single chunk
357  buffer.chunkCount = 1;
358  buffer.maxChunkCount = 1;
359  buffer.chunk[0].address = data;
360  buffer.chunk[0].length = (uint16_t) length;
361  buffer.chunk[0].size = 0;
362 
363  //Process incoming IPv6 packet
364  ipv6ProcessPacket(virtualInterface, (NetBuffer *) &buffer, 0,
365  ancillary);
366  //Continue processing
367  break;
368 #endif
369  //Unknown packet received?
370  default:
371  //Drop the received frame
372  error = ERROR_INVALID_PROTOCOL;
373  break;
374  }
375  }
376 
377  //Invalid frame received?
378  if(error)
379  {
380  //Update Ethernet statistics
381  ethUpdateErrorStats(virtualInterface, error);
382  }
383  }
384 }
385 
386 
387 /**
388  * @brief Send an Ethernet frame
389  * @param[in] interface Underlying network interface
390  * @param[in] destAddr MAC address of the destination host
391  * @param[in] type Ethernet type
392  * @param[in] buffer Multi-part buffer containing the payload
393  * @param[in] offset Offset to the first payload byte
394  * @param[in] ancillary Additional options passed to the stack along with
395  * the packet
396  * @return Error code
397  **/
398 
400  uint16_t type, NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
401 {
402  error_t error;
403  uint32_t crc;
404  size_t length;
405  EthHeader *header;
406  NetInterface *physicalInterface;
407 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
408  uint8_t port;
409 #endif
410 #if (ETH_VLAN_SUPPORT == ENABLED)
411  uint16_t vlanId;
412 #endif
413 #if (ETH_VMAN_SUPPORT == ENABLED)
414  uint16_t vmanId;
415 #endif
416 
417 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
418  //Get the switch port identifier assigned to the interface
419  port = nicGetSwitchPort(interface);
420 
421  //Port separation mode?
422  if(port != 0)
423  {
424  //Force the destination port
425  ancillary->port = port;
426  }
427 #endif
428 
429 #if (ETH_VLAN_SUPPORT == ENABLED)
430  //Get the VLAN identifier assigned to the interface
431  vlanId = nicGetVlanId(interface);
432 
433  //Valid VLAN identifier?
434  if(vlanId != 0)
435  {
436  //The VLAN tag is inserted in the Ethernet frame
437  error = ethEncodeVlanTag(buffer, &offset, vlanId, ancillary->vlanPcp,
438  ancillary->vlanDei, type);
439  //Any error to report?
440  if(error)
441  return error;
442 
443  //A distinct EtherType has been allocated for use in the TPID field
445  }
446 #endif
447 
448 #if (ETH_VMAN_SUPPORT == ENABLED)
449  //Get the VMAN identifier assigned to the interface
450  vmanId = nicGetVmanId(interface);
451 
452  //Valid VMAN identifier?
453  if(vmanId != 0)
454  {
455  //The VMAN tag is inserted in the Ethernet frame
456  error = ethEncodeVlanTag(buffer, &offset, vmanId, ancillary->vmanPcp,
457  ancillary->vmanDei, type);
458  //Any error to report?
459  if(error)
460  return error;
461 
462  //A distinct EtherType has been allocated for use in the TPID field
464  }
465 #endif
466 
467  //If the source address is not specified, then use the MAC address of the
468  //interface as source address
469  if(macCompAddr(&ancillary->srcMacAddr, &MAC_UNSPECIFIED_ADDR))
470  {
471  NetInterface *logicalInterface;
472 
473  //Point to the logical interface
474  logicalInterface = nicGetLogicalInterface(interface);
475  //Get the MAC address of the interface
476  ancillary->srcMacAddr = logicalInterface->macAddr;
477  }
478 
479  //Sanity check
480  if(offset < sizeof(EthHeader))
482 
483  //Make room for the Ethernet header
484  offset -= sizeof(EthHeader);
485  //Calculate the length of the frame
486  length = netBufferGetLength(buffer) - offset;
487 
488  //Point to the beginning of the frame
489  header = netBufferAt(buffer, offset, 0);
490 
491  //Format Ethernet header
492  header->destAddr = *destAddr;
493  header->srcAddr = ancillary->srcMacAddr;
494  header->type = htons(type);
495 
496  //Update Ethernet statistics
497  ethUpdateOutStats(interface, &header->destAddr, length);
498 
499  //Debug message
500  TRACE_DEBUG("Sending Ethernet frame (%" PRIuSIZE " bytes)...\r\n", length);
501  //Dump Ethernet header contents for debugging purpose
502  ethDumpHeader(header);
503 
504 #if (ETH_VLAN_SUPPORT == ENABLED)
505  //Dump VLAN identifier
506  if(vlanId != 0)
507  {
508  TRACE_DEBUG(" VLAN Id = %" PRIu16 "\r\n", vlanId);
509  }
510 #endif
511 #if (ETH_VMAN_SUPPORT == ENABLED)
512  //Dump VMAN identifier
513  if(vmanId != 0)
514  {
515  TRACE_DEBUG(" VMAN Id = %" PRIu16 "\r\n", vmanId);
516  }
517 #endif
518 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
519  //Dump switch port identifier
520  if(ancillary->port != 0)
521  {
522  TRACE_DEBUG(" Switch Port = %" PRIu8 "\r\n", ancillary->port);
523  }
524 #endif
525 
526  //Point to the physical interface
527  physicalInterface = nicGetPhysicalInterface(interface);
528 
529 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
530  //Check whether port tagging is supported by the switch
531  if(physicalInterface->switchDriver != NULL &&
532  physicalInterface->switchDriver->tagFrame != NULL)
533  {
534  //Add VLAN tag (SMSC switches) or tail tag (Micrel switches)
535  error = physicalInterface->switchDriver->tagFrame(physicalInterface,
536  buffer, &offset, ancillary);
537  //Any error to report?
538  if(error)
539  return error;
540 
541  //Recalculate the length of the frame
542  length = netBufferGetLength(buffer) - offset;
543  }
544 #endif
545 
546  //Valid NIC driver?
547  if(physicalInterface->nicDriver != NULL)
548  {
549  //Automatic padding not supported by hardware?
550  if(!physicalInterface->nicDriver->autoPadding)
551  {
552  //The host controller should manually add padding to the packet before
553  //transmitting it
554  error = ethPadFrame(buffer, &length);
555  //Any error to report?
556  if(error)
557  return error;
558  }
559 
560  //CRC calculation not supported by hardware?
561  if(!physicalInterface->nicDriver->autoCrcCalc)
562  {
563  //Compute CRC over the header and payload
564  crc = ethCalcCrcEx(buffer, offset, length);
565  //Convert from host byte order to little-endian byte order
566  crc = htole32(crc);
567 
568  //Append the calculated CRC value
569  error = netBufferAppend(buffer, &crc, sizeof(crc));
570  //Any error to report?
571  if(error)
572  return error;
573 
574  //Adjust the length of the frame
575  length += sizeof(crc);
576  }
577  }
578 
579  //Forward the frame to the physical interface
580  error = nicSendPacket(physicalInterface, buffer, offset, ancillary);
581 
582  //Return status code
583  return error;
584 }
585 
586 
587 /**
588  * @brief Add a unicast/multicast address to the MAC filter table
589  * @param[in] interface Underlying network interface
590  * @param[in] macAddr MAC address to accept
591  * @return Error code
592  **/
593 
594 error_t ethAcceptMacAddr(NetInterface *interface, const MacAddr *macAddr)
595 {
596  uint_t i;
597  MacFilterEntry *entry;
598  MacFilterEntry *firstFreeEntry;
599 
600  //Keep track of the first free entry
601  firstFreeEntry = NULL;
602 
603  //Go through the MAC filter table
604  for(i = 0; i < MAC_ADDR_FILTER_SIZE; i++)
605  {
606  //Point to the current entry
607  entry = &interface->macAddrFilter[i];
608 
609  //Valid entry?
610  if(entry->refCount > 0)
611  {
612  //Check whether the table already contains the specified MAC address
613  if(macCompAddr(&entry->addr, macAddr))
614  {
615  //Increment the reference count
616  entry->refCount++;
617  //No error to report
618  return NO_ERROR;
619  }
620  }
621  else
622  {
623  //Keep track of the first free entry
624  if(firstFreeEntry == NULL)
625  {
626  firstFreeEntry = entry;
627  }
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
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:594
#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
Ipv4Addr destAddr
Definition: ipv4.h:329
void ethUpdateInStats(NetInterface *interface, const MacAddr *destMacAddr)
Update Ethernet input statistics.
signed int int_t
Definition: compiler_port.h:49
uint_t chunkCount
Definition: net_mem.h:98
Eui64
Definition: ethernet.h:210
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:281
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:222
void ipv4ProcessPacket(NetInterface *interface, Ipv4Header *packet, size_t length, NetRxAncillary *ancillary)
Incoming IPv4 packet processing.
Definition: ipv4.c:606
@ MAC_ADDR_FLAG_LOCAL
Definition: ethernet.h:154
bool_t addFlag
Definition: ethernet.h:265
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:399
uint_t refCount
Reference count for the current entry.
Definition: ethernet.h:264
error_t ethCheckCrc(NetInterface *interface, const uint8_t *frame, size_t length)
Ethernet CRC verification.
uint8_t type
Definition: coap_common.h:176
#define NET_INTERFACE_COUNT
Definition: net.h:114
void ipv6ProcessPacket(NetInterface *interface, NetBuffer *ipPacket, size_t ipPacketOffset, NetRxAncillary *ancillary)
Incoming IPv6 packet processing.
Definition: ipv6.c:976
@ ETH_TYPE_IPV4
Definition: ethernet.h:164
EthHeader
Definition: ethernet.h:223
#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.
VlanTag
Definition: ethernet.h:246
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.
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:85
void ethProcessFrame(NetInterface *interface, uint8_t *frame, size_t length, NetRxAncillary *ancillary)
Process an incoming Ethernet frame.
Definition: ethernet.c:84
void(* LlcRxCallback)(NetInterface *interface, EthHeader *header, const uint8_t *data, size_t length, NetRxAncillary *ancillary, void *param)
LLC frame received callback.
Definition: ethernet.h:274
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:231
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 * address
Definition: net_mem.h:78
#define MIB2_IF_INC_COUNTER32(name, value)
Definition: mib2_module.h:156
@ 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:263
@ 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:385
#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:285
Eui64 interfaceId
Definition: ipv6cp.h:71
uint8_t length
Definition: tcp.h:368
void arpProcessPacket(NetInterface *interface, ArpPacket *arpPacket, size_t length)
Incoming ARP packet processing.
Definition: arp.c:546
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
MacAddr
Definition: ethernet.h:195
error_t nicUpdateMacAddrFilter(NetInterface *interface)
Configure MAC address filtering.
Definition: nic.c:353
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:267
#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:262
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
#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
uint8_t value[]
Definition: tcp.h:369
@ 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:64
@ ERROR_ADDRESS_NOT_FOUND
Definition: error.h:258
@ 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.
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:266
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:135
TCP/IP stack core.
NetInterface * nicGetLogicalInterface(NetInterface *interface)
Retrieve logical interface.
Definition: nic.c:53
uint16_t nicGetVmanId(NetInterface *interface)
Retrieve VMAN identifier.
Definition: nic.c:176
uint16_t size
Definition: net_mem.h:80
uint16_t nicGetVlanId(NetInterface *interface)
Retrieve VLAN identifier.
Definition: nic.c:145
#define osIsupper(c)
Definition: os_port.h:279
ARP (Address Resolution Protocol)
Helper functions for Ethernet.
uint8_t nicGetSwitchPort(NetInterface *interface)
Retrieve switch port identifier.
Definition: nic.c:114
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:53
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
const MacAddr MAC_BROADCAST_ADDR
Definition: ethernet.c:55