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.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 "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);
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  firstFreeEntry = entry;
626  }
627  }
628 
629  //Check whether the multicast filter table is full
630  if(firstFreeEntry == NULL)
631  {
632  //A new entry cannot be added
633  return ERROR_FAILURE;
634  }
635 
636  //Add a new entry to the table
637  firstFreeEntry->addr = *macAddr;
638  //Initialize the reference count
639  firstFreeEntry->refCount = 1;
640 
641  //Force the network interface controller to add the current
642  //entry to its MAC filter table
643  firstFreeEntry->addFlag = TRUE;
644  firstFreeEntry->deleteFlag = FALSE;
645 
646  //Update the MAC filter table
647  nicUpdateMacAddrFilter(interface);
648 
649  //Clear the flag
650  firstFreeEntry->addFlag = FALSE;
651 
652  //No error to report
653  return NO_ERROR;
654 }
655 
656 
657 /**
658  * @brief Remove a unicast/multicast address from the MAC filter table
659  * @param[in] interface Underlying network interface
660  * @param[in] macAddr MAC address to drop
661  * @return Error code
662  **/
663 
664 error_t ethDropMacAddr(NetInterface *interface, const MacAddr *macAddr)
665 {
666  uint_t i;
667  MacFilterEntry *entry;
668 
669  //Go through the MAC filter table
670  for(i = 0; i < MAC_ADDR_FILTER_SIZE; i++)
671  {
672  //Point to the current entry
673  entry = &interface->macAddrFilter[i];
674 
675  //Valid entry?
676  if(entry->refCount > 0)
677  {
678  //Specified MAC address found?
679  if(macCompAddr(&entry->addr, macAddr))
680  {
681  //Decrement the reference count
682  entry->refCount--;
683 
684  //Remove the entry if the reference count drops to zero
685  if(entry->refCount == 0)
686  {
687  //Force the network interface controller to remove the current
688  //entry from its MAC filter table
689  entry->deleteFlag = TRUE;
690 
691  //Update the MAC filter table
692  nicUpdateMacAddrFilter(interface);
693 
694  //Clear the flag
695  entry->deleteFlag = FALSE;
696  //Remove the multicast address from the list
697  entry->addr = MAC_UNSPECIFIED_ADDR;
698  }
699 
700  //No error to report
701  return NO_ERROR;
702  }
703  }
704  }
705 
706  //The specified MAC address does not exist
708 }
709 
710 
711 /**
712  * @brief Register LLC frame received callback
713  * @param[in] interface Underlying network interface
714  * @param[in] callback Callback function to be called when a LLC frame is received
715  * @param[in] param Callback function parameter (optional)
716  * @return Error code
717  **/
718 
720  void *param)
721 {
722 #if (ETH_LLC_SUPPORT == ENABLED)
723  //Check parameters
724  if(interface == NULL)
726 
727  //Register LLC frame received callback
728  interface->llcRxCallback = callback;
729  //This opaque pointer will be directly passed to the callback function
730  interface->llcRxParam = param;
731 
732  //Successful processing
733  return NO_ERROR;
734 #else
735  //Not implemented
736  return ERROR_NOT_IMPLEMENTED;
737 #endif
738 }
739 
740 
741 /**
742  * @brief Unregister LLC frame received callback
743  * @param[in] interface Underlying network interface
744  * @return Error code
745  **/
746 
748 {
749 #if (ETH_LLC_SUPPORT == ENABLED)
750  //Check parameters
751  if(interface == NULL)
753 
754  //Unregister LLC frame received callback
755  interface->llcRxCallback = NULL;
756  interface->llcRxParam = 0;
757 
758  //Successful processing
759  return NO_ERROR;
760 #else
761  //Not implemented
762  return ERROR_NOT_IMPLEMENTED;
763 #endif
764 }
765 
766 
767 /**
768  * @brief Allocate a buffer to hold an Ethernet frame
769  * @param[in] length Desired payload length
770  * @param[out] offset Offset to the first byte of the payload
771  * @return The function returns a pointer to the newly allocated
772  * buffer. If the system is out of resources, NULL is returned
773  **/
774 
775 NetBuffer *ethAllocBuffer(size_t length, size_t *offset)
776 {
777  size_t n;
778  NetBuffer *buffer;
779 
780  //Ethernet frame overhead
781  n = sizeof(EthHeader);
782 
783 #if (ETH_VLAN_SUPPORT == ENABLED)
784  //VLAN tagging overhead (802.1Q)
785  n += sizeof(VlanTag);
786 #endif
787 
788 #if (ETH_VMAN_SUPPORT == ENABLED)
789  //VMAN tagging overhead (802.1ad)
790  n += sizeof(VlanTag);
791 #endif
792 
793 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
794  //Switch port tagging overhead
795  n += ETH_PORT_TAG_SIZE;
796 #endif
797 
798  //Allocate a buffer to hold the Ethernet header and the payload
799  buffer = netBufferAlloc(length + n);
800  //Failed to allocate buffer?
801  if(buffer == NULL)
802  return NULL;
803 
804  //Offset to the first byte of the payload
805  *offset = n;
806 
807  //Return a pointer to the freshly allocated buffer
808  return buffer;
809 }
810 
811 
812 /**
813  * @brief Convert a string representation of a MAC address to a binary MAC address
814  * @param[in] str NULL-terminated string representing the MAC address
815  * @param[out] macAddr Binary representation of the MAC address
816  * @return Error code
817  **/
818 
819 error_t macStringToAddr(const char_t *str, MacAddr *macAddr)
820 {
821  error_t error;
822  int_t i = 0;
823  int_t value = -1;
824 
825  //Parse input string
826  while(1)
827  {
828  //Hexadecimal digit found?
829  if(isxdigit((uint8_t) *str))
830  {
831  //First digit to be decoded?
832  if(value < 0)
833  value = 0;
834 
835  //Update the value of the current byte
836  if(osIsdigit(*str))
837  {
838  value = (value * 16) + (*str - '0');
839  }
840  else if(osIsupper(*str))
841  {
842  value = (value * 16) + (*str - 'A' + 10);
843  }
844  else
845  {
846  value = (value * 16) + (*str - 'a' + 10);
847  }
848 
849  //Check resulting value
850  if(value > 0xFF)
851  {
852  //The conversion failed
853  error = ERROR_INVALID_SYNTAX;
854  break;
855  }
856  }
857  //Dash or colon separator found?
858  else if((*str == '-' || *str == ':') && i < 6)
859  {
860  //Each separator must be preceded by a valid number
861  if(value < 0)
862  {
863  //The conversion failed
864  error = ERROR_INVALID_SYNTAX;
865  break;
866  }
867 
868  //Save the current byte
869  macAddr->b[i++] = value;
870  //Prepare to decode the next byte
871  value = -1;
872  }
873  //End of string detected?
874  else if(*str == '\0' && i == 5)
875  {
876  //The NULL character must be preceded by a valid number
877  if(value < 0)
878  {
879  //The conversion failed
880  error = ERROR_INVALID_SYNTAX;
881  }
882  else
883  {
884  //Save the last byte of the MAC address
885  macAddr->b[i] = value;
886  //The conversion succeeded
887  error = NO_ERROR;
888  }
889 
890  //We are done
891  break;
892  }
893  //Invalid character...
894  else
895  {
896  //The conversion failed
897  error = ERROR_INVALID_SYNTAX;
898  break;
899  }
900 
901  //Point to the next character
902  str++;
903  }
904 
905  //Return status code
906  return error;
907 }
908 
909 
910 /**
911  * @brief Convert a MAC address to a dash delimited string
912  * @param[in] macAddr Pointer to the MAC address
913  * @param[out] str NULL-terminated string representing the MAC address
914  * @return Pointer to the formatted string
915  **/
916 
917 char_t *macAddrToString(const MacAddr *macAddr, char_t *str)
918 {
919  static char_t buffer[24];
920 
921  //The str parameter is optional
922  if(str == NULL)
923  {
924  str = buffer;
925  }
926 
927  //Format MAC address
928  osSprintf(str, "%02" PRIX8 "-%02" PRIX8 "-%02" PRIX8
929  "-%02" PRIX8 "-%02" PRIX8 "-%02" PRIX8,
930  macAddr->b[0], macAddr->b[1], macAddr->b[2],
931  macAddr->b[3], macAddr->b[4], macAddr->b[5]);
932 
933  //Return a pointer to the formatted string
934  return str;
935 }
936 
937 
938 /**
939  * @brief Map a MAC address to the IPv6 modified EUI-64 identifier
940  * @param[in] macAddr Host MAC address
941  * @param[out] interfaceId IPv6 modified EUI-64 identifier
942  **/
943 
944 void macAddrToEui64(const MacAddr *macAddr, Eui64 *interfaceId)
945 {
946  //Copy the Organization Unique Identifier (OUI)
947  interfaceId->b[0] = macAddr->b[0];
948  interfaceId->b[1] = macAddr->b[1];
949  interfaceId->b[2] = macAddr->b[2];
950 
951  //The middle 16 bits are given the value 0xFFFE
952  interfaceId->b[3] = 0xFF;
953  interfaceId->b[4] = 0xFE;
954 
955  //Copy the right-most 24 bits of the MAC address
956  interfaceId->b[5] = macAddr->b[3];
957  interfaceId->b[6] = macAddr->b[4];
958  interfaceId->b[7] = macAddr->b[5];
959 
960  //Modified EUI-64 format interface identifiers are
961  //formed by inverting the Universal/Local bit
963 }
964 
965 
966 /**
967  * @brief Dump Ethernet header for debugging purpose
968  * @param[in] ethHeader Pointer to the Ethernet header
969  **/
970 
971 void ethDumpHeader(const EthHeader *ethHeader)
972 {
973  //Dump Ethernet header contents
974  TRACE_DEBUG(" Dest Addr = %s\r\n", macAddrToString(&ethHeader->destAddr, NULL));
975  TRACE_DEBUG(" Src Addr = %s\r\n", macAddrToString(&ethHeader->srcAddr, NULL));
976  TRACE_DEBUG(" Type = 0x%04" PRIX16 "\r\n", ntohs(ethHeader->type));
977 }
978 
979 #endif
980 #if (ETH_SUPPORT == ENABLED || IPV6_SUPPORT == ENABLED)
981 
982 //Unspecified EUI-64 address
983 const Eui64 EUI64_UNSPECIFIED_ADDR = {{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}};
984 
985 
986 /**
987  * @brief Convert a string representation of an EUI-64 address to a binary EUI-64 address
988  * @param[in] str NULL-terminated string representing the EUI-64 address
989  * @param[out] eui64 Binary representation of the EUI-64 address
990  * @return Error code
991  **/
992 
994 {
995  error_t error;
996  int_t i = 0;
997  int_t value = -1;
998 
999  //Parse input string
1000  while(1)
1001  {
1002  //Hexadecimal digit found?
1003  if(isxdigit((uint8_t) *str))
1004  {
1005  //First digit to be decoded?
1006  if(value < 0)
1007  {
1008  value = 0;
1009  }
1010 
1011  //Update the value of the current byte
1012  if(osIsdigit(*str))
1013  {
1014  value = (value * 16) + (*str - '0');
1015  }
1016  else if(osIsupper(*str))
1017  {
1018  value = (value * 16) + (*str - 'A' + 10);
1019  }
1020  else
1021  {
1022  value = (value * 16) + (*str - 'a' + 10);
1023  }
1024 
1025  //Check resulting value
1026  if(value > 0xFF)
1027  {
1028  //The conversion failed
1029  error = ERROR_INVALID_SYNTAX;
1030  break;
1031  }
1032  }
1033  //Dash or colon separator found?
1034  else if((*str == '-' || *str == ':') && i < 8)
1035  {
1036  //Each separator must be preceded by a valid number
1037  if(value < 0)
1038  {
1039  //The conversion failed
1040  error = ERROR_INVALID_SYNTAX;
1041  break;
1042  }
1043 
1044  //Save the current byte
1045  eui64->b[i++] = value;
1046  //Prepare to decode the next byte
1047  value = -1;
1048  }
1049  //End of string detected?
1050  else if(*str == '\0' && i == 7)
1051  {
1052  //The NULL character must be preceded by a valid number
1053  if(value < 0)
1054  {
1055  //The conversion failed
1056  error = ERROR_INVALID_SYNTAX;
1057  }
1058  else
1059  {
1060  //Save the last byte of the EUI-64 address
1061  eui64->b[i] = value;
1062  //The conversion succeeded
1063  error = NO_ERROR;
1064  }
1065 
1066  //We are done
1067  break;
1068  }
1069  //Invalid character...
1070  else
1071  {
1072  //The conversion failed
1073  error = ERROR_INVALID_SYNTAX;
1074  break;
1075  }
1076 
1077  //Point to the next character
1078  str++;
1079  }
1080 
1081  //Return status code
1082  return error;
1083 }
1084 
1085 
1086 /**
1087  * @brief Convert an EUI-64 address to a dash delimited string
1088  * @param[in] eui64 Pointer to the EUI-64 address
1089  * @param[out] str NULL-terminated string representing the EUI-64 address
1090  * @return Pointer to the formatted string
1091  **/
1092 
1093 char_t *eui64AddrToString(const Eui64 *eui64, char_t *str)
1094 {
1095  static char_t buffer[32];
1096 
1097  //The str parameter is optional
1098  if(str == NULL)
1099  {
1100  str = buffer;
1101  }
1102 
1103  //Format EUI-64 identifier
1104  osSprintf(str, "%02" PRIX8 "-%02" PRIX8 "-%02" PRIX8 "-%02" PRIX8
1105  "-%02" PRIX8 "-%02" PRIX8 "-%02" PRIX8 "-%02" PRIX8,
1106  eui64->b[0], eui64->b[1], eui64->b[2], eui64->b[3],
1107  eui64->b[4], eui64->b[5], eui64->b[6], eui64->b[7]);
1108 
1109  //Return a pointer to the formatted string
1110  return str;
1111 }
1112 
1113 #endif
void arpProcessPacket(NetInterface *interface, ArpPacket *arpPacket, size_t length)
Incoming ARP packet processing.
Definition: arp.c:546
ARP (Address Resolution Protocol)
ArpPacket
Definition: arp.h:161
uint8_t type
Definition: coap_common.h:176
signed int int_t
Definition: compiler_port.h:49
unsigned int uint_t
Definition: compiler_port.h:50
#define PRIuSIZE
char char_t
Definition: compiler_port.h:48
#define htole32(value)
Definition: cpu_endian.h:430
#define htons(value)
Definition: cpu_endian.h:413
#define ntohs(value)
Definition: cpu_endian.h:421
Debugging facilities.
#define TRACE_DEBUG(...)
Definition: debug.h:107
uint8_t n
uint16_t port
Definition: dns_common.h:267
error_t
Error codes.
Definition: error.h:43
@ ERROR_INVALID_PROTOCOL
Definition: error.h:101
@ ERROR_INVALID_SYNTAX
Definition: error.h:68
@ ERROR_NOT_IMPLEMENTED
Definition: error.h:66
@ NO_ERROR
Success.
Definition: error.h:44
@ ERROR_ADDRESS_NOT_FOUND
Definition: error.h:257
@ ERROR_INVALID_LENGTH
Definition: error.h:111
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
error_t ethDetachLlcRxCalback(NetInterface *interface)
Unregister LLC frame received callback.
Definition: ethernet.c:747
error_t ethDropMacAddr(NetInterface *interface, const MacAddr *macAddr)
Remove a unicast/multicast address from the MAC filter table.
Definition: ethernet.c:664
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
const MacAddr MAC_UNSPECIFIED_ADDR
Definition: ethernet.c:53
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:993
error_t ethInit(NetInterface *interface)
Ethernet related initialization.
Definition: ethernet.c:64
error_t ethAttachLlcRxCalback(NetInterface *interface, LlcRxCallback callback, void *param)
Register LLC frame received callback.
Definition: ethernet.c:719
const Eui64 EUI64_UNSPECIFIED_ADDR
Definition: ethernet.c:983
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:819
char_t * macAddrToString(const MacAddr *macAddr, char_t *str)
Convert a MAC address to a dash delimited string.
Definition: ethernet.c:917
void ethDumpHeader(const EthHeader *ethHeader)
Dump Ethernet header for debugging purpose.
Definition: ethernet.c:971
NetBuffer * ethAllocBuffer(size_t length, size_t *offset)
Allocate a buffer to hold an Ethernet frame.
Definition: ethernet.c:775
void macAddrToEui64(const MacAddr *macAddr, Eui64 *interfaceId)
Map a MAC address to the IPv6 modified EUI-64 identifier.
Definition: ethernet.c:944
error_t ethAcceptMacAddr(NetInterface *interface, const MacAddr *macAddr)
Add a unicast/multicast address to the MAC filter table.
Definition: ethernet.c:594
void ethProcessFrame(NetInterface *interface, uint8_t *frame, size_t length, NetRxAncillary *ancillary)
Process an incoming Ethernet frame.
Definition: ethernet.c:84
const MacAddr MAC_BROADCAST_ADDR
Definition: ethernet.c:55
char_t * eui64AddrToString(const Eui64 *eui64, char_t *str)
Convert an EUI-64 address to a dash delimited string.
Definition: ethernet.c:1093
Ethernet.
#define ETH_PORT_TAG_SIZE
Definition: ethernet.h:81
Eui64
Definition: ethernet.h:210
@ ETH_TYPE_VLAN
Definition: ethernet.h:167
@ ETH_TYPE_VMAN
Definition: ethernet.h:170
@ ETH_TYPE_IPV6
Definition: ethernet.h:168
@ ETH_TYPE_ARP
Definition: ethernet.h:165
@ ETH_TYPE_IPV4
Definition: ethernet.h:164
#define ETH_CRC_SIZE
Definition: ethernet.h:114
#define ETH_MTU
Definition: ethernet.h:116
uint8_t data[]
Definition: ethernet.h:222
#define macCompAddr(macAddr1, macAddr2)
Definition: ethernet.h:130
EthHeader
Definition: ethernet.h:223
MacAddr
Definition: ethernet.h:195
#define MAC_ADDR_FILTER_SIZE
Definition: ethernet.h:95
@ MAC_ADDR_FLAG_LOCAL
Definition: ethernet.h:154
VlanTag
Definition: ethernet.h:246
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
#define VLAN_VID_MASK
Definition: ethernet.h:124
void ethUpdateErrorStats(NetInterface *interface, error_t error)
Update Ethernet error statistics.
bool_t ethTrapIgmpPacket(EthHeader *header, uint8_t *data, size_t length)
Trap IGMP packets.
error_t ethCheckCrc(NetInterface *interface, const uint8_t *frame, size_t length)
Ethernet CRC verification.
error_t ethPadFrame(NetBuffer *buffer, size_t *length)
Ethernet frame padding.
void ethUpdateOutStats(NetInterface *interface, const MacAddr *destMacAddr, size_t length)
Update Ethernet output statistics.
uint32_t ethCalcCrcEx(const NetBuffer *buffer, size_t offset, size_t length)
Calculate CRC over a multi-part buffer.
error_t ethCheckDestAddr(NetInterface *interface, const MacAddr *macAddr)
Destination MAC address filtering.
error_t ethEncodeVlanTag(NetBuffer *buffer, size_t *offset, uint16_t vlanId, int8_t vlanPcp, int8_t vlanDei, uint16_t type)
VLAN tag encoding.
void ethUpdateInStats(NetInterface *interface, const MacAddr *destMacAddr)
Update Ethernet input statistics.
error_t ethDecodeVlanTag(const uint8_t *frame, size_t length, uint16_t *vlanId, uint16_t *type)
VLAN tag decoding.
Helper functions for Ethernet.
Interfaces Group MIB module.
#define IF_MIB_INC_COUNTER32(name, value)
Definition: if_mib_module.h:47
#define IF_MIB_INC_COUNTER64(name, value)
Definition: if_mib_module.h:48
void ipv4ProcessPacket(NetInterface *interface, Ipv4Header *packet, size_t length, NetRxAncillary *ancillary)
Incoming IPv4 packet processing.
Definition: ipv4.c:602
IPv4 (Internet Protocol Version 4)
#define Ipv4Header
Definition: ipv4.h:36
Ipv4Addr destAddr
Definition: ipv4.h:299
void ipv6ProcessPacket(NetInterface *interface, NetBuffer *ipPacket, size_t ipPacketOffset, NetRxAncillary *ancillary)
Incoming IPv6 packet processing.
Definition: ipv6.c:968
IPv6 (Internet Protocol Version 6)
Eui64 interfaceId
Definition: ipv6cp.h:71
MIB-II module.
#define MIB2_IF_INC_COUNTER32(name, value)
Definition: mib2_module.h:156
TCP/IP stack core.
#define NET_INTERFACE_COUNT
Definition: net.h:113
#define NetInterface
Definition: net.h:36
#define netInterface
Definition: net_legacy.h:199
void * netBufferAt(const NetBuffer *buffer, size_t offset)
Returns a pointer to the data at the specified position.
Definition: net_mem.c:415
NetBuffer * netBufferAlloc(size_t length)
Allocate a multi-part buffer.
Definition: net_mem.c:243
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
error_t netBufferAppend(NetBuffer *dest, const void *src, size_t length)
Append data a multi-part buffer.
Definition: net_mem.c:588
#define NetRxAncillary
Definition: net_misc.h:40
#define NetTxAncillary
Definition: net_misc.h:36
error_t nicSendPacket(NetInterface *interface, const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send a packet to the network controller.
Definition: nic.c:280
uint16_t nicGetVmanId(NetInterface *interface)
Retrieve VMAN identifier.
Definition: nic.c:175
uint8_t nicGetSwitchPort(NetInterface *interface)
Retrieve switch port identifier.
Definition: nic.c:113
NetInterface * nicGetLogicalInterface(NetInterface *interface)
Retrieve logical interface.
Definition: nic.c:52
uint16_t nicGetVlanId(NetInterface *interface)
Retrieve VLAN identifier.
Definition: nic.c:144
error_t nicUpdateMacAddrFilter(NetInterface *interface)
Configure MAC address filtering.
Definition: nic.c:352
NetInterface * nicGetPhysicalInterface(NetInterface *interface)
Retrieve physical interface.
Definition: nic.c:84
Network interface controller abstraction layer.
#define osMemset(p, value, length)
Definition: os_port.h:135
#define osSprintf(dest,...)
Definition: os_port.h:231
#define osIsdigit(c)
Definition: os_port.h:279
#define TRUE
Definition: os_port.h:50
#define FALSE
Definition: os_port.h:46
#define osIsupper(c)
Definition: os_port.h:273
void rawSocketProcessEthPacket(NetInterface *interface, const uint8_t *data, size_t length, const NetRxAncillary *ancillary)
Process incoming Ethernet packet.
Definition: raw_socket.c:360
TCP/IP raw sockets.
Socket API.
uint16_t length
Definition: net_mem.h:79
uint16_t size
Definition: net_mem.h:80
void * address
Definition: net_mem.h:78
MAC filter table entry.
Definition: ethernet.h:262
bool_t addFlag
Definition: ethernet.h:265
MacAddr addr
MAC address.
Definition: ethernet.h:263
uint_t refCount
Reference count for the current entry.
Definition: ethernet.h:264
bool_t deleteFlag
Definition: ethernet.h:266
uint_t chunkCount
Definition: net_mem.h:98
uint_t maxChunkCount
Definition: net_mem.h:99
ChunkDesc chunk[1]
Definition: net_mem.h:100
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
uint8_t length
Definition: tcp.h:368
uint8_t value[]
Definition: tcp.h:369
TCP timer management.