nic.c
Go to the documentation of this file.
1 /**
2  * @file nic.c
3  * @brief Network interface controller abstraction layer
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2026 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.6.0
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL NIC_TRACE_LEVEL
33 
34 //Dependencies
35 #include "core/net.h"
36 #include "core/nic.h"
37 #include "core/ethernet.h"
38 #include "ipv4/ipv4_multicast.h"
39 #include "ipv4/ipv4_misc.h"
40 #include "ipv6/ipv6_multicast.h"
41 #include "ipv6/ipv6_misc.h"
42 #include "debug.h"
43 
44 
45 /**
46  * @brief Retrieve logical interface
47  * @param[in] interface Pointer to the network interface
48  * @return Pointer to the physical interface
49  **/
50 
52 {
53 #if (ETH_VLAN_SUPPORT == ENABLED)
54  uint_t i;
55  NetContext *context;
56 
57  //Point to the TCP/IP stack context
58  context = interface->netContext;
59 
60  //A virtual interface can inherit from multiple parent interfaces
61  for(i = 0; i < context->numInterfaces; i++)
62  {
63  //Check whether a valid MAC address has been assigned to the interface
64  if(!macCompAddr(&interface->macAddr, &MAC_UNSPECIFIED_ADDR))
65  break;
66 
67  //Last interface in the list?
68  if(interface->parent == NULL)
69  break;
70 
71  //Point to the interface on top of which the virtual interface runs
72  interface = interface->parent;
73  }
74 #endif
75 
76  //Return a pointer to the logical interface
77  return interface;
78 }
79 
80 
81 /**
82  * @brief Retrieve physical interface
83  * @param[in] interface Pointer to the network interface
84  * @return Pointer to the physical interface
85  **/
86 
88 {
89 #if (ETH_VIRTUAL_IF_SUPPORT == ENABLED || ETH_VLAN_SUPPORT == ENABLED || \
90  ETH_PORT_TAGGING_SUPPORT == ENABLED)
91  uint_t i;
92  NetContext *context;
93 
94  //Point to the TCP/IP stack context
95  context = interface->netContext;
96 
97  //A virtual interface can inherit from multiple parent interfaces
98  for(i = 0; i < context->numInterfaces; i++)
99  {
100  //Physical interface?
101  if(interface->nicDriver != NULL || interface->parent == NULL)
102  break;
103 
104  //Point to the interface on top of which the virtual interface runs
105  interface = interface->parent;
106  }
107 #endif
108 
109  //Return a pointer to the physical interface
110  return interface;
111 }
112 
113 
114 /**
115  * @brief Retrieve switch port identifier
116  * @param[in] interface Pointer to the network interface
117  * @return Switch port identifier
118  **/
119 
120 uint8_t nicGetSwitchPort(NetInterface *interface)
121 {
122 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
123  uint_t i;
124  NetContext *context;
125 
126  //Point to the TCP/IP stack context
127  context = interface->netContext;
128 
129  //A virtual interface can inherit from multiple parent interfaces
130  for(i = 0; i < context->numInterfaces; i++)
131  {
132  //Valid switch port identifier?
133  if(interface->port != 0 || interface->parent == NULL)
134  break;
135 
136  //Point to the interface on top of which the virtual interface runs
137  interface = interface->parent;
138  }
139 
140  //Return switch port identifier
141  return interface->port;
142 #else
143  //Ethernet port multiplication (VLAN or tail tagging) is not supported
144  return 0;
145 #endif
146 }
147 
148 
149 /**
150  * @brief Retrieve VLAN identifier
151  * @param[in] interface Pointer to the network interface
152  * @return VLAN identifier
153  **/
154 
155 uint16_t nicGetVlanId(NetInterface *interface)
156 {
157 #if (ETH_VLAN_SUPPORT == ENABLED)
158  uint_t i;
159  NetContext *context;
160 
161  //Point to the TCP/IP stack context
162  context = interface->netContext;
163 
164  //A virtual interface can inherit from multiple parent interfaces
165  for(i = 0; i < context->numInterfaces; i++)
166  {
167  //Valid VLAN identifier?
168  if(interface->vlanId != 0 || interface->parent == NULL)
169  break;
170 
171  //Point to the interface on top of which the virtual interface runs
172  interface = interface->parent;
173  }
174 
175  //Return VLAN identifier
176  return interface->vlanId;
177 #else
178  //VLAN is not supported
179  return 0;
180 #endif
181 }
182 
183 
184 /**
185  * @brief Retrieve VMAN identifier
186  * @param[in] interface Pointer to the network interface
187  * @return VMAN identifier
188  **/
189 
190 uint16_t nicGetVmanId(NetInterface *interface)
191 {
192 #if (ETH_VMAN_SUPPORT == ENABLED)
193  uint_t i;
194  NetContext *context;
195 
196  //Point to the TCP/IP stack context
197  context = interface->netContext;
198 
199  //A virtual interface can inherit from multiple parent interfaces
200  for(i = 0; i < context->numInterfaces; i++)
201  {
202  //Valid VMAN identifier?
203  if(interface->vmanId != 0 || interface->parent == NULL)
204  break;
205 
206  //Point to the interface on top of which the virtual interface runs
207  interface = interface->parent;
208  }
209 
210  //Return VMAN identifier
211  return interface->vmanId;
212 #else
213  //VMAN is not supported
214  return 0;
215 #endif
216 }
217 
218 
219 /**
220  * @brief Test parent/child relationship between 2 interfaces
221  * @param[in] interface Pointer to the child interface
222  * @param[in] parent Pointer to the parent interface
223  * @return TRUE is an existing parent/child relationship is found, else FALSE
224  **/
225 
227 {
228 #if (ETH_VIRTUAL_IF_SUPPORT == ENABLED || ETH_VLAN_SUPPORT == ENABLED || \
229  ETH_PORT_TAGGING_SUPPORT == ENABLED)
230  uint_t i;
231  bool_t flag;
232  NetContext *context;
233 
234  //Point to the TCP/IP stack context
235  context = interface->netContext;
236 
237  //Iterate through the parent interfaces
238  for(flag = FALSE, i = 0; i < context->numInterfaces; i++)
239  {
240  //Any parent/child relationship?
241  if(interface == parent)
242  {
243  flag = TRUE;
244  break;
245  }
246 
247  //Last interface in the list?
248  if(interface->parent == NULL)
249  break;
250 
251  //Point to the interface on top of which the virtual interface runs
252  interface = interface->parent;
253  }
254 
255  //Return TRUE is an existing parent/child relationship is found
256  return flag;
257 #else
258  //Virtual interfaces are not supported
259  return (interface == parent) ? TRUE : FALSE;
260 #endif
261 }
262 
263 
264 /**
265  * @brief Network controller timer handler
266  *
267  * This routine is periodically called by the TCP/IP stack to
268  * handle periodic operations such as polling the link state
269  *
270  * @param[in] interface Underlying network interface
271  **/
272 
273 void nicTick(NetInterface *interface)
274 {
275  //Valid NIC driver?
276  if(interface->nicDriver != NULL)
277  {
278  //Disable interrupts
279  interface->nicDriver->disableIrq(interface);
280 
281  //Handle periodic operations
282  interface->nicDriver->tick(interface);
283 
284  //Re-enable interrupts if necessary
285  if(interface->configured)
286  {
287  interface->nicDriver->enableIrq(interface);
288  }
289  }
290 }
291 
292 
293 /**
294  * @brief Send a packet to the network controller
295  * @param[in] interface Underlying network interface
296  * @param[in] buffer Multi-part buffer containing the data to send
297  * @param[in] offset Offset to the first data byte
298  * @param[in] ancillary Additional options passed to the stack along with
299  * the packet
300  * @return Error code
301  **/
302 
303 error_t nicSendPacket(NetInterface *interface, const NetBuffer *buffer,
304  size_t offset, NetTxAncillary *ancillary)
305 {
306  error_t error;
307  bool_t status;
308  NetContext *context;
309 
310 #if (TRACE_LEVEL >= TRACE_LEVEL_DEBUG)
311  //Retrieve the length of the packet
312  size_t length = netBufferGetLength(buffer) - offset;
313 
314  //Debug message
315  TRACE_DEBUG("Sending packet (%" PRIuSIZE " bytes)...\r\n", length);
316  TRACE_DEBUG_NET_BUFFER(" ", buffer, offset, length);
317 #endif
318 
319  //Point to the TCP/IP stack context
320  context = interface->netContext;
321 
322  //Gather entropy
323  context->entropy += netGetSystemTickCount();
324 
325  //Check whether the interface is enabled for operation
326  if(interface->configured && interface->nicDriver != NULL)
327  {
328  //Loopback interface?
329  if(interface->nicDriver->type == NIC_TYPE_LOOPBACK)
330  {
331  //The loopback interface is always available
332  status = TRUE;
333  }
334  else
335  {
336  //Wait for the transmitter to be ready to send
337  status = osWaitForEvent(&interface->nicTxEvent, NIC_MAX_BLOCKING_TIME);
338  }
339 
340  //Check whether the specified event is in signaled state
341  if(status)
342  {
343  //Disable interrupts
344  interface->nicDriver->disableIrq(interface);
345 
346  //Send the packet
347  error = interface->nicDriver->sendPacket(interface, buffer, offset,
348  ancillary);
349 
350  //Re-enable interrupts if necessary
351  if(interface->configured)
352  {
353  interface->nicDriver->enableIrq(interface);
354  }
355  }
356  else
357  {
358  //If the transmitter is busy, then drop the packet
359  error = NO_ERROR;
360  }
361  }
362  else
363  {
364  //Report an error
365  error = ERROR_INVALID_INTERFACE;
366  }
367 
368  //Return status code
369  return error;
370 }
371 
372 
373 /**
374  * @brief Configure MAC address filtering
375  * @param[in] interface Underlying network interface
376  * @return Error code
377  **/
378 
380 {
381  error_t error;
382 
383  //Valid NIC driver?
384  if(interface->nicDriver != NULL)
385  {
386  //Disable interrupts
387  interface->nicDriver->disableIrq(interface);
388 
389  //Update MAC filter table
390  error = interface->nicDriver->updateMacAddrFilter(interface);
391 
392  //Re-enable interrupts if necessary
393  if(interface->configured)
394  {
395  interface->nicDriver->enableIrq(interface);
396  }
397  }
398  else
399  {
400  //Report an error
401  error = ERROR_INVALID_INTERFACE;
402  }
403 
404  //Return status code
405  return error;
406 }
407 
408 
409 /**
410  * @brief Handle a packet received by the network controller
411  * @param[in] interface Underlying network interface
412  * @param[in] packet Incoming packet to process
413  * @param[in] length Total packet length
414  * @param[in] ancillary Additional options passed to the stack along with
415  * the packet
416  **/
417 
418 void nicProcessPacket(NetInterface *interface, uint8_t *packet, size_t length,
419  NetRxAncillary *ancillary)
420 {
421  NicType type;
422  NetContext *context;
423 
424  //Point to the TCP/IP stack context
425  context = interface->netContext;
426 
427  //Gather entropy
428  context->entropy += netGetSystemTickCount();
429 
430  //Check whether the interface is enabled for operation
431  if(interface->configured)
432  {
433  //Re-enable interrupts
434  interface->nicDriver->enableIrq(interface);
435 
436  //Debug message
437  TRACE_DEBUG("Packet received (%" PRIuSIZE " bytes)...\r\n", length);
438  TRACE_DEBUG_ARRAY(" ", packet, length);
439 
440  //Retrieve network interface type
441  type = interface->nicDriver->type;
442 
443 #if (ETH_SUPPORT == ENABLED)
444  //Ethernet interface?
445  if(type == NIC_TYPE_ETHERNET)
446  {
447  //Process incoming Ethernet frame
448  ethProcessFrame(interface, packet, length, ancillary);
449  }
450  else
451 #endif
452 #if (PPP_SUPPORT == ENABLED)
453  //PPP interface?
454  if(type == NIC_TYPE_PPP)
455  {
456  //Process incoming PPP frame
457  pppProcessFrame(interface, packet, length, ancillary);
458  }
459  else
460 #endif
461 #if (IPV4_SUPPORT == ENABLED)
462  //IPv4 interface?
463  if(type == NIC_TYPE_IPV4)
464  {
465  //Process incoming IPv4 packet
466  ipv4ProcessPacket(interface, (Ipv4Header *) packet, length,
467  ancillary);
468  }
469  else
470 #endif
471 #if (IPV6_SUPPORT == ENABLED)
472  //6LoWPAN interface?
473  if(type == NIC_TYPE_6LOWPAN)
474  {
475  NetBuffer1 buffer;
476 
477  //The incoming packet fits in a single chunk
478  buffer.chunkCount = 1;
479  buffer.maxChunkCount = 1;
480  buffer.chunk[0].address = packet;
481  buffer.chunk[0].length = (uint16_t) length;
482  buffer.chunk[0].size = 0;
483 
484  //Process incoming IPv6 packet
485  ipv6ProcessPacket(interface, (NetBuffer *) &buffer, 0, ancillary);
486  }
487  else
488 #endif
489 #if (NET_LOOPBACK_IF_SUPPORT == ENABLED)
490  //Loopback interface?
491  if(type == NIC_TYPE_LOOPBACK)
492  {
493 #if (IPV4_SUPPORT == ENABLED)
494  //IPv4 packet received?
495  if(length >= sizeof(Ipv4Header) && (packet[0] >> 4) == 4)
496  {
497  error_t error;
498  uint_t i;
499  Ipv4Header *header;
500 
501  //Point to the IPv4 header
502  header = (Ipv4Header *) packet;
503 
504  //Loop through network interfaces
505  for(i = 0; i < context->numInterfaces; i++)
506  {
507  //Multicast packet?
508  if(ipv4IsMulticastAddr(header->destAddr))
509  {
510  //Multicast address filtering
511  error = ipv4MulticastFilter(&context->interfaces[i],
512  header->destAddr, header->srcAddr);
513  }
514  else
515  {
516  //Unicast address filtering
517  error = ipv4CheckDestAddr(&context->interfaces[i],
518  header->destAddr);
519  }
520 
521  //Valid destination address?
522  if(!error)
523  {
524  //Process incoming IPv4 packet
525  ipv4ProcessPacket(&context->interfaces[i],
526  (Ipv4Header *) packet, length, ancillary);
527  }
528  }
529  }
530  else
531 #endif
532 #if (IPV6_SUPPORT == ENABLED)
533  //IPv6 packet received?
534  if(length >= sizeof(Ipv6Header) && (packet[0] >> 4) == 6)
535  {
536  error_t error;
537  uint_t i;
538  NetBuffer1 buffer;
539  Ipv6Header *header;
540 
541  //Point to the IPv6 header
542  header = (Ipv6Header *) packet;
543 
544  //Loop through network interfaces
545  for(i = 0; i < context->numInterfaces; i++)
546  {
547  //Multicast packet?
548  if(ipv6IsMulticastAddr(&header->destAddr))
549  {
550  //Multicast address filtering
551  error = ipv6MulticastFilter(&context->interfaces[i],
552  &header->destAddr, &header->srcAddr);
553  }
554  else
555  {
556  //Unicast address filtering
557  error = ipv6CheckDestAddr(&context->interfaces[i],
558  &header->destAddr);
559  }
560 
561  //Valid destination address?
562  if(!error)
563  {
564  //The incoming packet fits in a single chunk
565  buffer.chunkCount = 1;
566  buffer.maxChunkCount = 1;
567  buffer.chunk[0].address = packet;
568  buffer.chunk[0].length = (uint16_t) length;
569  buffer.chunk[0].size = 0;
570 
571  //Process incoming IPv6 packet
572  ipv6ProcessPacket(&context->interfaces[i],
573  (NetBuffer *) &buffer, 0, ancillary);
574  }
575  }
576  }
577  else
578 #endif
579  {
580  //Invalid version number
581  }
582  }
583  else
584 #endif
585  //Unknown interface type?
586  {
587  //Silently discard the received packet
588  }
589 
590  //Disable interrupts
591  interface->nicDriver->disableIrq(interface);
592  }
593 }
594 
595 
596 /**
597  * @brief Process link state change notification
598  * @param[in] interface Underlying network interface
599  **/
600 
602 {
603  uint_t i;
604  NetContext *context;
605  NetInterface *physicalInterface;
606  NetInterface *virtualInterface;
607 
608  //Point to the TCP/IP stack context
609  context = interface->netContext;
610 
611  //Gather entropy
612  context->entropy += netGetSystemTickCount();
613 
614  //Point to the physical interface
615  physicalInterface = nicGetPhysicalInterface(interface);
616 
617  //Re-enable interrupts if necessary
618  if(physicalInterface->configured)
619  {
620  physicalInterface->nicDriver->enableIrq(physicalInterface);
621  }
622 
623  //Loop through network interfaces
624  for(i = 0; i < context->numInterfaces; i++)
625  {
626  //Point to the current interface
627  virtualInterface = &context->interfaces[i];
628 
629  //Check whether the current virtual interface is attached to the physical
630  //interface
631  if(nicIsParentInterface(virtualInterface, interface) &&
632  nicGetSwitchPort(virtualInterface) == nicGetSwitchPort(interface))
633  {
634  //Set operation mode
635  virtualInterface->linkSpeed = interface->linkSpeed;
636  virtualInterface->duplexMode = interface->duplexMode;
637 
638  //Update link state
639  virtualInterface->linkState = interface->linkState;
640 
641  //Process link state change event
642  netProcessLinkChange(virtualInterface);
643  }
644  }
645 
646  //Disable interrupts
647  physicalInterface->nicDriver->disableIrq(physicalInterface);
648 }
void nicNotifyLinkChange(NetInterface *interface)
Process link state change notification.
Definition: nic.c:601
#define ipv4IsMulticastAddr(ipAddr)
Definition: ipv4.h:186
#define NetContext
Definition: net.h:36
int bool_t
Definition: compiler_port.h:63
#define Ipv4Header
Definition: ipv4.h:36
uint_t chunkCount
Definition: net_mem.h:98
@ ERROR_INVALID_INTERFACE
Invalid interface.
Definition: error.h:53
error_t nicSendPacket(NetInterface *interface, const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send a packet to the network controller.
Definition: nic.c:303
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
#define TRUE
Definition: os_port.h:50
void ipv4ProcessPacket(NetInterface *interface, Ipv4Header *packet, size_t length, NetRxAncillary *ancillary)
Incoming IPv4 packet processing.
Definition: ipv4.c:605
#define NIC_MAX_BLOCKING_TIME
Definition: nic.h:46
#define Ipv6Header
Definition: ipv6.h:36
uint8_t type
Definition: coap_common.h:176
error_t ipv6MulticastFilter(NetInterface *interface, const Ipv6Addr *destAddr, const Ipv6Addr *srcAddr)
Filter out incoming multicast traffic.
void ipv6ProcessPacket(NetInterface *interface, NetBuffer *ipPacket, size_t ipPacketOffset, NetRxAncillary *ancillary)
Incoming IPv6 packet processing.
Definition: ipv6.c:983
void nicProcessPacket(NetInterface *interface, uint8_t *packet, size_t length, NetRxAncillary *ancillary)
Handle a packet received by the network controller.
Definition: nic.c:418
ChunkDesc chunk[1]
Definition: net_mem.h:100
Ethernet.
#define TRACE_DEBUG_NET_BUFFER(p, b, o, n)
Definition: debug.h:121
IPv4 multicast filtering.
@ NIC_TYPE_LOOPBACK
Loopback interface.
Definition: nic.h:88
error_t ipv4CheckDestAddr(NetInterface *interface, Ipv4Addr ipAddr)
Destination IPv4 address filtering.
Definition: ipv4_misc.c:114
#define ipv6IsMulticastAddr(ipAddr)
Definition: ipv6.h:146
IPv6 multicast filtering.
Helper functions for IPv4.
uint16_t length
Definition: net_mem.h:79
#define FALSE
Definition: os_port.h:46
NetInterface * nicGetPhysicalInterface(NetInterface *interface)
Retrieve physical interface.
Definition: nic.c:87
void ethProcessFrame(NetInterface *interface, uint8_t *frame, size_t length, NetRxAncillary *ancillary)
Process an incoming Ethernet frame.
Definition: ethernet.c:82
error_t
Error codes.
Definition: error.h:43
NicType
NIC types.
Definition: nic.h:81
void * address
Definition: net_mem.h:78
uint_t maxChunkCount
Definition: net_mem.h:99
#define NetRxAncillary
Definition: net_misc.h:40
#define NetInterface
Definition: net.h:40
error_t ipv6CheckDestAddr(NetInterface *interface, const Ipv6Addr *ipAddr)
Destination IPv6 address filtering.
Definition: ipv6_misc.c:814
Helper functions for IPv6.
#define NetTxAncillary
Definition: net_misc.h:36
void pppProcessFrame(NetInterface *interface, uint8_t *frame, size_t length, NetRxAncillary *ancillary)
Process an incoming PPP frame.
Definition: ppp.c:910
uint8_t length
Definition: tcp.h:375
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
void netProcessLinkChange(NetInterface *interface)
Process link state change event.
Definition: net_misc.c:202
error_t nicUpdateMacAddrFilter(NetInterface *interface)
Configure MAC address filtering.
Definition: nic.c:379
error_t ipv4MulticastFilter(NetInterface *interface, Ipv4Addr destAddr, Ipv4Addr srcAddr)
Filter out incoming multicast traffic.
@ NIC_TYPE_PPP
PPP interface.
Definition: nic.h:84
#define TRACE_DEBUG(...)
Definition: debug.h:119
#define TRACE_DEBUG_ARRAY(p, a, n)
Definition: debug.h:120
bool_t osWaitForEvent(OsEvent *event, systime_t timeout)
Wait until the specified event is in the signaled state.
Network interface controller abstraction layer.
#define macCompAddr(macAddr1, macAddr2)
Definition: ethernet.h:130
#define netGetSystemTickCount()
Definition: net.h:197
@ NIC_TYPE_IPV4
IPv4 interface.
Definition: nic.h:85
#define PRIuSIZE
@ NIC_TYPE_6LOWPAN
6LoWPAN interface
Definition: nic.h:87
unsigned int uint_t
Definition: compiler_port.h:57
void nicTick(NetInterface *interface)
Network controller timer handler.
Definition: nic.c:273
TCP/IP stack core.
NetInterface * nicGetLogicalInterface(NetInterface *interface)
Retrieve logical interface.
Definition: nic.c:51
uint16_t nicGetVmanId(NetInterface *interface)
Retrieve VMAN identifier.
Definition: nic.c:190
uint16_t size
Definition: net_mem.h:80
uint16_t nicGetVlanId(NetInterface *interface)
Retrieve VLAN identifier.
Definition: nic.c:155
uint8_t nicGetSwitchPort(NetInterface *interface)
Retrieve switch port identifier.
Definition: nic.c:120
bool_t nicIsParentInterface(NetInterface *interface, NetInterface *parent)
Test parent/child relationship between 2 interfaces.
Definition: nic.c:226
const MacAddr MAC_UNSPECIFIED_ADDR
Definition: ethernet.c:51
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
@ NIC_TYPE_ETHERNET
Ethernet interface.
Definition: nic.h:83