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