]> The Tcpdump Group git mirrors - libpcap/blob - pcap-hurd.c
CI: Test with IPv6 support enabled/disabled
[libpcap] / pcap-hurd.c
1 #define _GNU_SOURCE
2
3 /* XXX Hack not to include the Mach BPF interface */
4 #define _DEVICE_BPF_H_
5
6 #ifdef HAVE_CONFIG_H
7 #include "config.h"
8 #endif
9
10 #include <fcntl.h>
11 #include <hurd.h>
12 #include <mach.h>
13 #include <time.h>
14 #include <errno.h>
15 #include <stdio.h>
16 #include <stddef.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <device/device.h>
20 #include <device/device_types.h>
21 #include <device/net_status.h>
22 #include <net/if_ether.h>
23
24 #include "pcap-int.h"
25
26 struct pcap_hurd {
27 struct pcap_stat stat;
28 device_t mach_dev;
29 mach_port_t rcv_port;
30 };
31
32 static struct bpf_insn filter[] = {
33 { NETF_IN | NETF_OUT | NETF_BPF, 0, 0, 0 },
34 { BPF_RET | BPF_K, 0, 0, MAXIMUM_SNAPLEN },
35 };
36
37 #define FILTER_COUNT (sizeof(filter) / sizeof(short))
38
39 static int
40 pcap_read_hurd(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
41 {
42 struct net_rcv_msg *msg;
43 struct pcap_hurd *ph;
44 struct pcap_pkthdr h;
45 struct timespec ts;
46 int ret, wirelen, caplen;
47 u_char *pkt;
48 kern_return_t kr;
49
50 ph = p->priv;
51 msg = (struct net_rcv_msg *)p->buffer;
52
53 retry:
54 if (p->break_loop) {
55 p->break_loop = 0;
56 return PCAP_ERROR_BREAK;
57 }
58
59 kr = mach_msg(&msg->msg_hdr, MACH_RCV_MSG | MACH_RCV_INTERRUPT, 0,
60 p->bufsize, ph->rcv_port, MACH_MSG_TIMEOUT_NONE,
61 MACH_PORT_NULL);
62
63 if (kr) {
64 if (kr == MACH_RCV_INTERRUPTED)
65 goto retry;
66
67 snprintf(p->errbuf, sizeof(p->errbuf), "mach_msg: %s",
68 pcap_strerror(kr));
69 return PCAP_ERROR;
70 }
71
72 ph->stat.ps_recv++;
73
74 /* XXX Ethernet support only */
75 wirelen = ETH_HLEN + msg->net_rcv_msg_packet_count
76 - sizeof(struct packet_header);
77 pkt = p->buffer + offsetof(struct net_rcv_msg, packet)
78 + sizeof(struct packet_header) - ETH_HLEN;
79 memmove(pkt, p->buffer + offsetof(struct net_rcv_msg, header),
80 ETH_HLEN);
81
82 caplen = (wirelen > p->snapshot) ? p->snapshot : wirelen;
83 ret = bpf_filter(p->fcode.bf_insns, pkt, wirelen, caplen);
84
85 if (!ret)
86 goto out;
87
88 clock_gettime(CLOCK_REALTIME, &ts);
89 h.ts.tv_sec = ts.tv_sec;
90 h.ts.tv_usec = ts.tv_nsec / 1000;
91 h.len = wirelen;
92 h.caplen = caplen;
93 callback(user, &h, pkt);
94
95 out:
96 return 1;
97 }
98
99 static int
100 pcap_inject_hurd(pcap_t *p, const void *buf, int size)
101 {
102 struct pcap_hurd *ph;
103 kern_return_t kr;
104 int count;
105
106 ph = p->priv;
107 kr = device_write(ph->mach_dev, D_NOWAIT, 0,
108 (io_buf_ptr_t)buf, size, &count);
109
110 if (kr) {
111 snprintf(p->errbuf, sizeof(p->errbuf), "device_write: %s",
112 pcap_strerror(kr));
113 return -1;
114 }
115
116 return count;
117 }
118
119 static int
120 pcap_stats_hurd(pcap_t *p, struct pcap_stat *ps)
121 {
122 struct pcap_hurd *ph;
123
124 ph = p->priv;
125 *ps = ph->stat;
126 return 0;
127 }
128
129 static void
130 pcap_cleanup_hurd(pcap_t *p)
131 {
132 struct pcap_hurd *ph;
133
134 ph = p->priv;
135
136 if (ph->rcv_port != MACH_PORT_NULL) {
137 mach_port_deallocate(mach_task_self(), ph->rcv_port);
138 ph->rcv_port = MACH_PORT_NULL;
139 }
140
141 if (ph->mach_dev != MACH_PORT_NULL) {
142 device_close(ph->mach_dev);
143 ph->mach_dev = MACH_PORT_NULL;
144 }
145
146 pcap_cleanup_live_common(p);
147 }
148
149 static int
150 pcap_activate_hurd(pcap_t *p)
151 {
152 struct pcap_hurd *ph;
153 mach_port_t master;
154 kern_return_t kr;
155
156 ph = p->priv;
157
158 /* Try devnode first */
159 master = file_name_lookup(p->opt.device, O_READ | O_WRITE, 0);
160
161 if (master != MACH_PORT_NULL)
162 kr = device_open(master, D_WRITE | D_READ, "eth", &ph->mach_dev);
163 else {
164 /* If unsuccessful, try Mach device */
165 kr = get_privileged_ports(NULL, &master);
166
167 if (kr) {
168 snprintf(p->errbuf, sizeof(p->errbuf),
169 "get_privileged_ports: %s", pcap_strerror(kr));
170 goto error;
171 }
172
173 kr = device_open(master, D_READ | D_WRITE, p->opt.device,
174 &ph->mach_dev);
175 }
176
177 mach_port_deallocate(mach_task_self(), master);
178
179 if (kr) {
180 snprintf(p->errbuf, sizeof(p->errbuf), "device_open: %s",
181 pcap_strerror(kr));
182 goto error;
183 }
184
185 kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE,
186 &ph->rcv_port);
187
188 if (kr) {
189 snprintf(p->errbuf, sizeof(p->errbuf), "mach_port_allocate: %s",
190 pcap_strerror(kr));
191 goto error;
192 }
193
194 kr = device_set_filter(ph->mach_dev, ph->rcv_port,
195 MACH_MSG_TYPE_MAKE_SEND, 0,
196 (filter_array_t)filter, FILTER_COUNT);
197
198 if (kr) {
199 snprintf(p->errbuf, sizeof(p->errbuf), "device_set_filter: %s",
200 pcap_strerror(kr));
201 goto error;
202 }
203
204 /* XXX Ethernet only currently */
205 p->linktype = DLT_EN10MB;
206
207 p->bufsize = sizeof(struct net_rcv_msg);
208 p->buffer = malloc(p->bufsize);
209
210 if (p->buffer == NULL) {
211 snprintf(p->errbuf, sizeof(p->errbuf), "malloc: %s",
212 pcap_strerror(errno));
213 goto error;
214 }
215
216 p->dlt_list = malloc(sizeof(*p->dlt_list));
217
218 if (p->dlt_list != NULL)
219 *p->dlt_list = DLT_EN10MB;
220
221 p->read_op = pcap_read_hurd;
222 p->inject_op = pcap_inject_hurd;
223 p->setfilter_op = install_bpf_program;
224 p->stats_op = pcap_stats_hurd;
225
226 return 0;
227
228 error:
229 pcap_cleanup_hurd(p);
230 return PCAP_ERROR;
231 }
232
233 pcap_t *
234 pcap_create_interface(const char *device _U_, char *ebuf)
235 {
236 struct pcap_hurd *ph;
237 pcap_t *p;
238
239 p = PCAP_CREATE_COMMON(ebuf, struct pcap_hurd);
240 if (p == NULL)
241 return NULL;
242
243 ph = p->priv;
244 ph->mach_dev = MACH_PORT_NULL;
245 ph->rcv_port = MACH_PORT_NULL;
246 p->activate_op = pcap_activate_hurd;
247 return p;
248 }
249
250 int
251 pcap_platform_finddevs(pcap_if_list_t *alldevsp, char *errbuf)
252 {
253 return 0;
254 }
255
256 /*
257 * Libpcap version string.
258 */
259 const char *
260 pcap_lib_version(void)
261 {
262 return PCAP_VERSION_STRING;
263 }