nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* |
2 | * Copyright (c) 1993, 1994, 1995, 1996, 1997 |
||
3 | * The Regents of the University of California. All rights reserved. |
||
4 | * |
||
5 | * Redistribution and use in source and binary forms, with or without |
||
6 | * modification, are permitted provided that: (1) source code distributions |
||
7 | * retain the above copyright notice and this paragraph in its entirety, (2) |
||
8 | * distributions including binary code include the above copyright notice and |
||
9 | * this paragraph in its entirety in the documentation or other materials |
||
10 | * provided with the distribution, and (3) all advertising materials mentioning |
||
11 | * features or use of this software display the following acknowledgement: |
||
12 | * ``This product includes software developed by the University of California, |
||
13 | * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of |
||
14 | * the University nor the names of its contributors may be used to endorse |
||
15 | * or promote products derived from this software without specific prior |
||
16 | * written permission. |
||
17 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||
18 | * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF |
||
19 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
||
20 | * |
||
21 | * This code contributed by Sagun Shakya (sagun.shakya@sun.com) |
||
22 | */ |
||
23 | /* |
||
24 | * Packet capture routines for DLPI using libdlpi under SunOS 5.11. |
||
25 | */ |
||
26 | |||
27 | #ifdef HAVE_CONFIG_H |
||
28 | #include "config.h" |
||
29 | #endif |
||
30 | |||
31 | #include <sys/types.h> |
||
32 | #include <sys/time.h> |
||
33 | #include <sys/bufmod.h> |
||
34 | #include <sys/stream.h> |
||
35 | #include <libdlpi.h> |
||
36 | #include <errno.h> |
||
37 | #include <memory.h> |
||
38 | #include <stropts.h> |
||
39 | #include <stdio.h> |
||
40 | #include <stdlib.h> |
||
41 | #include <string.h> |
||
42 | |||
43 | #include "pcap-int.h" |
||
44 | #include "dlpisubs.h" |
||
45 | |||
46 | /* Forwards. */ |
||
47 | static int dlpromiscon(pcap_t *, bpf_u_int32); |
||
48 | static int pcap_read_libdlpi(pcap_t *, int, pcap_handler, u_char *); |
||
49 | static int pcap_inject_libdlpi(pcap_t *, const void *, size_t); |
||
50 | static void pcap_libdlpi_err(const char *, const char *, int, char *); |
||
51 | static void pcap_cleanup_libdlpi(pcap_t *); |
||
52 | |||
53 | /* |
||
54 | * list_interfaces() will list all the network links that are |
||
55 | * available on a system. |
||
56 | */ |
||
57 | static boolean_t list_interfaces(const char *, void *); |
||
58 | |||
59 | typedef struct linknamelist { |
||
60 | char linkname[DLPI_LINKNAME_MAX]; |
||
61 | struct linknamelist *lnl_next; |
||
62 | } linknamelist_t; |
||
63 | |||
64 | typedef struct linkwalk { |
||
65 | linknamelist_t *lw_list; |
||
66 | int lw_err; |
||
67 | } linkwalk_t; |
||
68 | |||
69 | /* |
||
70 | * The caller of this function should free the memory allocated |
||
71 | * for each linknamelist_t "entry" allocated. |
||
72 | */ |
||
73 | static boolean_t |
||
74 | list_interfaces(const char *linkname, void *arg) |
||
75 | { |
||
76 | linkwalk_t *lwp = arg; |
||
77 | linknamelist_t *entry; |
||
78 | |||
79 | if ((entry = calloc(1, sizeof(linknamelist_t))) == NULL) { |
||
80 | lwp->lw_err = ENOMEM; |
||
81 | return (B_TRUE); |
||
82 | } |
||
83 | (void) strlcpy(entry->linkname, linkname, DLPI_LINKNAME_MAX); |
||
84 | |||
85 | if (lwp->lw_list == NULL) { |
||
86 | lwp->lw_list = entry; |
||
87 | } else { |
||
88 | entry->lnl_next = lwp->lw_list; |
||
89 | lwp->lw_list = entry; |
||
90 | } |
||
91 | |||
92 | return (B_FALSE); |
||
93 | } |
||
94 | |||
95 | static int |
||
96 | pcap_activate_libdlpi(pcap_t *p) |
||
97 | { |
||
98 | struct pcap_dlpi *pd = p->priv; |
||
99 | int status = 0; |
||
100 | int retv; |
||
101 | dlpi_handle_t dh; |
||
102 | dlpi_info_t dlinfo; |
||
103 | |||
104 | /* |
||
105 | * Enable Solaris raw and passive DLPI extensions; |
||
106 | * dlpi_open() will not fail if the underlying link does not support |
||
107 | * passive mode. See dlpi(7P) for details. |
||
108 | */ |
||
109 | retv = dlpi_open(p->opt.source, &dh, DLPI_RAW|DLPI_PASSIVE); |
||
110 | if (retv != DLPI_SUCCESS) { |
||
111 | if (retv == DLPI_ELINKNAMEINVAL || retv == DLPI_ENOLINK) |
||
112 | status = PCAP_ERROR_NO_SUCH_DEVICE; |
||
113 | else if (retv == DL_SYSERR && |
||
114 | (errno == EPERM || errno == EACCES)) |
||
115 | status = PCAP_ERROR_PERM_DENIED; |
||
116 | else |
||
117 | status = PCAP_ERROR; |
||
118 | pcap_libdlpi_err(p->opt.source, "dlpi_open", retv, |
||
119 | p->errbuf); |
||
120 | return (status); |
||
121 | } |
||
122 | pd->dlpi_hd = dh; |
||
123 | |||
124 | if (p->opt.rfmon) { |
||
125 | /* |
||
126 | * This device exists, but we don't support monitor mode |
||
127 | * any platforms that support DLPI. |
||
128 | */ |
||
129 | status = PCAP_ERROR_RFMON_NOTSUP; |
||
130 | goto bad; |
||
131 | } |
||
132 | |||
133 | /* Bind with DLPI_ANY_SAP. */ |
||
134 | if ((retv = dlpi_bind(pd->dlpi_hd, DLPI_ANY_SAP, 0)) != DLPI_SUCCESS) { |
||
135 | status = PCAP_ERROR; |
||
136 | pcap_libdlpi_err(p->opt.source, "dlpi_bind", retv, p->errbuf); |
||
137 | goto bad; |
||
138 | } |
||
139 | |||
140 | /* Enable promiscuous mode. */ |
||
141 | if (p->opt.promisc) { |
||
142 | retv = dlpromiscon(p, DL_PROMISC_PHYS); |
||
143 | if (retv < 0) { |
||
144 | /* |
||
145 | * "You don't have permission to capture on |
||
146 | * this device" and "you don't have permission |
||
147 | * to capture in promiscuous mode on this |
||
148 | * device" are different; let the user know, |
||
149 | * so if they can't get permission to |
||
150 | * capture in promiscuous mode, they can at |
||
151 | * least try to capture in non-promiscuous |
||
152 | * mode. |
||
153 | * |
||
154 | * XXX - you might have to capture in |
||
155 | * promiscuous mode to see outgoing packets. |
||
156 | */ |
||
157 | if (retv == PCAP_ERROR_PERM_DENIED) |
||
158 | status = PCAP_ERROR_PROMISC_PERM_DENIED; |
||
159 | else |
||
160 | status = retv; |
||
161 | goto bad; |
||
162 | } |
||
163 | } else { |
||
164 | /* Try to enable multicast. */ |
||
165 | retv = dlpromiscon(p, DL_PROMISC_MULTI); |
||
166 | if (retv < 0) { |
||
167 | status = retv; |
||
168 | goto bad; |
||
169 | } |
||
170 | } |
||
171 | |||
172 | /* Try to enable SAP promiscuity. */ |
||
173 | retv = dlpromiscon(p, DL_PROMISC_SAP); |
||
174 | if (retv < 0) { |
||
175 | /* |
||
176 | * Not fatal, since the DL_PROMISC_PHYS mode worked. |
||
177 | * Report it as a warning, however. |
||
178 | */ |
||
179 | if (p->opt.promisc) |
||
180 | status = PCAP_WARNING; |
||
181 | else { |
||
182 | status = retv; |
||
183 | goto bad; |
||
184 | } |
||
185 | } |
||
186 | |||
187 | /* Determine link type. */ |
||
188 | if ((retv = dlpi_info(pd->dlpi_hd, &dlinfo, 0)) != DLPI_SUCCESS) { |
||
189 | status = PCAP_ERROR; |
||
190 | pcap_libdlpi_err(p->opt.source, "dlpi_info", retv, p->errbuf); |
||
191 | goto bad; |
||
192 | } |
||
193 | |||
194 | if (pcap_process_mactype(p, dlinfo.di_mactype) != 0) { |
||
195 | status = PCAP_ERROR; |
||
196 | goto bad; |
||
197 | } |
||
198 | |||
199 | p->fd = dlpi_fd(pd->dlpi_hd); |
||
200 | |||
201 | /* Push and configure bufmod. */ |
||
202 | if (pcap_conf_bufmod(p, p->snapshot) != 0) { |
||
203 | status = PCAP_ERROR; |
||
204 | goto bad; |
||
205 | } |
||
206 | |||
207 | /* |
||
208 | * Flush the read side. |
||
209 | */ |
||
210 | if (ioctl(p->fd, I_FLUSH, FLUSHR) != 0) { |
||
211 | status = PCAP_ERROR; |
||
212 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "FLUSHR: %s", |
||
213 | pcap_strerror(errno)); |
||
214 | goto bad; |
||
215 | } |
||
216 | |||
217 | /* Allocate data buffer. */ |
||
218 | if (pcap_alloc_databuf(p) != 0) { |
||
219 | status = PCAP_ERROR; |
||
220 | goto bad; |
||
221 | } |
||
222 | |||
223 | /* |
||
224 | * "p->fd" is a FD for a STREAMS device, so "select()" and |
||
225 | * "poll()" should work on it. |
||
226 | */ |
||
227 | p->selectable_fd = p->fd; |
||
228 | |||
229 | p->read_op = pcap_read_libdlpi; |
||
230 | p->inject_op = pcap_inject_libdlpi; |
||
231 | p->setfilter_op = install_bpf_program; /* No kernel filtering */ |
||
232 | p->setdirection_op = NULL; /* Not implemented */ |
||
233 | p->set_datalink_op = NULL; /* Can't change data link type */ |
||
234 | p->getnonblock_op = pcap_getnonblock_fd; |
||
235 | p->setnonblock_op = pcap_setnonblock_fd; |
||
236 | p->stats_op = pcap_stats_dlpi; |
||
237 | p->cleanup_op = pcap_cleanup_libdlpi; |
||
238 | |||
239 | return (status); |
||
240 | bad: |
||
241 | pcap_cleanup_libdlpi(p); |
||
242 | return (status); |
||
243 | } |
||
244 | |||
245 | #define STRINGIFY(n) #n |
||
246 | |||
247 | static int |
||
248 | dlpromiscon(pcap_t *p, bpf_u_int32 level) |
||
249 | { |
||
250 | struct pcap_dlpi *pd = p->priv; |
||
251 | int retv; |
||
252 | int err; |
||
253 | |||
254 | retv = dlpi_promiscon(pd->dlpi_hd, level); |
||
255 | if (retv != DLPI_SUCCESS) { |
||
256 | if (retv == DL_SYSERR && |
||
257 | (errno == EPERM || errno == EACCES)) |
||
258 | err = PCAP_ERROR_PERM_DENIED; |
||
259 | else |
||
260 | err = PCAP_ERROR; |
||
261 | pcap_libdlpi_err(p->opt.source, "dlpi_promiscon" STRINGIFY(level), |
||
262 | retv, p->errbuf); |
||
263 | return (err); |
||
264 | } |
||
265 | return (0); |
||
266 | } |
||
267 | |||
268 | /* |
||
269 | * In Solaris, the "standard" mechanism" i.e SIOCGLIFCONF will only find |
||
270 | * network links that are plumbed and are up. dlpi_walk(3DLPI) will find |
||
271 | * additional network links present in the system. |
||
272 | */ |
||
273 | int |
||
274 | pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf) |
||
275 | { |
||
276 | int retv = 0; |
||
277 | |||
278 | linknamelist_t *entry, *next; |
||
279 | linkwalk_t lw = {NULL, 0}; |
||
280 | int save_errno; |
||
281 | |||
282 | /* dlpi_walk() for loopback will be added here. */ |
||
283 | |||
284 | dlpi_walk(list_interfaces, &lw, 0); |
||
285 | |||
286 | if (lw.lw_err != 0) { |
||
287 | snprintf(errbuf, PCAP_ERRBUF_SIZE, |
||
288 | "dlpi_walk: %s", pcap_strerror(lw.lw_err)); |
||
289 | retv = -1; |
||
290 | goto done; |
||
291 | } |
||
292 | |||
293 | /* Add linkname if it does not exist on the list. */ |
||
294 | for (entry = lw.lw_list; entry != NULL; entry = entry->lnl_next) { |
||
295 | if (pcap_add_if(alldevsp, entry->linkname, 0, NULL, errbuf) < 0) |
||
296 | retv = -1; |
||
297 | } |
||
298 | done: |
||
299 | save_errno = errno; |
||
300 | for (entry = lw.lw_list; entry != NULL; entry = next) { |
||
301 | next = entry->lnl_next; |
||
302 | free(entry); |
||
303 | } |
||
304 | errno = save_errno; |
||
305 | |||
306 | return (retv); |
||
307 | } |
||
308 | |||
309 | /* |
||
310 | * Read data received on DLPI handle. Returns -2 if told to terminate, else |
||
311 | * returns the number of packets read. |
||
312 | */ |
||
313 | static int |
||
314 | pcap_read_libdlpi(pcap_t *p, int count, pcap_handler callback, u_char *user) |
||
315 | { |
||
316 | struct pcap_dlpi *pd = p->priv; |
||
317 | int len; |
||
318 | u_char *bufp; |
||
319 | size_t msglen; |
||
320 | int retv; |
||
321 | |||
322 | len = p->cc; |
||
323 | if (len != 0) { |
||
324 | bufp = p->bp; |
||
325 | goto process_pkts; |
||
326 | } |
||
327 | do { |
||
328 | /* Has "pcap_breakloop()" been called? */ |
||
329 | if (p->break_loop) { |
||
330 | /* |
||
331 | * Yes - clear the flag that indicates that it has, |
||
332 | * and return -2 to indicate that we were told to |
||
333 | * break out of the loop. |
||
334 | */ |
||
335 | p->break_loop = 0; |
||
336 | return (-2); |
||
337 | } |
||
338 | |||
339 | msglen = p->bufsize; |
||
340 | bufp = p->buffer + p->offset; |
||
341 | |||
342 | retv = dlpi_recv(pd->dlpi_hd, NULL, NULL, bufp, |
||
343 | &msglen, -1, NULL); |
||
344 | if (retv != DLPI_SUCCESS) { |
||
345 | /* |
||
346 | * This is most likely a call to terminate out of the |
||
347 | * loop. So, do not return an error message, instead |
||
348 | * check if "pcap_breakloop()" has been called above. |
||
349 | */ |
||
350 | if (retv == DL_SYSERR && errno == EINTR) { |
||
351 | len = 0; |
||
352 | continue; |
||
353 | } |
||
354 | pcap_libdlpi_err(dlpi_linkname(pd->dlpi_hd), |
||
355 | "dlpi_recv", retv, p->errbuf); |
||
356 | return (-1); |
||
357 | } |
||
358 | len = msglen; |
||
359 | } while (len == 0); |
||
360 | |||
361 | process_pkts: |
||
362 | return (pcap_process_pkts(p, callback, user, count, bufp, len)); |
||
363 | } |
||
364 | |||
365 | static int |
||
366 | pcap_inject_libdlpi(pcap_t *p, const void *buf, size_t size) |
||
367 | { |
||
368 | struct pcap_dlpi *pd = p->priv; |
||
369 | int retv; |
||
370 | |||
371 | retv = dlpi_send(pd->dlpi_hd, NULL, 0, buf, size, NULL); |
||
372 | if (retv != DLPI_SUCCESS) { |
||
373 | pcap_libdlpi_err(dlpi_linkname(pd->dlpi_hd), "dlpi_send", retv, |
||
374 | p->errbuf); |
||
375 | return (-1); |
||
376 | } |
||
377 | /* |
||
378 | * dlpi_send(3DLPI) does not provide a way to return the number of |
||
379 | * bytes sent on the wire. Based on the fact that DLPI_SUCCESS was |
||
380 | * returned we are assuming 'size' bytes were sent. |
||
381 | */ |
||
382 | return (size); |
||
383 | } |
||
384 | |||
385 | /* |
||
386 | * Close dlpi handle. |
||
387 | */ |
||
388 | static void |
||
389 | pcap_cleanup_libdlpi(pcap_t *p) |
||
390 | { |
||
391 | struct pcap_dlpi *pd = p->priv; |
||
392 | |||
393 | if (pd->dlpi_hd != NULL) { |
||
394 | dlpi_close(pd->dlpi_hd); |
||
395 | pd->dlpi_hd = NULL; |
||
396 | p->fd = -1; |
||
397 | } |
||
398 | pcap_cleanup_live_common(p); |
||
399 | } |
||
400 | |||
401 | /* |
||
402 | * Write error message to buffer. |
||
403 | */ |
||
404 | static void |
||
405 | pcap_libdlpi_err(const char *linkname, const char *func, int err, char *errbuf) |
||
406 | { |
||
407 | snprintf(errbuf, PCAP_ERRBUF_SIZE, "libpcap: %s failed on %s: %s", |
||
408 | func, linkname, dlpi_strerror(err)); |
||
409 | } |
||
410 | |||
411 | pcap_t * |
||
412 | pcap_create_interface(const char *device, char *ebuf) |
||
413 | { |
||
414 | pcap_t *p; |
||
415 | |||
416 | p = pcap_create_common(device, ebuf, sizeof (struct pcap_dlpi)); |
||
417 | if (p == NULL) |
||
418 | return (NULL); |
||
419 | |||
420 | p->activate_op = pcap_activate_libdlpi; |
||
421 | return (p); |
||
422 | } |