pcap_driver.c
Go to the documentation of this file.
1 /**
2  * @file pcap_driver.c
3  * @brief PCAP driver
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 <stdlib.h>
36 #include "core/net.h"
38 #include "debug.h"
39 
40 //Undefine conflicting definitions
41 #undef Socket
42 #undef htons
43 #undef htonl
44 #undef ntohs
45 #undef ntohl
46 
47 //PCAP dependencies
48 #include <pcap.h>
49 
50 //Undefine conflicting definitions
51 #undef interface
52 
53 
54 /**
55  * @brief Packet descriptor
56  **/
57 
58 typedef struct
59 {
60  size_t length;
63 
64 
65 /**
66  * @brief PCAP driver context
67  **/
68 
69 typedef struct
70 {
71  pcap_t *handle;
76 
77 
78 /**
79  * @brief PCAP driver
80  **/
81 
83 {
85  ETH_MTU,
93  NULL,
94  NULL,
95  NULL,
96  TRUE,
97  TRUE,
98  TRUE,
99  TRUE
100 };
101 
102 
103 /**
104  * @brief PCAP driver initialization
105  * @param[in] interface Underlying network interface
106  * @return Error code
107  **/
108 
110 {
111  int_t ret;
112  uint_t i;
113  uint_t j;
114  pcap_if_t *device;
115  pcap_if_t *deviceList;
116  struct bpf_program filerCode;
117  char_t filterExpr[256];
118  char_t errorBuffer[PCAP_ERRBUF_SIZE];
119  PcapDriverContext *context;
120 #if (NET_RTOS_SUPPORT == ENABLED)
121  OsTaskId taskId;
122 #endif
123 
124  //Debug message
125  TRACE_INFO("Initializing PCAP driver...\r\n");
126 
127  //Allocate PCAP driver context
128  context = (PcapDriverContext *) osAllocMem(sizeof(PcapDriverContext));
129 
130  //Failed to allocate memory?
131  if(context == NULL)
132  {
133  //Debug message
134  printf("Failed to allocate context!\r\n");
135 
136  //Report an error
137  return ERROR_FAILURE;
138  }
139 
140  //Attach the PCAP driver context to the network interface
141  *((PcapDriverContext **) interface->nicContext) = context;
142  //Clear PCAP driver context
143  osMemset(context, 0, sizeof(PcapDriverContext));
144 
145  //Find all the devices
146  ret = pcap_findalldevs(&deviceList, errorBuffer);
147 
148  //Any error to report?
149  if(ret != 0)
150  {
151  //Debug message
152  printf("Failed to list devices!\r\n");
153 
154  //Clean up side effects
155  free(context);
156 
157  //Report an error
158  return ERROR_FAILURE;
159  }
160 
161  //No network adapter found?
162  if(deviceList == NULL)
163  {
164  //Debug message
165  printf("No network adapter found!\r\n");
166 
167  //Clean up side effects
168  free(context);
169 
170  //Exit immediately
171  return ERROR_FAILURE;
172  }
173 
174  //Network adapter selection
175  while(1)
176  {
177  //Debug message
178  printf("Network adapters:\r\n");
179 
180  //Point to the first device
181  device = deviceList;
182  i = 0;
183 
184  //Loop through the list of devices
185  while(device != NULL)
186  {
187  //Index of the current network adapter
188  printf(" %-2u", i + 1);
189 
190 #if !defined(_WIN32)
191  //Display the name of the device
192  if(device->name != NULL)
193  {
194  printf(" %-8s", device->name);
195  }
196 #endif
197  //Description of the device
198  if(device->description != NULL)
199  {
200  printf(" %s\r\n", device->description);
201  }
202  else
203  {
204  printf(" -\r\n");
205  }
206 
207  //Next device
208  device = device->next;
209  i++;
210  }
211 
212  //Valid network adapter identifier?
213  if(interface->phyAddr >= 1 && interface->phyAddr <= i)
214  {
215  j = interface->phyAddr;
216  break;
217  }
218  else
219  {
220  //Display message
221  printf("Select network adapter for %s interface (1-%u):", interface->name, i);
222  //Get user choice
223  scanf("%d", &j);
224 
225  //Valid selection?
226  if(j >= 1 && j <= i)
227  {
228  break;
229  }
230  }
231  }
232 
233  //Point to the first device
234  device = deviceList;
235 
236  //Point to the desired network adapter
237  for(i = 1; i < j; i++)
238  {
239  device = device->next;
240  }
241 
242  //Open the device
243  context->handle = pcap_open_live(device->name, 65535,
244  TRUE, PCAP_DRIVER_TIMEOUT, errorBuffer);
245 
246  //Failed to open device?
247  if(context->handle == NULL)
248  {
249  //Debug message
250  printf("Failed to open device!\r\n");
251 
252  //Clean up side effects
253  pcap_freealldevs(deviceList);
254  free(context);
255 
256  //Report an error
257  return ERROR_FAILURE;
258  }
259 
260  //Free the device list
261  pcap_freealldevs(deviceList);
262 
263  //Filter expression
264  osSprintf(filterExpr, "!(ether src %02x:%02x:%02x:%02x:%02x:%02x) && "
265  "((ether dst %02x:%02x:%02x:%02x:%02x:%02x) || (ether broadcast) || (ether multicast))",
266  interface->macAddr.b[0], interface->macAddr.b[1], interface->macAddr.b[2],
267  interface->macAddr.b[3], interface->macAddr.b[4], interface->macAddr.b[5],
268  interface->macAddr.b[0], interface->macAddr.b[1], interface->macAddr.b[2],
269  interface->macAddr.b[3], interface->macAddr.b[4], interface->macAddr.b[5]);
270 
271  //Compile the filter
272  ret = pcap_compile(context->handle, &filerCode, filterExpr, 1, 0);
273 
274  //Failed to open device?
275  if(ret != 0)
276  {
277  //Debug message
278  printf("Failed to compile filter!\r\n");
279 
280  //Clean up side effects
281  pcap_close(context->handle);
282  free(context);
283 
284  //Report an error
285  return ERROR_FAILURE;
286  }
287 
288  //Set the filter
289  ret = pcap_setfilter(context->handle, &filerCode);
290 
291  //Failed to open device?
292  if(ret != 0)
293  {
294  //Debug message
295  printf("Failed to set filter!\r\n");
296 
297  //Clean up side effects
298  pcap_close(context->handle);
299  free(context);
300 
301  //Report an error
302  return ERROR_FAILURE;
303  }
304 
305 #if (NET_RTOS_SUPPORT == ENABLED)
306  //Create the receive task
307  taskId = osCreateTask("PCAP", (OsTaskCode) pcapDriverTask, interface, NULL);
308 
309  //Failed to create the task?
310  if(taskId == OS_INVALID_TASK_ID)
311  {
312  //Debug message
313  printf("Failed to create task!\r\n");
314 
315  //Clean up side effects
316  pcap_close(context->handle);
317  free(context);
318 
319  //Report an error
320  return ERROR_FAILURE;
321  }
322 #endif
323 
324  //Accept any packets from the upper layer
325  osSetEvent(&interface->nicTxEvent);
326 
327  //Return status code
328  return NO_ERROR;
329 }
330 
331 
332 /**
333  * @brief PCAP timer handler
334  *
335  * This routine is periodically called by the TCP/IP stack to handle periodic
336  * operations such as polling the link state
337  *
338  * @param[in] interface Underlying network interface
339  **/
340 
341 void pcapDriverTick(NetInterface *interface)
342 {
343  //Not implemented
344 }
345 
346 
347 /**
348  * @brief Enable interrupts
349  * @param[in] interface Underlying network interface
350  **/
351 
353 {
354  //Not implemented
355 }
356 
357 
358 /**
359  * @brief Disable interrupts
360  * @param[in] interface Underlying network interface
361  **/
362 
364 {
365  //Not implemented
366 }
367 
368 
369 /**
370  * @brief PCAP event handler
371  * @param[in] interface Underlying network interface
372  **/
373 
375 {
376  uint_t n;
377  PcapDriverContext *context;
378  NetRxAncillary ancillary;
379 
380  //Point to the PCAP driver context
381  context = *((PcapDriverContext **) interface->nicContext);
382 
383  //Process all pending packets
384  while(context->queue[context->readIndex].length > 0)
385  {
386  //Additional options can be passed to the stack along with the packet
387  ancillary = NET_DEFAULT_RX_ANCILLARY;
388 
389  //Pass the packet to the upper layer
390  nicProcessPacket(interface, context->queue[context->readIndex].data,
391  context->queue[context->readIndex].length, &ancillary);
392 
393  //Compute the index of the next packet descriptor
394  n = (context->readIndex + 1) % PCAP_DRIVER_QUEUE_SIZE;
395 
396  //Release the current packet
397  context->queue[context->readIndex].length = 0;
398  //Point to the next packet descriptor
399  context->readIndex = n;
400  }
401 }
402 
403 
404 /**
405  * @brief Send a packet
406  * @param[in] interface Underlying network interface
407  * @param[in] buffer Multi-part buffer containing the data to send
408  * @param[in] offset Offset to the first data byte
409  * @param[in] ancillary Additional options passed to the stack along with
410  * the packet
411  * @return Error code
412  **/
413 
415  const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
416 {
417  int_t ret;
418  size_t length;
419  PcapDriverContext *context;
420  uint8_t temp[PCAP_DRIVER_MAX_PACKET_SIZE];
421 
422  //Point to the PCAP driver context
423  context = *((PcapDriverContext **) interface->nicContext);
424 
425  //Retrieve the length of the packet
426  length = netBufferGetLength(buffer) - offset;
427 
428  //Check the frame length
430  {
431  //The transmitter can accept another packet
432  osSetEvent(&interface->nicTxEvent);
433  //Report an error
434  return ERROR_INVALID_LENGTH;
435  }
436 
437  //Copy the packet to the transmit buffer
438  netBufferRead(temp, buffer, offset, length);
439 
440  //Send packet
441  ret = pcap_sendpacket(context->handle, temp, length);
442 
443  //The transmitter can accept another packet
444  osSetEvent(&interface->nicTxEvent);
445 
446  //Return status code
447  if(ret < 0)
448  {
449  return ERROR_FAILURE;
450  }
451  else
452  {
453  return NO_ERROR;
454  }
455 }
456 
457 
458 /**
459  * @brief Configure MAC address filtering
460  * @param[in] interface Underlying network interface
461  * @return Error code
462  **/
463 
465 {
466  //Not implemented
467  return NO_ERROR;
468 }
469 
470 
471 /**
472  * @brief PCAP receive task
473  * @param[in] interface Underlying network interface
474  **/
475 
476 void pcapDriverTask(NetInterface *interface)
477 {
478  int_t ret;
479  uint_t n;
480  uint_t length;
481  const uint8_t *data;
482  struct pcap_pkthdr *header;
483  PcapDriverContext *context;
484 
485  //Point to the PCAP driver context
486  context = *((PcapDriverContext **) interface->nicContext);
487 
488  //Process events
489  while(1)
490  {
491  //Wait for an incoming packet
492  ret = pcap_next_ex(context->handle, &header, &data);
493 
494  //Any packet received?
495  if(ret > 0)
496  {
497  //Retrieve the length of the packet
498  length = header->caplen;
499 
500  //Check the length of the received packet
502  {
503  //Check whether the link is up
504  if(interface->linkState)
505  {
506  //Compute the index of the next packet descriptor
507  n = (context->writeIndex + 1) % PCAP_DRIVER_QUEUE_SIZE;
508 
509  //Ensure the receive queue is not full
510  if(n != context->readIndex)
511  {
512  //Copy the incoming packet
513  osMemcpy(context->queue[context->writeIndex].data, data, length);
514  //Save the length of the packet
515  context->queue[context->writeIndex].length = length;
516 
517  //Point to the next packet descriptor
518  context->writeIndex = n;
519 
520  //Set event flag
521  interface->nicEvent = TRUE;
522  //Notify the TCP/IP stack of the event
524  }
525  }
526  }
527  }
528  else
529  {
530 #if (NET_RTOS_SUPPORT == DISABLED)
531  //No packet has been received
532  break;
533 #endif
534  }
535  }
536 }
signed int int_t
Definition: compiler_port.h:49
unsigned int uint_t
Definition: compiler_port.h:50
char char_t
Definition: compiler_port.h:48
Debugging facilities.
#define TRACE_INFO(...)
Definition: debug.h:95
uint8_t n
error_t
Error codes.
Definition: error.h:43
@ NO_ERROR
Success.
Definition: error.h:44
@ ERROR_INVALID_LENGTH
Definition: error.h:111
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
#define ETH_MTU
Definition: ethernet.h:116
uint8_t data[]
Definition: ethernet.h:222
TCP/IP stack core.
#define NetInterface
Definition: net.h:36
#define netEvent
Definition: net_legacy.h:196
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
size_t netBufferRead(void *dest, const NetBuffer *src, size_t srcOffset, size_t length)
Read data from a multi-part buffer.
Definition: net_mem.c:674
const NetRxAncillary NET_DEFAULT_RX_ANCILLARY
Definition: net_misc.c:101
#define NetRxAncillary
Definition: net_misc.h:40
#define NetTxAncillary
Definition: net_misc.h:36
void nicProcessPacket(NetInterface *interface, uint8_t *packet, size_t length, NetRxAncillary *ancillary)
Handle a packet received by the network controller.
Definition: nic.c:391
@ NIC_TYPE_ETHERNET
Ethernet interface.
Definition: nic.h:83
#define osMemset(p, value, length)
Definition: os_port.h:135
#define osMemcpy(dest, src, length)
Definition: os_port.h:141
#define osSprintf(dest,...)
Definition: os_port.h:231
#define TRUE
Definition: os_port.h:50
__weak_func void * osAllocMem(size_t size)
Allocate a memory block.
OsTaskId osCreateTask(const char_t *name, OsTaskCode taskCode, void *arg, const OsTaskParameters *params)
Create a task.
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
void(* OsTaskCode)(void *arg)
Task routine.
#define OS_INVALID_TASK_ID
thread_t * OsTaskId
Task identifier.
void pcapDriverEventHandler(NetInterface *interface)
PCAP event handler.
Definition: pcap_driver.c:374
void pcapDriverEnableIrq(NetInterface *interface)
Enable interrupts.
Definition: pcap_driver.c:352
error_t pcapDriverSendPacket(NetInterface *interface, const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send a packet.
Definition: pcap_driver.c:414
error_t pcapDriverInit(NetInterface *interface)
PCAP driver initialization.
Definition: pcap_driver.c:109
void pcapDriverTask(NetInterface *interface)
PCAP receive task.
Definition: pcap_driver.c:476
void pcapDriverDisableIrq(NetInterface *interface)
Disable interrupts.
Definition: pcap_driver.c:363
const NicDriver pcapDriver
PCAP driver.
Definition: pcap_driver.c:82
void pcapDriverTick(NetInterface *interface)
PCAP timer handler.
Definition: pcap_driver.c:341
error_t pcapDriverUpdateMacAddrFilter(NetInterface *interface)
Configure MAC address filtering.
Definition: pcap_driver.c:464
PCAP driver.
#define PCAP_DRIVER_TIMEOUT
Definition: pcap_driver.h:53
#define PCAP_DRIVER_MAX_PACKET_SIZE
Definition: pcap_driver.h:39
#define PCAP_DRIVER_QUEUE_SIZE
Definition: pcap_driver.h:46
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
NIC driver.
Definition: nic.h:283
PCAP driver context.
Definition: pcap_driver.c:70
PcapDriverPacket queue[PCAP_DRIVER_QUEUE_SIZE]
Definition: pcap_driver.c:74
Packet descriptor.
Definition: pcap_driver.c:59
uint8_t data[PCAP_DRIVER_MAX_PACKET_SIZE]
Definition: pcap_driver.c:61
uint8_t length
Definition: tcp.h:368