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.c299
1 files changed, 232 insertions, 67 deletions
diff --git a/contrib/libpcap/pcap-dlpi.c b/contrib/libpcap/pcap-dlpi.c
index 4692b9c..1a152bc 100644
--- a/contrib/libpcap/pcap-dlpi.c
+++ b/contrib/libpcap/pcap-dlpi.c
@@ -38,7 +38,11 @@
#ifndef lint
static const char rcsid[] =
- "@(#) $Header: /tcpdump/master/libpcap/pcap-dlpi.c,v 1.52.1.1 1999/10/07 23:46:40 mcr Exp $ (LBL)";
+ "@(#) $Header: /tcpdump/master/libpcap/pcap-dlpi.c,v 1.63 2000/11/22 05:32:55 guy Exp $ (LBL)";
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
#endif
#include <sys/types.h>
@@ -80,7 +84,6 @@ static const char rcsid[] =
#include "pcap-int.h"
-#include "gnuc.h"
#ifdef HAVE_OS_PROTO_H
#include "os-proto.h"
#endif
@@ -159,7 +162,8 @@ pcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
cc = 0;
continue;
}
- strcpy(p->errbuf, pcap_strerror(errno));
+ strlcpy(p->errbuf, pcap_strerror(errno),
+ sizeof(p->errbuf));
return (-1);
}
cc = data.len;
@@ -241,54 +245,101 @@ pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)
p = (pcap_t *)malloc(sizeof(*p));
if (p == NULL) {
- strcpy(ebuf, pcap_strerror(errno));
+ strlcpy(ebuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE);
return (NULL);
}
memset(p, 0, sizeof(*p));
+#ifdef HAVE_DEV_DLPI
/*
- ** Determine device and ppa
+ ** Remove any "/dev/" on the front of the device.
*/
- cp = strpbrk(device, "0123456789");
+ cp = strrchr(device, '/');
+ if (cp == NULL)
+ cp = device;
+ else
+ cp++;
+ strlcpy(dname, cp, sizeof(dname));
+
+ /*
+ * Split the name into a device type and a unit number.
+ */
+ cp = strpbrk(dname, "0123456789");
if (cp == NULL) {
- sprintf(ebuf, "%s missing unit number", device);
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "%s missing unit number", device);
goto bad;
}
ppa = strtol(cp, &eos, 10);
if (*eos != '\0') {
- sprintf(ebuf, "%s bad unit number", device);
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "%s bad unit number", device);
goto bad;
}
+ *cp = '\0';
- if (*device == '/')
- strcpy(dname, device);
- else
- sprintf(dname, "%s/%s", PCAP_DEV_PREFIX, device);
-#ifdef HAVE_DEV_DLPI
- /* Map network device to /dev/dlpi unit */
+ /*
+ * Use "/dev/dlpi" as the device.
+ *
+ * XXX - HP's DLPI Programmer's Guide for HP-UX 11.00 says that
+ * the "dl_mjr_num" field is for the "major number of interface
+ * driver"; that's the major of "/dev/dlpi" on the system on
+ * which I tried this, but there may be DLPI devices that
+ * use a different driver, in which case we may need to
+ * search "/dev" for the appropriate device with that major
+ * device number, rather than hardwiring "/dev/dlpi".
+ */
cp = "/dev/dlpi";
if ((p->fd = open(cp, O_RDWR)) < 0) {
- sprintf(ebuf, "%s: %s", cp, pcap_strerror(errno));
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "%s: %s", cp, pcap_strerror(errno));
goto bad;
}
- /* Map network interface to /dev/dlpi unit */
+
+ /*
+ * Get a table of all PPAs for that device, and search that
+ * table for the specified device type name and unit number.
+ */
ppa = get_dlpi_ppa(p->fd, dname, ppa, ebuf);
if (ppa < 0)
goto bad;
#else
+ /*
+ ** Determine device and ppa
+ */
+ cp = strpbrk(device, "0123456789");
+ if (cp == NULL) {
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s missing unit number",
+ device);
+ goto bad;
+ }
+ ppa = strtol(cp, &eos, 10);
+ if (*eos != '\0') {
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s bad unit number", device);
+ goto bad;
+ }
+
+ if (*device == '/')
+ strlcpy(dname, device, sizeof(dname));
+ else
+ snprintf(dname, sizeof(dname), "%s/%s", PCAP_DEV_PREFIX,
+ device);
+
/* Try device without unit number */
- strcpy(dname2, dname);
+ strlcpy(dname2, dname, sizeof(dname2));
cp = strchr(dname, *cp);
*cp = '\0';
if ((p->fd = open(dname, O_RDWR)) < 0) {
if (errno != ENOENT) {
- sprintf(ebuf, "%s: %s", dname, pcap_strerror(errno));
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s: %s", dname,
+ pcap_strerror(errno));
goto bad;
}
/* Try again with unit number */
if ((p->fd = open(dname2, O_RDWR)) < 0) {
- sprintf(ebuf, "%s: %s", dname2, pcap_strerror(errno));
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s: %s", dname2,
+ pcap_strerror(errno));
goto bad;
}
/* XXX Assume unit zero */
@@ -314,7 +365,14 @@ pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)
** using SINIX)
*/
#if !defined(HAVE_HPUX9) && !defined(HAVE_HPUX10_20) && !defined(sinix)
+#ifdef _AIX
+ /* According to IBM's AIX Support Line, the dl_sap value
+ ** should not be less than 0x600 (1536) for standard ethernet
+ */
+ if (dlbindreq(p->fd, 1537, ebuf) < 0 ||
+#else
if (dlbindreq(p->fd, 0, ebuf) < 0 ||
+#endif
dlbindack(p->fd, (char *)buf, ebuf) < 0)
goto bad;
#endif
@@ -391,7 +449,8 @@ pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)
break;
default:
- sprintf(ebuf, "unknown mac type 0x%lu", infop->dl_mac_type);
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "unknown mac type %lu",
+ infop->dl_mac_type);
goto bad;
}
@@ -400,7 +459,8 @@ pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)
** This is a non standard SunOS hack to get the ethernet header.
*/
if (strioctl(p->fd, DLIOCRAW, 0, NULL) < 0) {
- sprintf(ebuf, "DLIOCRAW: %s", pcap_strerror(errno));
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "DLIOCRAW: %s",
+ pcap_strerror(errno));
goto bad;
}
#endif
@@ -410,7 +470,8 @@ pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)
** Another non standard call to get the data nicely buffered
*/
if (ioctl(p->fd, I_PUSH, "bufmod") != 0) {
- sprintf(ebuf, "I_PUSH bufmod: %s", pcap_strerror(errno));
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "I_PUSH bufmod: %s",
+ pcap_strerror(errno));
goto bad;
}
@@ -437,7 +498,8 @@ pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)
#endif
if (ss > 0 &&
strioctl(p->fd, SBIOCSSNAP, sizeof(ss), (char *)&ss) != 0) {
- sprintf(ebuf, "SBIOCSSNAP: %s", pcap_strerror(errno));
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "SBIOCSSNAP: %s",
+ pcap_strerror(errno));
goto bad;
}
@@ -445,12 +507,14 @@ pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)
** Set up the bufmod flags
*/
if (strioctl(p->fd, SBIOCGFLAGS, sizeof(flag), (char *)&flag) < 0) {
- sprintf(ebuf, "SBIOCGFLAGS: %s", pcap_strerror(errno));
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "SBIOCGFLAGS: %s",
+ pcap_strerror(errno));
goto bad;
}
flag |= SB_NO_DROPS;
if (strioctl(p->fd, SBIOCSFLAGS, sizeof(flag), (char *)&flag) != 0) {
- sprintf(ebuf, "SBIOCSFLAGS: %s", pcap_strerror(errno));
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "SBIOCSFLAGS: %s",
+ pcap_strerror(errno));
goto bad;
}
/*
@@ -462,7 +526,8 @@ pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)
to.tv_sec = to_ms / 1000;
to.tv_usec = (to_ms * 1000) % 1000000;
if (strioctl(p->fd, SBIOCSTIME, sizeof(to), (char *)&to) != 0) {
- sprintf(ebuf, "SBIOCSTIME: %s", pcap_strerror(errno));
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "SBIOCSTIME: %s",
+ pcap_strerror(errno));
goto bad;
}
}
@@ -472,7 +537,8 @@ pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)
** As the last operation flush the read side.
*/
if (ioctl(p->fd, I_FLUSH, FLUSHR) != 0) {
- sprintf(ebuf, "FLUSHR: %s", pcap_strerror(errno));
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "FLUSHR: %s",
+ pcap_strerror(errno));
goto bad;
}
/* Allocate data buffer */
@@ -489,7 +555,8 @@ int
pcap_setfilter(pcap_t *p, struct bpf_program *fp)
{
- p->fcode = *fp;
+ if (install_bpf_program(p, fp) < 0)
+ return (-1);
return (0);
}
@@ -505,7 +572,8 @@ send_request(int fd, char *ptr, int len, char *what, char *ebuf)
flags = 0;
if (putmsg(fd, &ctl, (struct strbuf *) NULL, flags) < 0) {
- sprintf(ebuf, "send_request: putmsg \"%s\": %s",
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "send_request: putmsg \"%s\": %s",
what, pcap_strerror(errno));
return (-1);
}
@@ -525,7 +593,7 @@ recv_ack(int fd, int size, const char *what, char *bufp, char *ebuf)
flags = 0;
if (getmsg(fd, &ctl, (struct strbuf*)NULL, &flags) < 0) {
- sprintf(ebuf, "recv_ack: %s getmsg: %s",
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "recv_ack: %s getmsg: %s",
what, pcap_strerror(errno));
return (-1);
}
@@ -547,37 +615,40 @@ recv_ack(int fd, int size, const char *what, char *bufp, char *ebuf)
switch (dlp->error_ack.dl_errno) {
case DL_BADPPA:
- sprintf(ebuf, "recv_ack: %s bad ppa (device unit)",
- what);
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "recv_ack: %s bad ppa (device unit)", what);
break;
case DL_SYSERR:
- sprintf(ebuf, "recv_ack: %s: %s",
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "recv_ack: %s: %s",
what, pcap_strerror(dlp->error_ack.dl_unix_errno));
break;
case DL_UNSUPPORTED:
- sprintf(ebuf,
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
"recv_ack: %s: Service not supplied by provider",
what);
break;
default:
- sprintf(ebuf, "recv_ack: %s error 0x%x",
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "recv_ack: %s error 0x%x",
what, (bpf_u_int32)dlp->error_ack.dl_errno);
break;
}
return (-1);
default:
- sprintf(ebuf, "recv_ack: %s unexpected primitive ack 0x%x ",
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "recv_ack: %s unexpected primitive ack 0x%x ",
what, (bpf_u_int32)dlp->dl_primitive);
return (-1);
}
if (ctl.len < size) {
- sprintf(ebuf, "recv_ack: %s ack too small (%d < %d)",
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "recv_ack: %s ack too small (%d < %d)",
what, ctl.len, size);
return (-1);
}
@@ -709,29 +780,57 @@ get_release(bpf_u_int32 *majorp, bpf_u_int32 *minorp, bpf_u_int32 *microp)
#ifdef DL_HP_PPA_ACK_OBS
/*
- * Under HP-UX 10, we can ask for the ppa
+ * Under HP-UX 10 and HP-UX 11, we can ask for the ppa
*/
-/* Determine ppa number that specifies ifname */
+/*
+ * Determine ppa number that specifies ifname.
+ *
+ * If the "dl_hp_ppa_info_t" doesn't have a "dl_module_id_1" member,
+ * the code that's used here is the old code for HP-UX 10.x.
+ *
+ * However, HP-UX 10.20, at least, appears to have such a member
+ * in its "dl_hp_ppa_info_t" structure, so the new code is used.
+ * The new code didn't work on an old 10.20 system on which Rick
+ * Jones of HP tried it, but with later patches installed, it
+ * worked - it appears that the older system had those members but
+ * didn't put anything in them, so, if the search by name fails, we
+ * do the old search.
+ *
+ * Rick suggests that making sure your system is "up on the latest
+ * lancommon/DLPI/driver patches" is probably a good idea; it'd fix
+ * that problem, as well as allowing libpcap to see packets sent
+ * from the system on which the libpcap application is being run.
+ * (On 10.20, in addition to getting the latest patches, you need
+ * to turn the kernel "lanc_outbound_promisc_flag" flag on with ADB;
+ * a posting to "comp.sys.hp.hpux" at
+ *
+ * http://www.deja.com/[ST_rn=ps]/getdoc.xp?AN=558092266
+ *
+ * says that, to see the machine's outgoing traffic, you'd need to
+ * apply the right patches to your system, and also set that variable
+ * with:
+
+echo 'lanc_outbound_promisc_flag/W1' | /usr/bin/adb -w /stand/vmunix /dev/kmem
+
+ * which could be put in, for example, "/sbin/init.d/lan".
+ *
+ * Setting the variable is not necessary on HP-UX 11.x.
+ */
static int
get_dlpi_ppa(register int fd, register const char *device, register int unit,
register char *ebuf)
{
register dl_hp_ppa_ack_t *ap;
- register dl_hp_ppa_info_t *ip;
+ register dl_hp_ppa_info_t *ipstart, *ip;
register int i;
+ char dname[100];
register u_long majdev;
- dl_hp_ppa_req_t req;
struct stat statbuf;
+ dl_hp_ppa_req_t req;
bpf_u_int32 buf[MAXDLBUF];
- if (stat(device, &statbuf) < 0) {
- sprintf(ebuf, "stat: %s: %s", device, pcap_strerror(errno));
- return (-1);
- }
- majdev = major(statbuf.st_rdev);
-
memset((char *)&req, 0, sizeof(req));
req.dl_primitive = DL_HP_PPA_REQ;
@@ -741,20 +840,81 @@ get_dlpi_ppa(register int fd, register const char *device, register int unit,
return (-1);
ap = (dl_hp_ppa_ack_t *)buf;
- ip = (dl_hp_ppa_info_t *)((u_char *)ap + ap->dl_offset);
+ ipstart = (dl_hp_ppa_info_t *)((u_char *)ap + ap->dl_offset);
+ ip = ipstart;
- for(i = 0; i < ap->dl_count; i++) {
- if (ip->dl_mjr_num == majdev && ip->dl_instance_num == unit)
- break;
+#ifdef HAVE_HP_PPA_INFO_T_DL_MODULE_ID_1
+ /*
+ * The "dl_hp_ppa_info_t" structure has a "dl_module_id_1"
+ * member that should, in theory, contain the part of the
+ * name for the device that comes before the unit number,
+ * and should also have a "dl_module_id_2" member that may
+ * contain an alternate name (e.g., I think Ethernet devices
+ * have both "lan", for "lanN", and "snap", for "snapN", with
+ * the former being for Ethernet packets and the latter being
+ * for 802.3/802.2 packets).
+ *
+ * Search for the device that has the specified name and
+ * instance number.
+ */
+ for (i = 0; i < ap->dl_count; i++) {
+ if ((strcmp(ip->dl_module_id_1, device) == 0 ||
+ strcmp(ip->dl_module_id_2, device) == 0) &&
+ ip->dl_instance_num == unit)
+ break;
- ip = (dl_hp_ppa_info_t *)((u_char *)ip + ip->dl_next_offset);
- }
+ ip = (dl_hp_ppa_info_t *)((u_char *)ipstart + ip->dl_next_offset);
+ }
+#else
+ /*
+ * We don't have that member, so the search is impossible; make it
+ * look as if the search failed.
+ */
+ i = ap->dl_count;
+#endif
+
+ if (i == ap->dl_count) {
+ /*
+ * Well, we didn't, or can't, find the device by name.
+ *
+ * HP-UX 10.20, whilst it has "dl_module_id_1" and
+ * "dl_module_id_2" fields in the "dl_hp_ppa_info_t",
+ * doesn't seem to fill them in unless the system is
+ * at a reasonably up-to-date patch level.
+ *
+ * Older HP-UX 10.x systems might not have those fields
+ * at all.
+ *
+ * Therefore, we'll search for the entry with the major
+ * device number of a device with the name "/dev/<dev><unit>",
+ * if such a device exists, as the old code did.
+ */
+ snprintf(dname, sizeof(dname), "/dev/%s%d", device, unit);
+ if (stat(dname, &statbuf) < 0) {
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "stat: %s: %s",
+ dname, pcap_strerror(errno));
+ return (-1);
+ }
+ majdev = major(statbuf.st_rdev);
+
+ ip = ipstart;
+
+ for (i = 0; i < ap->dl_count; i++) {
+ if (ip->dl_mjr_num == majdev &&
+ ip->dl_instance_num == unit)
+ break;
+
+ ip = (dl_hp_ppa_info_t *)((u_char *)ipstart + ip->dl_next_offset);
+ }
+ }
if (i == ap->dl_count) {
- sprintf(ebuf, "can't find PPA for %s", device);
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "can't find /dev/dlpi PPA for %s%d", device, unit);
return (-1);
}
if (ip->dl_hdw_state == HDW_DEAD) {
- sprintf(ebuf, "%s: hardware state: DOWN\n", device);
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "%s%d: hardware state: DOWN\n", device, unit);
return (-1);
}
return ((int)ip->dl_ppa);
@@ -783,23 +943,26 @@ get_dlpi_ppa(register int fd, register const char *ifname, register int unit,
register int kd;
void *addr;
struct ifnet ifnet;
- char if_name[sizeof(ifnet.if_name)], tifname[32];
+ char if_name[sizeof(ifnet.if_name) + 1];
cp = strrchr(ifname, '/');
if (cp != NULL)
ifname = cp + 1;
if (nlist(path_vmunix, &nl) < 0) {
- sprintf(ebuf, "nlist %s failed", path_vmunix);
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "nlist %s failed",
+ path_vmunix);
return (-1);
}
if (nl[NL_IFNET].n_value == 0) {
- sprintf(ebuf, "could't find %s kernel symbol",
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "could't find %s kernel symbol",
nl[NL_IFNET].n_name);
return (-1);
}
kd = open("/dev/kmem", O_RDONLY);
if (kd < 0) {
- sprintf(ebuf, "kmem open: %s", pcap_strerror(errno));
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "kmem open: %s",
+ pcap_strerror(errno));
return (-1);
}
if (dlpi_kread(kd, nl[NL_IFNET].n_value,
@@ -811,17 +974,16 @@ get_dlpi_ppa(register int fd, register const char *ifname, register int unit,
if (dlpi_kread(kd, (off_t)addr,
&ifnet, sizeof(ifnet), ebuf) < 0 ||
dlpi_kread(kd, (off_t)ifnet.if_name,
- if_name, sizeof(if_name), ebuf) < 0) {
+ if_name, sizeof(ifnet.if_name), ebuf) < 0) {
(void)close(kd);
return (-1);
}
- sprintf(tifname, "%.*s%d",
- (int)sizeof(if_name), if_name, ifnet.if_unit);
- if (strcmp(tifname, ifname) == 0)
+ if_name[sizeof(ifnet.if_name)] = '\0';
+ if (strcmp(if_name, ifname) == 0 && ifnet.if_unit == unit)
return (ifnet.if_index);
}
- sprintf(ebuf, "Can't find %s", ifname);
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "Can't find %s", ifname);
return (-1);
}
@@ -832,15 +994,18 @@ dlpi_kread(register int fd, register off_t addr,
register int cc;
if (lseek(fd, addr, SEEK_SET) < 0) {
- sprintf(ebuf, "lseek: %s", pcap_strerror(errno));
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "lseek: %s",
+ pcap_strerror(errno));
return (-1);
}
cc = read(fd, buf, len);
if (cc < 0) {
- sprintf(ebuf, "read: %s", pcap_strerror(errno));
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "read: %s",
+ pcap_strerror(errno));
return (-1);
} else if (cc != len) {
- sprintf(ebuf, "short read (%d != %d)", cc, len);
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "short read (%d != %d)", cc,
+ len);
return (-1);
}
return (cc);
OpenPOWER on IntegriCloud