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