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-2019 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 1.9.6
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  OsTask *task;
122 #endif
123 
124  //Debug message
125  TRACE_INFO("Initializing PCAP driver...\r\n");
126 
127  //Allocate PCAP driver context
128  context = (PcapDriverContext *) malloc(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  memset(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  printf(" %-8s", device->name);
194 #endif
195  //Description of the device
196  if(device->description != NULL)
197  printf(" %s\r\n", device->description);
198  else
199  printf(" -\r\n");
200 
201  //Next device
202  device = device->next;
203  i++;
204  }
205 
206  //Display message
207  printf("Select network adapter for %s interface (1-%u):", interface->name, i);
208  //Get user choice
209  scanf("%d", &j);
210 
211  //Valid selection?
212  if(j >= 1 && j <= i)
213  break;
214  }
215 
216  //Point to the first device
217  device = deviceList;
218 
219  //Point to the desired network adapter
220  for(i = 1; i < j; i++)
221  device = device->next;
222 
223  //Open the device
224  context->handle = pcap_open_live(device->name, 65535,
225  TRUE, PCAP_DRIVER_TIMEOUT, errorBuffer);
226 
227  //Failed to open device?
228  if(context->handle == NULL)
229  {
230  //Debug message
231  printf("Failed to open device!\r\n");
232 
233  //Clean up side effects
234  pcap_freealldevs(deviceList);
235  free(context);
236 
237  //Report an error
238  return ERROR_FAILURE;
239  }
240 
241  //Free the device list
242  pcap_freealldevs(deviceList);
243 
244  //Filter expression
245  sprintf(filterExpr, "!(ether src %02x:%02x:%02x:%02x:%02x:%02x) && "
246  "((ether dst %02x:%02x:%02x:%02x:%02x:%02x) || (ether broadcast) || (ether multicast))",
247  interface->macAddr.b[0], interface->macAddr.b[1], interface->macAddr.b[2],
248  interface->macAddr.b[3], interface->macAddr.b[4], interface->macAddr.b[5],
249  interface->macAddr.b[0], interface->macAddr.b[1], interface->macAddr.b[2],
250  interface->macAddr.b[3], interface->macAddr.b[4], interface->macAddr.b[5]);
251 
252  //Compile the filter
253  ret = pcap_compile(context->handle, &filerCode, filterExpr, 1, 0);
254 
255  //Failed to open device?
256  if(ret != 0)
257  {
258  //Debug message
259  printf("Failed to compile filter!\r\n");
260 
261  //Clean up side effects
262  pcap_close(context->handle);
263  free(context);
264 
265  //Report an error
266  return ERROR_FAILURE;
267  }
268 
269  //Set the filter
270  ret = pcap_setfilter(context->handle, &filerCode);
271 
272  //Failed to open device?
273  if(ret != 0)
274  {
275  //Debug message
276  printf("Failed to set filter!\r\n");
277 
278  //Clean up side effects
279  pcap_close(context->handle);
280  free(context);
281 
282  //Report an error
283  return ERROR_FAILURE;
284  }
285 
286 #if (NET_RTOS_SUPPORT == ENABLED)
287  //Create the receive task
288  task = osCreateTask("PCAP", (OsTaskCode) pcapDriverTask, interface, 0, 0);
289 
290  //Failed to create the task?
291  if(task == OS_INVALID_HANDLE)
292  {
293  //Debug message
294  printf("Failed to create task!\r\n");
295 
296  //Clean up side effects
297  pcap_close(context->handle);
298  free(context);
299 
300  //Report an error
301  return ERROR_FAILURE;
302  }
303 #endif
304 
305  //Accept any packets from the upper layer
306  osSetEvent(&interface->nicTxEvent);
307 
308  //Return status code
309  return NO_ERROR;
310 }
311 
312 
313 /**
314  * @brief PCAP timer handler
315  *
316  * This routine is periodically called by the TCP/IP stack to
317  * handle periodic operations such as polling the link state
318  *
319  * @param[in] interface Underlying network interface
320  **/
321 
322 void pcapDriverTick(NetInterface *interface)
323 {
324  //Not implemented
325 }
326 
327 
328 /**
329  * @brief Enable interrupts
330  * @param[in] interface Underlying network interface
331  **/
332 
334 {
335  //Not implemented
336 }
337 
338 
339 /**
340  * @brief Disable interrupts
341  * @param[in] interface Underlying network interface
342  **/
343 
345 {
346  //Not implemented
347 }
348 
349 
350 /**
351  * @brief PCAP event handler
352  * @param[in] interface Underlying network interface
353  **/
354 
356 {
357  uint_t n;
358  PcapDriverContext *context;
359 
360  //Point to the PCAP driver context
361  context = *((PcapDriverContext **) interface->nicContext);
362 
363  //Process all pending packets
364  while(context->queue[context->readIndex].length > 0)
365  {
366  //Pass the packet to the upper layer
367  nicProcessPacket(interface, context->queue[context->readIndex].data,
368  context->queue[context->readIndex].length);
369 
370  //Compute the index of the next packet descriptor
371  n = (context->readIndex + 1) % PCAP_DRIVER_QUEUE_SIZE;
372 
373  //Release the current packet
374  context->queue[context->readIndex].length = 0;
375  //Point to the next packet descriptor
376  context->readIndex = n;
377  }
378 }
379 
380 
381 /**
382  * @brief Send a packet
383  * @param[in] interface Underlying network interface
384  * @param[in] buffer Multi-part buffer containing the data to send
385  * @param[in] offset Offset to the first data byte
386  * @return Error code
387  **/
388 
390  const NetBuffer *buffer, size_t offset)
391 {
392  int_t ret;
393  size_t length;
394  PcapDriverContext *context;
395  uint8_t temp[PCAP_DRIVER_MAX_PACKET_SIZE];
396 
397  //Point to the PCAP driver context
398  context = *((PcapDriverContext **) interface->nicContext);
399 
400  //Retrieve the length of the packet
401  length = netBufferGetLength(buffer) - offset;
402 
403  //Check the frame length
405  {
406  //The transmitter can accept another packet
407  osSetEvent(&interface->nicTxEvent);
408  //Report an error
409  return ERROR_INVALID_LENGTH;
410  }
411 
412  //Copy the packet to the transmit buffer
413  netBufferRead(temp, buffer, offset, length);
414 
415  //Send packet
416  ret = pcap_sendpacket(context->handle, temp, length);
417 
418  //The transmitter can accept another packet
419  osSetEvent(&interface->nicTxEvent);
420 
421  //Return status code
422  if(ret < 0)
423  return ERROR_FAILURE;
424  else
425  return NO_ERROR;
426 }
427 
428 
429 /**
430  * @brief Configure MAC address filtering
431  * @param[in] interface Underlying network interface
432  * @return Error code
433  **/
434 
436 {
437  //Not implemented
438  return NO_ERROR;
439 }
440 
441 
442 /**
443  * @brief PCAP receive task
444  * @param[in] interface Underlying network interface
445  **/
446 
447 void pcapDriverTask(NetInterface *interface)
448 {
449  int_t ret;
450  uint_t n;
451  uint_t length;
452  const uint8_t *data;
453  struct pcap_pkthdr *header;
454  PcapDriverContext *context;
455 
456  //Point to the PCAP driver context
457  context = *((PcapDriverContext **) interface->nicContext);
458 
459  //Process events
460  while(1)
461  {
462  //Wait for an incoming packet
463  ret = pcap_next_ex(context->handle, &header, &data);
464 
465  //Any packet received?
466  if(ret > 0)
467  {
468  //Retrieve the length of the packet
469  length = header->caplen;
470 
471  //Check the length of the received packet
473  {
474  //Check whether the link is up
475  if(interface->linkState)
476  {
477  //Compute the index of the next packet descriptor
478  n = (context->writeIndex + 1) % PCAP_DRIVER_QUEUE_SIZE;
479 
480  //Ensure the receive queue is not full
481  if(n != context->readIndex)
482  {
483  //Copy the incoming packet
484  memcpy(context->queue[context->writeIndex].data, data, length);
485  //Save the length of the packet
486  context->queue[context->writeIndex].length = length;
487 
488  //Point to the next packet descriptor
489  context->writeIndex = n;
490 
491  //Set event flag
492  interface->nicEvent = TRUE;
493  //Notify the TCP/IP stack of the event
495  }
496  }
497  }
498  }
499  else
500  {
501 #if (NET_RTOS_SUPPORT == DISABLED)
502  //No packet has been received
503  break;
504 #endif
505  }
506  }
507 }
uint8_t length
Definition: dtls_misc.h:149
void pcapDriverTick(NetInterface *interface)
PCAP timer handler.
Definition: pcap_driver.c:322
#define PCAP_DRIVER_MAX_PACKET_SIZE
Definition: pcap_driver.h:39
signed int int_t
Definition: compiler_port.h:44
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:672
void nicProcessPacket(NetInterface *interface, uint8_t *packet, size_t length)
Handle a packet received by the network controller.
Definition: nic.c:383
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:88
#define TRUE
Definition: os_port.h:50
void pcapDriverEventHandler(NetInterface *interface)
PCAP event handler.
Definition: pcap_driver.c:355
const NicDriver pcapDriver
PCAP driver.
Definition: pcap_driver.c:82
PCAP driver context.
Definition: pcap_driver.c:69
error_t pcapDriverInit(NetInterface *interface)
PCAP driver initialization.
Definition: pcap_driver.c:109
OsTask * osCreateTask(const char_t *name, OsTaskCode taskCode, void *param, size_t stackSize, int_t priority)
Create a new task.
error_t
Error codes.
Definition: error.h:42
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
#define NetInterface
Definition: net.h:36
Task object.
@ ERROR_INVALID_LENGTH
Definition: error.h:109
#define PCAP_DRIVER_TIMEOUT
Definition: pcap_driver.h:53
OsEvent netEvent
Definition: net.c:77
PcapDriverPacket queue[PCAP_DRIVER_QUEUE_SIZE]
Definition: pcap_driver.c:74
#define TRACE_INFO(...)
Definition: debug.h:94
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
Packet descriptor.
Definition: pcap_driver.c:58
void pcapDriverEnableIrq(NetInterface *interface)
Enable interrupts.
Definition: pcap_driver.c:333
PCAP driver.
uint8_t data[PCAP_DRIVER_MAX_PACKET_SIZE]
Definition: pcap_driver.c:61
error_t pcapDriverSendPacket(NetInterface *interface, const NetBuffer *buffer, size_t offset)
Send a packet.
Definition: pcap_driver.c:389
char char_t
Definition: compiler_port.h:43
#define OS_INVALID_HANDLE
Definition: os_port.h:79
#define ETH_MTU
Definition: ethernet.h:91
void(* OsTaskCode)(void *param)
Task routine.
uint8_t n
error_t pcapDriverUpdateMacAddrFilter(NetInterface *interface)
Configure MAC address filtering.
Definition: pcap_driver.c:435
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
#define PCAP_DRIVER_QUEUE_SIZE
Definition: pcap_driver.h:46
unsigned int uint_t
Definition: compiler_port.h:45
TCP/IP stack core.
uint8_t data[]
Definition: dtls_misc.h:176
NIC driver.
Definition: nic.h:179
void pcapDriverDisableIrq(NetInterface *interface)
Disable interrupts.
Definition: pcap_driver.c:344
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
void pcapDriverTask(NetInterface *interface)
PCAP receive task.
Definition: pcap_driver.c:447
@ NIC_TYPE_ETHERNET
Ethernet interface.
Definition: nic.h:79