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-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 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_misc.h"
39 #include "ipv6/ipv6_misc.h"
40 #include "debug.h"
41 
42 //Tick counter to handle periodic operations
44 
45 
46 /**
47  * @brief Retrieve logical interface
48  * @param[in] interface Pointer to the network interface
49  * @return Pointer to the physical interface
50  **/
51 
53 {
54 #if (ETH_VLAN_SUPPORT == ENABLED)
55  uint_t i;
56 
57  //A virtual interface can inherit from multiple parent interfaces
58  for(i = 0; i < NET_INTERFACE_COUNT; i++)
59  {
60  //Check whether a valid MAC address has been assigned to the interface
61  if(!macCompAddr(&interface->macAddr, &MAC_UNSPECIFIED_ADDR))
62  break;
63 
64  //Last interface in the list?
65  if(interface->parent == NULL)
66  break;
67 
68  //Point to the interface on top of which the virtual interface runs
69  interface = interface->parent;
70  }
71 #endif
72 
73  //Return a pointer to the logical interface
74  return interface;
75 }
76 
77 
78 /**
79  * @brief Retrieve physical interface
80  * @param[in] interface Pointer to the network interface
81  * @return Pointer to the physical interface
82  **/
83 
85 {
86 #if (ETH_VIRTUAL_IF_SUPPORT == ENABLED || ETH_VLAN_SUPPORT == ENABLED || \
87  ETH_PORT_TAGGING_SUPPORT == ENABLED)
88  uint_t i;
89 
90  //A virtual interface can inherit from multiple parent interfaces
91  for(i = 0; i < NET_INTERFACE_COUNT; i++)
92  {
93  //Physical interface?
94  if(interface->nicDriver != NULL || interface->parent == NULL)
95  break;
96 
97  //Point to the interface on top of which the virtual interface runs
98  interface = interface->parent;
99  }
100 #endif
101 
102  //Return a pointer to the physical interface
103  return interface;
104 }
105 
106 
107 /**
108  * @brief Retrieve switch port identifier
109  * @param[in] interface Pointer to the network interface
110  * @return Switch port identifier
111  **/
112 
113 uint8_t nicGetSwitchPort(NetInterface *interface)
114 {
115 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
116  uint_t i;
117 
118  //A virtual interface can inherit from multiple parent interfaces
119  for(i = 0; i < NET_INTERFACE_COUNT; i++)
120  {
121  //Valid switch port identifier?
122  if(interface->port != 0 || interface->parent == NULL)
123  break;
124 
125  //Point to the interface on top of which the virtual interface runs
126  interface = interface->parent;
127  }
128 
129  //Return switch port identifier
130  return interface->port;
131 #else
132  //Ethernet port multiplication (VLAN or tail tagging) is not supported
133  return 0;
134 #endif
135 }
136 
137 
138 /**
139  * @brief Retrieve VLAN identifier
140  * @param[in] interface Pointer to the network interface
141  * @return VLAN identifier
142  **/
143 
144 uint16_t nicGetVlanId(NetInterface *interface)
145 {
146 #if (ETH_VLAN_SUPPORT == ENABLED)
147  uint_t i;
148 
149  //A virtual interface can inherit from multiple parent interfaces
150  for(i = 0; i < NET_INTERFACE_COUNT; i++)
151  {
152  //Valid VLAN identifier?
153  if(interface->vlanId != 0 || interface->parent == NULL)
154  break;
155 
156  //Point to the interface on top of which the virtual interface runs
157  interface = interface->parent;
158  }
159 
160  //Return VLAN identifier
161  return interface->vlanId;
162 #else
163  //VLAN is not supported
164  return 0;
165 #endif
166 }
167 
168 
169 /**
170  * @brief Retrieve VMAN identifier
171  * @param[in] interface Pointer to the network interface
172  * @return VMAN identifier
173  **/
174 
175 uint16_t nicGetVmanId(NetInterface *interface)
176 {
177 #if (ETH_VMAN_SUPPORT == ENABLED)
178  uint_t i;
179 
180  //A virtual interface can inherit from multiple parent interfaces
181  for(i = 0; i < NET_INTERFACE_COUNT; i++)
182  {
183  //Valid VMAN identifier?
184  if(interface->vmanId != 0 || interface->parent == NULL)
185  break;
186 
187  //Point to the interface on top of which the virtual interface runs
188  interface = interface->parent;
189  }
190 
191  //Return VMAN identifier
192  return interface->vmanId;
193 #else
194  //VMAN is not supported
195  return 0;
196 #endif
197 }
198 
199 
200 /**
201  * @brief Test parent/child relationship between 2 interfaces
202  * @param[in] interface Pointer to the child interface
203  * @param[in] parent Pointer to the parent interface
204  * @return TRUE is an existing parent/child relationship is found, else FALSE
205  **/
206 
208 {
209 #if (ETH_VIRTUAL_IF_SUPPORT == ENABLED || ETH_VLAN_SUPPORT == ENABLED || \
210  ETH_PORT_TAGGING_SUPPORT == ENABLED)
211  uint_t i;
212  bool_t flag;
213 
214  //Iterate through the parent interfaces
215  for(flag = FALSE, i = 0; i < NET_INTERFACE_COUNT; i++)
216  {
217  //Any parent/child relationship?
218  if(interface == parent)
219  {
220  flag = TRUE;
221  break;
222  }
223 
224  //Last interface in the list?
225  if(interface->parent == NULL)
226  break;
227 
228  //Point to the interface on top of which the virtual interface runs
229  interface = interface->parent;
230  }
231 
232  //Return TRUE is an existing parent/child relationship is found
233  return flag;
234 #else
235  //Virtual interfaces are not supported
236  return (interface == parent) ? TRUE : FALSE;
237 #endif
238 }
239 
240 
241 /**
242  * @brief Network controller timer handler
243  *
244  * This routine is periodically called by the TCP/IP stack to
245  * handle periodic operations such as polling the link state
246  *
247  * @param[in] interface Underlying network interface
248  **/
249 
250 void nicTick(NetInterface *interface)
251 {
252  //Valid NIC driver?
253  if(interface->nicDriver != NULL)
254  {
255  //Disable interrupts
256  interface->nicDriver->disableIrq(interface);
257 
258  //Handle periodic operations
259  interface->nicDriver->tick(interface);
260 
261  //Re-enable interrupts if necessary
262  if(interface->configured)
263  {
264  interface->nicDriver->enableIrq(interface);
265  }
266  }
267 }
268 
269 
270 /**
271  * @brief Send a packet to the network controller
272  * @param[in] interface Underlying network interface
273  * @param[in] buffer Multi-part buffer containing the data to send
274  * @param[in] offset Offset to the first data byte
275  * @param[in] ancillary Additional options passed to the stack along with
276  * the packet
277  * @return Error code
278  **/
279 
280 error_t nicSendPacket(NetInterface *interface, const NetBuffer *buffer,
281  size_t offset, NetTxAncillary *ancillary)
282 {
283  error_t error;
284  bool_t status;
285 
286 #if (TRACE_LEVEL >= TRACE_LEVEL_DEBUG)
287  //Retrieve the length of the packet
288  size_t length = netBufferGetLength(buffer) - offset;
289 
290  //Debug message
291  TRACE_DEBUG("Sending packet (%" PRIuSIZE " bytes)...\r\n", length);
292  TRACE_DEBUG_NET_BUFFER(" ", buffer, offset, length);
293 #endif
294 
295  //Gather entropy
297 
298  //Check whether the interface is enabled for operation
299  if(interface->configured && interface->nicDriver != NULL)
300  {
301  //Loopback interface?
302  if(interface->nicDriver->type == NIC_TYPE_LOOPBACK)
303  {
304  //The loopback interface is always available
305  status = TRUE;
306  }
307  else
308  {
309  //Wait for the transmitter to be ready to send
310  status = osWaitForEvent(&interface->nicTxEvent, NIC_MAX_BLOCKING_TIME);
311  }
312 
313  //Check whether the specified event is in signaled state
314  if(status)
315  {
316  //Disable interrupts
317  interface->nicDriver->disableIrq(interface);
318 
319  //Send the packet
320  error = interface->nicDriver->sendPacket(interface, buffer, offset,
321  ancillary);
322 
323  //Re-enable interrupts if necessary
324  if(interface->configured)
325  {
326  interface->nicDriver->enableIrq(interface);
327  }
328  }
329  else
330  {
331  //If the transmitter is busy, then drop the packet
332  error = NO_ERROR;
333  }
334  }
335  else
336  {
337  //Report an error
338  error = ERROR_INVALID_INTERFACE;
339  }
340 
341  //Return status code
342  return error;
343 }
344 
345 
346 /**
347  * @brief Configure MAC address filtering
348  * @param[in] interface Underlying network interface
349  * @return Error code
350  **/
351 
353 {
354  error_t error;
355 
356  //Valid NIC driver?
357  if(interface->nicDriver != NULL)
358  {
359  //Disable interrupts
360  interface->nicDriver->disableIrq(interface);
361 
362  //Update MAC filter table
363  error = interface->nicDriver->updateMacAddrFilter(interface);
364 
365  //Re-enable interrupts if necessary
366  if(interface->configured)
367  {
368  interface->nicDriver->enableIrq(interface);
369  }
370  }
371  else
372  {
373  //Report an error
374  error = ERROR_INVALID_INTERFACE;
375  }
376 
377  //Return status code
378  return error;
379 }
380 
381 
382 /**
383  * @brief Handle a packet received by the network controller
384  * @param[in] interface Underlying network interface
385  * @param[in] packet Incoming packet to process
386  * @param[in] length Total packet length
387  * @param[in] ancillary Additional options passed to the stack along with
388  * the packet
389  **/
390 
391 void nicProcessPacket(NetInterface *interface, uint8_t *packet, size_t length,
392  NetRxAncillary *ancillary)
393 {
394  NicType type;
395 
396  //Gather entropy
398 
399  //Check whether the interface is enabled for operation
400  if(interface->configured)
401  {
402  //Re-enable interrupts
403  interface->nicDriver->enableIrq(interface);
404 
405  //Debug message
406  TRACE_DEBUG("Packet received (%" PRIuSIZE " bytes)...\r\n", length);
407  TRACE_DEBUG_ARRAY(" ", packet, length);
408 
409  //Retrieve network interface type
410  type = interface->nicDriver->type;
411 
412 #if (ETH_SUPPORT == ENABLED)
413  //Ethernet interface?
414  if(type == NIC_TYPE_ETHERNET)
415  {
416  //Process incoming Ethernet frame
417  ethProcessFrame(interface, packet, length, ancillary);
418  }
419  else
420 #endif
421 #if (PPP_SUPPORT == ENABLED)
422  //PPP interface?
423  if(type == NIC_TYPE_PPP)
424  {
425  //Process incoming PPP frame
426  pppProcessFrame(interface, packet, length, ancillary);
427  }
428  else
429 #endif
430 #if (IPV4_SUPPORT == ENABLED)
431  //IPv4 interface?
432  if(type == NIC_TYPE_IPV4)
433  {
434  //Process incoming IPv4 packet
435  ipv4ProcessPacket(interface, (Ipv4Header *) packet, length,
436  ancillary);
437  }
438  else
439 #endif
440 #if (IPV6_SUPPORT == ENABLED)
441  //6LoWPAN interface?
442  if(type == NIC_TYPE_6LOWPAN)
443  {
444  NetBuffer1 buffer;
445 
446  //The incoming packet fits in a single chunk
447  buffer.chunkCount = 1;
448  buffer.maxChunkCount = 1;
449  buffer.chunk[0].address = packet;
450  buffer.chunk[0].length = (uint16_t) length;
451  buffer.chunk[0].size = 0;
452 
453  //Process incoming IPv6 packet
454  ipv6ProcessPacket(interface, (NetBuffer *) &buffer, 0, ancillary);
455  }
456  else
457 #endif
458 #if (NET_LOOPBACK_IF_SUPPORT == ENABLED)
459  //Loopback interface?
460  if(type == NIC_TYPE_LOOPBACK)
461  {
462 #if (IPV4_SUPPORT == ENABLED)
463  //IPv4 packet received?
464  if(length >= sizeof(Ipv4Header) && (packet[0] >> 4) == 4)
465  {
466  error_t error;
467  uint_t i;
468  Ipv4Header *header;
469 
470  //Point to the IPv4 header
471  header = (Ipv4Header *) packet;
472 
473  //Loop through network interfaces
474  for(i = 0; i < NET_INTERFACE_COUNT; i++)
475  {
476  //Check destination address
477  error = ipv4CheckDestAddr(&netInterface[i], header->destAddr);
478 
479  //Valid destination address?
480  if(!error)
481  {
482  //Process incoming IPv4 packet
483  ipv4ProcessPacket(&netInterface[i], (Ipv4Header *) packet,
484  length, ancillary);
485  }
486  }
487  }
488  else
489 #endif
490 #if (IPV6_SUPPORT == ENABLED)
491  //IPv6 packet received?
492  if(length >= sizeof(Ipv6Header) && (packet[0] >> 4) == 6)
493  {
494  error_t error;
495  uint_t i;
496  NetBuffer1 buffer;
497  Ipv6Header *header;
498 
499  //Point to the IPv6 header
500  header = (Ipv6Header *) packet;
501 
502  //Loop through network interfaces
503  for(i = 0; i < NET_INTERFACE_COUNT; i++)
504  {
505  //Check destination address
506  error = ipv6CheckDestAddr(&netInterface[i], &header->destAddr);
507 
508  //Valid destination address?
509  if(!error)
510  {
511  //The incoming packet fits in a single chunk
512  buffer.chunkCount = 1;
513  buffer.maxChunkCount = 1;
514  buffer.chunk[0].address = packet;
515  buffer.chunk[0].length = (uint16_t) length;
516  buffer.chunk[0].size = 0;
517 
518  //Process incoming IPv6 packet
519  ipv6ProcessPacket(&netInterface[i], (NetBuffer *) &buffer, 0,
520  ancillary);
521  }
522  }
523  }
524  else
525 #endif
526  {
527  //Invalid version number
528  }
529  }
530  else
531 #endif
532  //Unknown interface type?
533  {
534  //Silently discard the received packet
535  }
536 
537  //Disable interrupts
538  interface->nicDriver->disableIrq(interface);
539  }
540 }
541 
542 
543 /**
544  * @brief Process link state change notification
545  * @param[in] interface Underlying network interface
546  **/
547 
549 {
550  uint_t i;
551  NetInterface *physicalInterface;
552  NetInterface *virtualInterface;
553 
554  //Gather entropy
556 
557  //Point to the physical interface
558  physicalInterface = nicGetPhysicalInterface(interface);
559 
560  //Re-enable interrupts if necessary
561  if(physicalInterface->configured)
562  {
563  physicalInterface->nicDriver->enableIrq(physicalInterface);
564  }
565 
566  //Loop through network interfaces
567  for(i = 0; i < NET_INTERFACE_COUNT; i++)
568  {
569  //Point to the current interface
570  virtualInterface = &netInterface[i];
571 
572  //Check whether the current virtual interface is attached to the physical
573  //interface
574  if(nicIsParentInterface(virtualInterface, interface) &&
575  nicGetSwitchPort(virtualInterface) == nicGetSwitchPort(interface))
576  {
577  //Set operation mode
578  virtualInterface->linkSpeed = interface->linkSpeed;
579  virtualInterface->duplexMode = interface->duplexMode;
580 
581  //Update link state
582  virtualInterface->linkState = interface->linkState;
583 
584  //Process link state change event
585  netProcessLinkChange(virtualInterface);
586  }
587  }
588 
589  //Disable interrupts
590  physicalInterface->nicDriver->disableIrq(physicalInterface);
591 }
uint8_t type
Definition: coap_common.h:176
unsigned int uint_t
Definition: compiler_port.h:50
#define PRIuSIZE
int bool_t
Definition: compiler_port.h:53
Debugging facilities.
#define TRACE_DEBUG_ARRAY(p, a, n)
Definition: debug.h:108
#define TRACE_DEBUG_NET_BUFFER(p, b, o, n)
Definition: debug.h:109
#define TRACE_DEBUG(...)
Definition: debug.h:107
error_t
Error codes.
Definition: error.h:43
@ ERROR_INVALID_INTERFACE
Invalid interface.
Definition: error.h:53
@ NO_ERROR
Success.
Definition: error.h:44
const MacAddr MAC_UNSPECIFIED_ADDR
Definition: ethernet.c:53
void ethProcessFrame(NetInterface *interface, uint8_t *frame, size_t length, NetRxAncillary *ancillary)
Process an incoming Ethernet frame.
Definition: ethernet.c:84
Ethernet.
#define macCompAddr(macAddr1, macAddr2)
Definition: ethernet.h:130
void ipv4ProcessPacket(NetInterface *interface, Ipv4Header *packet, size_t length, NetRxAncillary *ancillary)
Incoming IPv4 packet processing.
Definition: ipv4.c:602
#define Ipv4Header
Definition: ipv4.h:36
error_t ipv4CheckDestAddr(NetInterface *interface, Ipv4Addr ipAddr)
Destination IPv4 address filtering.
Definition: ipv4_misc.c:117
Helper functions for IPv4.
void ipv6ProcessPacket(NetInterface *interface, NetBuffer *ipPacket, size_t ipPacketOffset, NetRxAncillary *ancillary)
Incoming IPv6 packet processing.
Definition: ipv6.c:968
#define Ipv6Header
Definition: ipv6.h:36
error_t ipv6CheckDestAddr(NetInterface *interface, const Ipv6Addr *ipAddr)
Destination IPv6 address filtering.
Definition: ipv6_misc.c:789
Helper functions for IPv6.
NetContext netContext
Definition: net.c:75
TCP/IP stack core.
#define NET_INTERFACE_COUNT
Definition: net.h:113
#define netGetSystemTickCount()
Definition: net.h:181
#define NetInterface
Definition: net.h:36
#define netInterface
Definition: net_legacy.h:199
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:198
#define NetRxAncillary
Definition: net_misc.h:40
#define NetTxAncillary
Definition: net_misc.h:36
systime_t nicTickCounter
Definition: nic.c:43
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
void nicProcessPacket(NetInterface *interface, uint8_t *packet, size_t length, NetRxAncillary *ancillary)
Handle a packet received by the network controller.
Definition: nic.c:391
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
void nicTick(NetInterface *interface)
Network controller timer handler.
Definition: nic.c:250
NetInterface * nicGetPhysicalInterface(NetInterface *interface)
Retrieve physical interface.
Definition: nic.c:84
void nicNotifyLinkChange(NetInterface *interface)
Process link state change notification.
Definition: nic.c:548
bool_t nicIsParentInterface(NetInterface *interface, NetInterface *parent)
Test parent/child relationship between 2 interfaces.
Definition: nic.c:207
Network interface controller abstraction layer.
#define NIC_MAX_BLOCKING_TIME
Definition: nic.h:46
NicType
NIC types.
Definition: nic.h:81
@ NIC_TYPE_LOOPBACK
Loopback interface.
Definition: nic.h:88
@ NIC_TYPE_6LOWPAN
6LoWPAN interface
Definition: nic.h:87
@ NIC_TYPE_IPV4
IPv4 interface.
Definition: nic.h:85
@ NIC_TYPE_ETHERNET
Ethernet interface.
Definition: nic.h:83
@ NIC_TYPE_PPP
PPP interface.
Definition: nic.h:84
#define TRUE
Definition: os_port.h:50
#define FALSE
Definition: os_port.h:46
bool_t osWaitForEvent(OsEvent *event, systime_t timeout)
Wait until the specified event is in the signaled state.
uint32_t systime_t
System time.
void pppProcessFrame(NetInterface *interface, uint8_t *frame, size_t length, NetRxAncillary *ancillary)
Process an incoming PPP frame.
Definition: ppp.c:909
uint16_t length
Definition: net_mem.h:79
uint16_t size
Definition: net_mem.h:80
void * address
Definition: net_mem.h:78
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
uint32_t entropy
Definition: net.h:321
uint8_t length
Definition: tcp.h:368