pcap-dlpi.c revision 127664
184865Sobrien/*
284865Sobrien * Copyright (c) 1993, 1994, 1995, 1996, 1997
384865Sobrien *	The Regents of the University of California.  All rights reserved.
484865Sobrien *
584865Sobrien * Redistribution and use in source and binary forms, with or without
684865Sobrien * modification, are permitted provided that: (1) source code distributions
784865Sobrien * retain the above copyright notice and this paragraph in its entirety, (2)
884865Sobrien * distributions including binary code include the above copyright notice and
984865Sobrien * this paragraph in its entirety in the documentation or other materials
1084865Sobrien * provided with the distribution, and (3) all advertising materials mentioning
1184865Sobrien * features or use of this software display the following acknowledgement:
1284865Sobrien * ``This product includes software developed by the University of California,
1384865Sobrien * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
1484865Sobrien * the University nor the names of its contributors may be used to endorse
1584865Sobrien * or promote products derived from this software without specific prior
1684865Sobrien * written permission.
1784865Sobrien * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
1884865Sobrien * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1984865Sobrien * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2084865Sobrien *
2184865Sobrien * This code contributed by Atanu Ghosh (atanu@cs.ucl.ac.uk),
2284865Sobrien * University College London.
2384865Sobrien */
2484865Sobrien
2584865Sobrien/*
2684865Sobrien * Packet capture routine for DLPI under SunOS 5, HP-UX 9/10/11, and AIX.
2784865Sobrien *
2884865Sobrien * Notes:
2984865Sobrien *
3084865Sobrien *    - Apparently the DLIOCRAW ioctl() is specific to SunOS.
3184865Sobrien *
3284865Sobrien *    - There is a bug in bufmod(7) such that setting the snapshot
3384865Sobrien *      length results in data being left of the front of the packet.
3484865Sobrien *
35104834Sobrien *    - It might be desirable to use pfmod(7) to filter packets in the
3684865Sobrien *      kernel when possible.
3784865Sobrien */
3884865Sobrien
3984865Sobrien#ifndef lint
4084865Sobrienstatic const char rcsid[] _U_ =
4184865Sobrien    "@(#) $Header: /tcpdump/master/libpcap/pcap-dlpi.c,v 1.91.2.3 2003/11/21 10:20:46 guy Exp $ (LBL)";
4284865Sobrien#endif
4384865Sobrien
4484865Sobrien#ifdef HAVE_CONFIG_H
45104834Sobrien#include "config.h"
4684865Sobrien#endif
4784865Sobrien
4884865Sobrien#include <sys/types.h>
4984865Sobrien#include <sys/time.h>
5084865Sobrien#ifdef HAVE_SYS_BUFMOD_H
51104834Sobrien#include <sys/bufmod.h>
52104834Sobrien#endif
5384865Sobrien#include <sys/dlpi.h>
5484865Sobrien#ifdef HAVE_SYS_DLPI_EXT_H
5584865Sobrien#include <sys/dlpi_ext.h>
5684865Sobrien#endif
5784865Sobrien#ifdef HAVE_HPUX9
5884865Sobrien#include <sys/socket.h>
5984865Sobrien#endif
6084865Sobrien#ifdef DL_HP_PPA_ACK_OBS
6184865Sobrien#include <sys/stat.h>
6284865Sobrien#endif
6384865Sobrien#include <sys/stream.h>
6484865Sobrien#if defined(HAVE_SOLARIS) && defined(HAVE_SYS_BUFMOD_H)
6584865Sobrien#include <sys/systeminfo.h>
6684865Sobrien#endif
6784865Sobrien
6884865Sobrien#ifdef HAVE_HPUX9
6984865Sobrien#include <net/if.h>
7084865Sobrien#endif
7184865Sobrien
7284865Sobrien#include <ctype.h>
7384865Sobrien#ifdef HAVE_HPUX9
7484865Sobrien#include <nlist.h>
7584865Sobrien#endif
7684865Sobrien#include <errno.h>
7784865Sobrien#include <fcntl.h>
7884865Sobrien#include <memory.h>
7984865Sobrien#include <stdio.h>
8084865Sobrien#include <stdlib.h>
8184865Sobrien#include <string.h>
8284865Sobrien#include <stropts.h>
8384865Sobrien#include <unistd.h>
8484865Sobrien
8584865Sobrien#include "pcap-int.h"
8684865Sobrien
8784865Sobrien#ifdef HAVE_OS_PROTO_H
8884865Sobrien#include "os-proto.h"
8984865Sobrien#endif
9084865Sobrien
9184865Sobrien#ifndef PCAP_DEV_PREFIX
9284865Sobrien#ifdef _AIX
9384865Sobrien#define PCAP_DEV_PREFIX "/dev/dlpi"
9484865Sobrien#else
9584865Sobrien#define PCAP_DEV_PREFIX "/dev"
9684865Sobrien#endif
9784865Sobrien#endif
9884865Sobrien
9984865Sobrien#define	MAXDLBUF	8192
10084865Sobrien
10184865Sobrien#ifdef HAVE_SYS_BUFMOD_H
10284865Sobrien
10384865Sobrien/*
10484865Sobrien * Size of a bufmod chunk to pass upstream; that appears to be the biggest
10584865Sobrien * value to which you can set it, and setting it to that value (which
10684865Sobrien * is bigger than what appears to be the Solaris default of 8192)
10784865Sobrien * reduces the number of packet drops.
10884865Sobrien */
10984865Sobrien#define CHUNKSIZE	65536
11084865Sobrien
11184865Sobrien/*
11284865Sobrien * Size of the buffer to allocate for packet data we read; it must be
11384865Sobrien * large enough to hold a chunk.
11484865Sobrien */
11584865Sobrien#define PKTBUFSIZE	CHUNKSIZE
11684865Sobrien
11784865Sobrien#else /* HAVE_SYS_BUFMOD_H */
11884865Sobrien
11984865Sobrien/*
12084865Sobrien * Size of the buffer to allocate for packet data we read; this is
12184865Sobrien * what the value used to be - there's no particular reason why it
12284865Sobrien * should be tied to MAXDLBUF, but we'll leave it as this for now.
12384865Sobrien */
12484865Sobrien#define PKTBUFSIZE	(MAXDLBUF * sizeof(bpf_u_int32))
12584865Sobrien
12684865Sobrien#endif
12784865Sobrien
12884865Sobrien/* Forwards */
12984865Sobrienstatic char *split_dname(char *, int *, char *);
13084865Sobrienstatic int dlattachreq(int, bpf_u_int32, char *);
13184865Sobrienstatic int dlbindack(int, char *, char *);
13284865Sobrienstatic int dlbindreq(int, bpf_u_int32, char *);
13384865Sobrienstatic int dlinfoack(int, char *, char *);
13484865Sobrienstatic int dlinforeq(int, char *);
13584865Sobrienstatic int dlokack(int, const char *, char *, char *);
13684865Sobrienstatic int recv_ack(int, int, const char *, char *, char *);
13784865Sobrienstatic char *dlstrerror(bpf_u_int32);
13884865Sobrienstatic char *dlprim(bpf_u_int32);
13984865Sobrienstatic int dlpromisconreq(int, bpf_u_int32, char *);
14084865Sobrien#if defined(HAVE_SOLARIS) && defined(HAVE_SYS_BUFMOD_H)
14184865Sobrienstatic char *get_release(bpf_u_int32 *, bpf_u_int32 *, bpf_u_int32 *);
14284865Sobrien#endif
14384865Sobrienstatic int send_request(int, char *, int, char *, char *);
14484865Sobrien#ifdef HAVE_SYS_BUFMOD_H
14584865Sobrienstatic int strioctl(int, int, int, char *);
14684865Sobrien#endif
14784865Sobrien#ifdef HAVE_HPUX9
14884865Sobrienstatic int dlpi_kread(int, off_t, void *, u_int, char *);
14984865Sobrien#endif
15084865Sobrien#ifdef HAVE_DEV_DLPI
15184865Sobrienstatic int get_dlpi_ppa(int, const char *, int, char *);
15284865Sobrien#endif
15384865Sobrien
15484865Sobrienstatic int
15584865Sobrienpcap_stats_dlpi(pcap_t *p, struct pcap_stat *ps)
15684865Sobrien{
15784865Sobrien
15884865Sobrien	/*
15984865Sobrien	 * "ps_recv" counts packets handed to the filter, not packets
16084865Sobrien	 * that passed the filter.  As filtering is done in userland,
16184865Sobrien	 * this does not include packets dropped because we ran out
16284865Sobrien	 * of buffer space.
16384865Sobrien	 *
16484865Sobrien	 * "ps_drop" counts packets dropped inside the DLPI service
16584865Sobrien	 * provider device device because of flow control requirements
16684865Sobrien	 * or resource exhaustion; it doesn't count packets dropped by
16784865Sobrien	 * the interface driver, or packets dropped upstream.  As
16884865Sobrien	 * filtering is done in userland, it counts packets regardless
16984865Sobrien	 * of whether they would've passed the filter.
17084865Sobrien	 *
17184865Sobrien	 * These statistics don't include packets not yet read from
17284865Sobrien	 * the kernel by libpcap, but they may include packets not
17384865Sobrien	 * yet read from libpcap by the application.
17484865Sobrien	 */
17584865Sobrien	*ps = p->md.stat;
17684865Sobrien	return (0);
17784865Sobrien}
17884865Sobrien
17984865Sobrien/* XXX Needed by HP-UX (at least) */
18084865Sobrienstatic bpf_u_int32 ctlbuf[MAXDLBUF];
18184865Sobrienstatic struct strbuf ctl = {
18284865Sobrien	MAXDLBUF,
18384865Sobrien	0,
18484865Sobrien	(char *)ctlbuf
18584865Sobrien};
18684865Sobrien
18784865Sobrienstatic int
18884865Sobrienpcap_read_dlpi(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
18984865Sobrien{
19084865Sobrien	register int cc, n, caplen, origlen;
19184865Sobrien	register u_char *bp, *ep, *pk;
19284865Sobrien	register struct bpf_insn *fcode;
19384865Sobrien#ifdef HAVE_SYS_BUFMOD_H
19484865Sobrien	register struct sb_hdr *sbp;
195104834Sobrien#ifdef LBL_ALIGN
196104834Sobrien	struct sb_hdr sbhdr;
197104834Sobrien#endif
198104834Sobrien#endif
199104834Sobrien	int flags;
200104834Sobrien	struct strbuf data;
201104834Sobrien	struct pcap_pkthdr pkthdr;
202104834Sobrien
203104834Sobrien	flags = 0;
204104834Sobrien	cc = p->cc;
205104834Sobrien	if (cc == 0) {
206104834Sobrien		data.buf = (char *)p->buffer + p->offset;
207104834Sobrien		data.maxlen = p->bufsize;
208104834Sobrien		data.len = 0;
209104834Sobrien		do {
210104834Sobrien			/*
211104834Sobrien			 * Has "pcap_breakloop()" been called?
212104834Sobrien			 */
213104834Sobrien			if (p->break_loop) {
214104834Sobrien				/*
215104834Sobrien				 * Yes - clear the flag that indicates
216104834Sobrien				 * that it has, and return -2 to
217104834Sobrien				 * indicate that we were told to
218104834Sobrien				 * break out of the loop.
21984865Sobrien				 */
22084865Sobrien				p->break_loop = 0;
22184865Sobrien				return (-2);
22284865Sobrien			}
22384865Sobrien			if (getmsg(p->fd, &ctl, &data, &flags) < 0) {
22484865Sobrien				/* Don't choke when we get ptraced */
22584865Sobrien				if (errno == EINTR) {
22684865Sobrien					cc = 0;
22784865Sobrien					continue;
22884865Sobrien				}
22984865Sobrien				strlcpy(p->errbuf, pcap_strerror(errno),
23084865Sobrien				    sizeof(p->errbuf));
23184865Sobrien				return (-1);
23284865Sobrien			}
23384865Sobrien			cc = data.len;
23484865Sobrien		} while (cc == 0);
23584865Sobrien		bp = p->buffer + p->offset;
23684865Sobrien	} else
23784865Sobrien		bp = p->bp;
23884865Sobrien
23984865Sobrien	/* Loop through packets */
24084865Sobrien	fcode = p->fcode.bf_insns;
24184865Sobrien	ep = bp + cc;
24284865Sobrien	n = 0;
24384865Sobrien#ifdef HAVE_SYS_BUFMOD_H
24484865Sobrien	while (bp < ep) {
24584865Sobrien		/*
24684865Sobrien		 * Has "pcap_breakloop()" been called?
24784865Sobrien		 * If so, return immediately - if we haven't read any
24884865Sobrien		 * packets, clear the flag and return -2 to indicate
24984865Sobrien		 * that we were told to break out of the loop, otherwise
25084865Sobrien		 * leave the flag set, so that the *next* call will break
25184865Sobrien		 * out of the loop without having read any packets, and
25284865Sobrien		 * return the number of packets we've processed so far.
25384865Sobrien		 */
25484865Sobrien		if (p->break_loop) {
25584865Sobrien			if (n == 0) {
25684865Sobrien				p->break_loop = 0;
25784865Sobrien				return (-2);
25884865Sobrien			} else {
25984865Sobrien				p->bp = bp;
26084865Sobrien				p->cc = ep - bp;
26184865Sobrien				return (n);
26284865Sobrien			}
26384865Sobrien		}
26484865Sobrien#ifdef LBL_ALIGN
26584865Sobrien		if ((long)bp & 3) {
26684865Sobrien			sbp = &sbhdr;
26784865Sobrien			memcpy(sbp, bp, sizeof(*sbp));
26884865Sobrien		} else
26984865Sobrien#endif
27084865Sobrien			sbp = (struct sb_hdr *)bp;
27184865Sobrien		p->md.stat.ps_drop = sbp->sbh_drops;
27284865Sobrien		pk = bp + sizeof(*sbp);
27384865Sobrien		bp += sbp->sbh_totlen;
27484865Sobrien		origlen = sbp->sbh_origlen;
27584865Sobrien		caplen = sbp->sbh_msglen;
27684865Sobrien#else
27784865Sobrien		origlen = cc;
27884865Sobrien		caplen = min(p->snapshot, cc);
27984865Sobrien		pk = bp;
28084865Sobrien		bp += caplen;
28184865Sobrien#endif
28284865Sobrien		++p->md.stat.ps_recv;
28384865Sobrien		if (bpf_filter(fcode, pk, origlen, caplen)) {
28484865Sobrien#ifdef HAVE_SYS_BUFMOD_H
28584865Sobrien			pkthdr.ts.tv_sec = sbp->sbh_timestamp.tv_sec;
28684865Sobrien			pkthdr.ts.tv_usec = sbp->sbh_timestamp.tv_usec;
28784865Sobrien#else
28884865Sobrien			(void)gettimeofday(&pkthdr.ts, NULL);
28984865Sobrien#endif
29084865Sobrien			pkthdr.len = origlen;
29184865Sobrien			pkthdr.caplen = caplen;
29284865Sobrien			/* Insure caplen does not exceed snapshot */
29384865Sobrien			if (pkthdr.caplen > p->snapshot)
29484865Sobrien				pkthdr.caplen = p->snapshot;
29584865Sobrien			(*callback)(user, &pkthdr, pk);
29684865Sobrien			if (++n >= cnt && cnt >= 0) {
29784865Sobrien				p->cc = ep - bp;
29884865Sobrien				p->bp = bp;
29984865Sobrien				return (n);
30084865Sobrien			}
30184865Sobrien		}
30284865Sobrien#ifdef HAVE_SYS_BUFMOD_H
30384865Sobrien	}
30484865Sobrien#endif
30584865Sobrien	p->cc = 0;
30684865Sobrien	return (n);
30784865Sobrien}
30884865Sobrien
30984865Sobrien#ifndef DL_IPATM
31084865Sobrien#define DL_IPATM	0x12	/* ATM Classical IP interface */
31184865Sobrien#endif
31284865Sobrien
31384865Sobrien#ifdef HAVE_SOLARIS
31484865Sobrien/*
31584865Sobrien * For SunATM.
31684865Sobrien */
31784865Sobrien#ifndef A_GET_UNITS
31884865Sobrien#define A_GET_UNITS	(('A'<<8)|118)
31984865Sobrien#endif /* A_GET_UNITS */
32084865Sobrien#ifndef A_PROMISCON_REQ
32184865Sobrien#define A_PROMISCON_REQ	(('A'<<8)|121)
32284865Sobrien#endif /* A_PROMISCON_REQ */
32384865Sobrien#endif /* HAVE_SOLARIS */
32484865Sobrien
32584865Sobrienstatic void
32684865Sobrienpcap_close_dlpi(pcap_t *p)
32784865Sobrien{
32884865Sobrien	if (p->buffer != NULL)
32984865Sobrien		free(p->buffer);
33084865Sobrien	if (p->fd >= 0)
33184865Sobrien		close(p->fd);
33284865Sobrien}
33384865Sobrien
33484865Sobrienpcap_t *
33584865Sobrienpcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
33684865Sobrien    char *ebuf)
33784865Sobrien{
33884865Sobrien	register char *cp;
33984865Sobrien	register pcap_t *p;
34084865Sobrien	int ppa;
34184865Sobrien#ifdef HAVE_SOLARIS
34284865Sobrien	int isatm = 0;
34384865Sobrien#endif
34484865Sobrien	register dl_info_ack_t *infop;
34584865Sobrien#ifdef HAVE_SYS_BUFMOD_H
34684865Sobrien	bpf_u_int32 ss, chunksize;
34784865Sobrien#ifdef HAVE_SOLARIS
34884865Sobrien	register char *release;
34984865Sobrien	bpf_u_int32 osmajor, osminor, osmicro;
35084865Sobrien#endif
35184865Sobrien#endif
35284865Sobrien	bpf_u_int32 buf[MAXDLBUF];
35384865Sobrien	char dname[100];
35484865Sobrien#ifndef HAVE_DEV_DLPI
35584865Sobrien	char dname2[100];
35684865Sobrien#endif
35784865Sobrien
35884865Sobrien	p = (pcap_t *)malloc(sizeof(*p));
35984865Sobrien	if (p == NULL) {
36084865Sobrien		strlcpy(ebuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE);
36184865Sobrien		return (NULL);
36284865Sobrien	}
36384865Sobrien	memset(p, 0, sizeof(*p));
36484865Sobrien	p->fd = -1;	/* indicate that it hasn't been opened yet */
36584865Sobrien
36684865Sobrien#ifdef HAVE_DEV_DLPI
36784865Sobrien	/*
36884865Sobrien	** Remove any "/dev/" on the front of the device.
36984865Sobrien	*/
37084865Sobrien	cp = strrchr(device, '/');
37184865Sobrien	if (cp == NULL)
37284865Sobrien		strlcpy(dname, device, sizeof(dname));
37384865Sobrien	else
37484865Sobrien		strlcpy(dname, cp + 1, sizeof(dname));
37584865Sobrien
37684865Sobrien	/*
37784865Sobrien	 * Split the device name into a device type name and a unit number;
37884865Sobrien	 * chop off the unit number, so "dname" is just a device type name.
37984865Sobrien	 */
38084865Sobrien	cp = split_dname(dname, &ppa, ebuf);
38184865Sobrien	if (cp == NULL)
38284865Sobrien		goto bad;
38384865Sobrien	*cp = '\0';
38484865Sobrien
38584865Sobrien	/*
38684865Sobrien	 * Use "/dev/dlpi" as the device.
38784865Sobrien	 *
38884865Sobrien	 * XXX - HP's DLPI Programmer's Guide for HP-UX 11.00 says that
38984865Sobrien	 * the "dl_mjr_num" field is for the "major number of interface
39084865Sobrien	 * driver"; that's the major of "/dev/dlpi" on the system on
39184865Sobrien	 * which I tried this, but there may be DLPI devices that
39284865Sobrien	 * use a different driver, in which case we may need to
39384865Sobrien	 * search "/dev" for the appropriate device with that major
39484865Sobrien	 * device number, rather than hardwiring "/dev/dlpi".
39584865Sobrien	 */
39684865Sobrien	cp = "/dev/dlpi";
39784865Sobrien	if ((p->fd = open(cp, O_RDWR)) < 0) {
39884865Sobrien		snprintf(ebuf, PCAP_ERRBUF_SIZE,
39984865Sobrien		    "%s: %s", cp, pcap_strerror(errno));
40084865Sobrien		goto bad;
40184865Sobrien	}
40284865Sobrien
40384865Sobrien	/*
40484865Sobrien	 * Get a table of all PPAs for that device, and search that
40584865Sobrien	 * table for the specified device type name and unit number.
40684865Sobrien	 */
40784865Sobrien	ppa = get_dlpi_ppa(p->fd, dname, ppa, ebuf);
40884865Sobrien	if (ppa < 0)
40984865Sobrien		goto bad;
41084865Sobrien#else
41184865Sobrien	/*
41284865Sobrien	 * If the device name begins with "/", assume it begins with
41384865Sobrien	 * the pathname of the directory containing the device to open;
41484865Sobrien	 * otherwise, concatenate the device directory name and the
41584865Sobrien	 * device name.
41684865Sobrien	 */
41784865Sobrien	if (*device == '/')
41884865Sobrien		strlcpy(dname, device, sizeof(dname));
41984865Sobrien	else
42084865Sobrien		snprintf(dname, sizeof(dname), "%s/%s", PCAP_DEV_PREFIX,
42184865Sobrien		    device);
42284865Sobrien
42384865Sobrien	/*
42484865Sobrien	 * Get the unit number, and a pointer to the end of the device
42584865Sobrien	 * type name.
42684865Sobrien	 */
42784865Sobrien	cp = split_dname(dname, &ppa, ebuf);
42884865Sobrien	if (cp == NULL)
42984865Sobrien		goto bad;
43084865Sobrien
43184865Sobrien	/*
43284865Sobrien	 * Make a copy of the device pathname, and then remove the unit
43384865Sobrien	 * number from the device pathname.
43484865Sobrien	 */
43584865Sobrien	strlcpy(dname2, dname, sizeof(dname));
43684865Sobrien	*cp = '\0';
43784865Sobrien
43884865Sobrien	/* Try device without unit number */
43984865Sobrien	if ((p->fd = open(dname, O_RDWR)) < 0) {
44084865Sobrien		if (errno != ENOENT) {
44184865Sobrien			snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s: %s", dname,
44284865Sobrien			    pcap_strerror(errno));
44384865Sobrien			goto bad;
44484865Sobrien		}
44584865Sobrien
44684865Sobrien		/* Try again with unit number */
44784865Sobrien		if ((p->fd = open(dname2, O_RDWR)) < 0) {
44884865Sobrien			snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s: %s", dname2,
44984865Sobrien			    pcap_strerror(errno));
45084865Sobrien			goto bad;
45184865Sobrien		}
45284865Sobrien		/* XXX Assume unit zero */
45384865Sobrien		ppa = 0;
45484865Sobrien	}
45584865Sobrien#endif
45684865Sobrien
45784865Sobrien	p->snapshot = snaplen;
45884865Sobrien
45984865Sobrien	/*
46084865Sobrien	** Attach if "style 2" provider
46184865Sobrien	*/
46284865Sobrien	if (dlinforeq(p->fd, ebuf) < 0 ||
46384865Sobrien	    dlinfoack(p->fd, (char *)buf, ebuf) < 0)
46484865Sobrien		goto bad;
46584865Sobrien	infop = &((union DL_primitives *)buf)->info_ack;
46684865Sobrien#ifdef HAVE_SOLARIS
46784865Sobrien	if (infop->dl_mac_type == DL_IPATM)
46884865Sobrien		isatm = 1;
46984865Sobrien#endif
47084865Sobrien	if (infop->dl_provider_style == DL_STYLE2 &&
47184865Sobrien	    (dlattachreq(p->fd, ppa, ebuf) < 0 ||
47284865Sobrien	    dlokack(p->fd, "attach", (char *)buf, ebuf) < 0))
47384865Sobrien		goto bad;
47484865Sobrien	/*
47584865Sobrien	** Bind (defer if using HP-UX 9 or HP-UX 10.20, totally skip if
47684865Sobrien	** using SINIX)
477104834Sobrien	*/
47884865Sobrien#if !defined(HAVE_HPUX9) && !defined(HAVE_HPUX10_20) && !defined(sinix)
47984865Sobrien#ifdef _AIX
48084865Sobrien	/* According to IBM's AIX Support Line, the dl_sap value
48184865Sobrien	** should not be less than 0x600 (1536) for standard Ethernet.
48284865Sobrien	** However, we seem to get DL_BADADDR - "DLSAP addr in improper
48384865Sobrien	** format or invalid" - errors if we use 1537 on the "tr0"
48484865Sobrien	** device, which, given that its name starts with "tr" and that
48584865Sobrien	** it's IBM, probably means a Token Ring device.  (Perhaps we
486104834Sobrien	** need to use 1537 on "/dev/dlpi/en" because that device is for
48784865Sobrien	** D/I/X Ethernet, the "SAP" is actually an Ethernet type, and
48884865Sobrien	** it rejects invalid Ethernet types.)
48984865Sobrien	**
490104834Sobrien	** So if 1537 fails, we try 2, as Hyung Sik Yoon of IBM Korea
49184865Sobrien	** says that works on Token Ring (he says that 0 does *not*
49284865Sobrien	** work; perhaps that's considered an invalid LLC SAP value - I
49384865Sobrien	** assume the SAP value in a DLPI bind is an LLC SAP for network
49484865Sobrien	** types that use 802.2 LLC).
49584865Sobrien	*/
49684865Sobrien	if ((dlbindreq(p->fd, 1537, ebuf) < 0 &&
497	     dlbindreq(p->fd, 2, ebuf) < 0) ||
498#else
499	if (dlbindreq(p->fd, 0, ebuf) < 0 ||
500#endif
501	    dlbindack(p->fd, (char *)buf, ebuf) < 0)
502		goto bad;
503#endif
504
505#ifdef HAVE_SOLARIS
506	if (isatm) {
507		/*
508		** Have to turn on some special ATM promiscuous mode
509		** for SunATM.
510		** Do *NOT* turn regular promiscuous mode on; it doesn't
511		** help, and may break things.
512		*/
513		if (strioctl(p->fd, A_PROMISCON_REQ, 0, NULL) < 0) {
514			snprintf(ebuf, PCAP_ERRBUF_SIZE, "A_PROMISCON_REQ: %s",
515			    pcap_strerror(errno));
516			goto bad;
517		}
518	} else
519#endif
520	if (promisc) {
521		/*
522		** Enable promiscuous
523		*/
524		if (dlpromisconreq(p->fd, DL_PROMISC_PHYS, ebuf) < 0 ||
525		    dlokack(p->fd, "promisc_phys", (char *)buf, ebuf) < 0)
526			goto bad;
527
528		/*
529		** Try to enable multicast (you would have thought
530		** promiscuous would be sufficient). (Skip if using
531		** HP-UX or SINIX)
532		*/
533#if !defined(__hpux) && !defined(sinix)
534		if (dlpromisconreq(p->fd, DL_PROMISC_MULTI, ebuf) < 0 ||
535		    dlokack(p->fd, "promisc_multi", (char *)buf, ebuf) < 0)
536			fprintf(stderr,
537			    "WARNING: DL_PROMISC_MULTI failed (%s)\n", ebuf);
538#endif
539	}
540	/*
541	** Try to enable sap (when not in promiscuous mode when using
542	** using HP-UX, when not doing SunATM on Solaris, and never
543	** under SINIX)
544	*/
545#ifndef sinix
546	if (
547#ifdef __hpux
548	    !promisc &&
549#endif
550#ifdef HAVE_SOLARIS
551	    !isatm &&
552#endif
553	    (dlpromisconreq(p->fd, DL_PROMISC_SAP, ebuf) < 0 ||
554	    dlokack(p->fd, "promisc_sap", (char *)buf, ebuf) < 0)) {
555		/* Not fatal if promisc since the DL_PROMISC_PHYS worked */
556		if (promisc)
557			fprintf(stderr,
558			    "WARNING: DL_PROMISC_SAP failed (%s)\n", ebuf);
559		else
560			goto bad;
561	}
562#endif
563
564	/*
565	** HP-UX 9 and HP-UX 10.20 must bind after setting promiscuous
566	** options)
567	*/
568#if defined(HAVE_HPUX9) || defined(HAVE_HPUX10_20)
569	if (dlbindreq(p->fd, 0, ebuf) < 0 ||
570	    dlbindack(p->fd, (char *)buf, ebuf) < 0)
571		goto bad;
572#endif
573
574	/*
575	** Determine link type
576	*/
577	if (dlinforeq(p->fd, ebuf) < 0 ||
578	    dlinfoack(p->fd, (char *)buf, ebuf) < 0)
579		goto bad;
580
581	infop = &((union DL_primitives *)buf)->info_ack;
582	switch (infop->dl_mac_type) {
583
584	case DL_CSMACD:
585	case DL_ETHER:
586		p->linktype = DLT_EN10MB;
587		p->offset = 2;
588		break;
589
590	case DL_FDDI:
591		p->linktype = DLT_FDDI;
592		p->offset = 3;
593		break;
594
595	case DL_TPR:
596		p->linktype = DLT_IEEE802;
597		p->offset = 2;
598		break;
599
600#ifdef HAVE_SOLARIS
601	case DL_IPATM:
602		p->linktype = DLT_SUNATM;
603		p->offset = 0;	/* works for LANE and LLC encapsulation */
604		break;
605#endif
606
607	default:
608		snprintf(ebuf, PCAP_ERRBUF_SIZE, "unknown mac type %lu",
609		    (unsigned long)infop->dl_mac_type);
610		goto bad;
611	}
612
613#ifdef	DLIOCRAW
614	/*
615	** This is a non standard SunOS hack to get the full raw link-layer
616	** header.
617	*/
618	if (strioctl(p->fd, DLIOCRAW, 0, NULL) < 0) {
619		snprintf(ebuf, PCAP_ERRBUF_SIZE, "DLIOCRAW: %s",
620		    pcap_strerror(errno));
621		goto bad;
622	}
623#endif
624
625#ifdef HAVE_SYS_BUFMOD_H
626	/*
627	** Another non standard call to get the data nicely buffered
628	*/
629	if (ioctl(p->fd, I_PUSH, "bufmod") != 0) {
630		snprintf(ebuf, PCAP_ERRBUF_SIZE, "I_PUSH bufmod: %s",
631		    pcap_strerror(errno));
632		goto bad;
633	}
634
635	/*
636	** Now that the bufmod is pushed lets configure it.
637	**
638	** There is a bug in bufmod(7). When dealing with messages of
639	** less than snaplen size it strips data from the beginning not
640	** the end.
641	**
642	** This bug is supposed to be fixed in 5.3.2. Also, there is a
643	** patch available. Ask for bugid 1149065.
644	*/
645	ss = snaplen;
646#ifdef HAVE_SOLARIS
647	release = get_release(&osmajor, &osminor, &osmicro);
648	if (osmajor == 5 && (osminor <= 2 || (osminor == 3 && osmicro < 2)) &&
649	    getenv("BUFMOD_FIXED") == NULL) {
650		fprintf(stderr,
651		"WARNING: bufmod is broken in SunOS %s; ignoring snaplen.\n",
652		    release);
653		ss = 0;
654	}
655#endif
656	if (ss > 0 &&
657	    strioctl(p->fd, SBIOCSSNAP, sizeof(ss), (char *)&ss) != 0) {
658		snprintf(ebuf, PCAP_ERRBUF_SIZE, "SBIOCSSNAP: %s",
659		    pcap_strerror(errno));
660		goto bad;
661	}
662
663	/*
664	** Set up the bufmod timeout
665	*/
666	if (to_ms != 0) {
667		struct timeval to;
668
669		to.tv_sec = to_ms / 1000;
670		to.tv_usec = (to_ms * 1000) % 1000000;
671		if (strioctl(p->fd, SBIOCSTIME, sizeof(to), (char *)&to) != 0) {
672			snprintf(ebuf, PCAP_ERRBUF_SIZE, "SBIOCSTIME: %s",
673			    pcap_strerror(errno));
674			goto bad;
675		}
676	}
677
678	/*
679	** Set the chunk length.
680	*/
681	chunksize = CHUNKSIZE;
682	if (strioctl(p->fd, SBIOCSCHUNK, sizeof(chunksize), (char *)&chunksize)
683	    != 0) {
684		snprintf(ebuf, PCAP_ERRBUF_SIZE, "SBIOCSCHUNKP: %s",
685		    pcap_strerror(errno));
686		goto bad;
687	}
688#endif
689
690	/*
691	** As the last operation flush the read side.
692	*/
693	if (ioctl(p->fd, I_FLUSH, FLUSHR) != 0) {
694		snprintf(ebuf, PCAP_ERRBUF_SIZE, "FLUSHR: %s",
695		    pcap_strerror(errno));
696		goto bad;
697	}
698
699	/* Allocate data buffer */
700	p->bufsize = PKTBUFSIZE;
701	p->buffer = (u_char *)malloc(p->bufsize + p->offset);
702	if (p->buffer == NULL) {
703		strlcpy(ebuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE);
704		goto bad;
705	}
706
707	/*
708	 * "p->fd" is an FD for a STREAMS device, so "select()" and
709	 * "poll()" should work on it.
710	 */
711	p->selectable_fd = p->fd;
712
713	p->read_op = pcap_read_dlpi;
714	p->setfilter_op = install_bpf_program;	/* no kernel filtering */
715	p->set_datalink_op = NULL;	/* can't change data link type */
716	p->getnonblock_op = pcap_getnonblock_fd;
717	p->setnonblock_op = pcap_setnonblock_fd;
718	p->stats_op = pcap_stats_dlpi;
719	p->close_op = pcap_close_dlpi;
720
721	return (p);
722bad:
723	if (p->fd >= 0)
724		close(p->fd);
725	free(p);
726	return (NULL);
727}
728
729/*
730 * Split a device name into a device type name and a unit number;
731 * return the a pointer to the beginning of the unit number, which
732 * is the end of the device type name, and set "*unitp" to the unit
733 * number.
734 *
735 * Returns NULL on error, and fills "ebuf" with an error message.
736 */
737static char *
738split_dname(char *device, int *unitp, char *ebuf)
739{
740	char *cp;
741	char *eos;
742	int unit;
743
744	/*
745	 * Look for a number at the end of the device name string.
746	 */
747	cp = device + strlen(device) - 1;
748	if (*cp < '0' || *cp > '9') {
749		snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s missing unit number",
750		    device);
751		return (NULL);
752	}
753
754	/* Digits at end of string are unit number */
755	while (cp-1 >= device && *(cp-1) >= '0' && *(cp-1) <= '9')
756		cp--;
757
758	unit = strtol(cp, &eos, 10);
759	if (*eos != '\0') {
760		snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s bad unit number", device);
761		return (NULL);
762	}
763	*unitp = unit;
764	return (cp);
765}
766
767int
768pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf)
769{
770#ifdef HAVE_SOLARIS
771	int fd;
772	union {
773		u_int nunits;
774		char pad[516];	/* XXX - must be at least 513; is 516
775				   in "atmgetunits" */
776	} buf;
777	char baname[2+1+1];
778	u_int i;
779
780	/*
781	 * We may have to do special magic to get ATM devices.
782	 */
783	if ((fd = open("/dev/ba", O_RDWR)) < 0) {
784		/*
785		 * We couldn't open the "ba" device.
786		 * For now, just give up; perhaps we should
787		 * return an error if the problem is neither
788		 * a "that device doesn't exist" error (ENOENT,
789		 * ENXIO, etc.) or a "you're not allowed to do
790		 * that" error (EPERM, EACCES).
791		 */
792		return (0);
793	}
794
795	if (strioctl(fd, A_GET_UNITS, sizeof(buf), (char *)&buf) < 0) {
796		snprintf(errbuf, PCAP_ERRBUF_SIZE, "A_GET_UNITS: %s",
797		    pcap_strerror(errno));
798		return (-1);
799	}
800	for (i = 0; i < buf.nunits; i++) {
801		snprintf(baname, sizeof baname, "ba%u", i);
802		if (pcap_add_if(alldevsp, baname, 0, NULL, errbuf) < 0)
803			return (-1);
804	}
805#endif
806
807	return (0);
808}
809
810static int
811send_request(int fd, char *ptr, int len, char *what, char *ebuf)
812{
813	struct	strbuf	ctl;
814	int	flags;
815
816	ctl.maxlen = 0;
817	ctl.len = len;
818	ctl.buf = ptr;
819
820	flags = 0;
821	if (putmsg(fd, &ctl, (struct strbuf *) NULL, flags) < 0) {
822		snprintf(ebuf, PCAP_ERRBUF_SIZE,
823		    "send_request: putmsg \"%s\": %s",
824		    what, pcap_strerror(errno));
825		return (-1);
826	}
827	return (0);
828}
829
830static int
831recv_ack(int fd, int size, const char *what, char *bufp, char *ebuf)
832{
833	union	DL_primitives	*dlp;
834	struct	strbuf	ctl;
835	int	flags;
836
837	ctl.maxlen = MAXDLBUF;
838	ctl.len = 0;
839	ctl.buf = bufp;
840
841	flags = 0;
842	if (getmsg(fd, &ctl, (struct strbuf*)NULL, &flags) < 0) {
843		snprintf(ebuf, PCAP_ERRBUF_SIZE, "recv_ack: %s getmsg: %s",
844		    what, pcap_strerror(errno));
845		return (-1);
846	}
847
848	dlp = (union DL_primitives *) ctl.buf;
849	switch (dlp->dl_primitive) {
850
851	case DL_INFO_ACK:
852	case DL_BIND_ACK:
853	case DL_OK_ACK:
854#ifdef DL_HP_PPA_ACK
855	case DL_HP_PPA_ACK:
856#endif
857		/* These are OK */
858		break;
859
860	case DL_ERROR_ACK:
861		switch (dlp->error_ack.dl_errno) {
862
863		case DL_SYSERR:
864			snprintf(ebuf, PCAP_ERRBUF_SIZE,
865			    "recv_ack: %s: UNIX error - %s",
866			    what, pcap_strerror(dlp->error_ack.dl_unix_errno));
867			break;
868
869		default:
870			snprintf(ebuf, PCAP_ERRBUF_SIZE, "recv_ack: %s: %s",
871			    what, dlstrerror(dlp->error_ack.dl_errno));
872			break;
873		}
874		return (-1);
875
876	default:
877		snprintf(ebuf, PCAP_ERRBUF_SIZE,
878		    "recv_ack: %s: Unexpected primitive ack %s",
879		    what, dlprim(dlp->dl_primitive));
880		return (-1);
881	}
882
883	if (ctl.len < size) {
884		snprintf(ebuf, PCAP_ERRBUF_SIZE,
885		    "recv_ack: %s: Ack too small (%d < %d)",
886		    what, ctl.len, size);
887		return (-1);
888	}
889	return (ctl.len);
890}
891
892static char *
893dlstrerror(bpf_u_int32 dl_errno)
894{
895	static char errstring[6+2+8+1];
896
897	switch (dl_errno) {
898
899	case DL_ACCESS:
900		return ("Improper permissions for request");
901
902	case DL_BADADDR:
903		return ("DLSAP addr in improper format or invalid");
904
905	case DL_BADCORR:
906		return ("Seq number not from outstand DL_CONN_IND");
907
908	case DL_BADDATA:
909		return ("User data exceeded provider limit");
910
911	case DL_BADPPA:
912#ifdef HAVE_DEV_DLPI
913		/*
914		 * With a single "/dev/dlpi" device used for all
915		 * DLPI providers, PPAs have nothing to do with
916		 * unit numbers.
917		 */
918		return ("Specified PPA was invalid");
919#else
920		/*
921		 * We have separate devices for separate devices;
922		 * the PPA is just the unit number.
923		 */
924		return ("Specified PPA (device unit) was invalid");
925#endif
926
927	case DL_BADPRIM:
928		return ("Primitive received not known by provider");
929
930	case DL_BADQOSPARAM:
931		return ("QOS parameters contained invalid values");
932
933	case DL_BADQOSTYPE:
934		return ("QOS structure type is unknown/unsupported");
935
936	case DL_BADSAP:
937		return ("Bad LSAP selector");
938
939	case DL_BADTOKEN:
940		return ("Token used not an active stream");
941
942	case DL_BOUND:
943		return ("Attempted second bind with dl_max_conind");
944
945	case DL_INITFAILED:
946		return ("Physical link initialization failed");
947
948	case DL_NOADDR:
949		return ("Provider couldn't allocate alternate address");
950
951	case DL_NOTINIT:
952		return ("Physical link not initialized");
953
954	case DL_OUTSTATE:
955		return ("Primitive issued in improper state");
956
957	case DL_SYSERR:
958		return ("UNIX system error occurred");
959
960	case DL_UNSUPPORTED:
961		return ("Requested service not supplied by provider");
962
963	case DL_UNDELIVERABLE:
964		return ("Previous data unit could not be delivered");
965
966	case DL_NOTSUPPORTED:
967		return ("Primitive is known but not supported");
968
969	case DL_TOOMANY:
970		return ("Limit exceeded");
971
972	case DL_NOTENAB:
973		return ("Promiscuous mode not enabled");
974
975	case DL_BUSY:
976		return ("Other streams for PPA in post-attached");
977
978	case DL_NOAUTO:
979		return ("Automatic handling XID&TEST not supported");
980
981	case DL_NOXIDAUTO:
982		return ("Automatic handling of XID not supported");
983
984	case DL_NOTESTAUTO:
985		return ("Automatic handling of TEST not supported");
986
987	case DL_XIDAUTO:
988		return ("Automatic handling of XID response");
989
990	case DL_TESTAUTO:
991		return ("Automatic handling of TEST response");
992
993	case DL_PENDING:
994		return ("Pending outstanding connect indications");
995
996	default:
997		sprintf(errstring, "Error %02x", dl_errno);
998		return (errstring);
999	}
1000}
1001
1002static char *
1003dlprim(bpf_u_int32 prim)
1004{
1005	static char primbuf[80];
1006
1007	switch (prim) {
1008
1009	case DL_INFO_REQ:
1010		return ("DL_INFO_REQ");
1011
1012	case DL_INFO_ACK:
1013		return ("DL_INFO_ACK");
1014
1015	case DL_ATTACH_REQ:
1016		return ("DL_ATTACH_REQ");
1017
1018	case DL_DETACH_REQ:
1019		return ("DL_DETACH_REQ");
1020
1021	case DL_BIND_REQ:
1022		return ("DL_BIND_REQ");
1023
1024	case DL_BIND_ACK:
1025		return ("DL_BIND_ACK");
1026
1027	case DL_UNBIND_REQ:
1028		return ("DL_UNBIND_REQ");
1029
1030	case DL_OK_ACK:
1031		return ("DL_OK_ACK");
1032
1033	case DL_ERROR_ACK:
1034		return ("DL_ERROR_ACK");
1035
1036	case DL_SUBS_BIND_REQ:
1037		return ("DL_SUBS_BIND_REQ");
1038
1039	case DL_SUBS_BIND_ACK:
1040		return ("DL_SUBS_BIND_ACK");
1041
1042	case DL_UNITDATA_REQ:
1043		return ("DL_UNITDATA_REQ");
1044
1045	case DL_UNITDATA_IND:
1046		return ("DL_UNITDATA_IND");
1047
1048	case DL_UDERROR_IND:
1049		return ("DL_UDERROR_IND");
1050
1051	case DL_UDQOS_REQ:
1052		return ("DL_UDQOS_REQ");
1053
1054	case DL_CONNECT_REQ:
1055		return ("DL_CONNECT_REQ");
1056
1057	case DL_CONNECT_IND:
1058		return ("DL_CONNECT_IND");
1059
1060	case DL_CONNECT_RES:
1061		return ("DL_CONNECT_RES");
1062
1063	case DL_CONNECT_CON:
1064		return ("DL_CONNECT_CON");
1065
1066	case DL_TOKEN_REQ:
1067		return ("DL_TOKEN_REQ");
1068
1069	case DL_TOKEN_ACK:
1070		return ("DL_TOKEN_ACK");
1071
1072	case DL_DISCONNECT_REQ:
1073		return ("DL_DISCONNECT_REQ");
1074
1075	case DL_DISCONNECT_IND:
1076		return ("DL_DISCONNECT_IND");
1077
1078	case DL_RESET_REQ:
1079		return ("DL_RESET_REQ");
1080
1081	case DL_RESET_IND:
1082		return ("DL_RESET_IND");
1083
1084	case DL_RESET_RES:
1085		return ("DL_RESET_RES");
1086
1087	case DL_RESET_CON:
1088		return ("DL_RESET_CON");
1089
1090	default:
1091		(void) sprintf(primbuf, "unknown primitive 0x%x", prim);
1092		return (primbuf);
1093	}
1094}
1095
1096static int
1097dlattachreq(int fd, bpf_u_int32 ppa, char *ebuf)
1098{
1099	dl_attach_req_t	req;
1100
1101	req.dl_primitive = DL_ATTACH_REQ;
1102	req.dl_ppa = ppa;
1103
1104	return (send_request(fd, (char *)&req, sizeof(req), "attach", ebuf));
1105}
1106
1107static int
1108dlbindreq(int fd, bpf_u_int32 sap, char *ebuf)
1109{
1110
1111	dl_bind_req_t	req;
1112
1113	memset((char *)&req, 0, sizeof(req));
1114	req.dl_primitive = DL_BIND_REQ;
1115#ifdef DL_HP_RAWDLS
1116	req.dl_max_conind = 1;			/* XXX magic number */
1117	/* 22 is INSAP as per the HP-UX DLPI Programmer's Guide */
1118	req.dl_sap = 22;
1119	req.dl_service_mode = DL_HP_RAWDLS;
1120#else
1121	req.dl_sap = sap;
1122#ifdef DL_CLDLS
1123	req.dl_service_mode = DL_CLDLS;
1124#endif
1125#endif
1126
1127	return (send_request(fd, (char *)&req, sizeof(req), "bind", ebuf));
1128}
1129
1130static int
1131dlbindack(int fd, char *bufp, char *ebuf)
1132{
1133
1134	return (recv_ack(fd, DL_BIND_ACK_SIZE, "bind", bufp, ebuf));
1135}
1136
1137static int
1138dlpromisconreq(int fd, bpf_u_int32 level, char *ebuf)
1139{
1140	dl_promiscon_req_t req;
1141
1142	req.dl_primitive = DL_PROMISCON_REQ;
1143	req.dl_level = level;
1144
1145	return (send_request(fd, (char *)&req, sizeof(req), "promiscon", ebuf));
1146}
1147
1148static int
1149dlokack(int fd, const char *what, char *bufp, char *ebuf)
1150{
1151
1152	return (recv_ack(fd, DL_OK_ACK_SIZE, what, bufp, ebuf));
1153}
1154
1155
1156static int
1157dlinforeq(int fd, char *ebuf)
1158{
1159	dl_info_req_t req;
1160
1161	req.dl_primitive = DL_INFO_REQ;
1162
1163	return (send_request(fd, (char *)&req, sizeof(req), "info", ebuf));
1164}
1165
1166static int
1167dlinfoack(int fd, char *bufp, char *ebuf)
1168{
1169
1170	return (recv_ack(fd, DL_INFO_ACK_SIZE, "info", bufp, ebuf));
1171}
1172
1173#ifdef HAVE_SYS_BUFMOD_H
1174static int
1175strioctl(int fd, int cmd, int len, char *dp)
1176{
1177	struct strioctl str;
1178	int rc;
1179
1180	str.ic_cmd = cmd;
1181	str.ic_timout = -1;
1182	str.ic_len = len;
1183	str.ic_dp = dp;
1184	rc = ioctl(fd, I_STR, &str);
1185
1186	if (rc < 0)
1187		return (rc);
1188	else
1189		return (str.ic_len);
1190}
1191#endif
1192
1193#if defined(HAVE_SOLARIS) && defined(HAVE_SYS_BUFMOD_H)
1194static char *
1195get_release(bpf_u_int32 *majorp, bpf_u_int32 *minorp, bpf_u_int32 *microp)
1196{
1197	char *cp;
1198	static char buf[32];
1199
1200	*majorp = 0;
1201	*minorp = 0;
1202	*microp = 0;
1203	if (sysinfo(SI_RELEASE, buf, sizeof(buf)) < 0)
1204		return ("?");
1205	cp = buf;
1206	if (!isdigit((unsigned char)*cp))
1207		return (buf);
1208	*majorp = strtol(cp, &cp, 10);
1209	if (*cp++ != '.')
1210		return (buf);
1211	*minorp =  strtol(cp, &cp, 10);
1212	if (*cp++ != '.')
1213		return (buf);
1214	*microp =  strtol(cp, &cp, 10);
1215	return (buf);
1216}
1217#endif
1218
1219#ifdef DL_HP_PPA_ACK_OBS
1220/*
1221 * Under HP-UX 10 and HP-UX 11, we can ask for the ppa
1222 */
1223
1224
1225/*
1226 * Determine ppa number that specifies ifname.
1227 *
1228 * If the "dl_hp_ppa_info_t" doesn't have a "dl_module_id_1" member,
1229 * the code that's used here is the old code for HP-UX 10.x.
1230 *
1231 * However, HP-UX 10.20, at least, appears to have such a member
1232 * in its "dl_hp_ppa_info_t" structure, so the new code is used.
1233 * The new code didn't work on an old 10.20 system on which Rick
1234 * Jones of HP tried it, but with later patches installed, it
1235 * worked - it appears that the older system had those members but
1236 * didn't put anything in them, so, if the search by name fails, we
1237 * do the old search.
1238 *
1239 * Rick suggests that making sure your system is "up on the latest
1240 * lancommon/DLPI/driver patches" is probably a good idea; it'd fix
1241 * that problem, as well as allowing libpcap to see packets sent
1242 * from the system on which the libpcap application is being run.
1243 * (On 10.20, in addition to getting the latest patches, you need
1244 * to turn the kernel "lanc_outbound_promisc_flag" flag on with ADB;
1245 * a posting to "comp.sys.hp.hpux" at
1246 *
1247 *	http://www.deja.com/[ST_rn=ps]/getdoc.xp?AN=558092266
1248 *
1249 * says that, to see the machine's outgoing traffic, you'd need to
1250 * apply the right patches to your system, and also set that variable
1251 * with:
1252
1253echo 'lanc_outbound_promisc_flag/W1' | /usr/bin/adb -w /stand/vmunix /dev/kmem
1254
1255 * which could be put in, for example, "/sbin/init.d/lan".
1256 *
1257 * Setting the variable is not necessary on HP-UX 11.x.
1258 */
1259static int
1260get_dlpi_ppa(register int fd, register const char *device, register int unit,
1261    register char *ebuf)
1262{
1263	register dl_hp_ppa_ack_t *ap;
1264	register dl_hp_ppa_info_t *ipstart, *ip;
1265	register int i;
1266	char dname[100];
1267	register u_long majdev;
1268	struct stat statbuf;
1269	dl_hp_ppa_req_t	req;
1270	char buf[MAXDLBUF];
1271	char *ppa_data_buf;
1272	dl_hp_ppa_ack_t	*dlp;
1273	struct strbuf ctl;
1274	int flags;
1275	int ppa;
1276
1277	memset((char *)&req, 0, sizeof(req));
1278	req.dl_primitive = DL_HP_PPA_REQ;
1279
1280	memset((char *)buf, 0, sizeof(buf));
1281	if (send_request(fd, (char *)&req, sizeof(req), "hpppa", ebuf) < 0)
1282		return (-1);
1283
1284	ctl.maxlen = DL_HP_PPA_ACK_SIZE;
1285	ctl.len = 0;
1286	ctl.buf = (char *)buf;
1287
1288	flags = 0;
1289	/*
1290	 * DLPI may return a big chunk of data for a DL_HP_PPA_REQ. The normal
1291	 * recv_ack will fail because it set the maxlen to MAXDLBUF (8192)
1292	 * which is NOT big enough for a DL_HP_PPA_REQ.
1293	 *
1294	 * This causes libpcap applications to fail on a system with HP-APA
1295	 * installed.
1296	 *
1297	 * To figure out how big the returned data is, we first call getmsg
1298	 * to get the small head and peek at the head to get the actual data
1299	 * length, and  then issue another getmsg to get the actual PPA data.
1300	 */
1301	/* get the head first */
1302	if (getmsg(fd, &ctl, (struct strbuf *)NULL, &flags) < 0) {
1303		snprintf(ebuf, PCAP_ERRBUF_SIZE,
1304		    "get_dlpi_ppa: hpppa getmsg: %s", pcap_strerror(errno));
1305		return (-1);
1306	}
1307
1308	dlp = (dl_hp_ppa_ack_t *)ctl.buf;
1309	if (dlp->dl_primitive != DL_HP_PPA_ACK) {
1310		snprintf(ebuf, PCAP_ERRBUF_SIZE,
1311		    "get_dlpi_ppa: hpppa unexpected primitive ack 0x%x",
1312		    (bpf_u_int32)dlp->dl_primitive);
1313		return (-1);
1314	}
1315
1316	if (ctl.len < DL_HP_PPA_ACK_SIZE) {
1317		snprintf(ebuf, PCAP_ERRBUF_SIZE,
1318		    "get_dlpi_ppa: hpppa ack too small (%d < %lu)",
1319		     ctl.len, (unsigned long)DL_HP_PPA_ACK_SIZE);
1320		return (-1);
1321	}
1322
1323	/* allocate buffer */
1324	if ((ppa_data_buf = (char *)malloc(dlp->dl_length)) == NULL) {
1325		snprintf(ebuf, PCAP_ERRBUF_SIZE,
1326		    "get_dlpi_ppa: hpppa malloc: %s", pcap_strerror(errno));
1327		return (-1);
1328	}
1329	ctl.maxlen = dlp->dl_length;
1330	ctl.len = 0;
1331	ctl.buf = (char *)ppa_data_buf;
1332	/* get the data */
1333	if (getmsg(fd, &ctl, (struct strbuf *)NULL, &flags) < 0) {
1334		snprintf(ebuf, PCAP_ERRBUF_SIZE,
1335		    "get_dlpi_ppa: hpppa getmsg: %s", pcap_strerror(errno));
1336		free(ppa_data_buf);
1337		return (-1);
1338	}
1339	if (ctl.len < dlp->dl_length) {
1340		snprintf(ebuf, PCAP_ERRBUF_SIZE,
1341		    "get_dlpi_ppa: hpppa ack too small (%d < %d)",
1342		    ctl.len, dlp->dl_length);
1343		free(ppa_data_buf);
1344		return (-1);
1345	}
1346
1347	ap = (dl_hp_ppa_ack_t *)buf;
1348	ipstart = (dl_hp_ppa_info_t *)ppa_data_buf;
1349	ip = ipstart;
1350
1351#ifdef HAVE_HP_PPA_INFO_T_DL_MODULE_ID_1
1352	/*
1353	 * The "dl_hp_ppa_info_t" structure has a "dl_module_id_1"
1354	 * member that should, in theory, contain the part of the
1355	 * name for the device that comes before the unit number,
1356	 * and should also have a "dl_module_id_2" member that may
1357	 * contain an alternate name (e.g., I think Ethernet devices
1358	 * have both "lan", for "lanN", and "snap", for "snapN", with
1359	 * the former being for Ethernet packets and the latter being
1360	 * for 802.3/802.2 packets).
1361	 *
1362	 * Search for the device that has the specified name and
1363	 * instance number.
1364	 */
1365	for (i = 0; i < ap->dl_count; i++) {
1366		if ((strcmp((const char *)ip->dl_module_id_1, device) == 0 ||
1367		     strcmp((const char *)ip->dl_module_id_2, device) == 0) &&
1368		    ip->dl_instance_num == unit)
1369			break;
1370
1371		ip = (dl_hp_ppa_info_t *)((u_char *)ipstart + ip->dl_next_offset);
1372	}
1373#else
1374	/*
1375	 * We don't have that member, so the search is impossible; make it
1376	 * look as if the search failed.
1377	 */
1378	i = ap->dl_count;
1379#endif
1380
1381	if (i == ap->dl_count) {
1382		/*
1383		 * Well, we didn't, or can't, find the device by name.
1384		 *
1385		 * HP-UX 10.20, whilst it has "dl_module_id_1" and
1386		 * "dl_module_id_2" fields in the "dl_hp_ppa_info_t",
1387		 * doesn't seem to fill them in unless the system is
1388		 * at a reasonably up-to-date patch level.
1389		 *
1390		 * Older HP-UX 10.x systems might not have those fields
1391		 * at all.
1392		 *
1393		 * Therefore, we'll search for the entry with the major
1394		 * device number of a device with the name "/dev/<dev><unit>",
1395		 * if such a device exists, as the old code did.
1396		 */
1397		snprintf(dname, sizeof(dname), "/dev/%s%d", device, unit);
1398		if (stat(dname, &statbuf) < 0) {
1399			snprintf(ebuf, PCAP_ERRBUF_SIZE, "stat: %s: %s",
1400			    dname, pcap_strerror(errno));
1401			return (-1);
1402		}
1403		majdev = major(statbuf.st_rdev);
1404
1405		ip = ipstart;
1406
1407		for (i = 0; i < ap->dl_count; i++) {
1408			if (ip->dl_mjr_num == majdev &&
1409			    ip->dl_instance_num == unit)
1410				break;
1411
1412			ip = (dl_hp_ppa_info_t *)((u_char *)ipstart + ip->dl_next_offset);
1413		}
1414	}
1415        if (i == ap->dl_count) {
1416                snprintf(ebuf, PCAP_ERRBUF_SIZE,
1417		    "can't find /dev/dlpi PPA for %s%d", device, unit);
1418		return (-1);
1419        }
1420        if (ip->dl_hdw_state == HDW_DEAD) {
1421                snprintf(ebuf, PCAP_ERRBUF_SIZE,
1422		    "%s%d: hardware state: DOWN\n", device, unit);
1423		free(ppa_data_buf);
1424		return (-1);
1425        }
1426        ppa = ip->dl_ppa;
1427        free(ppa_data_buf);
1428        return (ppa);
1429}
1430#endif
1431
1432#ifdef HAVE_HPUX9
1433/*
1434 * Under HP-UX 9, there is no good way to determine the ppa.
1435 * So punt and read it from /dev/kmem.
1436 */
1437static struct nlist nl[] = {
1438#define NL_IFNET 0
1439	{ "ifnet" },
1440	{ "" }
1441};
1442
1443static char path_vmunix[] = "/hp-ux";
1444
1445/* Determine ppa number that specifies ifname */
1446static int
1447get_dlpi_ppa(register int fd, register const char *ifname, register int unit,
1448    register char *ebuf)
1449{
1450	register const char *cp;
1451	register int kd;
1452	void *addr;
1453	struct ifnet ifnet;
1454	char if_name[sizeof(ifnet.if_name) + 1];
1455
1456	cp = strrchr(ifname, '/');
1457	if (cp != NULL)
1458		ifname = cp + 1;
1459	if (nlist(path_vmunix, &nl) < 0) {
1460		snprintf(ebuf, PCAP_ERRBUF_SIZE, "nlist %s failed",
1461		    path_vmunix);
1462		return (-1);
1463	}
1464	if (nl[NL_IFNET].n_value == 0) {
1465		snprintf(ebuf, PCAP_ERRBUF_SIZE,
1466		    "could't find %s kernel symbol",
1467		    nl[NL_IFNET].n_name);
1468		return (-1);
1469	}
1470	kd = open("/dev/kmem", O_RDONLY);
1471	if (kd < 0) {
1472		snprintf(ebuf, PCAP_ERRBUF_SIZE, "kmem open: %s",
1473		    pcap_strerror(errno));
1474		return (-1);
1475	}
1476	if (dlpi_kread(kd, nl[NL_IFNET].n_value,
1477	    &addr, sizeof(addr), ebuf) < 0) {
1478		close(kd);
1479		return (-1);
1480	}
1481	for (; addr != NULL; addr = ifnet.if_next) {
1482		if (dlpi_kread(kd, (off_t)addr,
1483		    &ifnet, sizeof(ifnet), ebuf) < 0 ||
1484		    dlpi_kread(kd, (off_t)ifnet.if_name,
1485		    if_name, sizeof(ifnet.if_name), ebuf) < 0) {
1486			(void)close(kd);
1487			return (-1);
1488		}
1489		if_name[sizeof(ifnet.if_name)] = '\0';
1490		if (strcmp(if_name, ifname) == 0 && ifnet.if_unit == unit)
1491			return (ifnet.if_index);
1492	}
1493
1494	snprintf(ebuf, PCAP_ERRBUF_SIZE, "Can't find %s", ifname);
1495	return (-1);
1496}
1497
1498static int
1499dlpi_kread(register int fd, register off_t addr,
1500    register void *buf, register u_int len, register char *ebuf)
1501{
1502	register int cc;
1503
1504	if (lseek(fd, addr, SEEK_SET) < 0) {
1505		snprintf(ebuf, PCAP_ERRBUF_SIZE, "lseek: %s",
1506		    pcap_strerror(errno));
1507		return (-1);
1508	}
1509	cc = read(fd, buf, len);
1510	if (cc < 0) {
1511		snprintf(ebuf, PCAP_ERRBUF_SIZE, "read: %s",
1512		    pcap_strerror(errno));
1513		return (-1);
1514	} else if (cc != len) {
1515		snprintf(ebuf, PCAP_ERRBUF_SIZE, "short read (%d != %d)", cc,
1516		    len);
1517		return (-1);
1518	}
1519	return (cc);
1520}
1521#endif
1522