302 lines
7.2 KiB
C
302 lines
7.2 KiB
C
/*
|
|
* Copyright (c) 2006-2021, RT-Thread Development Team
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Change Logs:
|
|
* Date Author Notes
|
|
* 2012-11-05 Bernard the first version
|
|
* 2012-11-13 Bernard merge prife's patch for exclusive
|
|
* access pcap driver.
|
|
*/
|
|
|
|
#ifdef _TIME_T_DEFINED
|
|
#undef _TIME_T_DEFINED
|
|
#endif
|
|
|
|
#ifdef _MSC_VER
|
|
/*
|
|
* we do not want the warnings about the old deprecated and unsecure CRT functions
|
|
* since these examples can be compiled under *nix as well
|
|
*/
|
|
#define _CRT_SECURE_NO_WARNINGS
|
|
#endif
|
|
#include <pcap.h>
|
|
|
|
#include <rtthread.h>
|
|
#include <netif/ethernetif.h>
|
|
|
|
#define MAX_ADDR_LEN 6
|
|
|
|
#define NETIF_DEVICE(netif) ((struct pcap_netif*)(netif))
|
|
#define NETIF_PCAP(netif) (NETIF_DEVICE(netif)->tap)
|
|
|
|
struct pcap_netif
|
|
{
|
|
/* inherit from ethernet device */
|
|
struct eth_device parent;
|
|
|
|
pcap_t *tap;
|
|
/* interface address info. */
|
|
rt_uint8_t dev_addr[MAX_ADDR_LEN]; /* hw address */
|
|
};
|
|
static struct pcap_netif pcap_netif_device;
|
|
static struct rt_semaphore sem_lock;
|
|
static rt_mailbox_t packet_mb = RT_NULL;
|
|
|
|
static void pcap_thread_entry(void* parameter)
|
|
{
|
|
pcap_if_t *netif;
|
|
pcap_t *tap;
|
|
char errbuf[PCAP_ERRBUF_SIZE];
|
|
struct pcap_pkthdr *header;
|
|
const u_char *pkt_data;
|
|
int res;
|
|
|
|
netif = (pcap_if_t *) parameter;
|
|
|
|
/* Open the adapter */
|
|
if ((tap = pcap_open_live(netif->name,
|
|
65536, // portion of the packet to capture.
|
|
1, // promiscuous mode (nonzero means promiscuous)
|
|
1, // read timeout, 0 blocked, -1 no timeout
|
|
errbuf )) == NULL)
|
|
{
|
|
rt_kprintf("Unable to open the adapter. %s is not supported by WinPcap\n", netif->name);
|
|
return;
|
|
}
|
|
|
|
NETIF_PCAP(&pcap_netif_device) = tap;
|
|
|
|
/* Read the packets */
|
|
while (1)
|
|
{
|
|
struct eth_device* eth;
|
|
struct pbuf *p;
|
|
|
|
rt_enter_critical();
|
|
res = pcap_next_ex(tap, &header, &pkt_data);
|
|
rt_exit_critical();
|
|
|
|
if (res == 0) continue;
|
|
|
|
eth = (struct eth_device*) &pcap_netif_device;
|
|
|
|
p = pbuf_alloc(PBUF_LINK, header->len, PBUF_RAM);
|
|
pbuf_take(p, pkt_data, header->len);
|
|
|
|
/* send to packet mailbox */
|
|
rt_mb_send_wait(packet_mb, (rt_uint32_t)p, RT_WAITING_FOREVER);
|
|
/* notify eth rx thread to receive packet */
|
|
eth_device_ready(eth);
|
|
}
|
|
}
|
|
|
|
static rt_err_t pcap_netif_init(rt_device_t dev)
|
|
{
|
|
rt_thread_t tid;
|
|
pcap_if_t *alldevs;
|
|
pcap_if_t *d;
|
|
pcap_t *tap;
|
|
int inum, i=0;
|
|
char errbuf[PCAP_ERRBUF_SIZE];
|
|
|
|
/* Retrieve the device list */
|
|
if(pcap_findalldevs(&alldevs, errbuf) == -1)
|
|
{
|
|
rt_kprintf("Error in pcap_findalldevs: %s\n", errbuf);
|
|
return -RT_ERROR;
|
|
}
|
|
|
|
/* Print the list */
|
|
for(d = alldevs; d; d = d->next)
|
|
{
|
|
rt_kprintf("%d. %s", ++i, d->name);
|
|
if (d->description)
|
|
rt_kprintf(" (%s)\n", d->description);
|
|
else
|
|
rt_kprintf(" (No description available)\n");
|
|
}
|
|
if(i == 0)
|
|
{
|
|
rt_kprintf("\nNo interfaces found! Make sure WinPcap is installed.\n");
|
|
return -RT_ERROR;
|
|
}
|
|
|
|
inum = 1;
|
|
/* Jump to the selected adapter */
|
|
for(d = alldevs, i = 0; i < inum-1 ;d = d->next, i++);
|
|
|
|
{
|
|
rt_kprintf("Select (%s) as network interface\n", d->description);
|
|
packet_mb = rt_mb_create("pcap", 64, RT_IPC_FLAG_FIFO);
|
|
tid = rt_thread_create("pcap", pcap_thread_entry, d,
|
|
2048, RT_THREAD_PRIORITY_MAX - 1, 10);
|
|
if (tid != RT_NULL)
|
|
{
|
|
rt_thread_startup(tid);
|
|
}
|
|
|
|
rt_thread_delay(100);
|
|
}
|
|
|
|
pcap_freealldevs(alldevs);
|
|
|
|
return RT_EOK;
|
|
}
|
|
|
|
static rt_err_t pcap_netif_open(rt_device_t dev, rt_uint16_t oflag)
|
|
{
|
|
return RT_EOK;
|
|
}
|
|
|
|
static rt_err_t pcap_netif_close(rt_device_t dev)
|
|
{
|
|
pcap_t *tap;
|
|
|
|
tap = NETIF_PCAP(dev);
|
|
|
|
pcap_close(tap);
|
|
return RT_EOK;
|
|
}
|
|
|
|
static rt_size_t pcap_netif_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
|
|
{
|
|
rt_set_errno(-RT_ENOSYS);
|
|
return 0;
|
|
}
|
|
|
|
static rt_size_t pcap_netif_write (rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
|
|
{
|
|
rt_set_errno(-RT_ENOSYS);
|
|
return 0;
|
|
}
|
|
|
|
static rt_err_t pcap_netif_control(rt_device_t dev, int cmd, void *args)
|
|
{
|
|
switch (cmd)
|
|
{
|
|
case NIOCTL_GADDR:
|
|
/* get mac address */
|
|
if (args) rt_memcpy(args, pcap_netif_device.dev_addr, 6);
|
|
else return -RT_ERROR;
|
|
break;
|
|
|
|
default :
|
|
break;
|
|
}
|
|
|
|
return RT_EOK;
|
|
}
|
|
|
|
rt_err_t pcap_netif_tx( rt_device_t dev, struct pbuf* p)
|
|
{
|
|
struct pbuf *q;
|
|
rt_uint8_t *ptr;
|
|
rt_uint8_t buf[2048];
|
|
rt_err_t result = RT_EOK;
|
|
pcap_t *tap;
|
|
int res;
|
|
|
|
tap = NETIF_PCAP(dev);
|
|
|
|
/* lock EMAC device */
|
|
rt_sem_take(&sem_lock, RT_WAITING_FOREVER);
|
|
|
|
/* copy data to tx buffer */
|
|
q = p;
|
|
ptr = (rt_uint8_t*)buf;
|
|
while (q)
|
|
{
|
|
memcpy(ptr, q->payload, q->len);
|
|
ptr += q->len;
|
|
q = q->next;
|
|
}
|
|
|
|
rt_enter_critical();
|
|
res = pcap_sendpacket(tap, buf, p->tot_len);
|
|
rt_exit_critical();
|
|
|
|
if (res != 0)
|
|
{
|
|
rt_kprintf("Error sending the packet: \n", pcap_geterr(tap));
|
|
result = -RT_ERROR;
|
|
}
|
|
|
|
/* unlock EMAC device */
|
|
rt_sem_release(&sem_lock);
|
|
|
|
return result;
|
|
}
|
|
|
|
struct pbuf *pcap_netif_rx(rt_device_t dev)
|
|
{
|
|
struct pbuf* p = RT_NULL;
|
|
|
|
rt_mb_recv(packet_mb, (rt_uint32_t*)&p, 0);
|
|
|
|
return p;
|
|
}
|
|
|
|
void pcap_netif_hw_init(void)
|
|
{
|
|
rt_sem_init(&sem_lock, "eth_lock", 1, RT_IPC_FLAG_FIFO);
|
|
|
|
pcap_netif_device.dev_addr[0] = 0x00;
|
|
pcap_netif_device.dev_addr[1] = 0x60;
|
|
pcap_netif_device.dev_addr[2] = 0x37;
|
|
/* set mac address: (only for test) */
|
|
pcap_netif_device.dev_addr[3] = 0x12;
|
|
pcap_netif_device.dev_addr[4] = 0x34;
|
|
pcap_netif_device.dev_addr[5] = 0x56;
|
|
|
|
pcap_netif_device.parent.parent.init = pcap_netif_init;
|
|
pcap_netif_device.parent.parent.open = pcap_netif_open;
|
|
pcap_netif_device.parent.parent.close = pcap_netif_close;
|
|
pcap_netif_device.parent.parent.read = pcap_netif_read;
|
|
pcap_netif_device.parent.parent.write = pcap_netif_write;
|
|
pcap_netif_device.parent.parent.control = pcap_netif_control;
|
|
pcap_netif_device.parent.parent.user_data = RT_NULL;
|
|
|
|
pcap_netif_device.parent.eth_rx = pcap_netif_rx;
|
|
pcap_netif_device.parent.eth_tx = pcap_netif_tx;
|
|
|
|
eth_device_init(&(pcap_netif_device.parent), "e0");
|
|
}
|
|
|
|
#include <finsh.h>
|
|
void list_pcap(void)
|
|
{
|
|
int i=0;
|
|
pcap_if_t *alldevs;
|
|
pcap_if_t *d;
|
|
char errbuf[PCAP_ERRBUF_SIZE];
|
|
|
|
/* Retrieve the device list */
|
|
if(pcap_findalldevs(&alldevs, errbuf) == -1)
|
|
{
|
|
rt_kprintf("Error in pcap_findalldevs: %s\n", errbuf);
|
|
return -RT_ERROR;
|
|
}
|
|
|
|
/* Print the list */
|
|
for(d = alldevs; d; d = d->next)
|
|
{
|
|
rt_kprintf("%d. %s", ++i, d->name);
|
|
if (d->description)
|
|
rt_kprintf(" (%s)\n", d->description);
|
|
else
|
|
rt_kprintf(" (No description available)\n");
|
|
}
|
|
if(i == 0)
|
|
{
|
|
rt_kprintf("\nNo interfaces found! Make sure WinPcap is installed.\n");
|
|
return -RT_ERROR;
|
|
}
|
|
|
|
pcap_freealldevs(alldevs);
|
|
|
|
return ;
|
|
}
|
|
FINSH_FUNCTION_EXPORT(list_pcap, show host netif adapter);
|