pcap-dlpi.c revision 147894
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),
22146768Ssam * University College London, and subsequently modified by
23147894Ssam * Guy Harris (guy@alum.mit.edu), Mark Pizzolato
24147894Ssam * <List-tcpdump-workers@subscriptions.pizzolato.net>,
25147894Ssam * and Mark C. Brown (mbrown@hp.com).
2617683Spst */
2717683Spst
2817683Spst/*
29127664Sbms * Packet capture routine for DLPI under SunOS 5, HP-UX 9/10/11, and AIX.
3017683Spst *
3117683Spst * Notes:
3217683Spst *
33146768Ssam *    - The DLIOCRAW ioctl() is specific to SunOS.
3417683Spst *
3517683Spst *    - There is a bug in bufmod(7) such that setting the snapshot
3617683Spst *      length results in data being left of the front of the packet.
3717683Spst *
3817683Spst *    - It might be desirable to use pfmod(7) to filter packets in the
39127664Sbms *      kernel when possible.
40146768Ssam *
41147894Ssam *    - An older version of the HP-UX DLPI Programmer's Guide, which
42147894Ssam *      I think was advertised as the 10.20 version, used to be available
43146768Ssam *      at
44146768Ssam *
45146768Ssam *            http://docs.hp.com/hpux/onlinedocs/B2355-90093/B2355-90093.html
46146768Ssam *
47146768Ssam *      but is no longer available; it can still be found at
48146768Ssam *
49146768Ssam *            http://h21007.www2.hp.com/dspp/files/unprotected/Drivers/Docs/Refs/B2355-90093.pdf
50146768Ssam *
51146768Ssam *      in PDF form.
52146768Ssam *
53147894Ssam *    - The HP-UX 10.x, 11.0, and 11i v1.6 version of the HP-UX DLPI
54147894Ssam *      Programmer's Guide, which I think was once advertised as the
55147894Ssam *      11.00 version is available at
56146768Ssam *
57147894Ssam *            http://docs.hp.com/en/B2355-90139/index.html
58146768Ssam *
59147894Ssam *    - The HP-UX 11i v2 version of the HP-UX DLPI Programmer's Guide
60147894Ssam *      is available at
61146768Ssam *
62147894Ssam *            http://docs.hp.com/en/B2355-90871/index.html
63146768Ssam *
64147894Ssam *    - All of the HP documents describe raw-mode services, which are
65147894Ssam *      what we use if DL_HP_RAWDLS is defined.  XXX - we use __hpux
66147894Ssam *      in some places to test for HP-UX, but use DL_HP_RAWDLS in
67147894Ssam *      other places; do we support any versions of HP-UX without
68147894Ssam *      DL_HP_RAWDLS?
6917683Spst */
7017683Spst
7126175Sfenner#ifndef lint
72127664Sbmsstatic const char rcsid[] _U_ =
73147894Ssam    "@(#) $Header: /tcpdump/master/libpcap/pcap-dlpi.c,v 1.108.2.5 2005/05/03 18:54:35 guy Exp $ (LBL)";
7426175Sfenner#endif
7526175Sfenner
7675107Sfenner#ifdef HAVE_CONFIG_H
7775107Sfenner#include "config.h"
7875107Sfenner#endif
7975107Sfenner
8017683Spst#include <sys/types.h>
8117683Spst#include <sys/time.h>
8217683Spst#ifdef HAVE_SYS_BUFMOD_H
8317683Spst#include <sys/bufmod.h>
8417683Spst#endif
8517683Spst#include <sys/dlpi.h>
8617683Spst#ifdef HAVE_SYS_DLPI_EXT_H
8717683Spst#include <sys/dlpi_ext.h>
8817683Spst#endif
8917683Spst#ifdef HAVE_HPUX9
9017683Spst#include <sys/socket.h>
9117683Spst#endif
92146768Ssam#ifdef DL_HP_PPA_REQ
9317683Spst#include <sys/stat.h>
9417683Spst#endif
9517683Spst#include <sys/stream.h>
9617683Spst#if defined(HAVE_SOLARIS) && defined(HAVE_SYS_BUFMOD_H)
9717683Spst#include <sys/systeminfo.h>
9817683Spst#endif
9917683Spst
10017683Spst#ifdef HAVE_HPUX9
10117683Spst#include <net/if.h>
10217683Spst#endif
10317683Spst
10417683Spst#include <ctype.h>
10517683Spst#ifdef HAVE_HPUX9
10617683Spst#include <nlist.h>
10717683Spst#endif
10817683Spst#include <errno.h>
10917683Spst#include <fcntl.h>
11017683Spst#include <memory.h>
11117683Spst#include <stdio.h>
11217683Spst#include <stdlib.h>
11317683Spst#include <string.h>
11417683Spst#include <stropts.h>
11517683Spst#include <unistd.h>
11617683Spst
117146768Ssam#ifdef HAVE_LIMITS_H
118146768Ssam#include <limits.h>
119146768Ssam#else
120146768Ssam#define INT_MAX		2147483647
121146768Ssam#endif
122146768Ssam
12317683Spst#include "pcap-int.h"
12417683Spst
12517683Spst#ifdef HAVE_OS_PROTO_H
12617683Spst#include "os-proto.h"
12717683Spst#endif
12817683Spst
12917683Spst#ifndef PCAP_DEV_PREFIX
13098530Sfenner#ifdef _AIX
13198530Sfenner#define PCAP_DEV_PREFIX "/dev/dlpi"
13298530Sfenner#else
13317683Spst#define PCAP_DEV_PREFIX "/dev"
13417683Spst#endif
13598530Sfenner#endif
13617683Spst
13717683Spst#define	MAXDLBUF	8192
13817683Spst
139127664Sbms#ifdef HAVE_SYS_BUFMOD_H
140127664Sbms
141127664Sbms/*
142127664Sbms * Size of a bufmod chunk to pass upstream; that appears to be the biggest
143127664Sbms * value to which you can set it, and setting it to that value (which
144127664Sbms * is bigger than what appears to be the Solaris default of 8192)
145127664Sbms * reduces the number of packet drops.
146127664Sbms */
147127664Sbms#define CHUNKSIZE	65536
148127664Sbms
149127664Sbms/*
150127664Sbms * Size of the buffer to allocate for packet data we read; it must be
151127664Sbms * large enough to hold a chunk.
152127664Sbms */
153127664Sbms#define PKTBUFSIZE	CHUNKSIZE
154127664Sbms
155127664Sbms#else /* HAVE_SYS_BUFMOD_H */
156127664Sbms
157127664Sbms/*
158127664Sbms * Size of the buffer to allocate for packet data we read; this is
159127664Sbms * what the value used to be - there's no particular reason why it
160127664Sbms * should be tied to MAXDLBUF, but we'll leave it as this for now.
161127664Sbms */
162127664Sbms#define PKTBUFSIZE	(MAXDLBUF * sizeof(bpf_u_int32))
163127664Sbms
164127664Sbms#endif
165127664Sbms
16617683Spst/* Forwards */
16798530Sfennerstatic char *split_dname(char *, int *, char *);
168146768Ssamstatic int dl_doattach(int, int, char *);
169147894Ssam#ifdef DL_HP_RAWDLS
170147894Ssamstatic int dl_dohpuxbind(int, char *);
171147894Ssam#endif
17217683Spststatic int dlattachreq(int, bpf_u_int32, char *);
173146768Ssamstatic int dlbindreq(int, bpf_u_int32, char *);
174147894Ssamstatic int dlbindack(int, char *, char *, int *);
175146768Ssamstatic int dlpromisconreq(int, bpf_u_int32, char *);
176146768Ssamstatic int dlokack(int, const char *, char *, char *);
177146768Ssamstatic int dlinforeq(int, char *);
17817683Spststatic int dlinfoack(int, char *, char *);
179146768Ssam#ifdef DL_HP_RAWDLS
180146768Ssamstatic int dlrawdatareq(int, const u_char *, int);
181146768Ssam#endif
182147894Ssamstatic int recv_ack(int, int, const char *, char *, char *, int *);
18398530Sfennerstatic char *dlstrerror(bpf_u_int32);
18498530Sfennerstatic char *dlprim(bpf_u_int32);
18517683Spst#if defined(HAVE_SOLARIS) && defined(HAVE_SYS_BUFMOD_H)
18617683Spststatic char *get_release(bpf_u_int32 *, bpf_u_int32 *, bpf_u_int32 *);
18717683Spst#endif
18817683Spststatic int send_request(int, char *, int, char *, char *);
18917683Spst#ifdef HAVE_SYS_BUFMOD_H
19017683Spststatic int strioctl(int, int, int, char *);
19117683Spst#endif
19217683Spst#ifdef HAVE_HPUX9
19317683Spststatic int dlpi_kread(int, off_t, void *, u_int, char *);
19417683Spst#endif
19517683Spst#ifdef HAVE_DEV_DLPI
19617683Spststatic int get_dlpi_ppa(int, const char *, int, char *);
19717683Spst#endif
19817683Spst
199127664Sbmsstatic int
200127664Sbmspcap_stats_dlpi(pcap_t *p, struct pcap_stat *ps)
20117683Spst{
20217683Spst
20398530Sfenner	/*
20498530Sfenner	 * "ps_recv" counts packets handed to the filter, not packets
20598530Sfenner	 * that passed the filter.  As filtering is done in userland,
206146768Ssam	 * this would not include packets dropped because we ran out
207146768Ssam	 * of buffer space; in order to make this more like other
208146768Ssam	 * platforms (Linux 2.4 and later, BSDs with BPF), where the
209146768Ssam	 * "packets received" count includes packets received but dropped
210146768Ssam	 * due to running out of buffer space, and to keep from confusing
211146768Ssam	 * applications that, for example, compute packet drop percentages,
212146768Ssam	 * we also make it count packets dropped by "bufmod" (otherwise we
213146768Ssam	 * might run the risk of the packet drop count being bigger than
214146768Ssam	 * the received-packet count).
21598530Sfenner	 *
216146768Ssam	 * "ps_drop" counts packets dropped by "bufmod" because of
217146768Ssam	 * flow control requirements or resource exhaustion; it doesn't
218146768Ssam	 * count packets dropped by the interface driver, or packets
219146768Ssam	 * dropped upstream.  As filtering is done in userland, it counts
220146768Ssam	 * packets regardless of whether they would've passed the filter.
22198530Sfenner	 *
22298530Sfenner	 * These statistics don't include packets not yet read from
22398530Sfenner	 * the kernel by libpcap, but they may include packets not
22498530Sfenner	 * yet read from libpcap by the application.
22598530Sfenner	 */
22617683Spst	*ps = p->md.stat;
227146768Ssam
228146768Ssam	/*
229146768Ssam	 * Add in the drop count, as per the above comment.
230146768Ssam	 */
231146768Ssam	ps->ps_recv += ps->ps_drop;
23217683Spst	return (0);
23317683Spst}
23417683Spst
23517683Spst/* XXX Needed by HP-UX (at least) */
23617683Spststatic bpf_u_int32 ctlbuf[MAXDLBUF];
23717683Spststatic struct strbuf ctl = {
23817683Spst	MAXDLBUF,
23917683Spst	0,
24017683Spst	(char *)ctlbuf
24117683Spst};
24217683Spst
243127664Sbmsstatic int
244127664Sbmspcap_read_dlpi(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
24517683Spst{
24617683Spst	register int cc, n, caplen, origlen;
24717683Spst	register u_char *bp, *ep, *pk;
24817683Spst	register struct bpf_insn *fcode;
24917683Spst#ifdef HAVE_SYS_BUFMOD_H
25017683Spst	register struct sb_hdr *sbp;
25117683Spst#ifdef LBL_ALIGN
25217683Spst	struct sb_hdr sbhdr;
25317683Spst#endif
25417683Spst#endif
25517683Spst	int flags;
25617683Spst	struct strbuf data;
25717683Spst	struct pcap_pkthdr pkthdr;
25817683Spst
25917683Spst	flags = 0;
26017683Spst	cc = p->cc;
26117683Spst	if (cc == 0) {
26217683Spst		data.buf = (char *)p->buffer + p->offset;
263127664Sbms		data.maxlen = p->bufsize;
26417683Spst		data.len = 0;
26517683Spst		do {
266127664Sbms			/*
267127664Sbms			 * Has "pcap_breakloop()" been called?
268127664Sbms			 */
269127664Sbms			if (p->break_loop) {
270127664Sbms				/*
271127664Sbms				 * Yes - clear the flag that indicates
272127664Sbms				 * that it has, and return -2 to
273127664Sbms				 * indicate that we were told to
274127664Sbms				 * break out of the loop.
275127664Sbms				 */
276127664Sbms				p->break_loop = 0;
277127664Sbms				return (-2);
278127664Sbms			}
279146768Ssam			/*
280146768Ssam			 * XXX - check for the DLPI primitive, which
281146768Ssam			 * would be DL_HP_RAWDATA_IND on HP-UX
282146768Ssam			 * if we're in raw mode?
283146768Ssam			 */
28417683Spst			if (getmsg(p->fd, &ctl, &data, &flags) < 0) {
28517683Spst				/* Don't choke when we get ptraced */
286146768Ssam				switch (errno) {
287146768Ssam
288146768Ssam				case EINTR:
28917683Spst					cc = 0;
29017683Spst					continue;
291146768Ssam
292146768Ssam				case EAGAIN:
293146768Ssam					return (0);
29417683Spst				}
29575107Sfenner				strlcpy(p->errbuf, pcap_strerror(errno),
29675107Sfenner				    sizeof(p->errbuf));
29717683Spst				return (-1);
29817683Spst			}
29917683Spst			cc = data.len;
30017683Spst		} while (cc == 0);
30117683Spst		bp = p->buffer + p->offset;
30217683Spst	} else
30317683Spst		bp = p->bp;
30417683Spst
30517683Spst	/* Loop through packets */
30617683Spst	fcode = p->fcode.bf_insns;
30717683Spst	ep = bp + cc;
30817683Spst	n = 0;
30917683Spst#ifdef HAVE_SYS_BUFMOD_H
31017683Spst	while (bp < ep) {
311127664Sbms		/*
312127664Sbms		 * Has "pcap_breakloop()" been called?
313127664Sbms		 * If so, return immediately - if we haven't read any
314127664Sbms		 * packets, clear the flag and return -2 to indicate
315127664Sbms		 * that we were told to break out of the loop, otherwise
316127664Sbms		 * leave the flag set, so that the *next* call will break
317127664Sbms		 * out of the loop without having read any packets, and
318127664Sbms		 * return the number of packets we've processed so far.
319127664Sbms		 */
320127664Sbms		if (p->break_loop) {
321127664Sbms			if (n == 0) {
322127664Sbms				p->break_loop = 0;
323127664Sbms				return (-2);
324127664Sbms			} else {
325127664Sbms				p->bp = bp;
326127664Sbms				p->cc = ep - bp;
327127664Sbms				return (n);
328127664Sbms			}
329127664Sbms		}
33017683Spst#ifdef LBL_ALIGN
33117683Spst		if ((long)bp & 3) {
33217683Spst			sbp = &sbhdr;
33317683Spst			memcpy(sbp, bp, sizeof(*sbp));
33417683Spst		} else
33517683Spst#endif
33617683Spst			sbp = (struct sb_hdr *)bp;
337127664Sbms		p->md.stat.ps_drop = sbp->sbh_drops;
33817683Spst		pk = bp + sizeof(*sbp);
33917683Spst		bp += sbp->sbh_totlen;
34017683Spst		origlen = sbp->sbh_origlen;
34117683Spst		caplen = sbp->sbh_msglen;
34217683Spst#else
34317683Spst		origlen = cc;
34417683Spst		caplen = min(p->snapshot, cc);
34517683Spst		pk = bp;
34617683Spst		bp += caplen;
34717683Spst#endif
34817683Spst		++p->md.stat.ps_recv;
34917683Spst		if (bpf_filter(fcode, pk, origlen, caplen)) {
35017683Spst#ifdef HAVE_SYS_BUFMOD_H
351127664Sbms			pkthdr.ts.tv_sec = sbp->sbh_timestamp.tv_sec;
352127664Sbms			pkthdr.ts.tv_usec = sbp->sbh_timestamp.tv_usec;
35317683Spst#else
35417683Spst			(void)gettimeofday(&pkthdr.ts, NULL);
35517683Spst#endif
35617683Spst			pkthdr.len = origlen;
35717683Spst			pkthdr.caplen = caplen;
35817683Spst			/* Insure caplen does not exceed snapshot */
35917683Spst			if (pkthdr.caplen > p->snapshot)
36017683Spst				pkthdr.caplen = p->snapshot;
36117683Spst			(*callback)(user, &pkthdr, pk);
36217683Spst			if (++n >= cnt && cnt >= 0) {
36317683Spst				p->cc = ep - bp;
36417683Spst				p->bp = bp;
36517683Spst				return (n);
36617683Spst			}
36717683Spst		}
36817683Spst#ifdef HAVE_SYS_BUFMOD_H
36917683Spst	}
37017683Spst#endif
37117683Spst	p->cc = 0;
37217683Spst	return (n);
37317683Spst}
37417683Spst
375146768Ssamstatic int
376146768Ssampcap_inject_dlpi(pcap_t *p, const void *buf, size_t size)
377146768Ssam{
378146768Ssam	int ret;
379146768Ssam
380146768Ssam#if defined(DLIOCRAW)
381146768Ssam	ret = write(p->fd, buf, size);
382146768Ssam	if (ret == -1) {
383146768Ssam		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: %s",
384146768Ssam		    pcap_strerror(errno));
385146768Ssam		return (-1);
386146768Ssam	}
387146768Ssam#elif defined(DL_HP_RAWDLS)
388146768Ssam	if (p->send_fd < 0) {
389146768Ssam		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
390146768Ssam		    "send: Output FD couldn't be opened");
391146768Ssam		return (-1);
392146768Ssam	}
393146768Ssam	ret = dlrawdatareq(p->send_fd, buf, size);
394146768Ssam	if (ret == -1) {
395146768Ssam		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: %s",
396146768Ssam		    pcap_strerror(errno));
397146768Ssam		return (-1);
398146768Ssam	}
399146768Ssam#else /* no raw mode */
400146768Ssam	/*
401146768Ssam	 * XXX - this is a pain, because you might have to extract
402146768Ssam	 * the address from the packet and use it in a DL_UNITDATA_REQ
403146768Ssam	 * request.  That would be dependent on the link-layer type.
404146768Ssam	 *
405146768Ssam	 * I also don't know what SAP you'd have to bind the descriptor
406146768Ssam	 * to, or whether you'd need separate "receive" and "send" FDs,
407146768Ssam	 * nor do I know whether you'd need different bindings for
408146768Ssam	 * D/I/X Ethernet and 802.3, or for {FDDI,Token Ring} plus
409146768Ssam	 * 802.2 and {FDDI,Token Ring} plus 802.2 plus SNAP.
410146768Ssam	 *
411146768Ssam	 * So, for now, we just return a "you can't send" indication,
412146768Ssam	 * and leave it up to somebody with a DLPI-based system lacking
413146768Ssam	 * both DLIOCRAW and DL_HP_RAWDLS to supply code to implement
414146768Ssam	 * packet transmission on that system.  If they do, they should
415146768Ssam	 * send it to us - but should not send us code that assumes
416146768Ssam	 * Ethernet; if the code doesn't work on non-Ethernet interfaces,
417146768Ssam	 * it should check "p->linktype" and reject the send request if
418146768Ssam	 * it's anything other than DLT_EN10MB.
419146768Ssam	 */
420146768Ssam	strlcpy(p->errbuf, "send: Not supported on this version of this OS",
421146768Ssam	    PCAP_ERRBUF_SIZE);
422146768Ssam	ret = -1;
423146768Ssam#endif /* raw mode */
424146768Ssam	return (ret);
425147894Ssam}
426146768Ssam
427127664Sbms#ifndef DL_IPATM
428127664Sbms#define DL_IPATM	0x12	/* ATM Classical IP interface */
429127664Sbms#endif
430127664Sbms
431127664Sbms#ifdef HAVE_SOLARIS
432127664Sbms/*
433127664Sbms * For SunATM.
434127664Sbms */
435127664Sbms#ifndef A_GET_UNITS
436127664Sbms#define A_GET_UNITS	(('A'<<8)|118)
437127664Sbms#endif /* A_GET_UNITS */
438127664Sbms#ifndef A_PROMISCON_REQ
439127664Sbms#define A_PROMISCON_REQ	(('A'<<8)|121)
440127664Sbms#endif /* A_PROMISCON_REQ */
441127664Sbms#endif /* HAVE_SOLARIS */
442127664Sbms
443127664Sbmsstatic void
444127664Sbmspcap_close_dlpi(pcap_t *p)
445127664Sbms{
446146768Ssam	pcap_close_common(p);
447146768Ssam	if (p->send_fd >= 0)
448146768Ssam		close(p->send_fd);
449127664Sbms}
450127664Sbms
45117683Spstpcap_t *
452127664Sbmspcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
453127664Sbms    char *ebuf)
45417683Spst{
45517683Spst	register char *cp;
45617683Spst	register pcap_t *p;
45798530Sfenner	int ppa;
458127664Sbms#ifdef HAVE_SOLARIS
459127664Sbms	int isatm = 0;
460127664Sbms#endif
46117683Spst	register dl_info_ack_t *infop;
46217683Spst#ifdef HAVE_SYS_BUFMOD_H
463127664Sbms	bpf_u_int32 ss, chunksize;
46417683Spst#ifdef HAVE_SOLARIS
46517683Spst	register char *release;
46617683Spst	bpf_u_int32 osmajor, osminor, osmicro;
46717683Spst#endif
46817683Spst#endif
46917683Spst	bpf_u_int32 buf[MAXDLBUF];
47017683Spst	char dname[100];
47117683Spst#ifndef HAVE_DEV_DLPI
47217683Spst	char dname2[100];
47317683Spst#endif
47417683Spst
47517683Spst	p = (pcap_t *)malloc(sizeof(*p));
47617683Spst	if (p == NULL) {
47775107Sfenner		strlcpy(ebuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE);
47817683Spst		return (NULL);
47917683Spst	}
48017683Spst	memset(p, 0, sizeof(*p));
48198530Sfenner	p->fd = -1;	/* indicate that it hasn't been opened yet */
482146768Ssam	p->send_fd = -1;
48317683Spst
48475107Sfenner#ifdef HAVE_DEV_DLPI
48517683Spst	/*
48675107Sfenner	** Remove any "/dev/" on the front of the device.
48717683Spst	*/
48875107Sfenner	cp = strrchr(device, '/');
48975107Sfenner	if (cp == NULL)
490127664Sbms		strlcpy(dname, device, sizeof(dname));
49175107Sfenner	else
492127664Sbms		strlcpy(dname, cp + 1, sizeof(dname));
49375107Sfenner
49475107Sfenner	/*
49598530Sfenner	 * Split the device name into a device type name and a unit number;
49698530Sfenner	 * chop off the unit number, so "dname" is just a device type name.
49775107Sfenner	 */
49898530Sfenner	cp = split_dname(dname, &ppa, ebuf);
49998530Sfenner	if (cp == NULL)
50017683Spst		goto bad;
50175107Sfenner	*cp = '\0';
50217683Spst
50375107Sfenner	/*
50475107Sfenner	 * Use "/dev/dlpi" as the device.
50575107Sfenner	 *
50675107Sfenner	 * XXX - HP's DLPI Programmer's Guide for HP-UX 11.00 says that
50775107Sfenner	 * the "dl_mjr_num" field is for the "major number of interface
50875107Sfenner	 * driver"; that's the major of "/dev/dlpi" on the system on
50975107Sfenner	 * which I tried this, but there may be DLPI devices that
51075107Sfenner	 * use a different driver, in which case we may need to
51175107Sfenner	 * search "/dev" for the appropriate device with that major
51275107Sfenner	 * device number, rather than hardwiring "/dev/dlpi".
51375107Sfenner	 */
51417683Spst	cp = "/dev/dlpi";
51517683Spst	if ((p->fd = open(cp, O_RDWR)) < 0) {
51675107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE,
51775107Sfenner		    "%s: %s", cp, pcap_strerror(errno));
51817683Spst		goto bad;
51917683Spst	}
52075107Sfenner
521146768Ssam#ifdef DL_HP_RAWDLS
52275107Sfenner	/*
523146768Ssam	 * XXX - HP-UX 10.20 and 11.xx don't appear to support sending and
524147894Ssam	 * receiving packets on the same descriptor - you need separate
525147894Ssam	 * descriptors for sending and receiving, bound to different SAPs.
526146768Ssam	 *
527146768Ssam	 * If the open fails, we just leave -1 in "p->send_fd" and reject
528146768Ssam	 * attempts to send packets, just as if, in pcap-bpf.c, we fail
529146768Ssam	 * to open the BPF device for reading and writing, we just try
530146768Ssam	 * to open it for reading only and, if that succeeds, just let
531146768Ssam	 * the send attempts fail.
532146768Ssam	 */
533146768Ssam	p->send_fd = open(cp, O_RDWR);
534146768Ssam#endif
535146768Ssam
536146768Ssam	/*
53775107Sfenner	 * Get a table of all PPAs for that device, and search that
53875107Sfenner	 * table for the specified device type name and unit number.
53975107Sfenner	 */
54017683Spst	ppa = get_dlpi_ppa(p->fd, dname, ppa, ebuf);
54117683Spst	if (ppa < 0)
54217683Spst		goto bad;
54317683Spst#else
54475107Sfenner	/*
54598530Sfenner	 * If the device name begins with "/", assume it begins with
54698530Sfenner	 * the pathname of the directory containing the device to open;
54798530Sfenner	 * otherwise, concatenate the device directory name and the
54898530Sfenner	 * device name.
54998530Sfenner	 */
55075107Sfenner	if (*device == '/')
55175107Sfenner		strlcpy(dname, device, sizeof(dname));
55275107Sfenner	else
55375107Sfenner		snprintf(dname, sizeof(dname), "%s/%s", PCAP_DEV_PREFIX,
55475107Sfenner		    device);
55575107Sfenner
55698530Sfenner	/*
557127664Sbms	 * Get the unit number, and a pointer to the end of the device
558127664Sbms	 * type name.
559127664Sbms	 */
560127664Sbms	cp = split_dname(dname, &ppa, ebuf);
561127664Sbms	if (cp == NULL)
562127664Sbms		goto bad;
563127664Sbms
564127664Sbms	/*
56598530Sfenner	 * Make a copy of the device pathname, and then remove the unit
56698530Sfenner	 * number from the device pathname.
56798530Sfenner	 */
56898530Sfenner	strlcpy(dname2, dname, sizeof(dname));
569127664Sbms	*cp = '\0';
57098530Sfenner
57117683Spst	/* Try device without unit number */
57217683Spst	if ((p->fd = open(dname, O_RDWR)) < 0) {
57317683Spst		if (errno != ENOENT) {
57475107Sfenner			snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s: %s", dname,
57575107Sfenner			    pcap_strerror(errno));
57617683Spst			goto bad;
57717683Spst		}
57817683Spst
57917683Spst		/* Try again with unit number */
58017683Spst		if ((p->fd = open(dname2, O_RDWR)) < 0) {
581146768Ssam			if (errno == ENOENT) {
582146768Ssam				/*
583146768Ssam				 * We just report "No DLPI device found"
584146768Ssam				 * with the device name, so people don't
585146768Ssam				 * get confused and think, for example,
586146768Ssam				 * that if they can't capture on "lo0"
587146768Ssam				 * on Solaris the fix is to change libpcap
588146768Ssam				 * (or the application that uses it) to
589146768Ssam				 * look for something other than "/dev/lo0",
590146768Ssam				 * as the fix is to look for an operating
591146768Ssam				 * system other than Solaris - you just
592146768Ssam				 * *can't* capture on a loopback interface
593146768Ssam				 * on Solaris, the lack of a DLPI device
594146768Ssam				 * for the loopback interface is just a
595146768Ssam				 * symptom of that inability.
596146768Ssam				 */
597146768Ssam				snprintf(ebuf, PCAP_ERRBUF_SIZE,
598146768Ssam				    "%s: No DLPI device found", device);
599146768Ssam			} else {
600146768Ssam				snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s: %s",
601146768Ssam				    dname2, pcap_strerror(errno));
602146768Ssam			}
60317683Spst			goto bad;
60417683Spst		}
60517683Spst		/* XXX Assume unit zero */
60617683Spst		ppa = 0;
60717683Spst	}
60817683Spst#endif
60917683Spst
61017683Spst	p->snapshot = snaplen;
61117683Spst
61217683Spst	/*
61317683Spst	** Attach if "style 2" provider
61417683Spst	*/
61517683Spst	if (dlinforeq(p->fd, ebuf) < 0 ||
61617683Spst	    dlinfoack(p->fd, (char *)buf, ebuf) < 0)
61717683Spst		goto bad;
61817683Spst	infop = &((union DL_primitives *)buf)->info_ack;
619127664Sbms#ifdef HAVE_SOLARIS
620127664Sbms	if (infop->dl_mac_type == DL_IPATM)
621127664Sbms		isatm = 1;
622127664Sbms#endif
623146768Ssam	if (infop->dl_provider_style == DL_STYLE2) {
624146768Ssam		if (dl_doattach(p->fd, ppa, ebuf) < 0)
625146768Ssam			goto bad;
626146768Ssam#ifdef DL_HP_RAWDLS
627146768Ssam		if (p->send_fd >= 0) {
628146768Ssam			if (dl_doattach(p->send_fd, ppa, ebuf) < 0)
629146768Ssam				goto bad;
630146768Ssam		}
631146768Ssam#endif
632146768Ssam	}
633146768Ssam
63417683Spst	/*
635147894Ssam	** Bind (defer if using HP-UX 9 or HP-UX 10.20 or later, totally
636147894Ssam	** skip if using SINIX)
63717683Spst	*/
638147894Ssam#if !defined(HAVE_HPUX9) && !defined(HAVE_HPUX10_20_OR_LATER) && !defined(sinix)
63975107Sfenner#ifdef _AIX
640147894Ssam	/*
641147894Ssam	** AIX.
642147894Ssam	** According to IBM's AIX Support Line, the dl_sap value
64398530Sfenner	** should not be less than 0x600 (1536) for standard Ethernet.
64498530Sfenner	** However, we seem to get DL_BADADDR - "DLSAP addr in improper
64598530Sfenner	** format or invalid" - errors if we use 1537 on the "tr0"
64698530Sfenner	** device, which, given that its name starts with "tr" and that
64798530Sfenner	** it's IBM, probably means a Token Ring device.  (Perhaps we
64898530Sfenner	** need to use 1537 on "/dev/dlpi/en" because that device is for
64998530Sfenner	** D/I/X Ethernet, the "SAP" is actually an Ethernet type, and
65098530Sfenner	** it rejects invalid Ethernet types.)
65198530Sfenner	**
65298530Sfenner	** So if 1537 fails, we try 2, as Hyung Sik Yoon of IBM Korea
65398530Sfenner	** says that works on Token Ring (he says that 0 does *not*
65498530Sfenner	** work; perhaps that's considered an invalid LLC SAP value - I
65598530Sfenner	** assume the SAP value in a DLPI bind is an LLC SAP for network
65698530Sfenner	** types that use 802.2 LLC).
65798530Sfenner	*/
65898530Sfenner	if ((dlbindreq(p->fd, 1537, ebuf) < 0 &&
65998530Sfenner	     dlbindreq(p->fd, 2, ebuf) < 0) ||
660147894Ssam	     dlbindack(p->fd, (char *)buf, ebuf, NULL) < 0)
661146768Ssam		goto bad;
662146768Ssam#elif defined(DL_HP_RAWDLS)
663146768Ssam	/*
664147894Ssam	** HP-UX 10.0x and 10.1x.
665146768Ssam	*/
666147894Ssam	if (dl_dohpuxbind(p->fd, ebuf) < 0)
667146768Ssam		goto bad;
668146768Ssam	if (p->send_fd >= 0) {
669146768Ssam		/*
670147894Ssam		** XXX - if this fails, just close send_fd and
671147894Ssam		** set it to -1, so that you can't send but can
672147894Ssam		** still receive?
673146768Ssam		*/
674147894Ssam		if (dl_dohpuxbind(p->send_fd, ebuf) < 0)
675146768Ssam			goto bad;
676146768Ssam	}
677146768Ssam#else /* neither AIX nor HP-UX */
678147894Ssam	/*
679147894Ssam	** Not Sinix, and neither AIX nor HP-UX - Solaris, and any other
680147894Ssam	** OS using DLPI.
681147894Ssam	**/
68217683Spst	if (dlbindreq(p->fd, 0, ebuf) < 0 ||
683147894Ssam	    dlbindack(p->fd, (char *)buf, ebuf, NULL) < 0)
68417683Spst		goto bad;
685147894Ssam#endif /* AIX vs. HP-UX vs. other */
686147894Ssam#endif /* !HP-UX 9 and !HP-UX 10.20 or later and !SINIX */
68717683Spst
688127664Sbms#ifdef HAVE_SOLARIS
689127664Sbms	if (isatm) {
690127664Sbms		/*
691127664Sbms		** Have to turn on some special ATM promiscuous mode
692127664Sbms		** for SunATM.
693127664Sbms		** Do *NOT* turn regular promiscuous mode on; it doesn't
694127664Sbms		** help, and may break things.
695127664Sbms		*/
696127664Sbms		if (strioctl(p->fd, A_PROMISCON_REQ, 0, NULL) < 0) {
697127664Sbms			snprintf(ebuf, PCAP_ERRBUF_SIZE, "A_PROMISCON_REQ: %s",
698127664Sbms			    pcap_strerror(errno));
699127664Sbms			goto bad;
700127664Sbms		}
701127664Sbms	} else
702127664Sbms#endif
70317683Spst	if (promisc) {
70417683Spst		/*
705146768Ssam		** Enable promiscuous (not necessary on send FD)
70617683Spst		*/
70717683Spst		if (dlpromisconreq(p->fd, DL_PROMISC_PHYS, ebuf) < 0 ||
70817683Spst		    dlokack(p->fd, "promisc_phys", (char *)buf, ebuf) < 0)
70917683Spst			goto bad;
71017683Spst
71117683Spst		/*
71217683Spst		** Try to enable multicast (you would have thought
71339291Sfenner		** promiscuous would be sufficient). (Skip if using
714146768Ssam		** HP-UX or SINIX) (Not necessary on send FD)
71517683Spst		*/
71639291Sfenner#if !defined(__hpux) && !defined(sinix)
71717683Spst		if (dlpromisconreq(p->fd, DL_PROMISC_MULTI, ebuf) < 0 ||
71817683Spst		    dlokack(p->fd, "promisc_multi", (char *)buf, ebuf) < 0)
71917683Spst			fprintf(stderr,
72017683Spst			    "WARNING: DL_PROMISC_MULTI failed (%s)\n", ebuf);
72117683Spst#endif
72217683Spst	}
72317683Spst	/*
724147894Ssam	** Try to enable SAP promiscuity (when not in promiscuous mode
725147894Ssam	** when using HP-UX, when not doing SunATM on Solaris, and never
726146768Ssam	** under SINIX) (Not necessary on send FD)
72717683Spst	*/
72817683Spst#ifndef sinix
72939291Sfenner	if (
73039291Sfenner#ifdef __hpux
73139291Sfenner	    !promisc &&
73239291Sfenner#endif
733127664Sbms#ifdef HAVE_SOLARIS
734127664Sbms	    !isatm &&
735127664Sbms#endif
73639291Sfenner	    (dlpromisconreq(p->fd, DL_PROMISC_SAP, ebuf) < 0 ||
73739291Sfenner	    dlokack(p->fd, "promisc_sap", (char *)buf, ebuf) < 0)) {
73817683Spst		/* Not fatal if promisc since the DL_PROMISC_PHYS worked */
73917683Spst		if (promisc)
74017683Spst			fprintf(stderr,
74117683Spst			    "WARNING: DL_PROMISC_SAP failed (%s)\n", ebuf);
74217683Spst		else
74317683Spst			goto bad;
74417683Spst	}
745147894Ssam#endif /* sinix */
74617683Spst
74717683Spst	/*
748147894Ssam	** HP-UX 9, and HP-UX 10.20 or later, must bind after setting
749147894Ssam	** promiscuous options.
75017683Spst	*/
751147894Ssam#if defined(HAVE_HPUX9) || defined(HAVE_HPUX10_20_OR_LATER)
752147894Ssam	if (dl_dohpuxbind(p->fd, ebuf) < 0)
75317683Spst		goto bad;
754147894Ssam	/*
755147894Ssam	** We don't set promiscuous mode on the send FD, but we'll defer
756147894Ssam	** binding it anyway, just to keep the HP-UX 9/10.20 or later
757147894Ssam	** code together.
758147894Ssam	*/
759147894Ssam	if (p->send_fd >= 0) {
760147894Ssam		/*
761147894Ssam		** XXX - if this fails, just close send_fd and
762147894Ssam		** set it to -1, so that you can't send but can
763147894Ssam		** still receive?
764147894Ssam		*/
765147894Ssam		if (dl_dohpuxbind(p->send_fd, ebuf) < 0)
766147894Ssam			goto bad;
767147894Ssam	}
76817683Spst#endif
76917683Spst
77017683Spst	/*
77117683Spst	** Determine link type
772146768Ssam	** XXX - get SAP length and address length as well, for use
773146768Ssam	** when sending packets.
77417683Spst	*/
77517683Spst	if (dlinforeq(p->fd, ebuf) < 0 ||
77617683Spst	    dlinfoack(p->fd, (char *)buf, ebuf) < 0)
77717683Spst		goto bad;
77817683Spst
77917683Spst	infop = &((union DL_primitives *)buf)->info_ack;
78017683Spst	switch (infop->dl_mac_type) {
78117683Spst
78217683Spst	case DL_CSMACD:
78317683Spst	case DL_ETHER:
78417683Spst		p->linktype = DLT_EN10MB;
78517683Spst		p->offset = 2;
786146768Ssam		/*
787146768Ssam		 * This is (presumably) a real Ethernet capture; give it a
788146768Ssam		 * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so
789146768Ssam		 * that an application can let you choose it, in case you're
790146768Ssam		 * capturing DOCSIS traffic that a Cisco Cable Modem
791146768Ssam		 * Termination System is putting out onto an Ethernet (it
792146768Ssam		 * doesn't put an Ethernet header onto the wire, it puts raw
793146768Ssam		 * DOCSIS frames out on the wire inside the low-level
794146768Ssam		 * Ethernet framing).
795146768Ssam		 */
796146768Ssam		p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2);
797146768Ssam		/*
798146768Ssam		 * If that fails, just leave the list empty.
799146768Ssam		 */
800146768Ssam		if (p->dlt_list != NULL) {
801146768Ssam			p->dlt_list[0] = DLT_EN10MB;
802146768Ssam			p->dlt_list[1] = DLT_DOCSIS;
803146768Ssam			p->dlt_count = 2;
804146768Ssam		}
80517683Spst		break;
80617683Spst
80717683Spst	case DL_FDDI:
80817683Spst		p->linktype = DLT_FDDI;
80939291Sfenner		p->offset = 3;
81017683Spst		break;
81117683Spst
81298530Sfenner	case DL_TPR:
813146768Ssam		/*
814146768Ssam		 * XXX - what about DL_TPB?  Is that Token Bus?
815146768Ssam		 */
81698530Sfenner		p->linktype = DLT_IEEE802;
81798530Sfenner		p->offset = 2;
81898530Sfenner		break;
81998530Sfenner
820127664Sbms#ifdef HAVE_SOLARIS
821127664Sbms	case DL_IPATM:
822127664Sbms		p->linktype = DLT_SUNATM;
823127664Sbms		p->offset = 0;	/* works for LANE and LLC encapsulation */
824127664Sbms		break;
825127664Sbms#endif
826127664Sbms
82717683Spst	default:
82875107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE, "unknown mac type %lu",
829127664Sbms		    (unsigned long)infop->dl_mac_type);
83017683Spst		goto bad;
83117683Spst	}
83217683Spst
83317683Spst#ifdef	DLIOCRAW
83417683Spst	/*
835127664Sbms	** This is a non standard SunOS hack to get the full raw link-layer
836127664Sbms	** header.
83717683Spst	*/
83817683Spst	if (strioctl(p->fd, DLIOCRAW, 0, NULL) < 0) {
83975107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE, "DLIOCRAW: %s",
84075107Sfenner		    pcap_strerror(errno));
84117683Spst		goto bad;
84217683Spst	}
84317683Spst#endif
84417683Spst
84517683Spst#ifdef HAVE_SYS_BUFMOD_H
84617683Spst	/*
84717683Spst	** Another non standard call to get the data nicely buffered
84817683Spst	*/
84917683Spst	if (ioctl(p->fd, I_PUSH, "bufmod") != 0) {
85075107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE, "I_PUSH bufmod: %s",
85175107Sfenner		    pcap_strerror(errno));
85217683Spst		goto bad;
85317683Spst	}
85417683Spst
85517683Spst	/*
85617683Spst	** Now that the bufmod is pushed lets configure it.
85717683Spst	**
85817683Spst	** There is a bug in bufmod(7). When dealing with messages of
85917683Spst	** less than snaplen size it strips data from the beginning not
86017683Spst	** the end.
86117683Spst	**
86217683Spst	** This bug is supposed to be fixed in 5.3.2. Also, there is a
86317683Spst	** patch available. Ask for bugid 1149065.
86417683Spst	*/
86517683Spst	ss = snaplen;
86617683Spst#ifdef HAVE_SOLARIS
86717683Spst	release = get_release(&osmajor, &osminor, &osmicro);
86817683Spst	if (osmajor == 5 && (osminor <= 2 || (osminor == 3 && osmicro < 2)) &&
86917683Spst	    getenv("BUFMOD_FIXED") == NULL) {
87017683Spst		fprintf(stderr,
87117683Spst		"WARNING: bufmod is broken in SunOS %s; ignoring snaplen.\n",
87217683Spst		    release);
87317683Spst		ss = 0;
87417683Spst	}
87517683Spst#endif
87617683Spst	if (ss > 0 &&
87717683Spst	    strioctl(p->fd, SBIOCSSNAP, sizeof(ss), (char *)&ss) != 0) {
87875107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE, "SBIOCSSNAP: %s",
87975107Sfenner		    pcap_strerror(errno));
88017683Spst		goto bad;
88117683Spst	}
88217683Spst
88317683Spst	/*
88417683Spst	** Set up the bufmod timeout
88517683Spst	*/
88617683Spst	if (to_ms != 0) {
88717683Spst		struct timeval to;
88817683Spst
88917683Spst		to.tv_sec = to_ms / 1000;
89017683Spst		to.tv_usec = (to_ms * 1000) % 1000000;
89117683Spst		if (strioctl(p->fd, SBIOCSTIME, sizeof(to), (char *)&to) != 0) {
89275107Sfenner			snprintf(ebuf, PCAP_ERRBUF_SIZE, "SBIOCSTIME: %s",
89375107Sfenner			    pcap_strerror(errno));
89417683Spst			goto bad;
89517683Spst		}
89617683Spst	}
897127664Sbms
898127664Sbms	/*
899127664Sbms	** Set the chunk length.
900127664Sbms	*/
901127664Sbms	chunksize = CHUNKSIZE;
902127664Sbms	if (strioctl(p->fd, SBIOCSCHUNK, sizeof(chunksize), (char *)&chunksize)
903127664Sbms	    != 0) {
904127664Sbms		snprintf(ebuf, PCAP_ERRBUF_SIZE, "SBIOCSCHUNKP: %s",
905127664Sbms		    pcap_strerror(errno));
906127664Sbms		goto bad;
907127664Sbms	}
90817683Spst#endif
90917683Spst
91017683Spst	/*
91117683Spst	** As the last operation flush the read side.
91217683Spst	*/
91317683Spst	if (ioctl(p->fd, I_FLUSH, FLUSHR) != 0) {
91475107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE, "FLUSHR: %s",
91575107Sfenner		    pcap_strerror(errno));
91617683Spst		goto bad;
91717683Spst	}
918127664Sbms
91917683Spst	/* Allocate data buffer */
920127664Sbms	p->bufsize = PKTBUFSIZE;
92117683Spst	p->buffer = (u_char *)malloc(p->bufsize + p->offset);
922127664Sbms	if (p->buffer == NULL) {
923127664Sbms		strlcpy(ebuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE);
924127664Sbms		goto bad;
925127664Sbms	}
92617683Spst
927127664Sbms	/*
928127664Sbms	 * "p->fd" is an FD for a STREAMS device, so "select()" and
929127664Sbms	 * "poll()" should work on it.
930127664Sbms	 */
931127664Sbms	p->selectable_fd = p->fd;
932127664Sbms
933127664Sbms	p->read_op = pcap_read_dlpi;
934146768Ssam	p->inject_op = pcap_inject_dlpi;
935127664Sbms	p->setfilter_op = install_bpf_program;	/* no kernel filtering */
936147894Ssam	p->setdirection_op = NULL;	/* Not implemented.*/
937127664Sbms	p->set_datalink_op = NULL;	/* can't change data link type */
938127664Sbms	p->getnonblock_op = pcap_getnonblock_fd;
939127664Sbms	p->setnonblock_op = pcap_setnonblock_fd;
940127664Sbms	p->stats_op = pcap_stats_dlpi;
941127664Sbms	p->close_op = pcap_close_dlpi;
942127664Sbms
94317683Spst	return (p);
94417683Spstbad:
94598530Sfenner	if (p->fd >= 0)
94698530Sfenner		close(p->fd);
947146768Ssam	if (p->send_fd >= 0)
948146768Ssam		close(p->send_fd);
949146768Ssam	/*
950146768Ssam	 * Get rid of any link-layer type list we allocated.
951146768Ssam	 */
952146768Ssam	if (p->dlt_list != NULL)
953146768Ssam		free(p->dlt_list);
95417683Spst	free(p);
95517683Spst	return (NULL);
95617683Spst}
95717683Spst
95898530Sfenner/*
95998530Sfenner * Split a device name into a device type name and a unit number;
96098530Sfenner * return the a pointer to the beginning of the unit number, which
96198530Sfenner * is the end of the device type name, and set "*unitp" to the unit
96298530Sfenner * number.
96398530Sfenner *
96498530Sfenner * Returns NULL on error, and fills "ebuf" with an error message.
96598530Sfenner */
96698530Sfennerstatic char *
96798530Sfennersplit_dname(char *device, int *unitp, char *ebuf)
96898530Sfenner{
96998530Sfenner	char *cp;
97098530Sfenner	char *eos;
971146768Ssam	long unit;
97298530Sfenner
97398530Sfenner	/*
97498530Sfenner	 * Look for a number at the end of the device name string.
97598530Sfenner	 */
97698530Sfenner	cp = device + strlen(device) - 1;
97798530Sfenner	if (*cp < '0' || *cp > '9') {
97898530Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s missing unit number",
97998530Sfenner		    device);
98098530Sfenner		return (NULL);
98198530Sfenner	}
98298530Sfenner
98398530Sfenner	/* Digits at end of string are unit number */
98498530Sfenner	while (cp-1 >= device && *(cp-1) >= '0' && *(cp-1) <= '9')
98598530Sfenner		cp--;
98698530Sfenner
987146768Ssam	errno = 0;
98898530Sfenner	unit = strtol(cp, &eos, 10);
98998530Sfenner	if (*eos != '\0') {
99098530Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s bad unit number", device);
99198530Sfenner		return (NULL);
99298530Sfenner	}
993146768Ssam	if (errno == ERANGE || unit > INT_MAX) {
994146768Ssam		snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s unit number too large",
995146768Ssam		    device);
996146768Ssam		return (NULL);
997146768Ssam	}
998146768Ssam	if (unit < 0) {
999146768Ssam		snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s unit number is negative",
1000146768Ssam		    device);
1001146768Ssam		return (NULL);
1002146768Ssam	}
1003146768Ssam	*unitp = (int)unit;
100498530Sfenner	return (cp);
100598530Sfenner}
100698530Sfenner
1007146768Ssamstatic int
1008146768Ssamdl_doattach(int fd, int ppa, char *ebuf)
1009146768Ssam{
1010146768Ssam	bpf_u_int32 buf[MAXDLBUF];
1011146768Ssam
1012146768Ssam	if (dlattachreq(fd, ppa, ebuf) < 0 ||
1013146768Ssam	    dlokack(fd, "attach", (char *)buf, ebuf) < 0)
1014146768Ssam		return (-1);
1015146768Ssam	return (0);
1016146768Ssam}
1017146768Ssam
1018147894Ssam#ifdef DL_HP_RAWDLS
1019147894Ssamstatic int
1020147894Ssamdl_dohpuxbind(int fd, char *ebuf)
1021147894Ssam{
1022147894Ssam	int hpsap;
1023147894Ssam	int uerror;
1024147894Ssam	bpf_u_int32 buf[MAXDLBUF];
1025147894Ssam
1026147894Ssam	/*
1027147894Ssam	 * XXX - we start at 22 because we used to use only 22, but
1028147894Ssam	 * that was just because that was the value used in some
1029147894Ssam	 * sample code from HP.  With what value *should* we start?
1030147894Ssam	 * Does it matter, given that we're enabling SAP promiscuity
1031147894Ssam	 * on the input FD?
1032147894Ssam	 */
1033147894Ssam	hpsap = 22;
1034147894Ssam	for (;;) {
1035147894Ssam		if (dlbindreq(fd, hpsap, ebuf) < 0)
1036147894Ssam			return (-1);
1037147894Ssam		if (dlbindack(fd, (char *)buf, ebuf, &uerror) >= 0)
1038147894Ssam			break;
1039147894Ssam		/*
1040147894Ssam		 * For any error other than a UNIX EBUSY, give up.
1041147894Ssam		 */
1042147894Ssam		if (uerror != EBUSY)
1043147894Ssam			return (-1);
1044147894Ssam
1045147894Ssam		/*
1046147894Ssam		 * For EBUSY, try the next SAP value; that means that
1047147894Ssam		 * somebody else is using that SAP.  Clear ebuf so
1048147894Ssam		 * that application doesn't report the "Device busy"
1049147894Ssam		 * error as a warning.
1050147894Ssam		 */
1051147894Ssam		*ebuf = '\0';
1052147894Ssam		hpsap++;
1053147894Ssam		if (hpsap > 100)
1054147894Ssam			return (-1);
1055147894Ssam	}
1056147894Ssam}
1057147894Ssam#endif
1058147894Ssam
105917683Spstint
1060127664Sbmspcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf)
106117683Spst{
1062127664Sbms#ifdef HAVE_SOLARIS
1063127664Sbms	int fd;
1064127664Sbms	union {
1065127664Sbms		u_int nunits;
1066127664Sbms		char pad[516];	/* XXX - must be at least 513; is 516
1067127664Sbms				   in "atmgetunits" */
1068127664Sbms	} buf;
1069127664Sbms	char baname[2+1+1];
1070127664Sbms	u_int i;
107117683Spst
1072127664Sbms	/*
1073127664Sbms	 * We may have to do special magic to get ATM devices.
1074127664Sbms	 */
1075127664Sbms	if ((fd = open("/dev/ba", O_RDWR)) < 0) {
1076127664Sbms		/*
1077127664Sbms		 * We couldn't open the "ba" device.
1078127664Sbms		 * For now, just give up; perhaps we should
1079127664Sbms		 * return an error if the problem is neither
1080127664Sbms		 * a "that device doesn't exist" error (ENOENT,
1081127664Sbms		 * ENXIO, etc.) or a "you're not allowed to do
1082127664Sbms		 * that" error (EPERM, EACCES).
1083127664Sbms		 */
1084127664Sbms		return (0);
1085127664Sbms	}
1086127664Sbms
1087127664Sbms	if (strioctl(fd, A_GET_UNITS, sizeof(buf), (char *)&buf) < 0) {
1088127664Sbms		snprintf(errbuf, PCAP_ERRBUF_SIZE, "A_GET_UNITS: %s",
1089127664Sbms		    pcap_strerror(errno));
109075107Sfenner		return (-1);
1091127664Sbms	}
1092127664Sbms	for (i = 0; i < buf.nunits; i++) {
1093127664Sbms		snprintf(baname, sizeof baname, "ba%u", i);
1094127664Sbms		if (pcap_add_if(alldevsp, baname, 0, NULL, errbuf) < 0)
1095127664Sbms			return (-1);
1096127664Sbms	}
1097127664Sbms#endif
1098127664Sbms
109917683Spst	return (0);
110017683Spst}
110117683Spst
110217683Spststatic int
110317683Spstsend_request(int fd, char *ptr, int len, char *what, char *ebuf)
110417683Spst{
110517683Spst	struct	strbuf	ctl;
110617683Spst	int	flags;
110717683Spst
110817683Spst	ctl.maxlen = 0;
110917683Spst	ctl.len = len;
111017683Spst	ctl.buf = ptr;
111117683Spst
111217683Spst	flags = 0;
111317683Spst	if (putmsg(fd, &ctl, (struct strbuf *) NULL, flags) < 0) {
111475107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE,
111575107Sfenner		    "send_request: putmsg \"%s\": %s",
111617683Spst		    what, pcap_strerror(errno));
111717683Spst		return (-1);
111817683Spst	}
111917683Spst	return (0);
112017683Spst}
112117683Spst
112217683Spststatic int
1123147894Ssamrecv_ack(int fd, int size, const char *what, char *bufp, char *ebuf, int *uerror)
112417683Spst{
112517683Spst	union	DL_primitives	*dlp;
112617683Spst	struct	strbuf	ctl;
112717683Spst	int	flags;
112817683Spst
112917683Spst	ctl.maxlen = MAXDLBUF;
113017683Spst	ctl.len = 0;
113117683Spst	ctl.buf = bufp;
113217683Spst
113317683Spst	flags = 0;
113417683Spst	if (getmsg(fd, &ctl, (struct strbuf*)NULL, &flags) < 0) {
113575107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE, "recv_ack: %s getmsg: %s",
113617683Spst		    what, pcap_strerror(errno));
113717683Spst		return (-1);
113817683Spst	}
113917683Spst
114017683Spst	dlp = (union DL_primitives *) ctl.buf;
114117683Spst	switch (dlp->dl_primitive) {
114217683Spst
114317683Spst	case DL_INFO_ACK:
114417683Spst	case DL_BIND_ACK:
114517683Spst	case DL_OK_ACK:
114617683Spst#ifdef DL_HP_PPA_ACK
114717683Spst	case DL_HP_PPA_ACK:
114817683Spst#endif
114917683Spst		/* These are OK */
115017683Spst		break;
115117683Spst
115217683Spst	case DL_ERROR_ACK:
115317683Spst		switch (dlp->error_ack.dl_errno) {
115417683Spst
115598530Sfenner		case DL_SYSERR:
1156147894Ssam			if (uerror != NULL)
1157147894Ssam				*uerror = dlp->error_ack.dl_unix_errno;
115875107Sfenner			snprintf(ebuf, PCAP_ERRBUF_SIZE,
115998530Sfenner			    "recv_ack: %s: UNIX error - %s",
116017683Spst			    what, pcap_strerror(dlp->error_ack.dl_unix_errno));
116117683Spst			break;
116217683Spst
116317683Spst		default:
1164147894Ssam			if (uerror != NULL)
1165147894Ssam				*uerror = 0;
116698530Sfenner			snprintf(ebuf, PCAP_ERRBUF_SIZE, "recv_ack: %s: %s",
116798530Sfenner			    what, dlstrerror(dlp->error_ack.dl_errno));
116817683Spst			break;
116917683Spst		}
117017683Spst		return (-1);
117117683Spst
117217683Spst	default:
1173147894Ssam		if (uerror != NULL)
1174147894Ssam			*uerror = 0;
117575107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE,
117698530Sfenner		    "recv_ack: %s: Unexpected primitive ack %s",
117798530Sfenner		    what, dlprim(dlp->dl_primitive));
117817683Spst		return (-1);
117917683Spst	}
118017683Spst
118117683Spst	if (ctl.len < size) {
1182147894Ssam		if (uerror != NULL)
1183147894Ssam			*uerror = 0;
118475107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE,
118598530Sfenner		    "recv_ack: %s: Ack too small (%d < %d)",
118617683Spst		    what, ctl.len, size);
118717683Spst		return (-1);
118817683Spst	}
118917683Spst	return (ctl.len);
119017683Spst}
119117683Spst
119298530Sfennerstatic char *
119398530Sfennerdlstrerror(bpf_u_int32 dl_errno)
119498530Sfenner{
119598530Sfenner	static char errstring[6+2+8+1];
119698530Sfenner
119798530Sfenner	switch (dl_errno) {
119898530Sfenner
119998530Sfenner	case DL_ACCESS:
120098530Sfenner		return ("Improper permissions for request");
120198530Sfenner
120298530Sfenner	case DL_BADADDR:
120398530Sfenner		return ("DLSAP addr in improper format or invalid");
120498530Sfenner
120598530Sfenner	case DL_BADCORR:
120698530Sfenner		return ("Seq number not from outstand DL_CONN_IND");
120798530Sfenner
120898530Sfenner	case DL_BADDATA:
120998530Sfenner		return ("User data exceeded provider limit");
121098530Sfenner
121198530Sfenner	case DL_BADPPA:
121298530Sfenner#ifdef HAVE_DEV_DLPI
121398530Sfenner		/*
121498530Sfenner		 * With a single "/dev/dlpi" device used for all
121598530Sfenner		 * DLPI providers, PPAs have nothing to do with
121698530Sfenner		 * unit numbers.
121798530Sfenner		 */
121898530Sfenner		return ("Specified PPA was invalid");
121998530Sfenner#else
122098530Sfenner		/*
122198530Sfenner		 * We have separate devices for separate devices;
122298530Sfenner		 * the PPA is just the unit number.
122398530Sfenner		 */
122498530Sfenner		return ("Specified PPA (device unit) was invalid");
122598530Sfenner#endif
122698530Sfenner
122798530Sfenner	case DL_BADPRIM:
122898530Sfenner		return ("Primitive received not known by provider");
122998530Sfenner
123098530Sfenner	case DL_BADQOSPARAM:
123198530Sfenner		return ("QOS parameters contained invalid values");
123298530Sfenner
123398530Sfenner	case DL_BADQOSTYPE:
123498530Sfenner		return ("QOS structure type is unknown/unsupported");
123598530Sfenner
123698530Sfenner	case DL_BADSAP:
123798530Sfenner		return ("Bad LSAP selector");
123898530Sfenner
123998530Sfenner	case DL_BADTOKEN:
124098530Sfenner		return ("Token used not an active stream");
124198530Sfenner
124298530Sfenner	case DL_BOUND:
124398530Sfenner		return ("Attempted second bind with dl_max_conind");
124498530Sfenner
124598530Sfenner	case DL_INITFAILED:
124698530Sfenner		return ("Physical link initialization failed");
124798530Sfenner
124898530Sfenner	case DL_NOADDR:
124998530Sfenner		return ("Provider couldn't allocate alternate address");
125098530Sfenner
125198530Sfenner	case DL_NOTINIT:
125298530Sfenner		return ("Physical link not initialized");
125398530Sfenner
125498530Sfenner	case DL_OUTSTATE:
125598530Sfenner		return ("Primitive issued in improper state");
125698530Sfenner
125798530Sfenner	case DL_SYSERR:
125898530Sfenner		return ("UNIX system error occurred");
125998530Sfenner
126098530Sfenner	case DL_UNSUPPORTED:
126198530Sfenner		return ("Requested service not supplied by provider");
126298530Sfenner
126398530Sfenner	case DL_UNDELIVERABLE:
126498530Sfenner		return ("Previous data unit could not be delivered");
126598530Sfenner
126698530Sfenner	case DL_NOTSUPPORTED:
126798530Sfenner		return ("Primitive is known but not supported");
126898530Sfenner
126998530Sfenner	case DL_TOOMANY:
127098530Sfenner		return ("Limit exceeded");
127198530Sfenner
127298530Sfenner	case DL_NOTENAB:
127398530Sfenner		return ("Promiscuous mode not enabled");
127498530Sfenner
127598530Sfenner	case DL_BUSY:
127698530Sfenner		return ("Other streams for PPA in post-attached");
127798530Sfenner
127898530Sfenner	case DL_NOAUTO:
127998530Sfenner		return ("Automatic handling XID&TEST not supported");
128098530Sfenner
128198530Sfenner	case DL_NOXIDAUTO:
128298530Sfenner		return ("Automatic handling of XID not supported");
128398530Sfenner
128498530Sfenner	case DL_NOTESTAUTO:
128598530Sfenner		return ("Automatic handling of TEST not supported");
128698530Sfenner
128798530Sfenner	case DL_XIDAUTO:
128898530Sfenner		return ("Automatic handling of XID response");
128998530Sfenner
129098530Sfenner	case DL_TESTAUTO:
129198530Sfenner		return ("Automatic handling of TEST response");
129298530Sfenner
129398530Sfenner	case DL_PENDING:
129498530Sfenner		return ("Pending outstanding connect indications");
129598530Sfenner
129698530Sfenner	default:
129798530Sfenner		sprintf(errstring, "Error %02x", dl_errno);
129898530Sfenner		return (errstring);
129998530Sfenner	}
130098530Sfenner}
130198530Sfenner
130298530Sfennerstatic char *
130398530Sfennerdlprim(bpf_u_int32 prim)
130498530Sfenner{
130598530Sfenner	static char primbuf[80];
130698530Sfenner
130798530Sfenner	switch (prim) {
130898530Sfenner
130998530Sfenner	case DL_INFO_REQ:
131098530Sfenner		return ("DL_INFO_REQ");
131198530Sfenner
131298530Sfenner	case DL_INFO_ACK:
131398530Sfenner		return ("DL_INFO_ACK");
131498530Sfenner
131598530Sfenner	case DL_ATTACH_REQ:
131698530Sfenner		return ("DL_ATTACH_REQ");
131798530Sfenner
131898530Sfenner	case DL_DETACH_REQ:
131998530Sfenner		return ("DL_DETACH_REQ");
132098530Sfenner
132198530Sfenner	case DL_BIND_REQ:
132298530Sfenner		return ("DL_BIND_REQ");
132398530Sfenner
132498530Sfenner	case DL_BIND_ACK:
132598530Sfenner		return ("DL_BIND_ACK");
132698530Sfenner
132798530Sfenner	case DL_UNBIND_REQ:
132898530Sfenner		return ("DL_UNBIND_REQ");
132998530Sfenner
133098530Sfenner	case DL_OK_ACK:
133198530Sfenner		return ("DL_OK_ACK");
133298530Sfenner
133398530Sfenner	case DL_ERROR_ACK:
133498530Sfenner		return ("DL_ERROR_ACK");
133598530Sfenner
133698530Sfenner	case DL_SUBS_BIND_REQ:
133798530Sfenner		return ("DL_SUBS_BIND_REQ");
133898530Sfenner
133998530Sfenner	case DL_SUBS_BIND_ACK:
134098530Sfenner		return ("DL_SUBS_BIND_ACK");
134198530Sfenner
134298530Sfenner	case DL_UNITDATA_REQ:
134398530Sfenner		return ("DL_UNITDATA_REQ");
134498530Sfenner
134598530Sfenner	case DL_UNITDATA_IND:
134698530Sfenner		return ("DL_UNITDATA_IND");
134798530Sfenner
134898530Sfenner	case DL_UDERROR_IND:
134998530Sfenner		return ("DL_UDERROR_IND");
135098530Sfenner
135198530Sfenner	case DL_UDQOS_REQ:
135298530Sfenner		return ("DL_UDQOS_REQ");
135398530Sfenner
135498530Sfenner	case DL_CONNECT_REQ:
135598530Sfenner		return ("DL_CONNECT_REQ");
135698530Sfenner
135798530Sfenner	case DL_CONNECT_IND:
135898530Sfenner		return ("DL_CONNECT_IND");
135998530Sfenner
136098530Sfenner	case DL_CONNECT_RES:
136198530Sfenner		return ("DL_CONNECT_RES");
136298530Sfenner
136398530Sfenner	case DL_CONNECT_CON:
136498530Sfenner		return ("DL_CONNECT_CON");
136598530Sfenner
136698530Sfenner	case DL_TOKEN_REQ:
136798530Sfenner		return ("DL_TOKEN_REQ");
136898530Sfenner
136998530Sfenner	case DL_TOKEN_ACK:
137098530Sfenner		return ("DL_TOKEN_ACK");
137198530Sfenner
137298530Sfenner	case DL_DISCONNECT_REQ:
137398530Sfenner		return ("DL_DISCONNECT_REQ");
137498530Sfenner
137598530Sfenner	case DL_DISCONNECT_IND:
137698530Sfenner		return ("DL_DISCONNECT_IND");
137798530Sfenner
137898530Sfenner	case DL_RESET_REQ:
137998530Sfenner		return ("DL_RESET_REQ");
138098530Sfenner
138198530Sfenner	case DL_RESET_IND:
138298530Sfenner		return ("DL_RESET_IND");
138398530Sfenner
138498530Sfenner	case DL_RESET_RES:
138598530Sfenner		return ("DL_RESET_RES");
138698530Sfenner
138798530Sfenner	case DL_RESET_CON:
138898530Sfenner		return ("DL_RESET_CON");
138998530Sfenner
139098530Sfenner	default:
139198530Sfenner		(void) sprintf(primbuf, "unknown primitive 0x%x", prim);
139298530Sfenner		return (primbuf);
139398530Sfenner	}
139498530Sfenner}
139598530Sfenner
139617683Spststatic int
139717683Spstdlattachreq(int fd, bpf_u_int32 ppa, char *ebuf)
139817683Spst{
139917683Spst	dl_attach_req_t	req;
140017683Spst
140117683Spst	req.dl_primitive = DL_ATTACH_REQ;
140217683Spst	req.dl_ppa = ppa;
140317683Spst
140417683Spst	return (send_request(fd, (char *)&req, sizeof(req), "attach", ebuf));
140517683Spst}
140617683Spst
140717683Spststatic int
140817683Spstdlbindreq(int fd, bpf_u_int32 sap, char *ebuf)
140917683Spst{
141017683Spst
141117683Spst	dl_bind_req_t	req;
141217683Spst
141317683Spst	memset((char *)&req, 0, sizeof(req));
141417683Spst	req.dl_primitive = DL_BIND_REQ;
1415147894Ssam	/* XXX - what if neither of these are defined? */
1416147894Ssam#if defined(DL_HP_RAWDLS)
141717683Spst	req.dl_max_conind = 1;			/* XXX magic number */
141817683Spst	req.dl_service_mode = DL_HP_RAWDLS;
1419147894Ssam#elif defined(DL_CLDLS)
142026175Sfenner	req.dl_service_mode = DL_CLDLS;
142117683Spst#endif
1422147894Ssam	req.dl_sap = sap;
142317683Spst
142417683Spst	return (send_request(fd, (char *)&req, sizeof(req), "bind", ebuf));
142517683Spst}
142617683Spst
142717683Spststatic int
1428147894Ssamdlbindack(int fd, char *bufp, char *ebuf, int *uerror)
142917683Spst{
143017683Spst
1431147894Ssam	return (recv_ack(fd, DL_BIND_ACK_SIZE, "bind", bufp, ebuf, uerror));
143217683Spst}
143317683Spst
143417683Spststatic int
143517683Spstdlpromisconreq(int fd, bpf_u_int32 level, char *ebuf)
143617683Spst{
143717683Spst	dl_promiscon_req_t req;
143817683Spst
143917683Spst	req.dl_primitive = DL_PROMISCON_REQ;
144017683Spst	req.dl_level = level;
144117683Spst
144217683Spst	return (send_request(fd, (char *)&req, sizeof(req), "promiscon", ebuf));
144317683Spst}
144417683Spst
144517683Spststatic int
144617683Spstdlokack(int fd, const char *what, char *bufp, char *ebuf)
144717683Spst{
144817683Spst
1449147894Ssam	return (recv_ack(fd, DL_OK_ACK_SIZE, what, bufp, ebuf, NULL));
145017683Spst}
145117683Spst
145217683Spst
145317683Spststatic int
145417683Spstdlinforeq(int fd, char *ebuf)
145517683Spst{
145617683Spst	dl_info_req_t req;
145717683Spst
145817683Spst	req.dl_primitive = DL_INFO_REQ;
145917683Spst
146017683Spst	return (send_request(fd, (char *)&req, sizeof(req), "info", ebuf));
146117683Spst}
146217683Spst
146317683Spststatic int
146417683Spstdlinfoack(int fd, char *bufp, char *ebuf)
146517683Spst{
146617683Spst
1467147894Ssam	return (recv_ack(fd, DL_INFO_ACK_SIZE, "info", bufp, ebuf, NULL));
146817683Spst}
146917683Spst
1470146768Ssam#ifdef DL_HP_RAWDLS
1471146768Ssam/*
1472146768Ssam * There's an ack *if* there's an error.
1473146768Ssam */
1474146768Ssamstatic int
1475146768Ssamdlrawdatareq(int fd, const u_char *datap, int datalen)
1476146768Ssam{
1477146768Ssam	struct strbuf ctl, data;
1478146768Ssam	long buf[MAXDLBUF];	/* XXX - char? */
1479146768Ssam	union DL_primitives *dlp;
1480146768Ssam	int dlen;
1481146768Ssam
1482146768Ssam	dlp = (union DL_primitives*) buf;
1483146768Ssam
1484146768Ssam	dlp->dl_primitive = DL_HP_RAWDATA_REQ;
1485146768Ssam	dlen = DL_HP_RAWDATA_REQ_SIZE;
1486146768Ssam
1487146768Ssam	/*
1488146768Ssam	 * HP's documentation doesn't appear to show us supplying any
1489146768Ssam	 * address pointed to by the control part of the message.
1490146768Ssam	 * I think that's what raw mode means - you just send the raw
1491146768Ssam	 * packet, you don't specify where to send it to, as that's
1492146768Ssam	 * implied by the destination address.
1493146768Ssam	 */
1494146768Ssam	ctl.maxlen = 0;
1495146768Ssam	ctl.len = dlen;
1496146768Ssam	ctl.buf = (void *)buf;
1497146768Ssam
1498146768Ssam	data.maxlen = 0;
1499146768Ssam	data.len = datalen;
1500146768Ssam	data.buf = (void *)datap;
1501146768Ssam
1502146768Ssam	return (putmsg(fd, &ctl, &data, 0));
1503146768Ssam}
1504146768Ssam#endif /* DL_HP_RAWDLS */
1505146768Ssam
150617683Spst#ifdef HAVE_SYS_BUFMOD_H
150717683Spststatic int
150817683Spststrioctl(int fd, int cmd, int len, char *dp)
150917683Spst{
151017683Spst	struct strioctl str;
151117683Spst	int rc;
151217683Spst
151317683Spst	str.ic_cmd = cmd;
151417683Spst	str.ic_timout = -1;
151517683Spst	str.ic_len = len;
151617683Spst	str.ic_dp = dp;
151717683Spst	rc = ioctl(fd, I_STR, &str);
151817683Spst
151917683Spst	if (rc < 0)
152017683Spst		return (rc);
152117683Spst	else
152217683Spst		return (str.ic_len);
152317683Spst}
152417683Spst#endif
152517683Spst
152617683Spst#if defined(HAVE_SOLARIS) && defined(HAVE_SYS_BUFMOD_H)
152717683Spststatic char *
152817683Spstget_release(bpf_u_int32 *majorp, bpf_u_int32 *minorp, bpf_u_int32 *microp)
152917683Spst{
153017683Spst	char *cp;
153117683Spst	static char buf[32];
153217683Spst
153317683Spst	*majorp = 0;
153417683Spst	*minorp = 0;
153517683Spst	*microp = 0;
153617683Spst	if (sysinfo(SI_RELEASE, buf, sizeof(buf)) < 0)
153717683Spst		return ("?");
153817683Spst	cp = buf;
153998530Sfenner	if (!isdigit((unsigned char)*cp))
154017683Spst		return (buf);
154117683Spst	*majorp = strtol(cp, &cp, 10);
154217683Spst	if (*cp++ != '.')
154317683Spst		return (buf);
154417683Spst	*minorp =  strtol(cp, &cp, 10);
154517683Spst	if (*cp++ != '.')
154617683Spst		return (buf);
154717683Spst	*microp =  strtol(cp, &cp, 10);
154817683Spst	return (buf);
154917683Spst}
155017683Spst#endif
155117683Spst
1552146768Ssam#ifdef DL_HP_PPA_REQ
155317683Spst/*
155475107Sfenner * Under HP-UX 10 and HP-UX 11, we can ask for the ppa
155517683Spst */
155617683Spst
155717683Spst
155875107Sfenner/*
155975107Sfenner * Determine ppa number that specifies ifname.
156075107Sfenner *
156175107Sfenner * If the "dl_hp_ppa_info_t" doesn't have a "dl_module_id_1" member,
156275107Sfenner * the code that's used here is the old code for HP-UX 10.x.
156375107Sfenner *
156475107Sfenner * However, HP-UX 10.20, at least, appears to have such a member
156575107Sfenner * in its "dl_hp_ppa_info_t" structure, so the new code is used.
156675107Sfenner * The new code didn't work on an old 10.20 system on which Rick
156775107Sfenner * Jones of HP tried it, but with later patches installed, it
156875107Sfenner * worked - it appears that the older system had those members but
156975107Sfenner * didn't put anything in them, so, if the search by name fails, we
157075107Sfenner * do the old search.
157175107Sfenner *
157275107Sfenner * Rick suggests that making sure your system is "up on the latest
157375107Sfenner * lancommon/DLPI/driver patches" is probably a good idea; it'd fix
157475107Sfenner * that problem, as well as allowing libpcap to see packets sent
157575107Sfenner * from the system on which the libpcap application is being run.
157675107Sfenner * (On 10.20, in addition to getting the latest patches, you need
157775107Sfenner * to turn the kernel "lanc_outbound_promisc_flag" flag on with ADB;
157875107Sfenner * a posting to "comp.sys.hp.hpux" at
157975107Sfenner *
158075107Sfenner *	http://www.deja.com/[ST_rn=ps]/getdoc.xp?AN=558092266
158175107Sfenner *
158275107Sfenner * says that, to see the machine's outgoing traffic, you'd need to
158375107Sfenner * apply the right patches to your system, and also set that variable
158475107Sfenner * with:
1585127664Sbms
158675107Sfennerecho 'lanc_outbound_promisc_flag/W1' | /usr/bin/adb -w /stand/vmunix /dev/kmem
158775107Sfenner
158875107Sfenner * which could be put in, for example, "/sbin/init.d/lan".
158975107Sfenner *
159075107Sfenner * Setting the variable is not necessary on HP-UX 11.x.
159175107Sfenner */
159217683Spststatic int
159317683Spstget_dlpi_ppa(register int fd, register const char *device, register int unit,
159417683Spst    register char *ebuf)
159517683Spst{
159617683Spst	register dl_hp_ppa_ack_t *ap;
159775107Sfenner	register dl_hp_ppa_info_t *ipstart, *ip;
159817683Spst	register int i;
159975107Sfenner	char dname[100];
160017683Spst	register u_long majdev;
160175107Sfenner	struct stat statbuf;
160217683Spst	dl_hp_ppa_req_t	req;
160398530Sfenner	char buf[MAXDLBUF];
160498530Sfenner	char *ppa_data_buf;
160598530Sfenner	dl_hp_ppa_ack_t	*dlp;
160698530Sfenner	struct strbuf ctl;
160798530Sfenner	int flags;
160898530Sfenner	int ppa;
160917683Spst
161017683Spst	memset((char *)&req, 0, sizeof(req));
161117683Spst	req.dl_primitive = DL_HP_PPA_REQ;
161217683Spst
161317683Spst	memset((char *)buf, 0, sizeof(buf));
161498530Sfenner	if (send_request(fd, (char *)&req, sizeof(req), "hpppa", ebuf) < 0)
161517683Spst		return (-1);
161617683Spst
161798530Sfenner	ctl.maxlen = DL_HP_PPA_ACK_SIZE;
161898530Sfenner	ctl.len = 0;
161998530Sfenner	ctl.buf = (char *)buf;
162098530Sfenner
162198530Sfenner	flags = 0;
162298530Sfenner	/*
162398530Sfenner	 * DLPI may return a big chunk of data for a DL_HP_PPA_REQ. The normal
162498530Sfenner	 * recv_ack will fail because it set the maxlen to MAXDLBUF (8192)
162598530Sfenner	 * which is NOT big enough for a DL_HP_PPA_REQ.
162698530Sfenner	 *
162798530Sfenner	 * This causes libpcap applications to fail on a system with HP-APA
162898530Sfenner	 * installed.
162998530Sfenner	 *
163098530Sfenner	 * To figure out how big the returned data is, we first call getmsg
163198530Sfenner	 * to get the small head and peek at the head to get the actual data
163298530Sfenner	 * length, and  then issue another getmsg to get the actual PPA data.
163398530Sfenner	 */
163498530Sfenner	/* get the head first */
163598530Sfenner	if (getmsg(fd, &ctl, (struct strbuf *)NULL, &flags) < 0) {
163698530Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE,
163798530Sfenner		    "get_dlpi_ppa: hpppa getmsg: %s", pcap_strerror(errno));
163898530Sfenner		return (-1);
163998530Sfenner	}
164098530Sfenner
164198530Sfenner	dlp = (dl_hp_ppa_ack_t *)ctl.buf;
164298530Sfenner	if (dlp->dl_primitive != DL_HP_PPA_ACK) {
164398530Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE,
164498530Sfenner		    "get_dlpi_ppa: hpppa unexpected primitive ack 0x%x",
164598530Sfenner		    (bpf_u_int32)dlp->dl_primitive);
164698530Sfenner		return (-1);
164798530Sfenner	}
1648127664Sbms
164998530Sfenner	if (ctl.len < DL_HP_PPA_ACK_SIZE) {
165098530Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE,
1651127664Sbms		    "get_dlpi_ppa: hpppa ack too small (%d < %lu)",
1652127664Sbms		     ctl.len, (unsigned long)DL_HP_PPA_ACK_SIZE);
165398530Sfenner		return (-1);
165498530Sfenner	}
1655127664Sbms
165698530Sfenner	/* allocate buffer */
165798530Sfenner	if ((ppa_data_buf = (char *)malloc(dlp->dl_length)) == NULL) {
165898530Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE,
165998530Sfenner		    "get_dlpi_ppa: hpppa malloc: %s", pcap_strerror(errno));
166098530Sfenner		return (-1);
166198530Sfenner	}
166298530Sfenner	ctl.maxlen = dlp->dl_length;
166398530Sfenner	ctl.len = 0;
166498530Sfenner	ctl.buf = (char *)ppa_data_buf;
166598530Sfenner	/* get the data */
166698530Sfenner	if (getmsg(fd, &ctl, (struct strbuf *)NULL, &flags) < 0) {
166798530Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE,
166898530Sfenner		    "get_dlpi_ppa: hpppa getmsg: %s", pcap_strerror(errno));
166998530Sfenner		free(ppa_data_buf);
167098530Sfenner		return (-1);
167198530Sfenner	}
167298530Sfenner	if (ctl.len < dlp->dl_length) {
167398530Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE,
167498530Sfenner		    "get_dlpi_ppa: hpppa ack too small (%d < %d)",
167598530Sfenner		    ctl.len, dlp->dl_length);
167698530Sfenner		free(ppa_data_buf);
167798530Sfenner		return (-1);
167898530Sfenner	}
167998530Sfenner
168017683Spst	ap = (dl_hp_ppa_ack_t *)buf;
168198530Sfenner	ipstart = (dl_hp_ppa_info_t *)ppa_data_buf;
168275107Sfenner	ip = ipstart;
168317683Spst
168475107Sfenner#ifdef HAVE_HP_PPA_INFO_T_DL_MODULE_ID_1
168575107Sfenner	/*
168675107Sfenner	 * The "dl_hp_ppa_info_t" structure has a "dl_module_id_1"
168775107Sfenner	 * member that should, in theory, contain the part of the
168875107Sfenner	 * name for the device that comes before the unit number,
168975107Sfenner	 * and should also have a "dl_module_id_2" member that may
169075107Sfenner	 * contain an alternate name (e.g., I think Ethernet devices
169175107Sfenner	 * have both "lan", for "lanN", and "snap", for "snapN", with
169275107Sfenner	 * the former being for Ethernet packets and the latter being
169375107Sfenner	 * for 802.3/802.2 packets).
169475107Sfenner	 *
169575107Sfenner	 * Search for the device that has the specified name and
169675107Sfenner	 * instance number.
169775107Sfenner	 */
169875107Sfenner	for (i = 0; i < ap->dl_count; i++) {
169998530Sfenner		if ((strcmp((const char *)ip->dl_module_id_1, device) == 0 ||
170098530Sfenner		     strcmp((const char *)ip->dl_module_id_2, device) == 0) &&
170175107Sfenner		    ip->dl_instance_num == unit)
170275107Sfenner			break;
170317683Spst
170475107Sfenner		ip = (dl_hp_ppa_info_t *)((u_char *)ipstart + ip->dl_next_offset);
170575107Sfenner	}
170675107Sfenner#else
170775107Sfenner	/*
170875107Sfenner	 * We don't have that member, so the search is impossible; make it
170975107Sfenner	 * look as if the search failed.
171075107Sfenner	 */
171175107Sfenner	i = ap->dl_count;
171275107Sfenner#endif
171375107Sfenner
171475107Sfenner	if (i == ap->dl_count) {
171575107Sfenner		/*
171675107Sfenner		 * Well, we didn't, or can't, find the device by name.
171775107Sfenner		 *
171875107Sfenner		 * HP-UX 10.20, whilst it has "dl_module_id_1" and
171975107Sfenner		 * "dl_module_id_2" fields in the "dl_hp_ppa_info_t",
172075107Sfenner		 * doesn't seem to fill them in unless the system is
172175107Sfenner		 * at a reasonably up-to-date patch level.
172275107Sfenner		 *
172375107Sfenner		 * Older HP-UX 10.x systems might not have those fields
172475107Sfenner		 * at all.
172575107Sfenner		 *
172675107Sfenner		 * Therefore, we'll search for the entry with the major
172775107Sfenner		 * device number of a device with the name "/dev/<dev><unit>",
172875107Sfenner		 * if such a device exists, as the old code did.
172975107Sfenner		 */
173075107Sfenner		snprintf(dname, sizeof(dname), "/dev/%s%d", device, unit);
173175107Sfenner		if (stat(dname, &statbuf) < 0) {
173275107Sfenner			snprintf(ebuf, PCAP_ERRBUF_SIZE, "stat: %s: %s",
173375107Sfenner			    dname, pcap_strerror(errno));
173475107Sfenner			return (-1);
173575107Sfenner		}
173675107Sfenner		majdev = major(statbuf.st_rdev);
173775107Sfenner
173875107Sfenner		ip = ipstart;
173975107Sfenner
174075107Sfenner		for (i = 0; i < ap->dl_count; i++) {
174175107Sfenner			if (ip->dl_mjr_num == majdev &&
174275107Sfenner			    ip->dl_instance_num == unit)
174375107Sfenner				break;
174475107Sfenner
174575107Sfenner			ip = (dl_hp_ppa_info_t *)((u_char *)ipstart + ip->dl_next_offset);
174675107Sfenner		}
174775107Sfenner	}
1748147894Ssam	if (i == ap->dl_count) {
1749147894Ssam		snprintf(ebuf, PCAP_ERRBUF_SIZE,
175075107Sfenner		    "can't find /dev/dlpi PPA for %s%d", device, unit);
175117683Spst		return (-1);
1752147894Ssam	}
1753147894Ssam	if (ip->dl_hdw_state == HDW_DEAD) {
1754147894Ssam		snprintf(ebuf, PCAP_ERRBUF_SIZE,
175575107Sfenner		    "%s%d: hardware state: DOWN\n", device, unit);
175698530Sfenner		free(ppa_data_buf);
175717683Spst		return (-1);
1758147894Ssam	}
1759147894Ssam	ppa = ip->dl_ppa;
1760147894Ssam	free(ppa_data_buf);
1761147894Ssam	return (ppa);
176217683Spst}
176317683Spst#endif
176417683Spst
176517683Spst#ifdef HAVE_HPUX9
176617683Spst/*
176717683Spst * Under HP-UX 9, there is no good way to determine the ppa.
176817683Spst * So punt and read it from /dev/kmem.
176917683Spst */
177017683Spststatic struct nlist nl[] = {
177117683Spst#define NL_IFNET 0
177217683Spst	{ "ifnet" },
177317683Spst	{ "" }
177417683Spst};
177517683Spst
177617683Spststatic char path_vmunix[] = "/hp-ux";
177717683Spst
177817683Spst/* Determine ppa number that specifies ifname */
177917683Spststatic int
178017683Spstget_dlpi_ppa(register int fd, register const char *ifname, register int unit,
178117683Spst    register char *ebuf)
178217683Spst{
178317683Spst	register const char *cp;
178417683Spst	register int kd;
178517683Spst	void *addr;
178617683Spst	struct ifnet ifnet;
178775107Sfenner	char if_name[sizeof(ifnet.if_name) + 1];
178817683Spst
178917683Spst	cp = strrchr(ifname, '/');
179017683Spst	if (cp != NULL)
179117683Spst		ifname = cp + 1;
179217683Spst	if (nlist(path_vmunix, &nl) < 0) {
179375107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE, "nlist %s failed",
179475107Sfenner		    path_vmunix);
179517683Spst		return (-1);
179617683Spst	}
179717683Spst	if (nl[NL_IFNET].n_value == 0) {
179875107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE,
179975107Sfenner		    "could't find %s kernel symbol",
180017683Spst		    nl[NL_IFNET].n_name);
180117683Spst		return (-1);
180217683Spst	}
180317683Spst	kd = open("/dev/kmem", O_RDONLY);
180417683Spst	if (kd < 0) {
180575107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE, "kmem open: %s",
180675107Sfenner		    pcap_strerror(errno));
180717683Spst		return (-1);
180817683Spst	}
180917683Spst	if (dlpi_kread(kd, nl[NL_IFNET].n_value,
181017683Spst	    &addr, sizeof(addr), ebuf) < 0) {
181117683Spst		close(kd);
181217683Spst		return (-1);
181317683Spst	}
181417683Spst	for (; addr != NULL; addr = ifnet.if_next) {
181517683Spst		if (dlpi_kread(kd, (off_t)addr,
181617683Spst		    &ifnet, sizeof(ifnet), ebuf) < 0 ||
181717683Spst		    dlpi_kread(kd, (off_t)ifnet.if_name,
181875107Sfenner		    if_name, sizeof(ifnet.if_name), ebuf) < 0) {
181917683Spst			(void)close(kd);
182017683Spst			return (-1);
182117683Spst		}
182275107Sfenner		if_name[sizeof(ifnet.if_name)] = '\0';
182375107Sfenner		if (strcmp(if_name, ifname) == 0 && ifnet.if_unit == unit)
182417683Spst			return (ifnet.if_index);
182517683Spst	}
182617683Spst
182775107Sfenner	snprintf(ebuf, PCAP_ERRBUF_SIZE, "Can't find %s", ifname);
182817683Spst	return (-1);
182917683Spst}
183017683Spst
183117683Spststatic int
183217683Spstdlpi_kread(register int fd, register off_t addr,
183317683Spst    register void *buf, register u_int len, register char *ebuf)
183417683Spst{
183517683Spst	register int cc;
183617683Spst
183739291Sfenner	if (lseek(fd, addr, SEEK_SET) < 0) {
183875107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE, "lseek: %s",
183975107Sfenner		    pcap_strerror(errno));
184017683Spst		return (-1);
184117683Spst	}
184217683Spst	cc = read(fd, buf, len);
184317683Spst	if (cc < 0) {
184475107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE, "read: %s",
184575107Sfenner		    pcap_strerror(errno));
184617683Spst		return (-1);
184717683Spst	} else if (cc != len) {
184875107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE, "short read (%d != %d)", cc,
184975107Sfenner		    len);
185017683Spst		return (-1);
185117683Spst	}
185217683Spst	return (cc);
185317683Spst}
185417683Spst#endif
1855