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