1 /*
2  * Copyright (c) 2006-2021, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2012-11-05     Bernard      the first version
9  * 2012-11-13     Bernard      merge prife's patch for exclusive
10  *                             access pcap driver.
11  */
12 
13 #ifdef _TIME_T_DEFINED
14 #undef _TIME_T_DEFINED
15 #endif
16 
17 #ifdef _MSC_VER
18 /*
19  * we do not want the warnings about the old deprecated and unsecure CRT functions
20  * since these examples can be compiled under *nix as well
21  */
22 #define _CRT_SECURE_NO_WARNINGS
23 #endif
24 #include <pcap.h>
25 
26 #include <rtthread.h>
27 #include <netif/ethernetif.h>
28 
29 #define DBG_TAG    "pcap.netif"
30 #define DBG_LVL    DBG_INFO
31 #include <rtdbg.h>
32 
33 #define MAX_ADDR_LEN 6
34 
35 #define NETIF_DEVICE(netif) ((struct pcap_netif*)(netif))
36 #define NETIF_PCAP(netif)   (NETIF_DEVICE(netif)->tap)
37 
38 struct pcap_netif
39 {
40     /* inherit from ethernet device */
41     struct eth_device parent;
42 
43     pcap_t *tap;
44     /* interface address info. */
45     rt_uint8_t  dev_addr[MAX_ADDR_LEN];     /* hw address   */
46 };
47 static struct pcap_netif pcap_netif_device;
48 static struct rt_semaphore sem_lock;
49 static rt_mailbox_t packet_mb = RT_NULL;
50 
pcap_thread_entry(void * parameter)51 static void pcap_thread_entry(void* parameter)
52 {
53     pcap_if_t *netif;
54     pcap_t *tap;
55     char errbuf[PCAP_ERRBUF_SIZE];
56     struct pcap_pkthdr *header;
57     const u_char *pkt_data;
58     int res;
59 
60     netif = (pcap_if_t *) parameter;
61 
62     /* Open the adapter */
63     if ((tap = pcap_open_live(netif->name,
64         65536, // portion of the packet to capture.
65         1,     // promiscuous mode (nonzero means promiscuous)
66         1,     // read timeout, 0 blocked, -1 no timeout
67         errbuf )) == NULL)
68     {
69         rt_kprintf("Unable to open the adapter. %s is not supported by WinPcap\n", netif->name);
70         return;
71     }
72 
73     NETIF_PCAP(&pcap_netif_device) = tap;
74 
75     /* Read the packets */
76     while (1)
77     {
78         struct eth_device* eth;
79         struct pbuf *p;
80 
81         rt_enter_critical();
82         res = pcap_next_ex(tap, &header, &pkt_data);
83         rt_exit_critical();
84 
85         if (res == 0) continue;
86 
87         eth = (struct eth_device*) &pcap_netif_device;
88 
89         p = pbuf_alloc(PBUF_LINK, header->len, PBUF_RAM);
90         pbuf_take(p, pkt_data, header->len);
91 
92         /* send to packet mailbox */
93         rt_mb_send_wait(packet_mb, (rt_uint32_t)p, RT_WAITING_FOREVER);
94         /* notify eth rx thread to receive packet */
95         eth_device_ready(eth);
96     }
97 }
98 
pcap_netif_init(rt_device_t dev)99 static rt_err_t pcap_netif_init(rt_device_t dev)
100 {
101     rt_thread_t tid;
102     pcap_if_t *alldevs;
103     pcap_if_t *d;
104     pcap_t *tap;
105     int inum, i=0;
106     char errbuf[PCAP_ERRBUF_SIZE];
107 
108     /* Retrieve the device list */
109     if(pcap_findalldevs(&alldevs, errbuf) == -1)
110     {
111         rt_kprintf("Error in pcap_findalldevs: %s\n", errbuf);
112         return -RT_ERROR;
113     }
114 
115     /* Print the list */
116     for(d = alldevs; d; d = d->next)
117     {
118         rt_kprintf("%d. %s", ++i, d->name);
119         if (d->description)
120             rt_kprintf(" (%s)\n", d->description);
121         else
122             rt_kprintf(" (No description available)\n");
123     }
124     if(i == 0)
125     {
126         rt_kprintf("\nNo interfaces found! Make sure WinPcap is installed.\n");
127         return -RT_ERROR;
128     }
129 
130     inum = 1;
131     /* Jump to the selected adapter */
132     for(d = alldevs, i = 0; i < inum-1 ;d = d->next, i++);
133 
134     {
135         rt_kprintf("Select (%s) as network interface\n", d->description);
136         packet_mb = rt_mb_create("pcap", 64, RT_IPC_FLAG_FIFO);
137         tid = rt_thread_create("pcap", pcap_thread_entry, d,
138             2048, RT_THREAD_PRIORITY_MAX - 1, 10);
139         if (tid != RT_NULL)
140         {
141             rt_thread_startup(tid);
142         }
143 
144         rt_thread_delay(100);
145     }
146 
147     pcap_freealldevs(alldevs);
148 
149     return RT_EOK;
150 }
151 
pcap_netif_open(rt_device_t dev,rt_uint16_t oflag)152 static rt_err_t pcap_netif_open(rt_device_t dev, rt_uint16_t oflag)
153 {
154     return RT_EOK;
155 }
156 
pcap_netif_close(rt_device_t dev)157 static rt_err_t pcap_netif_close(rt_device_t dev)
158 {
159     pcap_t *tap;
160 
161     tap = NETIF_PCAP(dev);
162 
163     pcap_close(tap);
164     return RT_EOK;
165 }
166 
pcap_netif_read(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t size)167 static rt_ssize_t pcap_netif_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
168 {
169     rt_set_errno(-RT_ENOSYS);
170     return 0;
171 }
172 
pcap_netif_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)173 static rt_ssize_t pcap_netif_write (rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
174 {
175     rt_set_errno(-RT_ENOSYS);
176     return 0;
177 }
178 
pcap_netif_control(rt_device_t dev,int cmd,void * args)179 static rt_err_t pcap_netif_control(rt_device_t dev, int cmd, void *args)
180 {
181     switch (cmd)
182     {
183     case NIOCTL_GADDR:
184         /* get mac address */
185         if (args) rt_memcpy(args, pcap_netif_device.dev_addr, 6);
186         else return -RT_ERROR;
187         break;
188 
189     default :
190         break;
191     }
192 
193     return RT_EOK;
194 }
195 
pcap_netif_tx(rt_device_t dev,struct pbuf * p)196 rt_err_t pcap_netif_tx( rt_device_t dev, struct pbuf* p)
197 {
198     struct pbuf *q;
199     rt_uint8_t *ptr;
200     rt_uint8_t buf[2048];
201     rt_err_t result = RT_EOK;
202     pcap_t *tap;
203     int res;
204 
205     tap = NETIF_PCAP(dev);
206 
207     /* lock EMAC device */
208     rt_sem_take(&sem_lock, RT_WAITING_FOREVER);
209 
210     /* check if the total length of pbuf exceeds the size of buf */
211     if(p->tot_len > 2048)
212     {
213         LOG_E("Sending the packet: send data exceed max len 2048!");
214         rt_sem_release(&sem_lock);
215         return -RT_ERROR;
216     }
217 
218     /* copy data to tx buffer */
219     q = p;
220     ptr = (rt_uint8_t*)buf;
221     while (q)
222     {
223         memcpy(ptr, q->payload, q->len);
224         ptr += q->len;
225         q = q->next;
226     }
227 
228     rt_enter_critical();
229     res = pcap_sendpacket(tap, buf, p->tot_len);
230     rt_exit_critical();
231 
232     if (res != 0)
233     {
234         LOG_E("Sending the packet: %s", pcap_geterr(tap));
235         result = -RT_ERROR;
236     }
237 
238     /* unlock EMAC device */
239     rt_sem_release(&sem_lock);
240 
241     return result;
242 }
243 
pcap_netif_rx(rt_device_t dev)244 struct pbuf *pcap_netif_rx(rt_device_t dev)
245 {
246     struct pbuf* p = RT_NULL;
247 
248     rt_mb_recv(packet_mb, (rt_uint32_t*)&p, 0);
249 
250     return p;
251 }
252 
pcap_netif_hw_init(void)253 void pcap_netif_hw_init(void)
254 {
255     rt_sem_init(&sem_lock, "eth_lock", 1, RT_IPC_FLAG_FIFO);
256 
257     pcap_netif_device.dev_addr[0] = 0x00;
258     pcap_netif_device.dev_addr[1] = 0x60;
259     pcap_netif_device.dev_addr[2] = 0x37;
260     /* set mac address: (only for test) */
261     pcap_netif_device.dev_addr[3] = 0x12;
262     pcap_netif_device.dev_addr[4] = 0x34;
263     pcap_netif_device.dev_addr[5] = 0x56;
264 
265     pcap_netif_device.parent.parent.init        = pcap_netif_init;
266     pcap_netif_device.parent.parent.open        = pcap_netif_open;
267     pcap_netif_device.parent.parent.close       = pcap_netif_close;
268     pcap_netif_device.parent.parent.read        = pcap_netif_read;
269     pcap_netif_device.parent.parent.write       = pcap_netif_write;
270     pcap_netif_device.parent.parent.control     = pcap_netif_control;
271     pcap_netif_device.parent.parent.user_data   = RT_NULL;
272 
273     pcap_netif_device.parent.eth_rx         = pcap_netif_rx;
274     pcap_netif_device.parent.eth_tx         = pcap_netif_tx;
275 
276     eth_device_init(&(pcap_netif_device.parent), "e0");
277 }
278 
279 #include <finsh.h>
list_pcap(void)280 void list_pcap(void)
281 {
282     int i=0;
283     pcap_if_t *alldevs;
284     pcap_if_t *d;
285     char errbuf[PCAP_ERRBUF_SIZE];
286 
287     /* Retrieve the device list */
288     if(pcap_findalldevs(&alldevs, errbuf) == -1)
289     {
290         rt_kprintf("Error in pcap_findalldevs: %s\n", errbuf);
291         return -RT_ERROR;
292     }
293 
294     /* Print the list */
295     for(d = alldevs; d; d = d->next)
296     {
297         rt_kprintf("%d. %s", ++i, d->name);
298         if (d->description)
299             rt_kprintf(" (%s)\n", d->description);
300         else
301             rt_kprintf(" (No description available)\n");
302     }
303     if(i == 0)
304     {
305         rt_kprintf("\nNo interfaces found! Make sure WinPcap is installed.\n");
306         return -RT_ERROR;
307     }
308 
309     pcap_freealldevs(alldevs);
310 
311     return ;
312 }
313 FINSH_FUNCTION_EXPORT(list_pcap, show host netif adapter);
314