1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
4*4882a593Smuzhiyun */
5*4882a593Smuzhiyun
6*4882a593Smuzhiyun #include <errno.h>
7*4882a593Smuzhiyun #include <pcap.h>
8*4882a593Smuzhiyun #include <string.h>
9*4882a593Smuzhiyun #include <asm/types.h>
10*4882a593Smuzhiyun #include <net_user.h>
11*4882a593Smuzhiyun #include "pcap_user.h"
12*4882a593Smuzhiyun #include <um_malloc.h>
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun #define PCAP_FD(p) (*(int *)(p))
15*4882a593Smuzhiyun
pcap_user_init(void * data,void * dev)16*4882a593Smuzhiyun static int pcap_user_init(void *data, void *dev)
17*4882a593Smuzhiyun {
18*4882a593Smuzhiyun struct pcap_data *pri = data;
19*4882a593Smuzhiyun pcap_t *p;
20*4882a593Smuzhiyun char errors[PCAP_ERRBUF_SIZE];
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun p = pcap_open_live(pri->host_if, ETH_MAX_PACKET + ETH_HEADER_OTHER,
23*4882a593Smuzhiyun pri->promisc, 0, errors);
24*4882a593Smuzhiyun if (p == NULL) {
25*4882a593Smuzhiyun printk(UM_KERN_ERR "pcap_user_init : pcap_open_live failed - "
26*4882a593Smuzhiyun "'%s'\n", errors);
27*4882a593Smuzhiyun return -EINVAL;
28*4882a593Smuzhiyun }
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun pri->dev = dev;
31*4882a593Smuzhiyun pri->pcap = p;
32*4882a593Smuzhiyun return 0;
33*4882a593Smuzhiyun }
34*4882a593Smuzhiyun
pcap_user_open(void * data)35*4882a593Smuzhiyun static int pcap_user_open(void *data)
36*4882a593Smuzhiyun {
37*4882a593Smuzhiyun struct pcap_data *pri = data;
38*4882a593Smuzhiyun __u32 netmask;
39*4882a593Smuzhiyun int err;
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun if (pri->pcap == NULL)
42*4882a593Smuzhiyun return -ENODEV;
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun if (pri->filter != NULL) {
45*4882a593Smuzhiyun err = dev_netmask(pri->dev, &netmask);
46*4882a593Smuzhiyun if (err < 0) {
47*4882a593Smuzhiyun printk(UM_KERN_ERR "pcap_user_open : dev_netmask failed\n");
48*4882a593Smuzhiyun return -EIO;
49*4882a593Smuzhiyun }
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun pri->compiled = uml_kmalloc(sizeof(struct bpf_program),
52*4882a593Smuzhiyun UM_GFP_KERNEL);
53*4882a593Smuzhiyun if (pri->compiled == NULL) {
54*4882a593Smuzhiyun printk(UM_KERN_ERR "pcap_user_open : kmalloc failed\n");
55*4882a593Smuzhiyun return -ENOMEM;
56*4882a593Smuzhiyun }
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun err = pcap_compile(pri->pcap,
59*4882a593Smuzhiyun (struct bpf_program *) pri->compiled,
60*4882a593Smuzhiyun pri->filter, pri->optimize, netmask);
61*4882a593Smuzhiyun if (err < 0) {
62*4882a593Smuzhiyun printk(UM_KERN_ERR "pcap_user_open : pcap_compile failed - "
63*4882a593Smuzhiyun "'%s'\n", pcap_geterr(pri->pcap));
64*4882a593Smuzhiyun goto out;
65*4882a593Smuzhiyun }
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun err = pcap_setfilter(pri->pcap, pri->compiled);
68*4882a593Smuzhiyun if (err < 0) {
69*4882a593Smuzhiyun printk(UM_KERN_ERR "pcap_user_open : pcap_setfilter "
70*4882a593Smuzhiyun "failed - '%s'\n", pcap_geterr(pri->pcap));
71*4882a593Smuzhiyun goto out;
72*4882a593Smuzhiyun }
73*4882a593Smuzhiyun }
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun return PCAP_FD(pri->pcap);
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun out:
78*4882a593Smuzhiyun kfree(pri->compiled);
79*4882a593Smuzhiyun return -EIO;
80*4882a593Smuzhiyun }
81*4882a593Smuzhiyun
pcap_remove(void * data)82*4882a593Smuzhiyun static void pcap_remove(void *data)
83*4882a593Smuzhiyun {
84*4882a593Smuzhiyun struct pcap_data *pri = data;
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun if (pri->compiled != NULL)
87*4882a593Smuzhiyun pcap_freecode(pri->compiled);
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun if (pri->pcap != NULL)
90*4882a593Smuzhiyun pcap_close(pri->pcap);
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun struct pcap_handler_data {
94*4882a593Smuzhiyun char *buffer;
95*4882a593Smuzhiyun int len;
96*4882a593Smuzhiyun };
97*4882a593Smuzhiyun
handler(u_char * data,const struct pcap_pkthdr * header,const u_char * packet)98*4882a593Smuzhiyun static void handler(u_char *data, const struct pcap_pkthdr *header,
99*4882a593Smuzhiyun const u_char *packet)
100*4882a593Smuzhiyun {
101*4882a593Smuzhiyun int len;
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun struct pcap_handler_data *hdata = (struct pcap_handler_data *) data;
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun len = hdata->len < header->caplen ? hdata->len : header->caplen;
106*4882a593Smuzhiyun memcpy(hdata->buffer, packet, len);
107*4882a593Smuzhiyun hdata->len = len;
108*4882a593Smuzhiyun }
109*4882a593Smuzhiyun
pcap_user_read(int fd,void * buffer,int len,struct pcap_data * pri)110*4882a593Smuzhiyun int pcap_user_read(int fd, void *buffer, int len, struct pcap_data *pri)
111*4882a593Smuzhiyun {
112*4882a593Smuzhiyun struct pcap_handler_data hdata = ((struct pcap_handler_data)
113*4882a593Smuzhiyun { .buffer = buffer,
114*4882a593Smuzhiyun .len = len });
115*4882a593Smuzhiyun int n;
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun n = pcap_dispatch(pri->pcap, 1, handler, (u_char *) &hdata);
118*4882a593Smuzhiyun if (n < 0) {
119*4882a593Smuzhiyun printk(UM_KERN_ERR "pcap_dispatch failed - %s\n",
120*4882a593Smuzhiyun pcap_geterr(pri->pcap));
121*4882a593Smuzhiyun return -EIO;
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun else if (n == 0)
124*4882a593Smuzhiyun return 0;
125*4882a593Smuzhiyun return hdata.len;
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun const struct net_user_info pcap_user_info = {
129*4882a593Smuzhiyun .init = pcap_user_init,
130*4882a593Smuzhiyun .open = pcap_user_open,
131*4882a593Smuzhiyun .close = NULL,
132*4882a593Smuzhiyun .remove = pcap_remove,
133*4882a593Smuzhiyun .add_address = NULL,
134*4882a593Smuzhiyun .delete_address = NULL,
135*4882a593Smuzhiyun .mtu = ETH_MAX_PACKET,
136*4882a593Smuzhiyun .max_packet = ETH_MAX_PACKET + ETH_HEADER_OTHER,
137*4882a593Smuzhiyun };
138