2008-03-13 18:13:57 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 1993, 1994, 1995, 1996, 1997
|
|
|
|
* The Regents of the University of California. All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that: (1) source code distributions
|
|
|
|
* retain the above copyright notice and this paragraph in its entirety, (2)
|
|
|
|
* distributions including binary code include the above copyright notice and
|
|
|
|
* this paragraph in its entirety in the documentation or other materials
|
|
|
|
* provided with the distribution, and (3) all advertising materials mentioning
|
|
|
|
* features or use of this software display the following acknowledgement:
|
|
|
|
* ``This product includes software developed by the University of California,
|
|
|
|
* Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
|
|
|
|
* the University nor the names of its contributors may be used to endorse
|
|
|
|
* or promote products derived from this software without specific prior
|
|
|
|
* written permission.
|
|
|
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
|
|
|
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
|
|
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
*
|
|
|
|
* This code contributed by Sagun Shakya (sagun.shakya@sun.com)
|
|
|
|
*/
|
|
|
|
/*
|
|
|
|
* Packet capture routines for DLPI using libdlpi under SunOS 5.11.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef lint
|
|
|
|
static const char rcsid[] _U_ =
|
2008-04-14 20:40:58 +00:00
|
|
|
"@(#) $Header: /tcpdump/master/libpcap/pcap-libdlpi.c,v 1.6 2008-04-14 20:40:58 guy Exp $ (LBL)";
|
2008-03-13 18:13:57 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/bufmod.h>
|
|
|
|
#include <sys/stream.h>
|
|
|
|
#include <libdlpi.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <memory.h>
|
|
|
|
#include <stropts.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "pcap-int.h"
|
|
|
|
#include "dlpisubs.h"
|
|
|
|
|
|
|
|
/* Forwards. */
|
|
|
|
static int pcap_read_libdlpi(pcap_t *, int, pcap_handler, u_char *);
|
|
|
|
static int pcap_inject_libdlpi(pcap_t *, const void *, size_t);
|
|
|
|
static void pcap_close_libdlpi(pcap_t *);
|
|
|
|
static void pcap_libdlpi_err(const char *, const char *, int, char *);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* list_interfaces() will list all the network links that are
|
|
|
|
* available on a system.
|
|
|
|
*/
|
|
|
|
static boolean_t list_interfaces(const char *, void *);
|
|
|
|
|
|
|
|
typedef struct linknamelist {
|
|
|
|
char linkname[DLPI_LINKNAME_MAX];
|
|
|
|
struct linknamelist *lnl_next;
|
|
|
|
} linknamelist_t;
|
|
|
|
|
|
|
|
typedef struct linkwalk {
|
|
|
|
linknamelist_t *lw_list;
|
|
|
|
int lw_err;
|
|
|
|
} linkwalk_t;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The caller of this function should free the memory allocated
|
|
|
|
* for each linknamelist_t "entry" allocated.
|
|
|
|
*/
|
|
|
|
static boolean_t
|
|
|
|
list_interfaces(const char *linkname, void *arg)
|
|
|
|
{
|
|
|
|
linkwalk_t *lwp = arg;
|
|
|
|
linknamelist_t *entry;
|
|
|
|
|
|
|
|
if ((entry = calloc(1, sizeof(linknamelist_t))) == NULL) {
|
|
|
|
lwp->lw_err = ENOMEM;
|
|
|
|
return (B_TRUE);
|
|
|
|
}
|
|
|
|
(void) strlcpy(entry->linkname, linkname, DLPI_LINKNAME_MAX);
|
|
|
|
|
|
|
|
if (lwp->lw_list == NULL) {
|
|
|
|
lwp->lw_list = entry;
|
|
|
|
} else {
|
|
|
|
entry->lnl_next = lwp->lw_list;
|
|
|
|
lwp->lw_list = entry;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (B_FALSE);
|
|
|
|
}
|
|
|
|
|
From Paolo Abeni and me: split pcap_open_live() into a "get a pcap_t
handle" routine, an 'activate a pcap_t handle" routine, and some "set
the properties of the pcap_t handle" routines, so that, for example, the
buffer size can be set on a BPF device before the device is bound to an
interface.
Add additional routines to set monitor mode, and make at least an
initial attempt at supporting that on Linux, *BSD, and Mac OS X 10.4 and
10.5. (Very much "initial" for Linux, which is a twisty little maze of
wireless drivers, many different.)
Have a "timeout" member of the pcap_md structure on all platforms, use
that on Windows instead of the "timeout" member of the pcap_t structure,
and get rid of the "timeout" member of that structure.
2008-04-04 19:37:44 +00:00
|
|
|
static int
|
|
|
|
pcap_activate_libdlpi(pcap_t *p)
|
2008-03-13 18:13:57 +00:00
|
|
|
{
|
|
|
|
int retv;
|
|
|
|
dlpi_handle_t dh;
|
|
|
|
dlpi_info_t dlinfo;
|
Add an error for "you don't have permission to open that device", as
that often means "sorry, this platform requires you to run as root or to
somehow tweak the system to give you capture privileges", and
applications might want to explain that in a way that does a better job
of letting the user know what they have to do.
Try to return or PCAP_ERROR_PERM_DENIED for open errors, rather than
just returning PCAP_ERROR, so that the application can, if it chooses,
try to explain the error better (as those two errors are the ones that
don't mean "there's probably some obscure OS or libpcap problem", but
mean, instead, "you made an error" or "you need to get permission to
capture").
Check for monitor mode *after* checking whether the device exists in the
first place; a non-existent device doesn't support monitor mode, but
that's because it doesn't, well, exist, and the latter would be a more
meaningful error.
Have pcap_open_live() supply an error message for return values other
than PCAP_ERROR, PCAP_ERROR_NO_SUCH_DEVICE, and PCAP_ERROR_PERM_DENIED -
those all supply error strings (PCAP_ERROR because it's for various OS
problems that might require debugging, and the other two because there
might be multiple causes).
2008-04-09 19:58:02 +00:00
|
|
|
int err = PCAP_ERROR;
|
From Paolo Abeni and me: split pcap_open_live() into a "get a pcap_t
handle" routine, an 'activate a pcap_t handle" routine, and some "set
the properties of the pcap_t handle" routines, so that, for example, the
buffer size can be set on a BPF device before the device is bound to an
interface.
Add additional routines to set monitor mode, and make at least an
initial attempt at supporting that on Linux, *BSD, and Mac OS X 10.4 and
10.5. (Very much "initial" for Linux, which is a twisty little maze of
wireless drivers, many different.)
Have a "timeout" member of the pcap_md structure on all platforms, use
that on Windows instead of the "timeout" member of the pcap_t structure,
and get rid of the "timeout" member of that structure.
2008-04-04 19:37:44 +00:00
|
|
|
|
2008-03-13 18:13:57 +00:00
|
|
|
/*
|
|
|
|
* Enable Solaris raw and passive DLPI extensions;
|
|
|
|
* dlpi_open() will not fail if the underlying link does not support
|
|
|
|
* passive mode. See dlpi(7P) for details.
|
|
|
|
*/
|
From Paolo Abeni and me: split pcap_open_live() into a "get a pcap_t
handle" routine, an 'activate a pcap_t handle" routine, and some "set
the properties of the pcap_t handle" routines, so that, for example, the
buffer size can be set on a BPF device before the device is bound to an
interface.
Add additional routines to set monitor mode, and make at least an
initial attempt at supporting that on Linux, *BSD, and Mac OS X 10.4 and
10.5. (Very much "initial" for Linux, which is a twisty little maze of
wireless drivers, many different.)
Have a "timeout" member of the pcap_md structure on all platforms, use
that on Windows instead of the "timeout" member of the pcap_t structure,
and get rid of the "timeout" member of that structure.
2008-04-04 19:37:44 +00:00
|
|
|
retv = dlpi_open(p->opt.source, &dh, DLPI_RAW|DLPI_PASSIVE);
|
2008-03-13 18:13:57 +00:00
|
|
|
if (retv != DLPI_SUCCESS) {
|
Add an error for "you don't have permission to open that device", as
that often means "sorry, this platform requires you to run as root or to
somehow tweak the system to give you capture privileges", and
applications might want to explain that in a way that does a better job
of letting the user know what they have to do.
Try to return or PCAP_ERROR_PERM_DENIED for open errors, rather than
just returning PCAP_ERROR, so that the application can, if it chooses,
try to explain the error better (as those two errors are the ones that
don't mean "there's probably some obscure OS or libpcap problem", but
mean, instead, "you made an error" or "you need to get permission to
capture").
Check for monitor mode *after* checking whether the device exists in the
first place; a non-existent device doesn't support monitor mode, but
that's because it doesn't, well, exist, and the latter would be a more
meaningful error.
Have pcap_open_live() supply an error message for return values other
than PCAP_ERROR, PCAP_ERROR_NO_SUCH_DEVICE, and PCAP_ERROR_PERM_DENIED -
those all supply error strings (PCAP_ERROR because it's for various OS
problems that might require debugging, and the other two because there
might be multiple causes).
2008-04-09 19:58:02 +00:00
|
|
|
if (retv == DLPI_ELINKNAMEINVAL || retv == DLPI_ENOLINK)
|
|
|
|
err = PCAP_ERROR_NO_SUCH_DEVICE;
|
|
|
|
else if (retv == DLPI_SYSERR && errno == EACCES)
|
|
|
|
err = PCAP_ERROR_PERM_DENIED;
|
|
|
|
pcap_libdlpi_err(p->opt.source, "dlpi_open", retv,
|
|
|
|
p->errbuf);
|
|
|
|
return (err);
|
2008-03-13 18:13:57 +00:00
|
|
|
}
|
|
|
|
p->dlpi_hd = dh;
|
|
|
|
|
Add an error for "you don't have permission to open that device", as
that often means "sorry, this platform requires you to run as root or to
somehow tweak the system to give you capture privileges", and
applications might want to explain that in a way that does a better job
of letting the user know what they have to do.
Try to return or PCAP_ERROR_PERM_DENIED for open errors, rather than
just returning PCAP_ERROR, so that the application can, if it chooses,
try to explain the error better (as those two errors are the ones that
don't mean "there's probably some obscure OS or libpcap problem", but
mean, instead, "you made an error" or "you need to get permission to
capture").
Check for monitor mode *after* checking whether the device exists in the
first place; a non-existent device doesn't support monitor mode, but
that's because it doesn't, well, exist, and the latter would be a more
meaningful error.
Have pcap_open_live() supply an error message for return values other
than PCAP_ERROR, PCAP_ERROR_NO_SUCH_DEVICE, and PCAP_ERROR_PERM_DENIED -
those all supply error strings (PCAP_ERROR because it's for various OS
problems that might require debugging, and the other two because there
might be multiple causes).
2008-04-09 19:58:02 +00:00
|
|
|
if (p->opt.rfmon) {
|
|
|
|
/*
|
|
|
|
* This device exists, but we don't support monitor mode
|
|
|
|
* any platforms that support DLPI.
|
|
|
|
*/
|
|
|
|
err = PCAP_ERROR_RFMON_NOTSUP;
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
2008-03-13 18:13:57 +00:00
|
|
|
/* Bind with DLPI_ANY_SAP. */
|
|
|
|
if ((retv = dlpi_bind(p->dlpi_hd, DLPI_ANY_SAP, 0)) != DLPI_SUCCESS) {
|
From Paolo Abeni and me: split pcap_open_live() into a "get a pcap_t
handle" routine, an 'activate a pcap_t handle" routine, and some "set
the properties of the pcap_t handle" routines, so that, for example, the
buffer size can be set on a BPF device before the device is bound to an
interface.
Add additional routines to set monitor mode, and make at least an
initial attempt at supporting that on Linux, *BSD, and Mac OS X 10.4 and
10.5. (Very much "initial" for Linux, which is a twisty little maze of
wireless drivers, many different.)
Have a "timeout" member of the pcap_md structure on all platforms, use
that on Windows instead of the "timeout" member of the pcap_t structure,
and get rid of the "timeout" member of that structure.
2008-04-04 19:37:44 +00:00
|
|
|
pcap_libdlpi_err(p->opt.source, "dlpi_bind", retv, p->errbuf);
|
2008-03-13 18:13:57 +00:00
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Enable promiscuous mode. */
|
From Paolo Abeni and me: split pcap_open_live() into a "get a pcap_t
handle" routine, an 'activate a pcap_t handle" routine, and some "set
the properties of the pcap_t handle" routines, so that, for example, the
buffer size can be set on a BPF device before the device is bound to an
interface.
Add additional routines to set monitor mode, and make at least an
initial attempt at supporting that on Linux, *BSD, and Mac OS X 10.4 and
10.5. (Very much "initial" for Linux, which is a twisty little maze of
wireless drivers, many different.)
Have a "timeout" member of the pcap_md structure on all platforms, use
that on Windows instead of the "timeout" member of the pcap_t structure,
and get rid of the "timeout" member of that structure.
2008-04-04 19:37:44 +00:00
|
|
|
if (p->opt.promisc) {
|
2008-03-13 18:13:57 +00:00
|
|
|
retv = dlpi_promiscon(p->dlpi_hd, DL_PROMISC_PHYS);
|
|
|
|
if (retv != DLPI_SUCCESS) {
|
From Paolo Abeni and me: split pcap_open_live() into a "get a pcap_t
handle" routine, an 'activate a pcap_t handle" routine, and some "set
the properties of the pcap_t handle" routines, so that, for example, the
buffer size can be set on a BPF device before the device is bound to an
interface.
Add additional routines to set monitor mode, and make at least an
initial attempt at supporting that on Linux, *BSD, and Mac OS X 10.4 and
10.5. (Very much "initial" for Linux, which is a twisty little maze of
wireless drivers, many different.)
Have a "timeout" member of the pcap_md structure on all platforms, use
that on Windows instead of the "timeout" member of the pcap_t structure,
and get rid of the "timeout" member of that structure.
2008-04-04 19:37:44 +00:00
|
|
|
pcap_libdlpi_err(p->opt.source,
|
|
|
|
"dlpi_promisc(PHYSICAL)", retv, p->errbuf);
|
2008-03-13 18:13:57 +00:00
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* Try to enable multicast. */
|
|
|
|
retv = dlpi_promiscon(p->dlpi_hd, DL_PROMISC_MULTI);
|
|
|
|
if (retv != DLPI_SUCCESS) {
|
From Paolo Abeni and me: split pcap_open_live() into a "get a pcap_t
handle" routine, an 'activate a pcap_t handle" routine, and some "set
the properties of the pcap_t handle" routines, so that, for example, the
buffer size can be set on a BPF device before the device is bound to an
interface.
Add additional routines to set monitor mode, and make at least an
initial attempt at supporting that on Linux, *BSD, and Mac OS X 10.4 and
10.5. (Very much "initial" for Linux, which is a twisty little maze of
wireless drivers, many different.)
Have a "timeout" member of the pcap_md structure on all platforms, use
that on Windows instead of the "timeout" member of the pcap_t structure,
and get rid of the "timeout" member of that structure.
2008-04-04 19:37:44 +00:00
|
|
|
pcap_libdlpi_err(p->opt.source, "dlpi_promisc(MULTI)",
|
|
|
|
retv, p->errbuf);
|
2008-03-13 18:13:57 +00:00
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Try to enable SAP promiscuity. */
|
|
|
|
if ((retv = dlpi_promiscon(p->dlpi_hd, DL_PROMISC_SAP)) != DLPI_SUCCESS) {
|
|
|
|
if (!promisc) {
|
From Paolo Abeni and me: split pcap_open_live() into a "get a pcap_t
handle" routine, an 'activate a pcap_t handle" routine, and some "set
the properties of the pcap_t handle" routines, so that, for example, the
buffer size can be set on a BPF device before the device is bound to an
interface.
Add additional routines to set monitor mode, and make at least an
initial attempt at supporting that on Linux, *BSD, and Mac OS X 10.4 and
10.5. (Very much "initial" for Linux, which is a twisty little maze of
wireless drivers, many different.)
Have a "timeout" member of the pcap_md structure on all platforms, use
that on Windows instead of the "timeout" member of the pcap_t structure,
and get rid of the "timeout" member of that structure.
2008-04-04 19:37:44 +00:00
|
|
|
pcap_libdlpi_err(p->opt.source, "dlpi_promisc(SAP)",
|
|
|
|
retv, p->errbuf);
|
2008-03-13 18:13:57 +00:00
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Not fatal, since the DL_PROMISC_PHYS mode worked. */
|
|
|
|
fprintf(stderr, "WARNING: dlpi_promisc(SAP) failed on"
|
From Paolo Abeni and me: split pcap_open_live() into a "get a pcap_t
handle" routine, an 'activate a pcap_t handle" routine, and some "set
the properties of the pcap_t handle" routines, so that, for example, the
buffer size can be set on a BPF device before the device is bound to an
interface.
Add additional routines to set monitor mode, and make at least an
initial attempt at supporting that on Linux, *BSD, and Mac OS X 10.4 and
10.5. (Very much "initial" for Linux, which is a twisty little maze of
wireless drivers, many different.)
Have a "timeout" member of the pcap_md structure on all platforms, use
that on Windows instead of the "timeout" member of the pcap_t structure,
and get rid of the "timeout" member of that structure.
2008-04-04 19:37:44 +00:00
|
|
|
" %s:(%s)\n", p->opt.source, dlpi_strerror(retv));
|
2008-03-13 18:13:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Determine link type. */
|
|
|
|
if ((retv = dlpi_info(p->dlpi_hd, &dlinfo, 0)) != DLPI_SUCCESS) {
|
From Paolo Abeni and me: split pcap_open_live() into a "get a pcap_t
handle" routine, an 'activate a pcap_t handle" routine, and some "set
the properties of the pcap_t handle" routines, so that, for example, the
buffer size can be set on a BPF device before the device is bound to an
interface.
Add additional routines to set monitor mode, and make at least an
initial attempt at supporting that on Linux, *BSD, and Mac OS X 10.4 and
10.5. (Very much "initial" for Linux, which is a twisty little maze of
wireless drivers, many different.)
Have a "timeout" member of the pcap_md structure on all platforms, use
that on Windows instead of the "timeout" member of the pcap_t structure,
and get rid of the "timeout" member of that structure.
2008-04-04 19:37:44 +00:00
|
|
|
pcap_libdlpi_err(p->opt.source, "dlpi_info", retv, p->errbuf);
|
2008-03-13 18:13:57 +00:00
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
From Paolo Abeni and me: split pcap_open_live() into a "get a pcap_t
handle" routine, an 'activate a pcap_t handle" routine, and some "set
the properties of the pcap_t handle" routines, so that, for example, the
buffer size can be set on a BPF device before the device is bound to an
interface.
Add additional routines to set monitor mode, and make at least an
initial attempt at supporting that on Linux, *BSD, and Mac OS X 10.4 and
10.5. (Very much "initial" for Linux, which is a twisty little maze of
wireless drivers, many different.)
Have a "timeout" member of the pcap_md structure on all platforms, use
that on Windows instead of the "timeout" member of the pcap_t structure,
and get rid of the "timeout" member of that structure.
2008-04-04 19:37:44 +00:00
|
|
|
if (pcap_process_mactype(p, dlinfo.di_mactype) != 0)
|
2008-03-13 18:13:57 +00:00
|
|
|
goto bad;
|
|
|
|
|
|
|
|
p->fd = dlpi_fd(p->dlpi_hd);
|
|
|
|
|
|
|
|
/* Push and configure bufmod. */
|
From Paolo Abeni and me: split pcap_open_live() into a "get a pcap_t
handle" routine, an 'activate a pcap_t handle" routine, and some "set
the properties of the pcap_t handle" routines, so that, for example, the
buffer size can be set on a BPF device before the device is bound to an
interface.
Add additional routines to set monitor mode, and make at least an
initial attempt at supporting that on Linux, *BSD, and Mac OS X 10.4 and
10.5. (Very much "initial" for Linux, which is a twisty little maze of
wireless drivers, many different.)
Have a "timeout" member of the pcap_md structure on all platforms, use
that on Windows instead of the "timeout" member of the pcap_t structure,
and get rid of the "timeout" member of that structure.
2008-04-04 19:37:44 +00:00
|
|
|
if (pcap_conf_bufmod(p, snaplen, p->md.timeout) != 0)
|
2008-03-13 18:13:57 +00:00
|
|
|
goto bad;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Flush the read side.
|
|
|
|
*/
|
|
|
|
if (ioctl(p->fd, I_FLUSH, FLUSHR) != 0) {
|
From Paolo Abeni and me: split pcap_open_live() into a "get a pcap_t
handle" routine, an 'activate a pcap_t handle" routine, and some "set
the properties of the pcap_t handle" routines, so that, for example, the
buffer size can be set on a BPF device before the device is bound to an
interface.
Add additional routines to set monitor mode, and make at least an
initial attempt at supporting that on Linux, *BSD, and Mac OS X 10.4 and
10.5. (Very much "initial" for Linux, which is a twisty little maze of
wireless drivers, many different.)
Have a "timeout" member of the pcap_md structure on all platforms, use
that on Windows instead of the "timeout" member of the pcap_t structure,
and get rid of the "timeout" member of that structure.
2008-04-04 19:37:44 +00:00
|
|
|
snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "FLUSHR: %s",
|
2008-03-13 18:13:57 +00:00
|
|
|
pcap_strerror(errno));
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Allocate data buffer. */
|
From Paolo Abeni and me: split pcap_open_live() into a "get a pcap_t
handle" routine, an 'activate a pcap_t handle" routine, and some "set
the properties of the pcap_t handle" routines, so that, for example, the
buffer size can be set on a BPF device before the device is bound to an
interface.
Add additional routines to set monitor mode, and make at least an
initial attempt at supporting that on Linux, *BSD, and Mac OS X 10.4 and
10.5. (Very much "initial" for Linux, which is a twisty little maze of
wireless drivers, many different.)
Have a "timeout" member of the pcap_md structure on all platforms, use
that on Windows instead of the "timeout" member of the pcap_t structure,
and get rid of the "timeout" member of that structure.
2008-04-04 19:37:44 +00:00
|
|
|
if (pcap_alloc_databuf(p) != 0)
|
2008-03-13 18:13:57 +00:00
|
|
|
goto bad;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "p->fd" is a FD for a STREAMS device, so "select()" and
|
|
|
|
* "poll()" should work on it.
|
|
|
|
*/
|
|
|
|
p->selectable_fd = p->fd;
|
|
|
|
|
|
|
|
p->read_op = pcap_read_libdlpi;
|
|
|
|
p->inject_op = pcap_inject_libdlpi;
|
|
|
|
p->setfilter_op = install_bpf_program; /* No kernel filtering */
|
|
|
|
p->setdirection_op = NULL; /* Not implemented */
|
|
|
|
p->set_datalink_op = NULL; /* Can't change data link type */
|
|
|
|
p->getnonblock_op = pcap_getnonblock_fd;
|
|
|
|
p->setnonblock_op = pcap_setnonblock_fd;
|
|
|
|
p->stats_op = pcap_stats_dlpi;
|
2008-04-14 20:40:58 +00:00
|
|
|
p->cleanup_op = pcap_cleanup_libdlpi;
|
2008-03-13 18:13:57 +00:00
|
|
|
|
From Paolo Abeni and me: split pcap_open_live() into a "get a pcap_t
handle" routine, an 'activate a pcap_t handle" routine, and some "set
the properties of the pcap_t handle" routines, so that, for example, the
buffer size can be set on a BPF device before the device is bound to an
interface.
Add additional routines to set monitor mode, and make at least an
initial attempt at supporting that on Linux, *BSD, and Mac OS X 10.4 and
10.5. (Very much "initial" for Linux, which is a twisty little maze of
wireless drivers, many different.)
Have a "timeout" member of the pcap_md structure on all platforms, use
that on Windows instead of the "timeout" member of the pcap_t structure,
and get rid of the "timeout" member of that structure.
2008-04-04 19:37:44 +00:00
|
|
|
return (0);
|
2008-03-13 18:13:57 +00:00
|
|
|
bad:
|
2008-04-14 20:40:58 +00:00
|
|
|
pcap_cleanup_libdlpi(p);
|
Add an error for "you don't have permission to open that device", as
that often means "sorry, this platform requires you to run as root or to
somehow tweak the system to give you capture privileges", and
applications might want to explain that in a way that does a better job
of letting the user know what they have to do.
Try to return or PCAP_ERROR_PERM_DENIED for open errors, rather than
just returning PCAP_ERROR, so that the application can, if it chooses,
try to explain the error better (as those two errors are the ones that
don't mean "there's probably some obscure OS or libpcap problem", but
mean, instead, "you made an error" or "you need to get permission to
capture").
Check for monitor mode *after* checking whether the device exists in the
first place; a non-existent device doesn't support monitor mode, but
that's because it doesn't, well, exist, and the latter would be a more
meaningful error.
Have pcap_open_live() supply an error message for return values other
than PCAP_ERROR, PCAP_ERROR_NO_SUCH_DEVICE, and PCAP_ERROR_PERM_DENIED -
those all supply error strings (PCAP_ERROR because it's for various OS
problems that might require debugging, and the other two because there
might be multiple causes).
2008-04-09 19:58:02 +00:00
|
|
|
return (err);
|
2008-03-13 18:13:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* In Solaris, the "standard" mechanism" i.e SIOCGLIFCONF will only find
|
|
|
|
* network links that are plumbed and are up. dlpi_walk(3DLPI) will find
|
|
|
|
* additional network links present in the system.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf)
|
|
|
|
{
|
|
|
|
int retv = 0;
|
|
|
|
|
|
|
|
linknamelist_t *entry, *next;
|
|
|
|
linkwalk_t lw = {NULL, 0};
|
|
|
|
int save_errno;
|
|
|
|
|
|
|
|
/* dlpi_walk() for loopback will be added here. */
|
|
|
|
|
|
|
|
dlpi_walk(list_interfaces, &lw, 0);
|
|
|
|
|
|
|
|
if (lw.lw_err != 0) {
|
|
|
|
snprintf(errbuf, PCAP_ERRBUF_SIZE,
|
|
|
|
"dlpi_walk: %s", pcap_strerror(lw.lw_err));
|
|
|
|
retv = -1;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add linkname if it does not exist on the list. */
|
|
|
|
for (entry = lw.lw_list; entry != NULL; entry = entry->lnl_next) {
|
|
|
|
if (pcap_add_if(alldevsp, entry->linkname, 0, NULL, errbuf) < 0)
|
|
|
|
retv = -1;
|
|
|
|
}
|
|
|
|
done:
|
|
|
|
save_errno = errno;
|
|
|
|
for (entry = lw.lw_list; entry != NULL; entry = next) {
|
|
|
|
next = entry->lnl_next;
|
|
|
|
free(entry);
|
|
|
|
}
|
|
|
|
errno = save_errno;
|
|
|
|
|
|
|
|
return (retv);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read data received on DLPI handle. Returns -2 if told to terminate, else
|
|
|
|
* returns the number of packets read.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
pcap_read_libdlpi(pcap_t *p, int count, pcap_handler callback, u_char *user)
|
|
|
|
{
|
|
|
|
int len;
|
|
|
|
u_char *bufp;
|
|
|
|
size_t msglen;
|
|
|
|
int retv;
|
|
|
|
|
|
|
|
len = p->cc;
|
|
|
|
if (len != 0) {
|
|
|
|
bufp = p->bp;
|
|
|
|
goto process_pkts;
|
|
|
|
}
|
|
|
|
do {
|
|
|
|
/* Has "pcap_breakloop()" been called? */
|
|
|
|
if (p->break_loop) {
|
|
|
|
/*
|
|
|
|
* Yes - clear the flag that indicates that it has,
|
|
|
|
* and return -2 to indicate that we were told to
|
|
|
|
* break out of the loop.
|
|
|
|
*/
|
|
|
|
p->break_loop = 0;
|
|
|
|
return (-2);
|
|
|
|
}
|
|
|
|
|
|
|
|
msglen = p->bufsize;
|
|
|
|
bufp = p->buffer + p->offset;
|
|
|
|
|
|
|
|
retv = dlpi_recv(p->dlpi_hd, NULL, NULL, bufp,
|
|
|
|
&msglen, -1, NULL);
|
|
|
|
if (retv != DLPI_SUCCESS) {
|
|
|
|
/*
|
|
|
|
* This is most likely a call to terminate out of the
|
|
|
|
* loop. So, do not return an error message, instead
|
|
|
|
* check if "pcap_breakloop()" has been called above.
|
|
|
|
*/
|
|
|
|
if (retv == DL_SYSERR && errno == EINTR) {
|
|
|
|
len = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
pcap_libdlpi_err(dlpi_linkname(p->dlpi_hd),
|
|
|
|
"dlpi_recv", retv, p->errbuf);
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
len = msglen;
|
|
|
|
} while (len == 0);
|
|
|
|
|
|
|
|
process_pkts:
|
|
|
|
return (pcap_process_pkts(p, callback, user, count, bufp, len));
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
pcap_inject_libdlpi(pcap_t *p, const void *buf, size_t size)
|
|
|
|
{
|
|
|
|
int retv;
|
|
|
|
|
|
|
|
retv = dlpi_send(p->dlpi_hd, NULL, 0, buf, size, NULL);
|
|
|
|
if (retv != DLPI_SUCCESS) {
|
|
|
|
pcap_libdlpi_err(dlpi_linkname(p->dlpi_hd), "dlpi_send", retv,
|
|
|
|
p->errbuf);
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* dlpi_send(3DLPI) does not provide a way to return the number of
|
|
|
|
* bytes sent on the wire. Based on the fact that DLPI_SUCCESS was
|
|
|
|
* returned we are assuming 'size' bytes were sent.
|
|
|
|
*/
|
|
|
|
return (size);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2008-04-14 20:40:58 +00:00
|
|
|
* Close dlpi handle.
|
2008-03-13 18:13:57 +00:00
|
|
|
*/
|
|
|
|
static void
|
2008-04-14 20:40:58 +00:00
|
|
|
pcap_cleanup_libdlpi(pcap_t *p)
|
2008-03-13 18:13:57 +00:00
|
|
|
{
|
2008-04-14 20:40:58 +00:00
|
|
|
if (p->dlpi_hd != NULL) {
|
|
|
|
dlpi_close(p->dlpi_hd);
|
|
|
|
p->dlpi_hd = NULL;
|
|
|
|
p->fd = -1;
|
|
|
|
}
|
|
|
|
pcap_cleanup_live_common(p);
|
2008-03-13 18:13:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Write error message to buffer.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
pcap_libdlpi_err(const char *linkname, const char *func, int err, char *errbuf)
|
|
|
|
{
|
|
|
|
snprintf(errbuf, PCAP_ERRBUF_SIZE, "libpcap: %s failed on %s: %s",
|
|
|
|
func, linkname, dlpi_strerror(err));
|
|
|
|
}
|
From Paolo Abeni and me: split pcap_open_live() into a "get a pcap_t
handle" routine, an 'activate a pcap_t handle" routine, and some "set
the properties of the pcap_t handle" routines, so that, for example, the
buffer size can be set on a BPF device before the device is bound to an
interface.
Add additional routines to set monitor mode, and make at least an
initial attempt at supporting that on Linux, *BSD, and Mac OS X 10.4 and
10.5. (Very much "initial" for Linux, which is a twisty little maze of
wireless drivers, many different.)
Have a "timeout" member of the pcap_md structure on all platforms, use
that on Windows instead of the "timeout" member of the pcap_t structure,
and get rid of the "timeout" member of that structure.
2008-04-04 19:37:44 +00:00
|
|
|
|
|
|
|
pcap_t *
|
|
|
|
pcap_create(const char *device, char *ebuf)
|
|
|
|
{
|
|
|
|
pcap_t *p;
|
|
|
|
|
|
|
|
p = pcap_create_common(device, ebuf);
|
|
|
|
if (p == NULL)
|
|
|
|
return (NULL);
|
|
|
|
|
|
|
|
p->activate_op = pcap_activate_libdlpi;
|
|
|
|
return (p);
|
|
|
|
}
|