summaryrefslogtreecommitdiffstats
path: root/contrib/libpcap/pcap-dlpi.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/libpcap/pcap-dlpi.c')
-rw-r--r--contrib/libpcap/pcap-dlpi.c334
1 files changed, 298 insertions, 36 deletions
diff --git a/contrib/libpcap/pcap-dlpi.c b/contrib/libpcap/pcap-dlpi.c
index f8a917a..c927629 100644
--- a/contrib/libpcap/pcap-dlpi.c
+++ b/contrib/libpcap/pcap-dlpi.c
@@ -19,7 +19,9 @@
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* This code contributed by Atanu Ghosh (atanu@cs.ucl.ac.uk),
- * University College London.
+ * University College London, and subsequently modified by
+ * Guy Harris (guy@alum.mit.edu) and Mark Pizzolato
+ * <List-tcpdump-workers@subscriptions.pizzolato.net>.
*/
/*
@@ -27,18 +29,40 @@
*
* Notes:
*
- * - Apparently the DLIOCRAW ioctl() is specific to SunOS.
+ * - The DLIOCRAW ioctl() is specific to SunOS.
*
* - There is a bug in bufmod(7) such that setting the snapshot
* length results in data being left of the front of the packet.
*
* - It might be desirable to use pfmod(7) to filter packets in the
* kernel when possible.
+ *
+ * - The HP-UX 10.20 DLPI Programmer's Guide used to be available
+ * at
+ *
+ * http://docs.hp.com/hpux/onlinedocs/B2355-90093/B2355-90093.html
+ *
+ * but is no longer available; it can still be found at
+ *
+ * http://h21007.www2.hp.com/dspp/files/unprotected/Drivers/Docs/Refs/B2355-90093.pdf
+ *
+ * in PDF form.
+ *
+ * - The HP-UX 11.00 DLPI Programmer's Guide is available at
+ *
+ * http://docs.hp.com/hpux/onlinedocs/B2355-90139/B2355-90139.html
+ *
+ * and in PDF form at
+ *
+ * http://h21007.www2.hp.com/dspp/files/unprotected/Drivers/Docs/Refs/B2355-90139.pdf
+ *
+ * - Both of the HP documents describe raw-mode services, which are
+ * what we use if DL_HP_RAWDLS is defined.
*/
#ifndef lint
static const char rcsid[] _U_ =
- "@(#) $Header: /tcpdump/master/libpcap/pcap-dlpi.c,v 1.91.2.3 2003/11/21 10:20:46 guy Exp $ (LBL)";
+ "@(#) $Header: /tcpdump/master/libpcap/pcap-dlpi.c,v 1.108 2004/10/19 07:06:12 guy Exp $ (LBL)";
#endif
#ifdef HAVE_CONFIG_H
@@ -57,7 +81,7 @@ static const char rcsid[] _U_ =
#ifdef HAVE_HPUX9
#include <sys/socket.h>
#endif
-#ifdef DL_HP_PPA_ACK_OBS
+#ifdef DL_HP_PPA_REQ
#include <sys/stat.h>
#endif
#include <sys/stream.h>
@@ -82,6 +106,12 @@ static const char rcsid[] _U_ =
#include <stropts.h>
#include <unistd.h>
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#else
+#define INT_MAX 2147483647
+#endif
+
#include "pcap-int.h"
#ifdef HAVE_OS_PROTO_H
@@ -127,16 +157,20 @@ static const char rcsid[] _U_ =
/* Forwards */
static char *split_dname(char *, int *, char *);
+static int dl_doattach(int, int, char *);
static int dlattachreq(int, bpf_u_int32, char *);
-static int dlbindack(int, char *, char *);
static int dlbindreq(int, bpf_u_int32, char *);
-static int dlinfoack(int, char *, char *);
-static int dlinforeq(int, char *);
+static int dlbindack(int, char *, char *);
+static int dlpromisconreq(int, bpf_u_int32, char *);
static int dlokack(int, const char *, char *, char *);
+static int dlinforeq(int, char *);
+static int dlinfoack(int, char *, char *);
+#ifdef DL_HP_RAWDLS
+static int dlrawdatareq(int, const u_char *, int);
+#endif
static int recv_ack(int, int, const char *, char *, char *);
static char *dlstrerror(bpf_u_int32);
static char *dlprim(bpf_u_int32);
-static int dlpromisconreq(int, bpf_u_int32, char *);
#if defined(HAVE_SOLARIS) && defined(HAVE_SYS_BUFMOD_H)
static char *get_release(bpf_u_int32 *, bpf_u_int32 *, bpf_u_int32 *);
#endif
@@ -158,21 +192,32 @@ pcap_stats_dlpi(pcap_t *p, struct pcap_stat *ps)
/*
* "ps_recv" counts packets handed to the filter, not packets
* that passed the filter. As filtering is done in userland,
- * this does not include packets dropped because we ran out
- * of buffer space.
+ * this would not include packets dropped because we ran out
+ * of buffer space; in order to make this more like other
+ * platforms (Linux 2.4 and later, BSDs with BPF), where the
+ * "packets received" count includes packets received but dropped
+ * due to running out of buffer space, and to keep from confusing
+ * applications that, for example, compute packet drop percentages,
+ * we also make it count packets dropped by "bufmod" (otherwise we
+ * might run the risk of the packet drop count being bigger than
+ * the received-packet count).
*
- * "ps_drop" counts packets dropped inside the DLPI service
- * provider device device because of flow control requirements
- * or resource exhaustion; it doesn't count packets dropped by
- * the interface driver, or packets dropped upstream. As
- * filtering is done in userland, it counts packets regardless
- * of whether they would've passed the filter.
+ * "ps_drop" counts packets dropped by "bufmod" because of
+ * flow control requirements or resource exhaustion; it doesn't
+ * count packets dropped by the interface driver, or packets
+ * dropped upstream. As filtering is done in userland, it counts
+ * packets regardless of whether they would've passed the filter.
*
* These statistics don't include packets not yet read from
* the kernel by libpcap, but they may include packets not
* yet read from libpcap by the application.
*/
*ps = p->md.stat;
+
+ /*
+ * Add in the drop count, as per the above comment.
+ */
+ ps->ps_recv += ps->ps_drop;
return (0);
}
@@ -220,11 +265,21 @@ pcap_read_dlpi(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
p->break_loop = 0;
return (-2);
}
+ /*
+ * XXX - check for the DLPI primitive, which
+ * would be DL_HP_RAWDATA_IND on HP-UX
+ * if we're in raw mode?
+ */
if (getmsg(p->fd, &ctl, &data, &flags) < 0) {
/* Don't choke when we get ptraced */
- if (errno == EINTR) {
+ switch (errno) {
+
+ case EINTR:
cc = 0;
continue;
+
+ case EAGAIN:
+ return (0);
}
strlcpy(p->errbuf, pcap_strerror(errno),
sizeof(p->errbuf));
@@ -306,6 +361,58 @@ pcap_read_dlpi(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
return (n);
}
+static int
+pcap_inject_dlpi(pcap_t *p, const void *buf, size_t size)
+{
+ int ret;
+
+#if defined(DLIOCRAW)
+ ret = write(p->fd, buf, size);
+ if (ret == -1) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: %s",
+ pcap_strerror(errno));
+ return (-1);
+ }
+#elif defined(DL_HP_RAWDLS)
+ if (p->send_fd < 0) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "send: Output FD couldn't be opened");
+ return (-1);
+ }
+ ret = dlrawdatareq(p->send_fd, buf, size);
+ if (ret == -1) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: %s",
+ pcap_strerror(errno));
+ return (-1);
+ }
+#else /* no raw mode */
+ /*
+ * XXX - this is a pain, because you might have to extract
+ * the address from the packet and use it in a DL_UNITDATA_REQ
+ * request. That would be dependent on the link-layer type.
+ *
+ * I also don't know what SAP you'd have to bind the descriptor
+ * to, or whether you'd need separate "receive" and "send" FDs,
+ * nor do I know whether you'd need different bindings for
+ * D/I/X Ethernet and 802.3, or for {FDDI,Token Ring} plus
+ * 802.2 and {FDDI,Token Ring} plus 802.2 plus SNAP.
+ *
+ * So, for now, we just return a "you can't send" indication,
+ * and leave it up to somebody with a DLPI-based system lacking
+ * both DLIOCRAW and DL_HP_RAWDLS to supply code to implement
+ * packet transmission on that system. If they do, they should
+ * send it to us - but should not send us code that assumes
+ * Ethernet; if the code doesn't work on non-Ethernet interfaces,
+ * it should check "p->linktype" and reject the send request if
+ * it's anything other than DLT_EN10MB.
+ */
+ strlcpy(p->errbuf, "send: Not supported on this version of this OS",
+ PCAP_ERRBUF_SIZE);
+ ret = -1;
+#endif /* raw mode */
+ return (ret);
+}
+
#ifndef DL_IPATM
#define DL_IPATM 0x12 /* ATM Classical IP interface */
#endif
@@ -325,10 +432,9 @@ pcap_read_dlpi(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
static void
pcap_close_dlpi(pcap_t *p)
{
- if (p->buffer != NULL)
- free(p->buffer);
- if (p->fd >= 0)
- close(p->fd);
+ pcap_close_common(p);
+ if (p->send_fd >= 0)
+ close(p->send_fd);
}
pcap_t *
@@ -362,6 +468,7 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
}
memset(p, 0, sizeof(*p));
p->fd = -1; /* indicate that it hasn't been opened yet */
+ p->send_fd = -1;
#ifdef HAVE_DEV_DLPI
/*
@@ -400,6 +507,22 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
goto bad;
}
+#ifdef DL_HP_RAWDLS
+ /*
+ * XXX - HP-UX 10.20 and 11.xx don't appear to support sending and
+ * receiving packets on the same descriptor - you have to bind the
+ * descriptor on which you receive to a SAP of 22 and bind the
+ * descriptor on which you send to a SAP of 24.
+ *
+ * If the open fails, we just leave -1 in "p->send_fd" and reject
+ * attempts to send packets, just as if, in pcap-bpf.c, we fail
+ * to open the BPF device for reading and writing, we just try
+ * to open it for reading only and, if that succeeds, just let
+ * the send attempts fail.
+ */
+ p->send_fd = open(cp, O_RDWR);
+#endif
+
/*
* Get a table of all PPAs for that device, and search that
* table for the specified device type name and unit number.
@@ -445,8 +568,28 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
/* Try again with unit number */
if ((p->fd = open(dname2, O_RDWR)) < 0) {
- snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s: %s", dname2,
- pcap_strerror(errno));
+ if (errno == ENOENT) {
+ /*
+ * We just report "No DLPI device found"
+ * with the device name, so people don't
+ * get confused and think, for example,
+ * that if they can't capture on "lo0"
+ * on Solaris the fix is to change libpcap
+ * (or the application that uses it) to
+ * look for something other than "/dev/lo0",
+ * as the fix is to look for an operating
+ * system other than Solaris - you just
+ * *can't* capture on a loopback interface
+ * on Solaris, the lack of a DLPI device
+ * for the loopback interface is just a
+ * symptom of that inability.
+ */
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "%s: No DLPI device found", device);
+ } else {
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s: %s",
+ dname2, pcap_strerror(errno));
+ }
goto bad;
}
/* XXX Assume unit zero */
@@ -467,10 +610,17 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
if (infop->dl_mac_type == DL_IPATM)
isatm = 1;
#endif
- if (infop->dl_provider_style == DL_STYLE2 &&
- (dlattachreq(p->fd, ppa, ebuf) < 0 ||
- dlokack(p->fd, "attach", (char *)buf, ebuf) < 0))
- goto bad;
+ if (infop->dl_provider_style == DL_STYLE2) {
+ if (dl_doattach(p->fd, ppa, ebuf) < 0)
+ goto bad;
+#ifdef DL_HP_RAWDLS
+ if (p->send_fd >= 0) {
+ if (dl_doattach(p->send_fd, ppa, ebuf) < 0)
+ goto bad;
+ }
+#endif
+ }
+
/*
** Bind (defer if using HP-UX 9 or HP-UX 10.20, totally skip if
** using SINIX)
@@ -495,12 +645,34 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
*/
if ((dlbindreq(p->fd, 1537, ebuf) < 0 &&
dlbindreq(p->fd, 2, ebuf) < 0) ||
-#else
+ dlbindack(p->fd, (char *)buf, ebuf) < 0)
+ goto bad;
+#elif defined(DL_HP_RAWDLS)
+ /*
+ ** This is the descriptor on which we receive packets; we
+ ** bind it to 22, as that's INSAP, as per the HP-UX DLPI
+ ** Programmer's Guide.
+ */
+ if (dlbindreq(p->fd, 22, ebuf) < 0 ||
+ dlbindack(p->fd, (char *)buf, ebuf) < 0)
+ goto bad;
+
+ if (p->send_fd >= 0) {
+ /*
+ ** This is the descriptor on which we send packets; we
+ ** bind it to 24, as that's OUTSAP, as per the HP-UX
+ ** DLPI Programmer's Guide.
+ */
+ if (dlbindreq(p->send_fd, 24, ebuf) < 0 ||
+ dlbindack(p->send_fd, (char *)buf, ebuf) < 0)
+ goto bad;
+ }
+#else /* neither AIX nor HP-UX */
if (dlbindreq(p->fd, 0, ebuf) < 0 ||
-#endif
dlbindack(p->fd, (char *)buf, ebuf) < 0)
goto bad;
-#endif
+#endif /* SAP to bind to */
+#endif /* HP-UX 9 or 10.20 or SINIX */
#ifdef HAVE_SOLARIS
if (isatm) {
@@ -519,7 +691,7 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
#endif
if (promisc) {
/*
- ** Enable promiscuous
+ ** Enable promiscuous (not necessary on send FD)
*/
if (dlpromisconreq(p->fd, DL_PROMISC_PHYS, ebuf) < 0 ||
dlokack(p->fd, "promisc_phys", (char *)buf, ebuf) < 0)
@@ -528,7 +700,7 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
/*
** Try to enable multicast (you would have thought
** promiscuous would be sufficient). (Skip if using
- ** HP-UX or SINIX)
+ ** HP-UX or SINIX) (Not necessary on send FD)
*/
#if !defined(__hpux) && !defined(sinix)
if (dlpromisconreq(p->fd, DL_PROMISC_MULTI, ebuf) < 0 ||
@@ -540,7 +712,7 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
/*
** Try to enable sap (when not in promiscuous mode when using
** using HP-UX, when not doing SunATM on Solaris, and never
- ** under SINIX)
+ ** under SINIX) (Not necessary on send FD)
*/
#ifndef sinix
if (
@@ -573,6 +745,8 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
/*
** Determine link type
+ ** XXX - get SAP length and address length as well, for use
+ ** when sending packets.
*/
if (dlinforeq(p->fd, ebuf) < 0 ||
dlinfoack(p->fd, (char *)buf, ebuf) < 0)
@@ -585,6 +759,25 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
case DL_ETHER:
p->linktype = DLT_EN10MB;
p->offset = 2;
+ /*
+ * This is (presumably) a real Ethernet capture; give it a
+ * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so
+ * that an application can let you choose it, in case you're
+ * capturing DOCSIS traffic that a Cisco Cable Modem
+ * Termination System is putting out onto an Ethernet (it
+ * doesn't put an Ethernet header onto the wire, it puts raw
+ * DOCSIS frames out on the wire inside the low-level
+ * Ethernet framing).
+ */
+ p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2);
+ /*
+ * If that fails, just leave the list empty.
+ */
+ if (p->dlt_list != NULL) {
+ p->dlt_list[0] = DLT_EN10MB;
+ p->dlt_list[1] = DLT_DOCSIS;
+ p->dlt_count = 2;
+ }
break;
case DL_FDDI:
@@ -593,6 +786,9 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
break;
case DL_TPR:
+ /*
+ * XXX - what about DL_TPB? Is that Token Bus?
+ */
p->linktype = DLT_IEEE802;
p->offset = 2;
break;
@@ -711,6 +907,7 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
p->selectable_fd = p->fd;
p->read_op = pcap_read_dlpi;
+ p->inject_op = pcap_inject_dlpi;
p->setfilter_op = install_bpf_program; /* no kernel filtering */
p->set_datalink_op = NULL; /* can't change data link type */
p->getnonblock_op = pcap_getnonblock_fd;
@@ -722,6 +919,13 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
bad:
if (p->fd >= 0)
close(p->fd);
+ if (p->send_fd >= 0)
+ close(p->send_fd);
+ /*
+ * Get rid of any link-layer type list we allocated.
+ */
+ if (p->dlt_list != NULL)
+ free(p->dlt_list);
free(p);
return (NULL);
}
@@ -739,7 +943,7 @@ split_dname(char *device, int *unitp, char *ebuf)
{
char *cp;
char *eos;
- int unit;
+ long unit;
/*
* Look for a number at the end of the device name string.
@@ -755,15 +959,37 @@ split_dname(char *device, int *unitp, char *ebuf)
while (cp-1 >= device && *(cp-1) >= '0' && *(cp-1) <= '9')
cp--;
+ errno = 0;
unit = strtol(cp, &eos, 10);
if (*eos != '\0') {
snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s bad unit number", device);
return (NULL);
}
- *unitp = unit;
+ if (errno == ERANGE || unit > INT_MAX) {
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s unit number too large",
+ device);
+ return (NULL);
+ }
+ if (unit < 0) {
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s unit number is negative",
+ device);
+ return (NULL);
+ }
+ *unitp = (int)unit;
return (cp);
}
+static int
+dl_doattach(int fd, int ppa, char *ebuf)
+{
+ bpf_u_int32 buf[MAXDLBUF];
+
+ if (dlattachreq(fd, ppa, ebuf) < 0 ||
+ dlokack(fd, "attach", (char *)buf, ebuf) < 0)
+ return (-1);
+ return (0);
+}
+
int
pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf)
{
@@ -1170,6 +1396,42 @@ dlinfoack(int fd, char *bufp, char *ebuf)
return (recv_ack(fd, DL_INFO_ACK_SIZE, "info", bufp, ebuf));
}
+#ifdef DL_HP_RAWDLS
+/*
+ * There's an ack *if* there's an error.
+ */
+static int
+dlrawdatareq(int fd, const u_char *datap, int datalen)
+{
+ struct strbuf ctl, data;
+ long buf[MAXDLBUF]; /* XXX - char? */
+ union DL_primitives *dlp;
+ int dlen;
+
+ dlp = (union DL_primitives*) buf;
+
+ dlp->dl_primitive = DL_HP_RAWDATA_REQ;
+ dlen = DL_HP_RAWDATA_REQ_SIZE;
+
+ /*
+ * HP's documentation doesn't appear to show us supplying any
+ * address pointed to by the control part of the message.
+ * I think that's what raw mode means - you just send the raw
+ * packet, you don't specify where to send it to, as that's
+ * implied by the destination address.
+ */
+ ctl.maxlen = 0;
+ ctl.len = dlen;
+ ctl.buf = (void *)buf;
+
+ data.maxlen = 0;
+ data.len = datalen;
+ data.buf = (void *)datap;
+
+ return (putmsg(fd, &ctl, &data, 0));
+}
+#endif /* DL_HP_RAWDLS */
+
#ifdef HAVE_SYS_BUFMOD_H
static int
strioctl(int fd, int cmd, int len, char *dp)
@@ -1216,7 +1478,7 @@ get_release(bpf_u_int32 *majorp, bpf_u_int32 *minorp, bpf_u_int32 *microp)
}
#endif
-#ifdef DL_HP_PPA_ACK_OBS
+#ifdef DL_HP_PPA_REQ
/*
* Under HP-UX 10 and HP-UX 11, we can ask for the ppa
*/
OpenPOWER on IntegriCloud