/* * 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 #include #include #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_ssize_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_ssize_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 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);