diff options
Diffstat (limited to 'contrib/libpcap/pcap-dlpi.c')
-rw-r--r-- | contrib/libpcap/pcap-dlpi.c | 299 |
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); |