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  * Copyright (C) 2010-2018 Oryx Embedded SARL. All rights reserved.
8  *
9  * This file is part of CycloneTCP Open.
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software Foundation,
23  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24  *
25  * @author Oryx Embedded SARL (www.oryx-embedded.com)
26  * @version 1.9.0
27  **/
28 
29 //Switch to the appropriate trace level
30 #define TRACE_LEVEL NIC_TRACE_LEVEL
31 
32 //Dependencies
33 #include "core/net.h"
34 #include "core/nic.h"
35 #include "core/socket.h"
36 #include "core/raw_socket.h"
37 #include "core/tcp_misc.h"
38 #include "core/udp.h"
39 #include "ipv4/ipv4.h"
40 #include "ipv6/ipv6.h"
41 #include "dns/dns_cache.h"
42 #include "dns/dns_client.h"
43 #include "mdns/mdns_client.h"
44 #include "mdns/mdns_responder.h"
45 #include "dns_sd/dns_sd.h"
46 #include "mibs/mib2_module.h"
47 #include "mibs/if_mib_module.h"
48 #include "debug.h"
49 
50 //Tick counter to handle periodic operations
52 
53 
54 /**
55  * @brief Retrieve logical interface
56  * @param[in] interface Pointer to the network interface
57  * @return Pointer to the physical interface
58  **/
59 
61 {
62 #if (ETH_VLAN_SUPPORT == ENABLED)
63  //Virtual interface?
64  if(interface->vlanId != 0 && interface->parent != NULL)
65  {
66  if(macCompAddr(&interface->macAddr, &MAC_UNSPECIFIED_ADDR))
67  {
68  //Point to the interface on top of which the virtual interface runs
69  interface = interface->parent;
70  }
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_VLAN_SUPPORT == ENABLED)
88  //Virtual interface?
89  if(interface->vlanId != 0 && interface->parent != NULL)
90  {
91  if(macCompAddr(&interface->macAddr, &MAC_UNSPECIFIED_ADDR))
92  {
93  //Point to the interface on top of which the virtual interface runs
94  interface = interface->parent;
95  }
96  }
97 #endif
98 
99 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
100  //Ethernet port multiplication using VLAN or tail tagging?
101  if(interface->port != 0 && interface->parent != NULL)
102  {
103  //Point to the physical interface
104  interface = interface->parent;
105  }
106 #endif
107 
108  //Return a pointer to the physical interface
109  return interface;
110 }
111 
112 
113 /**
114  * @brief Network controller timer handler
115  *
116  * This routine is periodically called by the TCP/IP stack to
117  * handle periodic operations such as polling the link state
118  *
119  * @param[in] interface Underlying network interface
120  **/
121 
122 void nicTick(NetInterface *interface)
123 {
124  //Valid NIC driver?
125  if(interface->nicDriver != NULL)
126  {
127  //Disable interrupts
128  interface->nicDriver->disableIrq(interface);
129 
130  //Handle periodic operations
131  interface->nicDriver->tick(interface);
132 
133  //Re-enable interrupts if necessary
134  if(interface->configured)
135  interface->nicDriver->enableIrq(interface);
136  }
137 }
138 
139 
140 /**
141  * @brief Send a packet to the network controller
142  * @param[in] interface Underlying network interface
143  * @param[in] buffer Multi-part buffer containing the data to send
144  * @param[in] offset Offset to the first data byte
145  * @return Error code
146  **/
147 
148 error_t nicSendPacket(NetInterface *interface, const NetBuffer *buffer, size_t offset)
149 {
150  error_t error;
151  bool_t status;
152 
153 #if (TRACE_LEVEL >= TRACE_LEVEL_DEBUG)
154  //Retrieve the length of the packet
155  size_t length = netBufferGetLength(buffer) - offset;
156 
157  //Debug message
158  TRACE_DEBUG("Sending packet (%" PRIuSIZE " bytes)...\r\n", length);
159  TRACE_DEBUG_NET_BUFFER(" ", buffer, offset, length);
160 #endif
161 
162  //Valid NIC driver?
163  if(interface->nicDriver != NULL)
164  {
165  //Wait for the transmitter to be ready to send
166  status = osWaitForEvent(&interface->nicTxEvent, NIC_MAX_BLOCKING_TIME);
167 
168  //Check whether the specified event is in signaled state
169  if(status)
170  {
171  //Disable interrupts
172  interface->nicDriver->disableIrq(interface);
173 
174  //Send Ethernet frame
175  error = interface->nicDriver->sendPacket(interface, buffer, offset);
176 
177  //Re-enable interrupts if necessary
178  if(interface->configured)
179  interface->nicDriver->enableIrq(interface);
180  }
181  else
182  {
183  //The transmitter is busy...
184  error = ERROR_TRANSMITTER_BUSY;
185  }
186  }
187  else
188  {
189  //Report an error
190  error = ERROR_INVALID_INTERFACE;
191  }
192 
193  //Return status code
194  return error;
195 }
196 
197 
198 /**
199  * @brief Configure MAC address filtering
200  * @param[in] interface Underlying network interface
201  * @return Error code
202  **/
203 
205 {
206  error_t error;
207 
208  //Valid NIC driver?
209  if(interface->nicDriver != NULL)
210  {
211  //Disable interrupts
212  interface->nicDriver->disableIrq(interface);
213 
214  //Update MAC filter table
215  error = interface->nicDriver->updateMacAddrFilter(interface);
216 
217  //Re-enable interrupts if necessary
218  if(interface->configured)
219  interface->nicDriver->enableIrq(interface);
220  }
221  else
222  {
223  //Report an error
224  error = ERROR_INVALID_INTERFACE;
225  }
226 
227  //Return status code
228  return error;
229 }
230 
231 
232 /**
233  * @brief Handle a packet received by the network controller
234  * @param[in] interface Underlying network interface
235  * @param[in] packet Incoming packet to process
236  * @param[in] length Total packet length
237  **/
238 
239 void nicProcessPacket(NetInterface *interface, void *packet, size_t length)
240 {
241  NicType type;
242 
243  //Re-enable interrupts if necessary
244  if(interface->configured)
245  interface->nicDriver->enableIrq(interface);
246 
247  //Debug message
248  TRACE_DEBUG("Packet received (%" PRIuSIZE " bytes)...\r\n", length);
249  TRACE_DEBUG_ARRAY(" ", packet, length);
250 
251  //Retrieve network interface type
252  type = interface->nicDriver->type;
253 
254  //Ethernet interface?
255  if(type == NIC_TYPE_ETHERNET)
256  {
257 #if (ETH_SUPPORT == ENABLED)
258  //Process incoming Ethernet frame
259  ethProcessFrame(interface, packet, length);
260 #endif
261  }
262  //PPP interface?
263  else if(type == NIC_TYPE_PPP)
264  {
265 #if (PPP_SUPPORT == ENABLED)
266  //Process incoming PPP frame
267  pppProcessFrame(interface, packet, length);
268 #endif
269  }
270  //6LoWPAN interface?
271  else if(type == NIC_TYPE_6LOWPAN)
272  {
273 #if (IPV6_SUPPORT == ENABLED)
274  NetBuffer1 buffer;
275 
276  //The incoming packet fits in a single chunk
277  buffer.chunkCount = 1;
278  buffer.maxChunkCount = 1;
279  buffer.chunk[0].address = packet;
280  buffer.chunk[0].length = (uint16_t) length;
281  buffer.chunk[0].size = 0;
282 
283  //Process incoming IPv6 packet
284  ipv6ProcessPacket(interface, (NetBuffer *) &buffer, 0);
285 #endif
286  }
287 
288  //Disable interrupts
289  interface->nicDriver->disableIrq(interface);
290 }
291 
292 
293 /**
294  * @brief Process link state change event
295  * @param[in] interface Underlying network interface
296  **/
297 
299 {
300  uint_t i;
301  Socket *socket;
302  NetInterface *curInterface;
303  NetInterface *logicalInterface;
304  NetInterface *physicalInterface;
305 
306  //Point to the physical interface
307  physicalInterface = nicGetPhysicalInterface(interface);
308 
309  //Re-enable interrupts if necessary
310  if(physicalInterface->configured)
311  physicalInterface->nicDriver->enableIrq(physicalInterface);
312 
313  //Loop through network interfaces
314  for(i = 0; i < NET_INTERFACE_COUNT; i++)
315  {
316  //Point to the current interface
317  curInterface = &netInterface[i];
318  //Point to the parent interface
319  logicalInterface = nicGetLogicalInterface(curInterface);
320 
321  //802.1q allows a single network interface to be bound to multiple
322  //virtual interfaces
323  if(logicalInterface == interface)
324  {
325  //Set operation mode
326  curInterface->linkSpeed = logicalInterface->linkSpeed;
327  curInterface->duplexMode = logicalInterface->duplexMode;
328 
329  //Update link state
330  curInterface->linkState = logicalInterface->linkState;
331 
332  //Check link state
333  if(curInterface->linkState)
334  {
335  //Display link state
336  TRACE_INFO("Link is up (%s)...\r\n", curInterface->name);
337 
338  //Display link speed
339  if(curInterface->linkSpeed == NIC_LINK_SPEED_1GBPS)
340  {
341  //1000BASE-T
342  TRACE_INFO(" Link speed = 1000 Mbps\r\n");
343  }
344  else if(curInterface->linkSpeed == NIC_LINK_SPEED_100MBPS)
345  {
346  //100BASE-TX
347  TRACE_INFO(" Link speed = 100 Mbps\r\n");
348  }
349  else if(curInterface->linkSpeed == NIC_LINK_SPEED_10MBPS)
350  {
351  //10BASE-T
352  TRACE_INFO(" Link speed = 10 Mbps\r\n");
353  }
354  else if(curInterface->linkSpeed != NIC_LINK_SPEED_UNKNOWN)
355  {
356  //10BASE-T
357  TRACE_INFO(" Link speed = %" PRIu32 " bps\r\n", curInterface->linkSpeed);
358  }
359 
360  //Display duplex mode
361  if(curInterface->duplexMode == NIC_FULL_DUPLEX_MODE)
362  {
363  //1000BASE-T
364  TRACE_INFO(" Duplex mode = Full-Duplex\r\n");
365  }
366  else if(curInterface->duplexMode == NIC_HALF_DUPLEX_MODE)
367  {
368  //100BASE-TX
369  TRACE_INFO(" Duplex mode = Half-Duplex\r\n");
370  }
371  }
372  else
373  {
374  //Display link state
375  TRACE_INFO("Link is down (%s)...\r\n", curInterface->name);
376  }
377 
378  //The time at which the interface entered its current operational state
379  MIB2_SET_TIME_TICKS(ifGroup.ifTable[curInterface->index].ifLastChange,
380  osGetSystemTime() / 10);
381  IF_MIB_SET_TIME_TICKS(ifTable[curInterface->index].ifLastChange,
382  osGetSystemTime() / 10);
383 
384 #if (IPV4_SUPPORT == ENABLED)
385  //Notify IPv4 of link state changes
386  ipv4LinkChangeEvent(curInterface);
387 #endif
388 
389 #if (IPV6_SUPPORT == ENABLED)
390  //Notify IPv6 of link state changes
391  ipv6LinkChangeEvent(curInterface);
392 #endif
393 
394 #if (DNS_CLIENT_SUPPORT == ENABLED || MDNS_CLIENT_SUPPORT == ENABLED || \
395  NBNS_CLIENT_SUPPORT == ENABLED)
396  //Flush DNS cache
397  dnsFlushCache(curInterface);
398 #endif
399 
400 #if (MDNS_RESPONDER_SUPPORT == ENABLED)
401  //Perform probing and announcing
402  mdnsResponderLinkChangeEvent(curInterface->mdnsResponderContext);
403 #endif
404 
405 #if (DNS_SD_SUPPORT == ENABLED)
406  //Perform probing and announcing
407  dnsSdLinkChangeEvent(curInterface->dnsSdContext);
408 #endif
409 
410  //Notify registered users of link state changes
411  netInvokeLinkChangeCallback(curInterface, curInterface->linkState);
412  }
413  }
414 
415  //Loop through opened sockets
416  for(i = 0; i < SOCKET_MAX_COUNT; i++)
417  {
418  //Point to the current socket
419  socket = socketTable + i;
420 
421 #if (TCP_SUPPORT == ENABLED)
422  //Connection-oriented socket?
423  if(socket->type == SOCKET_TYPE_STREAM)
424  {
426  }
427 #endif
428 #if (UDP_SUPPORT == ENABLED)
429  //Connectionless socket?
430  if(socket->type == SOCKET_TYPE_DGRAM)
431  {
433  }
434 #endif
435 #if (RAW_SOCKET_SUPPORT == ENABLED)
436  //Raw socket?
437  if(socket->type == SOCKET_TYPE_RAW_IP ||
438  socket->type == SOCKET_TYPE_RAW_ETH)
439  {
441  }
442 #endif
443  }
444 
445  //Disable interrupts
446  physicalInterface->nicDriver->disableIrq(physicalInterface);
447 }
void netInvokeLinkChangeCallback(NetInterface *interface, bool_t linkState)
Invoke link change callback.
Definition: net.c:1657
uint32_t systime_t
Definition: compiler_port.h:44
Interfaces Group MIB module.
mDNS responder (Multicast DNS)
void nicNotifyLinkChange(NetInterface *interface)
Process link state change event.
Definition: nic.c:298
systime_t osGetSystemTime(void)
Retrieve system time.
TCP/IP stack core.
Debugging facilities.
uint_t chunkCount
Definition: net_mem.h:96
uint_t maxChunkCount
Definition: net_mem.h:97
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:295
MIB-II module.
#define NIC_MAX_BLOCKING_TIME
Definition: nic.h:44
DNS cache management.
void ipv6ProcessPacket(NetInterface *interface, NetBuffer *ipPacket, size_t ipPacketOffset)
Incoming IPv6 packet processing.
Definition: ipv6.c:885
PPP interface.
Definition: nic.h:70
void udpUpdateEvents(Socket *socket)
Update UDP related events.
Definition: udp.c:679
error_t nicSendPacket(NetInterface *interface, const NetBuffer *buffer, size_t offset)
Send a packet to the network controller.
Definition: nic.c:148
char_t type
#define TRACE_DEBUG_ARRAY(p, a, n)
Definition: debug.h:99
#define SOCKET_MAX_COUNT
Definition: socket.h:43
void * address
Definition: net_mem.h:76
void dnsFlushCache(NetInterface *interface)
Flush DNS cache.
Definition: dns_cache.c:72
void ipv4LinkChangeEvent(NetInterface *interface)
Callback function for link change event.
Definition: ipv4.c:392
int_t socket(int_t family, int_t type, int_t protocol)
Create a socket that is bound to a specific transport service provider.
Definition: bsd_socket.c:106
Socket socketTable[SOCKET_MAX_COUNT]
Definition: socket.c:46
#define Socket
Definition: socket.h:34
#define MIB2_SET_TIME_TICKS(name, value)
Definition: mib2_module.h:153
uint16_t size
Definition: net_mem.h:78
DNS client (Domain Name System)
Invalid interface.
Definition: error.h:51
#define NET_INTERFACE_COUNT
Definition: net.h:108
TCP/IP raw sockets.
void ipv6LinkChangeEvent(NetInterface *interface)
Callback function for link change event.
Definition: ipv6.c:795
IPv4 (Internet Protocol Version 4)
ChunkDesc chunk[1]
Definition: net_mem.h:98
systime_t nicTickCounter
Definition: nic.c:51
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:86
NetInterface netInterface[NET_INTERFACE_COUNT]
Definition: net.c:74
const MacAddr MAC_UNSPECIFIED_ADDR
Definition: ethernet.c:53
void mdnsResponderLinkChangeEvent(MdnsResponderContext *context)
Callback function for link change event.
#define TRACE_INFO(...)
Definition: debug.h:86
Ethernet interface.
Definition: nic.h:69
IPv6 (Internet Protocol Version 6)
error_t nicUpdateMacAddrFilter(NetInterface *interface)
Configure MAC address filtering.
Definition: nic.c:204
uint16_t length
Definition: net_mem.h:77
void nicProcessPacket(NetInterface *interface, void *packet, size_t length)
Handle a packet received by the network controller.
Definition: nic.c:239
void dnsSdLinkChangeEvent(DnsSdContext *context)
Callback function for link change event.
Definition: dns_sd.c:669
error_t
Error codes.
Definition: error.h:40
bool_t osWaitForEvent(OsEvent *event, systime_t timeout)
Wait until the specified event is in the signaled state.
NetInterface * nicGetPhysicalInterface(NetInterface *interface)
Retrieve physical interface.
Definition: nic.c:85
unsigned int uint_t
Definition: compiler_port.h:43
mDNS client (Multicast DNS)
#define PRIuSIZE
Definition: compiler_port.h:72
#define NetInterface
Definition: net.h:34
Helper functions for TCP.
#define TRACE_DEBUG_NET_BUFFER(p, b, o, n)
Definition: debug.h:100
void tcpUpdateEvents(Socket *socket)
Update TCP related events.
Definition: tcp_misc.c:1754
#define macCompAddr(macAddr1, macAddr2)
Definition: ethernet.h:95
DNS-SD (DNS-Based Service Discovery)
void rawSocketUpdateEvents(Socket *socket)
Update event state for raw sockets.
Definition: raw_socket.c:745
6LoWPAN interface
Definition: nic.h:71
void nicTick(NetInterface *interface)
Network controller timer handler.
Definition: nic.c:122
NetInterface * nicGetLogicalInterface(NetInterface *interface)
Retrieve logical interface.
Definition: nic.c:60
Socket API.
void ethProcessFrame(NetInterface *interface, uint8_t *frame, size_t length)
Process an incoming Ethernet frame.
Definition: ethernet.c:168
uint8_t length
Definition: dtls_misc.h:140
NicType
NIC types.
Definition: nic.h:66
int bool_t
Definition: compiler_port.h:47
Network interface controller abstraction layer.
#define IF_MIB_SET_TIME_TICKS(name, value)
Definition: if_mib_module.h:44
UDP (User Datagram Protocol)
#define TRACE_DEBUG(...)
Definition: debug.h:98
void pppProcessFrame(NetInterface *interface, uint8_t *frame, size_t length)
Process an incoming PPP frame.
Definition: ppp.c:887