pcap-dlpi.c revision 75107
117683Spst/*
239291Sfenner * Copyright (c) 1993, 1994, 1995, 1996, 1997
317683Spst *	The Regents of the University of California.  All rights reserved.
417683Spst *
517683Spst * Redistribution and use in source and binary forms, with or without
617683Spst * modification, are permitted provided that: (1) source code distributions
717683Spst * retain the above copyright notice and this paragraph in its entirety, (2)
817683Spst * distributions including binary code include the above copyright notice and
917683Spst * this paragraph in its entirety in the documentation or other materials
1017683Spst * provided with the distribution, and (3) all advertising materials mentioning
1117683Spst * features or use of this software display the following acknowledgement:
1217683Spst * ``This product includes software developed by the University of California,
1317683Spst * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
1417683Spst * the University nor the names of its contributors may be used to endorse
1517683Spst * or promote products derived from this software without specific prior
1617683Spst * written permission.
1717683Spst * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
1817683Spst * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1917683Spst * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2017683Spst *
2117683Spst * This code contributed by Atanu Ghosh (atanu@cs.ucl.ac.uk),
2217683Spst * University College London.
2317683Spst */
2417683Spst
2517683Spst/*
2617683Spst * Packet capture routine for dlpi under SunOS 5
2717683Spst *
2817683Spst * Notes:
2917683Spst *
3017683Spst *    - Apparently the DLIOCRAW ioctl() is specific to SunOS.
3117683Spst *
3217683Spst *    - There is a bug in bufmod(7) such that setting the snapshot
3317683Spst *      length results in data being left of the front of the packet.
3417683Spst *
3517683Spst *    - It might be desirable to use pfmod(7) to filter packets in the
3617683Spst *      kernel.
3717683Spst */
3817683Spst
3926175Sfenner#ifndef lint
4026175Sfennerstatic const char rcsid[] =
4175107Sfenner    "@(#) $Header: /tcpdump/master/libpcap/pcap-dlpi.c,v 1.63 2000/11/22 05:32:55 guy Exp $ (LBL)";
4226175Sfenner#endif
4326175Sfenner
4475107Sfenner#ifdef HAVE_CONFIG_H
4575107Sfenner#include "config.h"
4675107Sfenner#endif
4775107Sfenner
4817683Spst#include <sys/types.h>
4917683Spst#include <sys/time.h>
5017683Spst#ifdef HAVE_SYS_BUFMOD_H
5117683Spst#include <sys/bufmod.h>
5217683Spst#endif
5317683Spst#include <sys/dlpi.h>
5417683Spst#ifdef HAVE_SYS_DLPI_EXT_H
5517683Spst#include <sys/dlpi_ext.h>
5617683Spst#endif
5717683Spst#ifdef HAVE_HPUX9
5817683Spst#include <sys/socket.h>
5917683Spst#endif
6017683Spst#ifdef DL_HP_PPA_ACK_OBS
6117683Spst#include <sys/stat.h>
6217683Spst#endif
6317683Spst#include <sys/stream.h>
6417683Spst#if defined(HAVE_SOLARIS) && defined(HAVE_SYS_BUFMOD_H)
6517683Spst#include <sys/systeminfo.h>
6617683Spst#endif
6717683Spst
6817683Spst#ifdef HAVE_HPUX9
6917683Spst#include <net/if.h>
7017683Spst#endif
7117683Spst
7217683Spst#include <ctype.h>
7317683Spst#ifdef HAVE_HPUX9
7417683Spst#include <nlist.h>
7517683Spst#endif
7617683Spst#include <errno.h>
7717683Spst#include <fcntl.h>
7817683Spst#include <memory.h>
7917683Spst#include <stdio.h>
8017683Spst#include <stdlib.h>
8117683Spst#include <string.h>
8217683Spst#include <stropts.h>
8317683Spst#include <unistd.h>
8417683Spst
8517683Spst#include "pcap-int.h"
8617683Spst
8717683Spst#ifdef HAVE_OS_PROTO_H
8817683Spst#include "os-proto.h"
8917683Spst#endif
9017683Spst
9117683Spst#ifndef PCAP_DEV_PREFIX
9217683Spst#define PCAP_DEV_PREFIX "/dev"
9317683Spst#endif
9417683Spst
9517683Spst#define	MAXDLBUF	8192
9617683Spst
9717683Spst/* Forwards */
9817683Spststatic int dlattachreq(int, bpf_u_int32, char *);
9917683Spststatic int dlbindack(int, char *, char *);
10017683Spststatic int dlbindreq(int, bpf_u_int32, char *);
10117683Spststatic int dlinfoack(int, char *, char *);
10217683Spststatic int dlinforeq(int, char *);
10317683Spststatic int dlokack(int, const char *, char *, char *);
10417683Spststatic int recv_ack(int, int, const char *, char *, char *);
10517683Spststatic int dlpromisconreq(int, bpf_u_int32, char *);
10617683Spst#if defined(HAVE_SOLARIS) && defined(HAVE_SYS_BUFMOD_H)
10717683Spststatic char *get_release(bpf_u_int32 *, bpf_u_int32 *, bpf_u_int32 *);
10817683Spst#endif
10917683Spststatic int send_request(int, char *, int, char *, char *);
11017683Spst#ifdef HAVE_SYS_BUFMOD_H
11117683Spststatic int strioctl(int, int, int, char *);
11217683Spst#endif
11317683Spst#ifdef HAVE_HPUX9
11417683Spststatic int dlpi_kread(int, off_t, void *, u_int, char *);
11517683Spst#endif
11617683Spst#ifdef HAVE_DEV_DLPI
11717683Spststatic int get_dlpi_ppa(int, const char *, int, char *);
11817683Spst#endif
11917683Spst
12017683Spstint
12117683Spstpcap_stats(pcap_t *p, struct pcap_stat *ps)
12217683Spst{
12317683Spst
12417683Spst	*ps = p->md.stat;
12517683Spst	return (0);
12617683Spst}
12717683Spst
12817683Spst/* XXX Needed by HP-UX (at least) */
12917683Spststatic bpf_u_int32 ctlbuf[MAXDLBUF];
13017683Spststatic struct strbuf ctl = {
13117683Spst	MAXDLBUF,
13217683Spst	0,
13317683Spst	(char *)ctlbuf
13417683Spst};
13517683Spst
13617683Spstint
13717683Spstpcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
13817683Spst{
13917683Spst	register int cc, n, caplen, origlen;
14017683Spst	register u_char *bp, *ep, *pk;
14117683Spst	register struct bpf_insn *fcode;
14217683Spst#ifdef HAVE_SYS_BUFMOD_H
14317683Spst	register struct sb_hdr *sbp;
14417683Spst#ifdef LBL_ALIGN
14517683Spst	struct sb_hdr sbhdr;
14617683Spst#endif
14717683Spst#endif
14817683Spst	int flags;
14917683Spst	struct strbuf data;
15017683Spst	struct pcap_pkthdr pkthdr;
15117683Spst
15217683Spst	flags = 0;
15317683Spst	cc = p->cc;
15417683Spst	if (cc == 0) {
15517683Spst		data.buf = (char *)p->buffer + p->offset;
15617683Spst		data.maxlen = MAXDLBUF;
15717683Spst		data.len = 0;
15817683Spst		do {
15917683Spst			if (getmsg(p->fd, &ctl, &data, &flags) < 0) {
16017683Spst				/* Don't choke when we get ptraced */
16117683Spst				if (errno == EINTR) {
16217683Spst					cc = 0;
16317683Spst					continue;
16417683Spst				}
16575107Sfenner				strlcpy(p->errbuf, pcap_strerror(errno),
16675107Sfenner				    sizeof(p->errbuf));
16717683Spst				return (-1);
16817683Spst			}
16917683Spst			cc = data.len;
17017683Spst		} while (cc == 0);
17117683Spst		bp = p->buffer + p->offset;
17217683Spst	} else
17317683Spst		bp = p->bp;
17417683Spst
17517683Spst	/* Loop through packets */
17617683Spst	fcode = p->fcode.bf_insns;
17717683Spst	ep = bp + cc;
17817683Spst	n = 0;
17917683Spst#ifdef HAVE_SYS_BUFMOD_H
18017683Spst	while (bp < ep) {
18117683Spst#ifdef LBL_ALIGN
18217683Spst		if ((long)bp & 3) {
18317683Spst			sbp = &sbhdr;
18417683Spst			memcpy(sbp, bp, sizeof(*sbp));
18517683Spst		} else
18617683Spst#endif
18717683Spst			sbp = (struct sb_hdr *)bp;
18817683Spst		p->md.stat.ps_drop += sbp->sbh_drops;
18917683Spst		pk = bp + sizeof(*sbp);
19017683Spst		bp += sbp->sbh_totlen;
19117683Spst		origlen = sbp->sbh_origlen;
19217683Spst		caplen = sbp->sbh_msglen;
19317683Spst#else
19417683Spst		origlen = cc;
19517683Spst		caplen = min(p->snapshot, cc);
19617683Spst		pk = bp;
19717683Spst		bp += caplen;
19817683Spst#endif
19917683Spst		++p->md.stat.ps_recv;
20017683Spst		if (bpf_filter(fcode, pk, origlen, caplen)) {
20117683Spst#ifdef HAVE_SYS_BUFMOD_H
20217683Spst			pkthdr.ts = sbp->sbh_timestamp;
20317683Spst#else
20417683Spst			(void)gettimeofday(&pkthdr.ts, NULL);
20517683Spst#endif
20617683Spst			pkthdr.len = origlen;
20717683Spst			pkthdr.caplen = caplen;
20817683Spst			/* Insure caplen does not exceed snapshot */
20917683Spst			if (pkthdr.caplen > p->snapshot)
21017683Spst				pkthdr.caplen = p->snapshot;
21117683Spst			(*callback)(user, &pkthdr, pk);
21217683Spst			if (++n >= cnt && cnt >= 0) {
21317683Spst				p->cc = ep - bp;
21417683Spst				p->bp = bp;
21517683Spst				return (n);
21617683Spst			}
21717683Spst		}
21817683Spst#ifdef HAVE_SYS_BUFMOD_H
21917683Spst	}
22017683Spst#endif
22117683Spst	p->cc = 0;
22217683Spst	return (n);
22317683Spst}
22417683Spst
22517683Spstpcap_t *
22617683Spstpcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)
22717683Spst{
22817683Spst	register char *cp;
22917683Spst	char *eos;
23017683Spst	register pcap_t *p;
23117683Spst	register int ppa;
23217683Spst	register dl_info_ack_t *infop;
23317683Spst#ifdef HAVE_SYS_BUFMOD_H
23417683Spst	bpf_u_int32 ss, flag;
23517683Spst#ifdef HAVE_SOLARIS
23617683Spst	register char *release;
23717683Spst	bpf_u_int32 osmajor, osminor, osmicro;
23817683Spst#endif
23917683Spst#endif
24017683Spst	bpf_u_int32 buf[MAXDLBUF];
24117683Spst	char dname[100];
24217683Spst#ifndef HAVE_DEV_DLPI
24317683Spst	char dname2[100];
24417683Spst#endif
24517683Spst
24617683Spst	p = (pcap_t *)malloc(sizeof(*p));
24717683Spst	if (p == NULL) {
24875107Sfenner		strlcpy(ebuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE);
24917683Spst		return (NULL);
25017683Spst	}
25117683Spst	memset(p, 0, sizeof(*p));
25217683Spst
25375107Sfenner#ifdef HAVE_DEV_DLPI
25417683Spst	/*
25575107Sfenner	** Remove any "/dev/" on the front of the device.
25617683Spst	*/
25775107Sfenner	cp = strrchr(device, '/');
25875107Sfenner	if (cp == NULL)
25975107Sfenner		cp = device;
26075107Sfenner	else
26175107Sfenner		cp++;
26275107Sfenner	strlcpy(dname, cp, sizeof(dname));
26375107Sfenner
26475107Sfenner	/*
26575107Sfenner	 * Split the name into a device type and a unit number.
26675107Sfenner	 */
26775107Sfenner	cp = strpbrk(dname, "0123456789");
26817683Spst	if (cp == NULL) {
26975107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE,
27075107Sfenner		    "%s missing unit number", device);
27117683Spst		goto bad;
27217683Spst	}
27317683Spst	ppa = strtol(cp, &eos, 10);
27417683Spst	if (*eos != '\0') {
27575107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE,
27675107Sfenner		    "%s bad unit number", device);
27717683Spst		goto bad;
27817683Spst	}
27975107Sfenner	*cp = '\0';
28017683Spst
28175107Sfenner	/*
28275107Sfenner	 * Use "/dev/dlpi" as the device.
28375107Sfenner	 *
28475107Sfenner	 * XXX - HP's DLPI Programmer's Guide for HP-UX 11.00 says that
28575107Sfenner	 * the "dl_mjr_num" field is for the "major number of interface
28675107Sfenner	 * driver"; that's the major of "/dev/dlpi" on the system on
28775107Sfenner	 * which I tried this, but there may be DLPI devices that
28875107Sfenner	 * use a different driver, in which case we may need to
28975107Sfenner	 * search "/dev" for the appropriate device with that major
29075107Sfenner	 * device number, rather than hardwiring "/dev/dlpi".
29175107Sfenner	 */
29217683Spst	cp = "/dev/dlpi";
29317683Spst	if ((p->fd = open(cp, O_RDWR)) < 0) {
29475107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE,
29575107Sfenner		    "%s: %s", cp, pcap_strerror(errno));
29617683Spst		goto bad;
29717683Spst	}
29875107Sfenner
29975107Sfenner	/*
30075107Sfenner	 * Get a table of all PPAs for that device, and search that
30175107Sfenner	 * table for the specified device type name and unit number.
30275107Sfenner	 */
30317683Spst	ppa = get_dlpi_ppa(p->fd, dname, ppa, ebuf);
30417683Spst	if (ppa < 0)
30517683Spst		goto bad;
30617683Spst#else
30775107Sfenner	/*
30875107Sfenner	** Determine device and ppa
30975107Sfenner	*/
31075107Sfenner	cp = strpbrk(device, "0123456789");
31175107Sfenner	if (cp == NULL) {
31275107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s missing unit number",
31375107Sfenner		    device);
31475107Sfenner		goto bad;
31575107Sfenner	}
31675107Sfenner	ppa = strtol(cp, &eos, 10);
31775107Sfenner	if (*eos != '\0') {
31875107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s bad unit number", device);
31975107Sfenner		goto bad;
32075107Sfenner	}
32175107Sfenner
32275107Sfenner	if (*device == '/')
32375107Sfenner		strlcpy(dname, device, sizeof(dname));
32475107Sfenner	else
32575107Sfenner		snprintf(dname, sizeof(dname), "%s/%s", PCAP_DEV_PREFIX,
32675107Sfenner		    device);
32775107Sfenner
32817683Spst	/* Try device without unit number */
32975107Sfenner	strlcpy(dname2, dname, sizeof(dname2));
33017683Spst	cp = strchr(dname, *cp);
33117683Spst	*cp = '\0';
33217683Spst	if ((p->fd = open(dname, O_RDWR)) < 0) {
33317683Spst		if (errno != ENOENT) {
33475107Sfenner			snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s: %s", dname,
33575107Sfenner			    pcap_strerror(errno));
33617683Spst			goto bad;
33717683Spst		}
33817683Spst
33917683Spst		/* Try again with unit number */
34017683Spst		if ((p->fd = open(dname2, O_RDWR)) < 0) {
34175107Sfenner			snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s: %s", dname2,
34275107Sfenner			    pcap_strerror(errno));
34317683Spst			goto bad;
34417683Spst		}
34517683Spst		/* XXX Assume unit zero */
34617683Spst		ppa = 0;
34717683Spst	}
34817683Spst#endif
34917683Spst
35017683Spst	p->snapshot = snaplen;
35117683Spst
35217683Spst	/*
35317683Spst	** Attach if "style 2" provider
35417683Spst	*/
35517683Spst	if (dlinforeq(p->fd, ebuf) < 0 ||
35617683Spst	    dlinfoack(p->fd, (char *)buf, ebuf) < 0)
35717683Spst		goto bad;
35817683Spst	infop = &((union DL_primitives *)buf)->info_ack;
35917683Spst	if (infop->dl_provider_style == DL_STYLE2 &&
36017683Spst	    (dlattachreq(p->fd, ppa, ebuf) < 0 ||
36117683Spst	    dlokack(p->fd, "attach", (char *)buf, ebuf) < 0))
36217683Spst		goto bad;
36317683Spst	/*
36439291Sfenner	** Bind (defer if using HP-UX 9 or HP-UX 10.20, totally skip if
36539291Sfenner	** using SINIX)
36617683Spst	*/
36739291Sfenner#if !defined(HAVE_HPUX9) && !defined(HAVE_HPUX10_20) && !defined(sinix)
36875107Sfenner#ifdef _AIX
36975107Sfenner        /* According to IBM's AIX Support Line, the dl_sap value
37075107Sfenner        ** should not be less than 0x600 (1536) for standard ethernet
37175107Sfenner         */
37275107Sfenner	if (dlbindreq(p->fd, 1537, ebuf) < 0 ||
37375107Sfenner#else
37417683Spst	if (dlbindreq(p->fd, 0, ebuf) < 0 ||
37575107Sfenner#endif
37617683Spst	    dlbindack(p->fd, (char *)buf, ebuf) < 0)
37717683Spst		goto bad;
37817683Spst#endif
37917683Spst
38017683Spst	if (promisc) {
38117683Spst		/*
38217683Spst		** Enable promiscuous
38317683Spst		*/
38417683Spst		if (dlpromisconreq(p->fd, DL_PROMISC_PHYS, ebuf) < 0 ||
38517683Spst		    dlokack(p->fd, "promisc_phys", (char *)buf, ebuf) < 0)
38617683Spst			goto bad;
38717683Spst
38817683Spst		/*
38917683Spst		** Try to enable multicast (you would have thought
39039291Sfenner		** promiscuous would be sufficient). (Skip if using
39139291Sfenner		** HP-UX or SINIX)
39217683Spst		*/
39339291Sfenner#if !defined(__hpux) && !defined(sinix)
39417683Spst		if (dlpromisconreq(p->fd, DL_PROMISC_MULTI, ebuf) < 0 ||
39517683Spst		    dlokack(p->fd, "promisc_multi", (char *)buf, ebuf) < 0)
39617683Spst			fprintf(stderr,
39717683Spst			    "WARNING: DL_PROMISC_MULTI failed (%s)\n", ebuf);
39817683Spst#endif
39917683Spst	}
40017683Spst	/*
40139291Sfenner	** Try to enable sap (when not in promiscuous mode when using
40239291Sfenner	** using HP-UX and never under SINIX)
40317683Spst	*/
40417683Spst#ifndef sinix
40539291Sfenner	if (
40639291Sfenner#ifdef __hpux
40739291Sfenner	    !promisc &&
40839291Sfenner#endif
40939291Sfenner	    (dlpromisconreq(p->fd, DL_PROMISC_SAP, ebuf) < 0 ||
41039291Sfenner	    dlokack(p->fd, "promisc_sap", (char *)buf, ebuf) < 0)) {
41117683Spst		/* Not fatal if promisc since the DL_PROMISC_PHYS worked */
41217683Spst		if (promisc)
41317683Spst			fprintf(stderr,
41417683Spst			    "WARNING: DL_PROMISC_SAP failed (%s)\n", ebuf);
41517683Spst		else
41617683Spst			goto bad;
41717683Spst	}
41817683Spst#endif
41917683Spst
42017683Spst	/*
42139291Sfenner	** HP-UX 9 and HP-UX 10.20 must bind after setting promiscuous
42239291Sfenner	** options)
42317683Spst	*/
42439291Sfenner#if defined(HAVE_HPUX9) || defined(HAVE_HPUX10_20)
42517683Spst	if (dlbindreq(p->fd, 0, ebuf) < 0 ||
42617683Spst	    dlbindack(p->fd, (char *)buf, ebuf) < 0)
42717683Spst		goto bad;
42817683Spst#endif
42917683Spst
43017683Spst	/*
43117683Spst	** Determine link type
43217683Spst	*/
43317683Spst	if (dlinforeq(p->fd, ebuf) < 0 ||
43417683Spst	    dlinfoack(p->fd, (char *)buf, ebuf) < 0)
43517683Spst		goto bad;
43617683Spst
43717683Spst	infop = &((union DL_primitives *)buf)->info_ack;
43817683Spst	switch (infop->dl_mac_type) {
43917683Spst
44017683Spst	case DL_CSMACD:
44117683Spst	case DL_ETHER:
44217683Spst		p->linktype = DLT_EN10MB;
44317683Spst		p->offset = 2;
44417683Spst		break;
44517683Spst
44617683Spst	case DL_FDDI:
44717683Spst		p->linktype = DLT_FDDI;
44839291Sfenner		p->offset = 3;
44917683Spst		break;
45017683Spst
45117683Spst	default:
45275107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE, "unknown mac type %lu",
45375107Sfenner		    infop->dl_mac_type);
45417683Spst		goto bad;
45517683Spst	}
45617683Spst
45717683Spst#ifdef	DLIOCRAW
45817683Spst	/*
45917683Spst	** This is a non standard SunOS hack to get the ethernet header.
46017683Spst	*/
46117683Spst	if (strioctl(p->fd, DLIOCRAW, 0, NULL) < 0) {
46275107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE, "DLIOCRAW: %s",
46375107Sfenner		    pcap_strerror(errno));
46417683Spst		goto bad;
46517683Spst	}
46617683Spst#endif
46717683Spst
46817683Spst#ifdef HAVE_SYS_BUFMOD_H
46917683Spst	/*
47017683Spst	** Another non standard call to get the data nicely buffered
47117683Spst	*/
47217683Spst	if (ioctl(p->fd, I_PUSH, "bufmod") != 0) {
47375107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE, "I_PUSH bufmod: %s",
47475107Sfenner		    pcap_strerror(errno));
47517683Spst		goto bad;
47617683Spst	}
47717683Spst
47817683Spst	/*
47917683Spst	** Now that the bufmod is pushed lets configure it.
48017683Spst	**
48117683Spst	** There is a bug in bufmod(7). When dealing with messages of
48217683Spst	** less than snaplen size it strips data from the beginning not
48317683Spst	** the end.
48417683Spst	**
48517683Spst	** This bug is supposed to be fixed in 5.3.2. Also, there is a
48617683Spst	** patch available. Ask for bugid 1149065.
48717683Spst	*/
48817683Spst	ss = snaplen;
48917683Spst#ifdef HAVE_SOLARIS
49017683Spst	release = get_release(&osmajor, &osminor, &osmicro);
49117683Spst	if (osmajor == 5 && (osminor <= 2 || (osminor == 3 && osmicro < 2)) &&
49217683Spst	    getenv("BUFMOD_FIXED") == NULL) {
49317683Spst		fprintf(stderr,
49417683Spst		"WARNING: bufmod is broken in SunOS %s; ignoring snaplen.\n",
49517683Spst		    release);
49617683Spst		ss = 0;
49717683Spst	}
49817683Spst#endif
49917683Spst	if (ss > 0 &&
50017683Spst	    strioctl(p->fd, SBIOCSSNAP, sizeof(ss), (char *)&ss) != 0) {
50175107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE, "SBIOCSSNAP: %s",
50275107Sfenner		    pcap_strerror(errno));
50317683Spst		goto bad;
50417683Spst	}
50517683Spst
50617683Spst	/*
50717683Spst	** Set up the bufmod flags
50817683Spst	*/
50917683Spst	if (strioctl(p->fd, SBIOCGFLAGS, sizeof(flag), (char *)&flag) < 0) {
51075107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE, "SBIOCGFLAGS: %s",
51175107Sfenner		    pcap_strerror(errno));
51217683Spst		goto bad;
51317683Spst	}
51417683Spst	flag |= SB_NO_DROPS;
51517683Spst	if (strioctl(p->fd, SBIOCSFLAGS, sizeof(flag), (char *)&flag) != 0) {
51675107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE, "SBIOCSFLAGS: %s",
51775107Sfenner		    pcap_strerror(errno));
51817683Spst		goto bad;
51917683Spst	}
52017683Spst	/*
52117683Spst	** Set up the bufmod timeout
52217683Spst	*/
52317683Spst	if (to_ms != 0) {
52417683Spst		struct timeval to;
52517683Spst
52617683Spst		to.tv_sec = to_ms / 1000;
52717683Spst		to.tv_usec = (to_ms * 1000) % 1000000;
52817683Spst		if (strioctl(p->fd, SBIOCSTIME, sizeof(to), (char *)&to) != 0) {
52975107Sfenner			snprintf(ebuf, PCAP_ERRBUF_SIZE, "SBIOCSTIME: %s",
53075107Sfenner			    pcap_strerror(errno));
53117683Spst			goto bad;
53217683Spst		}
53317683Spst	}
53417683Spst#endif
53517683Spst
53617683Spst	/*
53717683Spst	** As the last operation flush the read side.
53817683Spst	*/
53917683Spst	if (ioctl(p->fd, I_FLUSH, FLUSHR) != 0) {
54075107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE, "FLUSHR: %s",
54175107Sfenner		    pcap_strerror(errno));
54217683Spst		goto bad;
54317683Spst	}
54417683Spst	/* Allocate data buffer */
54517683Spst	p->bufsize = MAXDLBUF * sizeof(bpf_u_int32);
54617683Spst	p->buffer = (u_char *)malloc(p->bufsize + p->offset);
54717683Spst
54817683Spst	return (p);
54917683Spstbad:
55017683Spst	free(p);
55117683Spst	return (NULL);
55217683Spst}
55317683Spst
55417683Spstint
55517683Spstpcap_setfilter(pcap_t *p, struct bpf_program *fp)
55617683Spst{
55717683Spst
55875107Sfenner	if (install_bpf_program(p, fp) < 0)
55975107Sfenner		return (-1);
56017683Spst	return (0);
56117683Spst}
56217683Spst
56317683Spststatic int
56417683Spstsend_request(int fd, char *ptr, int len, char *what, char *ebuf)
56517683Spst{
56617683Spst	struct	strbuf	ctl;
56717683Spst	int	flags;
56817683Spst
56917683Spst	ctl.maxlen = 0;
57017683Spst	ctl.len = len;
57117683Spst	ctl.buf = ptr;
57217683Spst
57317683Spst	flags = 0;
57417683Spst	if (putmsg(fd, &ctl, (struct strbuf *) NULL, flags) < 0) {
57575107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE,
57675107Sfenner		    "send_request: putmsg \"%s\": %s",
57717683Spst		    what, pcap_strerror(errno));
57817683Spst		return (-1);
57917683Spst	}
58017683Spst	return (0);
58117683Spst}
58217683Spst
58317683Spststatic int
58417683Spstrecv_ack(int fd, int size, const char *what, char *bufp, char *ebuf)
58517683Spst{
58617683Spst	union	DL_primitives	*dlp;
58717683Spst	struct	strbuf	ctl;
58817683Spst	int	flags;
58917683Spst
59017683Spst	ctl.maxlen = MAXDLBUF;
59117683Spst	ctl.len = 0;
59217683Spst	ctl.buf = bufp;
59317683Spst
59417683Spst	flags = 0;
59517683Spst	if (getmsg(fd, &ctl, (struct strbuf*)NULL, &flags) < 0) {
59675107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE, "recv_ack: %s getmsg: %s",
59717683Spst		    what, pcap_strerror(errno));
59817683Spst		return (-1);
59917683Spst	}
60017683Spst
60117683Spst	dlp = (union DL_primitives *) ctl.buf;
60217683Spst	switch (dlp->dl_primitive) {
60317683Spst
60417683Spst	case DL_INFO_ACK:
60517683Spst	case DL_BIND_ACK:
60617683Spst	case DL_OK_ACK:
60717683Spst#ifdef DL_HP_PPA_ACK
60817683Spst	case DL_HP_PPA_ACK:
60917683Spst#endif
61017683Spst
61117683Spst		/* These are OK */
61217683Spst		break;
61317683Spst
61417683Spst	case DL_ERROR_ACK:
61517683Spst		switch (dlp->error_ack.dl_errno) {
61617683Spst
61717683Spst		case DL_BADPPA:
61875107Sfenner			snprintf(ebuf, PCAP_ERRBUF_SIZE,
61975107Sfenner			    "recv_ack: %s bad ppa (device unit)", what);
62017683Spst			break;
62117683Spst
62226175Sfenner
62317683Spst		case DL_SYSERR:
62475107Sfenner			snprintf(ebuf, PCAP_ERRBUF_SIZE, "recv_ack: %s: %s",
62517683Spst			    what, pcap_strerror(dlp->error_ack.dl_unix_errno));
62617683Spst			break;
62717683Spst
62826175Sfenner		case DL_UNSUPPORTED:
62975107Sfenner			snprintf(ebuf, PCAP_ERRBUF_SIZE,
63026175Sfenner			    "recv_ack: %s: Service not supplied by provider",
63126175Sfenner			    what);
63226175Sfenner			break;
63326175Sfenner
63417683Spst		default:
63575107Sfenner			snprintf(ebuf, PCAP_ERRBUF_SIZE,
63675107Sfenner			    "recv_ack: %s error 0x%x",
63717683Spst			    what, (bpf_u_int32)dlp->error_ack.dl_errno);
63817683Spst			break;
63917683Spst		}
64017683Spst		return (-1);
64117683Spst
64217683Spst	default:
64375107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE,
64475107Sfenner		    "recv_ack: %s unexpected primitive ack 0x%x ",
64517683Spst		    what, (bpf_u_int32)dlp->dl_primitive);
64617683Spst		return (-1);
64717683Spst	}
64817683Spst
64917683Spst	if (ctl.len < size) {
65075107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE,
65175107Sfenner		    "recv_ack: %s ack too small (%d < %d)",
65217683Spst		    what, ctl.len, size);
65317683Spst		return (-1);
65417683Spst	}
65517683Spst	return (ctl.len);
65617683Spst}
65717683Spst
65817683Spststatic int
65917683Spstdlattachreq(int fd, bpf_u_int32 ppa, char *ebuf)
66017683Spst{
66117683Spst	dl_attach_req_t	req;
66217683Spst
66317683Spst	req.dl_primitive = DL_ATTACH_REQ;
66417683Spst	req.dl_ppa = ppa;
66517683Spst
66617683Spst	return (send_request(fd, (char *)&req, sizeof(req), "attach", ebuf));
66717683Spst}
66817683Spst
66917683Spststatic int
67017683Spstdlbindreq(int fd, bpf_u_int32 sap, char *ebuf)
67117683Spst{
67217683Spst
67317683Spst	dl_bind_req_t	req;
67417683Spst
67517683Spst	memset((char *)&req, 0, sizeof(req));
67617683Spst	req.dl_primitive = DL_BIND_REQ;
67717683Spst#ifdef DL_HP_RAWDLS
67817683Spst	req.dl_max_conind = 1;			/* XXX magic number */
67917683Spst	/* 22 is INSAP as per the HP-UX DLPI Programmer's Guide */
68017683Spst	req.dl_sap = 22;
68117683Spst	req.dl_service_mode = DL_HP_RAWDLS;
68217683Spst#else
68317683Spst	req.dl_sap = sap;
68426175Sfenner#ifdef DL_CLDLS
68526175Sfenner	req.dl_service_mode = DL_CLDLS;
68617683Spst#endif
68726175Sfenner#endif
68817683Spst
68917683Spst	return (send_request(fd, (char *)&req, sizeof(req), "bind", ebuf));
69017683Spst}
69117683Spst
69217683Spststatic int
69317683Spstdlbindack(int fd, char *bufp, char *ebuf)
69417683Spst{
69517683Spst
69617683Spst	return (recv_ack(fd, DL_BIND_ACK_SIZE, "bind", bufp, ebuf));
69717683Spst}
69817683Spst
69917683Spststatic int
70017683Spstdlpromisconreq(int fd, bpf_u_int32 level, char *ebuf)
70117683Spst{
70217683Spst	dl_promiscon_req_t req;
70317683Spst
70417683Spst	req.dl_primitive = DL_PROMISCON_REQ;
70517683Spst	req.dl_level = level;
70617683Spst
70717683Spst	return (send_request(fd, (char *)&req, sizeof(req), "promiscon", ebuf));
70817683Spst}
70917683Spst
71017683Spststatic int
71117683Spstdlokack(int fd, const char *what, char *bufp, char *ebuf)
71217683Spst{
71317683Spst
71417683Spst	return (recv_ack(fd, DL_OK_ACK_SIZE, what, bufp, ebuf));
71517683Spst}
71617683Spst
71717683Spst
71817683Spststatic int
71917683Spstdlinforeq(int fd, char *ebuf)
72017683Spst{
72117683Spst	dl_info_req_t req;
72217683Spst
72317683Spst	req.dl_primitive = DL_INFO_REQ;
72417683Spst
72517683Spst	return (send_request(fd, (char *)&req, sizeof(req), "info", ebuf));
72617683Spst}
72717683Spst
72817683Spststatic int
72917683Spstdlinfoack(int fd, char *bufp, char *ebuf)
73017683Spst{
73117683Spst
73217683Spst	return (recv_ack(fd, DL_INFO_ACK_SIZE, "info", bufp, ebuf));
73317683Spst}
73417683Spst
73517683Spst#ifdef HAVE_SYS_BUFMOD_H
73617683Spststatic int
73717683Spststrioctl(int fd, int cmd, int len, char *dp)
73817683Spst{
73917683Spst	struct strioctl str;
74017683Spst	int rc;
74117683Spst
74217683Spst	str.ic_cmd = cmd;
74317683Spst	str.ic_timout = -1;
74417683Spst	str.ic_len = len;
74517683Spst	str.ic_dp = dp;
74617683Spst	rc = ioctl(fd, I_STR, &str);
74717683Spst
74817683Spst	if (rc < 0)
74917683Spst		return (rc);
75017683Spst	else
75117683Spst		return (str.ic_len);
75217683Spst}
75317683Spst#endif
75417683Spst
75517683Spst#if defined(HAVE_SOLARIS) && defined(HAVE_SYS_BUFMOD_H)
75617683Spststatic char *
75717683Spstget_release(bpf_u_int32 *majorp, bpf_u_int32 *minorp, bpf_u_int32 *microp)
75817683Spst{
75917683Spst	char *cp;
76017683Spst	static char buf[32];
76117683Spst
76217683Spst	*majorp = 0;
76317683Spst	*minorp = 0;
76417683Spst	*microp = 0;
76517683Spst	if (sysinfo(SI_RELEASE, buf, sizeof(buf)) < 0)
76617683Spst		return ("?");
76717683Spst	cp = buf;
76817683Spst	if (!isdigit(*cp))
76917683Spst		return (buf);
77017683Spst	*majorp = strtol(cp, &cp, 10);
77117683Spst	if (*cp++ != '.')
77217683Spst		return (buf);
77317683Spst	*minorp =  strtol(cp, &cp, 10);
77417683Spst	if (*cp++ != '.')
77517683Spst		return (buf);
77617683Spst	*microp =  strtol(cp, &cp, 10);
77717683Spst	return (buf);
77817683Spst}
77917683Spst#endif
78017683Spst
78117683Spst#ifdef DL_HP_PPA_ACK_OBS
78217683Spst/*
78375107Sfenner * Under HP-UX 10 and HP-UX 11, we can ask for the ppa
78417683Spst */
78517683Spst
78617683Spst
78775107Sfenner/*
78875107Sfenner * Determine ppa number that specifies ifname.
78975107Sfenner *
79075107Sfenner * If the "dl_hp_ppa_info_t" doesn't have a "dl_module_id_1" member,
79175107Sfenner * the code that's used here is the old code for HP-UX 10.x.
79275107Sfenner *
79375107Sfenner * However, HP-UX 10.20, at least, appears to have such a member
79475107Sfenner * in its "dl_hp_ppa_info_t" structure, so the new code is used.
79575107Sfenner * The new code didn't work on an old 10.20 system on which Rick
79675107Sfenner * Jones of HP tried it, but with later patches installed, it
79775107Sfenner * worked - it appears that the older system had those members but
79875107Sfenner * didn't put anything in them, so, if the search by name fails, we
79975107Sfenner * do the old search.
80075107Sfenner *
80175107Sfenner * Rick suggests that making sure your system is "up on the latest
80275107Sfenner * lancommon/DLPI/driver patches" is probably a good idea; it'd fix
80375107Sfenner * that problem, as well as allowing libpcap to see packets sent
80475107Sfenner * from the system on which the libpcap application is being run.
80575107Sfenner * (On 10.20, in addition to getting the latest patches, you need
80675107Sfenner * to turn the kernel "lanc_outbound_promisc_flag" flag on with ADB;
80775107Sfenner * a posting to "comp.sys.hp.hpux" at
80875107Sfenner *
80975107Sfenner *	http://www.deja.com/[ST_rn=ps]/getdoc.xp?AN=558092266
81075107Sfenner *
81175107Sfenner * says that, to see the machine's outgoing traffic, you'd need to
81275107Sfenner * apply the right patches to your system, and also set that variable
81375107Sfenner * with:
81475107Sfenner
81575107Sfennerecho 'lanc_outbound_promisc_flag/W1' | /usr/bin/adb -w /stand/vmunix /dev/kmem
81675107Sfenner
81775107Sfenner * which could be put in, for example, "/sbin/init.d/lan".
81875107Sfenner *
81975107Sfenner * Setting the variable is not necessary on HP-UX 11.x.
82075107Sfenner */
82117683Spststatic int
82217683Spstget_dlpi_ppa(register int fd, register const char *device, register int unit,
82317683Spst    register char *ebuf)
82417683Spst{
82517683Spst	register dl_hp_ppa_ack_t *ap;
82675107Sfenner	register dl_hp_ppa_info_t *ipstart, *ip;
82717683Spst	register int i;
82875107Sfenner	char dname[100];
82917683Spst	register u_long majdev;
83075107Sfenner	struct stat statbuf;
83117683Spst	dl_hp_ppa_req_t	req;
83217683Spst	bpf_u_int32 buf[MAXDLBUF];
83317683Spst
83417683Spst	memset((char *)&req, 0, sizeof(req));
83517683Spst	req.dl_primitive = DL_HP_PPA_REQ;
83617683Spst
83717683Spst	memset((char *)buf, 0, sizeof(buf));
83817683Spst	if (send_request(fd, (char *)&req, sizeof(req), "hpppa", ebuf) < 0 ||
83917683Spst	    recv_ack(fd, DL_HP_PPA_ACK_SIZE, "hpppa", (char *)buf, ebuf) < 0)
84017683Spst		return (-1);
84117683Spst
84217683Spst	ap = (dl_hp_ppa_ack_t *)buf;
84375107Sfenner	ipstart = (dl_hp_ppa_info_t *)((u_char *)ap + ap->dl_offset);
84475107Sfenner	ip = ipstart;
84517683Spst
84675107Sfenner#ifdef HAVE_HP_PPA_INFO_T_DL_MODULE_ID_1
84775107Sfenner	/*
84875107Sfenner	 * The "dl_hp_ppa_info_t" structure has a "dl_module_id_1"
84975107Sfenner	 * member that should, in theory, contain the part of the
85075107Sfenner	 * name for the device that comes before the unit number,
85175107Sfenner	 * and should also have a "dl_module_id_2" member that may
85275107Sfenner	 * contain an alternate name (e.g., I think Ethernet devices
85375107Sfenner	 * have both "lan", for "lanN", and "snap", for "snapN", with
85475107Sfenner	 * the former being for Ethernet packets and the latter being
85575107Sfenner	 * for 802.3/802.2 packets).
85675107Sfenner	 *
85775107Sfenner	 * Search for the device that has the specified name and
85875107Sfenner	 * instance number.
85975107Sfenner	 */
86075107Sfenner	for (i = 0; i < ap->dl_count; i++) {
86175107Sfenner		if ((strcmp(ip->dl_module_id_1, device) == 0 ||
86275107Sfenner		     strcmp(ip->dl_module_id_2, device) == 0) &&
86375107Sfenner		    ip->dl_instance_num == unit)
86475107Sfenner			break;
86517683Spst
86675107Sfenner		ip = (dl_hp_ppa_info_t *)((u_char *)ipstart + ip->dl_next_offset);
86775107Sfenner	}
86875107Sfenner#else
86975107Sfenner	/*
87075107Sfenner	 * We don't have that member, so the search is impossible; make it
87175107Sfenner	 * look as if the search failed.
87275107Sfenner	 */
87375107Sfenner	i = ap->dl_count;
87475107Sfenner#endif
87575107Sfenner
87675107Sfenner	if (i == ap->dl_count) {
87775107Sfenner		/*
87875107Sfenner		 * Well, we didn't, or can't, find the device by name.
87975107Sfenner		 *
88075107Sfenner		 * HP-UX 10.20, whilst it has "dl_module_id_1" and
88175107Sfenner		 * "dl_module_id_2" fields in the "dl_hp_ppa_info_t",
88275107Sfenner		 * doesn't seem to fill them in unless the system is
88375107Sfenner		 * at a reasonably up-to-date patch level.
88475107Sfenner		 *
88575107Sfenner		 * Older HP-UX 10.x systems might not have those fields
88675107Sfenner		 * at all.
88775107Sfenner		 *
88875107Sfenner		 * Therefore, we'll search for the entry with the major
88975107Sfenner		 * device number of a device with the name "/dev/<dev><unit>",
89075107Sfenner		 * if such a device exists, as the old code did.
89175107Sfenner		 */
89275107Sfenner		snprintf(dname, sizeof(dname), "/dev/%s%d", device, unit);
89375107Sfenner		if (stat(dname, &statbuf) < 0) {
89475107Sfenner			snprintf(ebuf, PCAP_ERRBUF_SIZE, "stat: %s: %s",
89575107Sfenner			    dname, pcap_strerror(errno));
89675107Sfenner			return (-1);
89775107Sfenner		}
89875107Sfenner		majdev = major(statbuf.st_rdev);
89975107Sfenner
90075107Sfenner		ip = ipstart;
90175107Sfenner
90275107Sfenner		for (i = 0; i < ap->dl_count; i++) {
90375107Sfenner			if (ip->dl_mjr_num == majdev &&
90475107Sfenner			    ip->dl_instance_num == unit)
90575107Sfenner				break;
90675107Sfenner
90775107Sfenner			ip = (dl_hp_ppa_info_t *)((u_char *)ipstart + ip->dl_next_offset);
90875107Sfenner		}
90975107Sfenner	}
91017683Spst        if (i == ap->dl_count) {
91175107Sfenner                snprintf(ebuf, PCAP_ERRBUF_SIZE,
91275107Sfenner		    "can't find /dev/dlpi PPA for %s%d", device, unit);
91317683Spst		return (-1);
91417683Spst        }
91517683Spst        if (ip->dl_hdw_state == HDW_DEAD) {
91675107Sfenner                snprintf(ebuf, PCAP_ERRBUF_SIZE,
91775107Sfenner		    "%s%d: hardware state: DOWN\n", device, unit);
91817683Spst		return (-1);
91917683Spst        }
92017683Spst        return ((int)ip->dl_ppa);
92117683Spst}
92217683Spst#endif
92317683Spst
92417683Spst#ifdef HAVE_HPUX9
92517683Spst/*
92617683Spst * Under HP-UX 9, there is no good way to determine the ppa.
92717683Spst * So punt and read it from /dev/kmem.
92817683Spst */
92917683Spststatic struct nlist nl[] = {
93017683Spst#define NL_IFNET 0
93117683Spst	{ "ifnet" },
93217683Spst	{ "" }
93317683Spst};
93417683Spst
93517683Spststatic char path_vmunix[] = "/hp-ux";
93617683Spst
93717683Spst/* Determine ppa number that specifies ifname */
93817683Spststatic int
93917683Spstget_dlpi_ppa(register int fd, register const char *ifname, register int unit,
94017683Spst    register char *ebuf)
94117683Spst{
94217683Spst	register const char *cp;
94317683Spst	register int kd;
94417683Spst	void *addr;
94517683Spst	struct ifnet ifnet;
94675107Sfenner	char if_name[sizeof(ifnet.if_name) + 1];
94717683Spst
94817683Spst	cp = strrchr(ifname, '/');
94917683Spst	if (cp != NULL)
95017683Spst		ifname = cp + 1;
95117683Spst	if (nlist(path_vmunix, &nl) < 0) {
95275107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE, "nlist %s failed",
95375107Sfenner		    path_vmunix);
95417683Spst		return (-1);
95517683Spst	}
95617683Spst	if (nl[NL_IFNET].n_value == 0) {
95775107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE,
95875107Sfenner		    "could't find %s kernel symbol",
95917683Spst		    nl[NL_IFNET].n_name);
96017683Spst		return (-1);
96117683Spst	}
96217683Spst	kd = open("/dev/kmem", O_RDONLY);
96317683Spst	if (kd < 0) {
96475107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE, "kmem open: %s",
96575107Sfenner		    pcap_strerror(errno));
96617683Spst		return (-1);
96717683Spst	}
96817683Spst	if (dlpi_kread(kd, nl[NL_IFNET].n_value,
96917683Spst	    &addr, sizeof(addr), ebuf) < 0) {
97017683Spst		close(kd);
97117683Spst		return (-1);
97217683Spst	}
97317683Spst	for (; addr != NULL; addr = ifnet.if_next) {
97417683Spst		if (dlpi_kread(kd, (off_t)addr,
97517683Spst		    &ifnet, sizeof(ifnet), ebuf) < 0 ||
97617683Spst		    dlpi_kread(kd, (off_t)ifnet.if_name,
97775107Sfenner		    if_name, sizeof(ifnet.if_name), ebuf) < 0) {
97817683Spst			(void)close(kd);
97917683Spst			return (-1);
98017683Spst		}
98175107Sfenner		if_name[sizeof(ifnet.if_name)] = '\0';
98275107Sfenner		if (strcmp(if_name, ifname) == 0 && ifnet.if_unit == unit)
98317683Spst			return (ifnet.if_index);
98417683Spst	}
98517683Spst
98675107Sfenner	snprintf(ebuf, PCAP_ERRBUF_SIZE, "Can't find %s", ifname);
98717683Spst	return (-1);
98817683Spst}
98917683Spst
99017683Spststatic int
99117683Spstdlpi_kread(register int fd, register off_t addr,
99217683Spst    register void *buf, register u_int len, register char *ebuf)
99317683Spst{
99417683Spst	register int cc;
99517683Spst
99639291Sfenner	if (lseek(fd, addr, SEEK_SET) < 0) {
99775107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE, "lseek: %s",
99875107Sfenner		    pcap_strerror(errno));
99917683Spst		return (-1);
100017683Spst	}
100117683Spst	cc = read(fd, buf, len);
100217683Spst	if (cc < 0) {
100375107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE, "read: %s",
100475107Sfenner		    pcap_strerror(errno));
100517683Spst		return (-1);
100617683Spst	} else if (cc != len) {
100775107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE, "short read (%d != %d)", cc,
100875107Sfenner		    len);
100917683Spst		return (-1);
101017683Spst	}
101117683Spst	return (cc);
101217683Spst}
101317683Spst#endif
1014