pcap-dlpi.c revision 98530
117683Spst/*
239291Sfenner * Copyright (c) 1993, 1994, 1995, 1996, 1997
317683Spst *	The Regents of the University of California.  All rights reserved.
417683Spst *
517683Spst * Redistribution and use in source and binary forms, with or without
617683Spst * modification, are permitted provided that: (1) source code distributions
717683Spst * retain the above copyright notice and this paragraph in its entirety, (2)
817683Spst * distributions including binary code include the above copyright notice and
917683Spst * this paragraph in its entirety in the documentation or other materials
1017683Spst * provided with the distribution, and (3) all advertising materials mentioning
1117683Spst * features or use of this software display the following acknowledgement:
1217683Spst * ``This product includes software developed by the University of California,
1317683Spst * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
1417683Spst * the University nor the names of its contributors may be used to endorse
1517683Spst * or promote products derived from this software without specific prior
1617683Spst * written permission.
1717683Spst * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
1817683Spst * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1917683Spst * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2017683Spst *
2117683Spst * This code contributed by Atanu Ghosh (atanu@cs.ucl.ac.uk),
2217683Spst * University College London.
2317683Spst */
2417683Spst
2517683Spst/*
2617683Spst * Packet capture routine for dlpi under SunOS 5
2717683Spst *
2817683Spst * Notes:
2917683Spst *
3017683Spst *    - Apparently the DLIOCRAW ioctl() is specific to SunOS.
3117683Spst *
3217683Spst *    - There is a bug in bufmod(7) such that setting the snapshot
3317683Spst *      length results in data being left of the front of the packet.
3417683Spst *
3517683Spst *    - It might be desirable to use pfmod(7) to filter packets in the
3617683Spst *      kernel.
3717683Spst */
3817683Spst
3926175Sfenner#ifndef lint
4026175Sfennerstatic const char rcsid[] =
4198530Sfenner    "@(#) $Header: /tcpdump/master/libpcap/pcap-dlpi.c,v 1.74 2001/12/10 07:14:15 guy Exp $ (LBL)";
4226175Sfenner#endif
4326175Sfenner
4475107Sfenner#ifdef HAVE_CONFIG_H
4575107Sfenner#include "config.h"
4675107Sfenner#endif
4775107Sfenner
4817683Spst#include <sys/types.h>
4917683Spst#include <sys/time.h>
5017683Spst#ifdef HAVE_SYS_BUFMOD_H
5117683Spst#include <sys/bufmod.h>
5217683Spst#endif
5317683Spst#include <sys/dlpi.h>
5417683Spst#ifdef HAVE_SYS_DLPI_EXT_H
5517683Spst#include <sys/dlpi_ext.h>
5617683Spst#endif
5717683Spst#ifdef HAVE_HPUX9
5817683Spst#include <sys/socket.h>
5917683Spst#endif
6017683Spst#ifdef DL_HP_PPA_ACK_OBS
6117683Spst#include <sys/stat.h>
6217683Spst#endif
6317683Spst#include <sys/stream.h>
6417683Spst#if defined(HAVE_SOLARIS) && defined(HAVE_SYS_BUFMOD_H)
6517683Spst#include <sys/systeminfo.h>
6617683Spst#endif
6717683Spst
6817683Spst#ifdef HAVE_HPUX9
6917683Spst#include <net/if.h>
7017683Spst#endif
7117683Spst
7217683Spst#include <ctype.h>
7317683Spst#ifdef HAVE_HPUX9
7417683Spst#include <nlist.h>
7517683Spst#endif
7617683Spst#include <errno.h>
7717683Spst#include <fcntl.h>
7817683Spst#include <memory.h>
7917683Spst#include <stdio.h>
8017683Spst#include <stdlib.h>
8117683Spst#include <string.h>
8217683Spst#include <stropts.h>
8317683Spst#include <unistd.h>
8417683Spst
8517683Spst#include "pcap-int.h"
8617683Spst
8717683Spst#ifdef HAVE_OS_PROTO_H
8817683Spst#include "os-proto.h"
8917683Spst#endif
9017683Spst
9117683Spst#ifndef PCAP_DEV_PREFIX
9298530Sfenner#ifdef _AIX
9398530Sfenner#define PCAP_DEV_PREFIX "/dev/dlpi"
9498530Sfenner#else
9517683Spst#define PCAP_DEV_PREFIX "/dev"
9617683Spst#endif
9798530Sfenner#endif
9817683Spst
9917683Spst#define	MAXDLBUF	8192
10017683Spst
10117683Spst/* Forwards */
10298530Sfennerstatic char *split_dname(char *, int *, char *);
10317683Spststatic int dlattachreq(int, bpf_u_int32, char *);
10417683Spststatic int dlbindack(int, char *, char *);
10517683Spststatic int dlbindreq(int, bpf_u_int32, char *);
10617683Spststatic int dlinfoack(int, char *, char *);
10717683Spststatic int dlinforeq(int, char *);
10817683Spststatic int dlokack(int, const char *, char *, char *);
10917683Spststatic int recv_ack(int, int, const char *, char *, char *);
11098530Sfennerstatic char *dlstrerror(bpf_u_int32);
11198530Sfennerstatic char *dlprim(bpf_u_int32);
11217683Spststatic int dlpromisconreq(int, bpf_u_int32, char *);
11317683Spst#if defined(HAVE_SOLARIS) && defined(HAVE_SYS_BUFMOD_H)
11417683Spststatic char *get_release(bpf_u_int32 *, bpf_u_int32 *, bpf_u_int32 *);
11517683Spst#endif
11617683Spststatic int send_request(int, char *, int, char *, char *);
11717683Spst#ifdef HAVE_SYS_BUFMOD_H
11817683Spststatic int strioctl(int, int, int, char *);
11917683Spst#endif
12017683Spst#ifdef HAVE_HPUX9
12117683Spststatic int dlpi_kread(int, off_t, void *, u_int, char *);
12217683Spst#endif
12317683Spst#ifdef HAVE_DEV_DLPI
12417683Spststatic int get_dlpi_ppa(int, const char *, int, char *);
12517683Spst#endif
12617683Spst
12717683Spstint
12817683Spstpcap_stats(pcap_t *p, struct pcap_stat *ps)
12917683Spst{
13017683Spst
13198530Sfenner	/*
13298530Sfenner	 * "ps_recv" counts packets handed to the filter, not packets
13398530Sfenner	 * that passed the filter.  As filtering is done in userland,
13498530Sfenner	 * this does not include packets dropped because we ran out
13598530Sfenner	 * of buffer space.
13698530Sfenner	 *
13798530Sfenner	 * "ps_drop" counts packets dropped inside the DLPI service
13898530Sfenner	 * provider device device because of flow control requirements
13998530Sfenner	 * or resource exhaustion; it doesn't count packets dropped by
14098530Sfenner	 * the interface driver, or packets dropped upstream.  As
14198530Sfenner	 * filtering is done in userland, it counts packets regardless
14298530Sfenner	 * of whether they would've passed the filter.
14398530Sfenner	 *
14498530Sfenner	 * These statistics don't include packets not yet read from
14598530Sfenner	 * the kernel by libpcap, but they may include packets not
14698530Sfenner	 * yet read from libpcap by the application.
14798530Sfenner	 */
14817683Spst	*ps = p->md.stat;
14917683Spst	return (0);
15017683Spst}
15117683Spst
15217683Spst/* XXX Needed by HP-UX (at least) */
15317683Spststatic bpf_u_int32 ctlbuf[MAXDLBUF];
15417683Spststatic struct strbuf ctl = {
15517683Spst	MAXDLBUF,
15617683Spst	0,
15717683Spst	(char *)ctlbuf
15817683Spst};
15917683Spst
16017683Spstint
16117683Spstpcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
16217683Spst{
16317683Spst	register int cc, n, caplen, origlen;
16417683Spst	register u_char *bp, *ep, *pk;
16517683Spst	register struct bpf_insn *fcode;
16617683Spst#ifdef HAVE_SYS_BUFMOD_H
16717683Spst	register struct sb_hdr *sbp;
16817683Spst#ifdef LBL_ALIGN
16917683Spst	struct sb_hdr sbhdr;
17017683Spst#endif
17117683Spst#endif
17217683Spst	int flags;
17317683Spst	struct strbuf data;
17417683Spst	struct pcap_pkthdr pkthdr;
17517683Spst
17617683Spst	flags = 0;
17717683Spst	cc = p->cc;
17817683Spst	if (cc == 0) {
17917683Spst		data.buf = (char *)p->buffer + p->offset;
18017683Spst		data.maxlen = MAXDLBUF;
18117683Spst		data.len = 0;
18217683Spst		do {
18317683Spst			if (getmsg(p->fd, &ctl, &data, &flags) < 0) {
18417683Spst				/* Don't choke when we get ptraced */
18517683Spst				if (errno == EINTR) {
18617683Spst					cc = 0;
18717683Spst					continue;
18817683Spst				}
18975107Sfenner				strlcpy(p->errbuf, pcap_strerror(errno),
19075107Sfenner				    sizeof(p->errbuf));
19117683Spst				return (-1);
19217683Spst			}
19317683Spst			cc = data.len;
19417683Spst		} while (cc == 0);
19517683Spst		bp = p->buffer + p->offset;
19617683Spst	} else
19717683Spst		bp = p->bp;
19817683Spst
19917683Spst	/* Loop through packets */
20017683Spst	fcode = p->fcode.bf_insns;
20117683Spst	ep = bp + cc;
20217683Spst	n = 0;
20317683Spst#ifdef HAVE_SYS_BUFMOD_H
20417683Spst	while (bp < ep) {
20517683Spst#ifdef LBL_ALIGN
20617683Spst		if ((long)bp & 3) {
20717683Spst			sbp = &sbhdr;
20817683Spst			memcpy(sbp, bp, sizeof(*sbp));
20917683Spst		} else
21017683Spst#endif
21117683Spst			sbp = (struct sb_hdr *)bp;
21217683Spst		p->md.stat.ps_drop += sbp->sbh_drops;
21317683Spst		pk = bp + sizeof(*sbp);
21417683Spst		bp += sbp->sbh_totlen;
21517683Spst		origlen = sbp->sbh_origlen;
21617683Spst		caplen = sbp->sbh_msglen;
21717683Spst#else
21817683Spst		origlen = cc;
21917683Spst		caplen = min(p->snapshot, cc);
22017683Spst		pk = bp;
22117683Spst		bp += caplen;
22217683Spst#endif
22317683Spst		++p->md.stat.ps_recv;
22417683Spst		if (bpf_filter(fcode, pk, origlen, caplen)) {
22517683Spst#ifdef HAVE_SYS_BUFMOD_H
22617683Spst			pkthdr.ts = sbp->sbh_timestamp;
22717683Spst#else
22817683Spst			(void)gettimeofday(&pkthdr.ts, NULL);
22917683Spst#endif
23017683Spst			pkthdr.len = origlen;
23117683Spst			pkthdr.caplen = caplen;
23217683Spst			/* Insure caplen does not exceed snapshot */
23317683Spst			if (pkthdr.caplen > p->snapshot)
23417683Spst				pkthdr.caplen = p->snapshot;
23517683Spst			(*callback)(user, &pkthdr, pk);
23617683Spst			if (++n >= cnt && cnt >= 0) {
23717683Spst				p->cc = ep - bp;
23817683Spst				p->bp = bp;
23917683Spst				return (n);
24017683Spst			}
24117683Spst		}
24217683Spst#ifdef HAVE_SYS_BUFMOD_H
24317683Spst	}
24417683Spst#endif
24517683Spst	p->cc = 0;
24617683Spst	return (n);
24717683Spst}
24817683Spst
24917683Spstpcap_t *
25017683Spstpcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)
25117683Spst{
25217683Spst	register char *cp;
25317683Spst	register pcap_t *p;
25498530Sfenner	int ppa;
25517683Spst	register dl_info_ack_t *infop;
25617683Spst#ifdef HAVE_SYS_BUFMOD_H
25717683Spst	bpf_u_int32 ss, flag;
25817683Spst#ifdef HAVE_SOLARIS
25917683Spst	register char *release;
26017683Spst	bpf_u_int32 osmajor, osminor, osmicro;
26117683Spst#endif
26217683Spst#endif
26317683Spst	bpf_u_int32 buf[MAXDLBUF];
26417683Spst	char dname[100];
26517683Spst#ifndef HAVE_DEV_DLPI
26617683Spst	char dname2[100];
26717683Spst#endif
26817683Spst
26917683Spst	p = (pcap_t *)malloc(sizeof(*p));
27017683Spst	if (p == NULL) {
27175107Sfenner		strlcpy(ebuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE);
27217683Spst		return (NULL);
27317683Spst	}
27417683Spst	memset(p, 0, sizeof(*p));
27598530Sfenner	p->fd = -1;	/* indicate that it hasn't been opened yet */
27617683Spst
27775107Sfenner#ifdef HAVE_DEV_DLPI
27817683Spst	/*
27975107Sfenner	** Remove any "/dev/" on the front of the device.
28017683Spst	*/
28175107Sfenner	cp = strrchr(device, '/');
28275107Sfenner	if (cp == NULL)
28375107Sfenner		cp = device;
28475107Sfenner	else
28575107Sfenner		cp++;
28675107Sfenner	strlcpy(dname, cp, sizeof(dname));
28775107Sfenner
28875107Sfenner	/*
28998530Sfenner	 * Split the device name into a device type name and a unit number;
29098530Sfenner	 * chop off the unit number, so "dname" is just a device type name.
29175107Sfenner	 */
29298530Sfenner	cp = split_dname(dname, &ppa, ebuf);
29398530Sfenner	if (cp == NULL)
29417683Spst		goto bad;
29575107Sfenner	*cp = '\0';
29617683Spst
29775107Sfenner	/*
29875107Sfenner	 * Use "/dev/dlpi" as the device.
29975107Sfenner	 *
30075107Sfenner	 * XXX - HP's DLPI Programmer's Guide for HP-UX 11.00 says that
30175107Sfenner	 * the "dl_mjr_num" field is for the "major number of interface
30275107Sfenner	 * driver"; that's the major of "/dev/dlpi" on the system on
30375107Sfenner	 * which I tried this, but there may be DLPI devices that
30475107Sfenner	 * use a different driver, in which case we may need to
30575107Sfenner	 * search "/dev" for the appropriate device with that major
30675107Sfenner	 * device number, rather than hardwiring "/dev/dlpi".
30775107Sfenner	 */
30817683Spst	cp = "/dev/dlpi";
30917683Spst	if ((p->fd = open(cp, O_RDWR)) < 0) {
31075107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE,
31175107Sfenner		    "%s: %s", cp, pcap_strerror(errno));
31217683Spst		goto bad;
31317683Spst	}
31475107Sfenner
31575107Sfenner	/*
31675107Sfenner	 * Get a table of all PPAs for that device, and search that
31775107Sfenner	 * table for the specified device type name and unit number.
31875107Sfenner	 */
31917683Spst	ppa = get_dlpi_ppa(p->fd, dname, ppa, ebuf);
32017683Spst	if (ppa < 0)
32117683Spst		goto bad;
32217683Spst#else
32375107Sfenner	/*
32498530Sfenner	 * Get the unit number, and a pointer to the end of the device
32598530Sfenner	 * type name.
32698530Sfenner	 */
32798530Sfenner	cp = split_dname(device, &ppa, ebuf);
32898530Sfenner	if (cp == NULL)
32975107Sfenner		goto bad;
33075107Sfenner
33198530Sfenner	/*
33298530Sfenner	 * If the device name begins with "/", assume it begins with
33398530Sfenner	 * the pathname of the directory containing the device to open;
33498530Sfenner	 * otherwise, concatenate the device directory name and the
33598530Sfenner	 * device name.
33698530Sfenner	 */
33775107Sfenner	if (*device == '/')
33875107Sfenner		strlcpy(dname, device, sizeof(dname));
33975107Sfenner	else
34075107Sfenner		snprintf(dname, sizeof(dname), "%s/%s", PCAP_DEV_PREFIX,
34175107Sfenner		    device);
34275107Sfenner
34398530Sfenner	/*
34498530Sfenner	 * Make a copy of the device pathname, and then remove the unit
34598530Sfenner	 * number from the device pathname.
34698530Sfenner	 */
34798530Sfenner	strlcpy(dname2, dname, sizeof(dname));
34898530Sfenner	*(dname + strlen(dname) - strlen(cp)) = '\0';
34998530Sfenner
35017683Spst	/* Try device without unit number */
35117683Spst	if ((p->fd = open(dname, O_RDWR)) < 0) {
35217683Spst		if (errno != ENOENT) {
35375107Sfenner			snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s: %s", dname,
35475107Sfenner			    pcap_strerror(errno));
35517683Spst			goto bad;
35617683Spst		}
35717683Spst
35817683Spst		/* Try again with unit number */
35917683Spst		if ((p->fd = open(dname2, O_RDWR)) < 0) {
36075107Sfenner			snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s: %s", dname2,
36175107Sfenner			    pcap_strerror(errno));
36217683Spst			goto bad;
36317683Spst		}
36417683Spst		/* XXX Assume unit zero */
36517683Spst		ppa = 0;
36617683Spst	}
36717683Spst#endif
36817683Spst
36917683Spst	p->snapshot = snaplen;
37017683Spst
37117683Spst	/*
37217683Spst	** Attach if "style 2" provider
37317683Spst	*/
37417683Spst	if (dlinforeq(p->fd, ebuf) < 0 ||
37517683Spst	    dlinfoack(p->fd, (char *)buf, ebuf) < 0)
37617683Spst		goto bad;
37717683Spst	infop = &((union DL_primitives *)buf)->info_ack;
37817683Spst	if (infop->dl_provider_style == DL_STYLE2 &&
37917683Spst	    (dlattachreq(p->fd, ppa, ebuf) < 0 ||
38017683Spst	    dlokack(p->fd, "attach", (char *)buf, ebuf) < 0))
38117683Spst		goto bad;
38217683Spst	/*
38339291Sfenner	** Bind (defer if using HP-UX 9 or HP-UX 10.20, totally skip if
38439291Sfenner	** using SINIX)
38517683Spst	*/
38639291Sfenner#if !defined(HAVE_HPUX9) && !defined(HAVE_HPUX10_20) && !defined(sinix)
38775107Sfenner#ifdef _AIX
38898530Sfenner	/* According to IBM's AIX Support Line, the dl_sap value
38998530Sfenner	** should not be less than 0x600 (1536) for standard Ethernet.
39098530Sfenner	** However, we seem to get DL_BADADDR - "DLSAP addr in improper
39198530Sfenner	** format or invalid" - errors if we use 1537 on the "tr0"
39298530Sfenner	** device, which, given that its name starts with "tr" and that
39398530Sfenner	** it's IBM, probably means a Token Ring device.  (Perhaps we
39498530Sfenner	** need to use 1537 on "/dev/dlpi/en" because that device is for
39598530Sfenner	** D/I/X Ethernet, the "SAP" is actually an Ethernet type, and
39698530Sfenner	** it rejects invalid Ethernet types.)
39798530Sfenner	**
39898530Sfenner	** So if 1537 fails, we try 2, as Hyung Sik Yoon of IBM Korea
39998530Sfenner	** says that works on Token Ring (he says that 0 does *not*
40098530Sfenner	** work; perhaps that's considered an invalid LLC SAP value - I
40198530Sfenner	** assume the SAP value in a DLPI bind is an LLC SAP for network
40298530Sfenner	** types that use 802.2 LLC).
40398530Sfenner	*/
40498530Sfenner	if ((dlbindreq(p->fd, 1537, ebuf) < 0 &&
40598530Sfenner	     dlbindreq(p->fd, 2, ebuf) < 0) ||
40675107Sfenner#else
40717683Spst	if (dlbindreq(p->fd, 0, ebuf) < 0 ||
40875107Sfenner#endif
40917683Spst	    dlbindack(p->fd, (char *)buf, ebuf) < 0)
41017683Spst		goto bad;
41117683Spst#endif
41217683Spst
41317683Spst	if (promisc) {
41417683Spst		/*
41517683Spst		** Enable promiscuous
41617683Spst		*/
41717683Spst		if (dlpromisconreq(p->fd, DL_PROMISC_PHYS, ebuf) < 0 ||
41817683Spst		    dlokack(p->fd, "promisc_phys", (char *)buf, ebuf) < 0)
41917683Spst			goto bad;
42017683Spst
42117683Spst		/*
42217683Spst		** Try to enable multicast (you would have thought
42339291Sfenner		** promiscuous would be sufficient). (Skip if using
42439291Sfenner		** HP-UX or SINIX)
42517683Spst		*/
42639291Sfenner#if !defined(__hpux) && !defined(sinix)
42717683Spst		if (dlpromisconreq(p->fd, DL_PROMISC_MULTI, ebuf) < 0 ||
42817683Spst		    dlokack(p->fd, "promisc_multi", (char *)buf, ebuf) < 0)
42917683Spst			fprintf(stderr,
43017683Spst			    "WARNING: DL_PROMISC_MULTI failed (%s)\n", ebuf);
43117683Spst#endif
43217683Spst	}
43317683Spst	/*
43439291Sfenner	** Try to enable sap (when not in promiscuous mode when using
43539291Sfenner	** using HP-UX and never under SINIX)
43617683Spst	*/
43717683Spst#ifndef sinix
43839291Sfenner	if (
43939291Sfenner#ifdef __hpux
44039291Sfenner	    !promisc &&
44139291Sfenner#endif
44239291Sfenner	    (dlpromisconreq(p->fd, DL_PROMISC_SAP, ebuf) < 0 ||
44339291Sfenner	    dlokack(p->fd, "promisc_sap", (char *)buf, ebuf) < 0)) {
44417683Spst		/* Not fatal if promisc since the DL_PROMISC_PHYS worked */
44517683Spst		if (promisc)
44617683Spst			fprintf(stderr,
44717683Spst			    "WARNING: DL_PROMISC_SAP failed (%s)\n", ebuf);
44817683Spst		else
44917683Spst			goto bad;
45017683Spst	}
45117683Spst#endif
45217683Spst
45317683Spst	/*
45439291Sfenner	** HP-UX 9 and HP-UX 10.20 must bind after setting promiscuous
45539291Sfenner	** options)
45617683Spst	*/
45739291Sfenner#if defined(HAVE_HPUX9) || defined(HAVE_HPUX10_20)
45817683Spst	if (dlbindreq(p->fd, 0, ebuf) < 0 ||
45917683Spst	    dlbindack(p->fd, (char *)buf, ebuf) < 0)
46017683Spst		goto bad;
46117683Spst#endif
46217683Spst
46317683Spst	/*
46417683Spst	** Determine link type
46517683Spst	*/
46617683Spst	if (dlinforeq(p->fd, ebuf) < 0 ||
46717683Spst	    dlinfoack(p->fd, (char *)buf, ebuf) < 0)
46817683Spst		goto bad;
46917683Spst
47017683Spst	infop = &((union DL_primitives *)buf)->info_ack;
47117683Spst	switch (infop->dl_mac_type) {
47217683Spst
47317683Spst	case DL_CSMACD:
47417683Spst	case DL_ETHER:
47517683Spst		p->linktype = DLT_EN10MB;
47617683Spst		p->offset = 2;
47717683Spst		break;
47817683Spst
47917683Spst	case DL_FDDI:
48017683Spst		p->linktype = DLT_FDDI;
48139291Sfenner		p->offset = 3;
48217683Spst		break;
48317683Spst
48498530Sfenner	case DL_TPR:
48598530Sfenner		p->linktype = DLT_IEEE802;
48698530Sfenner		p->offset = 2;
48798530Sfenner		break;
48898530Sfenner
48917683Spst	default:
49075107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE, "unknown mac type %lu",
49175107Sfenner		    infop->dl_mac_type);
49217683Spst		goto bad;
49317683Spst	}
49417683Spst
49517683Spst#ifdef	DLIOCRAW
49617683Spst	/*
49717683Spst	** This is a non standard SunOS hack to get the ethernet header.
49817683Spst	*/
49917683Spst	if (strioctl(p->fd, DLIOCRAW, 0, NULL) < 0) {
50075107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE, "DLIOCRAW: %s",
50175107Sfenner		    pcap_strerror(errno));
50217683Spst		goto bad;
50317683Spst	}
50417683Spst#endif
50517683Spst
50617683Spst#ifdef HAVE_SYS_BUFMOD_H
50717683Spst	/*
50817683Spst	** Another non standard call to get the data nicely buffered
50917683Spst	*/
51017683Spst	if (ioctl(p->fd, I_PUSH, "bufmod") != 0) {
51175107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE, "I_PUSH bufmod: %s",
51275107Sfenner		    pcap_strerror(errno));
51317683Spst		goto bad;
51417683Spst	}
51517683Spst
51617683Spst	/*
51717683Spst	** Now that the bufmod is pushed lets configure it.
51817683Spst	**
51917683Spst	** There is a bug in bufmod(7). When dealing with messages of
52017683Spst	** less than snaplen size it strips data from the beginning not
52117683Spst	** the end.
52217683Spst	**
52317683Spst	** This bug is supposed to be fixed in 5.3.2. Also, there is a
52417683Spst	** patch available. Ask for bugid 1149065.
52517683Spst	*/
52617683Spst	ss = snaplen;
52717683Spst#ifdef HAVE_SOLARIS
52817683Spst	release = get_release(&osmajor, &osminor, &osmicro);
52917683Spst	if (osmajor == 5 && (osminor <= 2 || (osminor == 3 && osmicro < 2)) &&
53017683Spst	    getenv("BUFMOD_FIXED") == NULL) {
53117683Spst		fprintf(stderr,
53217683Spst		"WARNING: bufmod is broken in SunOS %s; ignoring snaplen.\n",
53317683Spst		    release);
53417683Spst		ss = 0;
53517683Spst	}
53617683Spst#endif
53717683Spst	if (ss > 0 &&
53817683Spst	    strioctl(p->fd, SBIOCSSNAP, sizeof(ss), (char *)&ss) != 0) {
53975107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE, "SBIOCSSNAP: %s",
54075107Sfenner		    pcap_strerror(errno));
54117683Spst		goto bad;
54217683Spst	}
54317683Spst
54417683Spst	/*
54517683Spst	** Set up the bufmod flags
54617683Spst	*/
54717683Spst	if (strioctl(p->fd, SBIOCGFLAGS, sizeof(flag), (char *)&flag) < 0) {
54875107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE, "SBIOCGFLAGS: %s",
54975107Sfenner		    pcap_strerror(errno));
55017683Spst		goto bad;
55117683Spst	}
55217683Spst	flag |= SB_NO_DROPS;
55317683Spst	if (strioctl(p->fd, SBIOCSFLAGS, sizeof(flag), (char *)&flag) != 0) {
55475107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE, "SBIOCSFLAGS: %s",
55575107Sfenner		    pcap_strerror(errno));
55617683Spst		goto bad;
55717683Spst	}
55817683Spst	/*
55917683Spst	** Set up the bufmod timeout
56017683Spst	*/
56117683Spst	if (to_ms != 0) {
56217683Spst		struct timeval to;
56317683Spst
56417683Spst		to.tv_sec = to_ms / 1000;
56517683Spst		to.tv_usec = (to_ms * 1000) % 1000000;
56617683Spst		if (strioctl(p->fd, SBIOCSTIME, sizeof(to), (char *)&to) != 0) {
56775107Sfenner			snprintf(ebuf, PCAP_ERRBUF_SIZE, "SBIOCSTIME: %s",
56875107Sfenner			    pcap_strerror(errno));
56917683Spst			goto bad;
57017683Spst		}
57117683Spst	}
57217683Spst#endif
57317683Spst
57417683Spst	/*
57517683Spst	** As the last operation flush the read side.
57617683Spst	*/
57717683Spst	if (ioctl(p->fd, I_FLUSH, FLUSHR) != 0) {
57875107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE, "FLUSHR: %s",
57975107Sfenner		    pcap_strerror(errno));
58017683Spst		goto bad;
58117683Spst	}
58217683Spst	/* Allocate data buffer */
58317683Spst	p->bufsize = MAXDLBUF * sizeof(bpf_u_int32);
58417683Spst	p->buffer = (u_char *)malloc(p->bufsize + p->offset);
58517683Spst
58617683Spst	return (p);
58717683Spstbad:
58898530Sfenner	if (p->fd >= 0)
58998530Sfenner		close(p->fd);
59017683Spst	free(p);
59117683Spst	return (NULL);
59217683Spst}
59317683Spst
59498530Sfenner/*
59598530Sfenner * Split a device name into a device type name and a unit number;
59698530Sfenner * return the a pointer to the beginning of the unit number, which
59798530Sfenner * is the end of the device type name, and set "*unitp" to the unit
59898530Sfenner * number.
59998530Sfenner *
60098530Sfenner * Returns NULL on error, and fills "ebuf" with an error message.
60198530Sfenner */
60298530Sfennerstatic char *
60398530Sfennersplit_dname(char *device, int *unitp, char *ebuf)
60498530Sfenner{
60598530Sfenner	char *cp;
60698530Sfenner	char *eos;
60798530Sfenner	int unit;
60898530Sfenner
60998530Sfenner	/*
61098530Sfenner	 * Look for a number at the end of the device name string.
61198530Sfenner	 */
61298530Sfenner	cp = device + strlen(device) - 1;
61398530Sfenner	if (*cp < '0' || *cp > '9') {
61498530Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s missing unit number",
61598530Sfenner		    device);
61698530Sfenner		return (NULL);
61798530Sfenner	}
61898530Sfenner
61998530Sfenner	/* Digits at end of string are unit number */
62098530Sfenner	while (cp-1 >= device && *(cp-1) >= '0' && *(cp-1) <= '9')
62198530Sfenner		cp--;
62298530Sfenner
62398530Sfenner	unit = strtol(cp, &eos, 10);
62498530Sfenner	if (*eos != '\0') {
62598530Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s bad unit number", device);
62698530Sfenner		return (NULL);
62798530Sfenner	}
62898530Sfenner	*unitp = unit;
62998530Sfenner	return (cp);
63098530Sfenner}
63198530Sfenner
63217683Spstint
63317683Spstpcap_setfilter(pcap_t *p, struct bpf_program *fp)
63417683Spst{
63517683Spst
63675107Sfenner	if (install_bpf_program(p, fp) < 0)
63775107Sfenner		return (-1);
63817683Spst	return (0);
63917683Spst}
64017683Spst
64117683Spststatic int
64217683Spstsend_request(int fd, char *ptr, int len, char *what, char *ebuf)
64317683Spst{
64417683Spst	struct	strbuf	ctl;
64517683Spst	int	flags;
64617683Spst
64717683Spst	ctl.maxlen = 0;
64817683Spst	ctl.len = len;
64917683Spst	ctl.buf = ptr;
65017683Spst
65117683Spst	flags = 0;
65217683Spst	if (putmsg(fd, &ctl, (struct strbuf *) NULL, flags) < 0) {
65375107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE,
65475107Sfenner		    "send_request: putmsg \"%s\": %s",
65517683Spst		    what, pcap_strerror(errno));
65617683Spst		return (-1);
65717683Spst	}
65817683Spst	return (0);
65917683Spst}
66017683Spst
66117683Spststatic int
66217683Spstrecv_ack(int fd, int size, const char *what, char *bufp, char *ebuf)
66317683Spst{
66417683Spst	union	DL_primitives	*dlp;
66517683Spst	struct	strbuf	ctl;
66617683Spst	int	flags;
66717683Spst
66817683Spst	ctl.maxlen = MAXDLBUF;
66917683Spst	ctl.len = 0;
67017683Spst	ctl.buf = bufp;
67117683Spst
67217683Spst	flags = 0;
67317683Spst	if (getmsg(fd, &ctl, (struct strbuf*)NULL, &flags) < 0) {
67475107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE, "recv_ack: %s getmsg: %s",
67517683Spst		    what, pcap_strerror(errno));
67617683Spst		return (-1);
67717683Spst	}
67817683Spst
67917683Spst	dlp = (union DL_primitives *) ctl.buf;
68017683Spst	switch (dlp->dl_primitive) {
68117683Spst
68217683Spst	case DL_INFO_ACK:
68317683Spst	case DL_BIND_ACK:
68417683Spst	case DL_OK_ACK:
68517683Spst#ifdef DL_HP_PPA_ACK
68617683Spst	case DL_HP_PPA_ACK:
68717683Spst#endif
68817683Spst		/* These are OK */
68917683Spst		break;
69017683Spst
69117683Spst	case DL_ERROR_ACK:
69217683Spst		switch (dlp->error_ack.dl_errno) {
69317683Spst
69498530Sfenner		case DL_SYSERR:
69575107Sfenner			snprintf(ebuf, PCAP_ERRBUF_SIZE,
69698530Sfenner			    "recv_ack: %s: UNIX error - %s",
69717683Spst			    what, pcap_strerror(dlp->error_ack.dl_unix_errno));
69817683Spst			break;
69917683Spst
70017683Spst		default:
70198530Sfenner			snprintf(ebuf, PCAP_ERRBUF_SIZE, "recv_ack: %s: %s",
70298530Sfenner			    what, dlstrerror(dlp->error_ack.dl_errno));
70317683Spst			break;
70417683Spst		}
70517683Spst		return (-1);
70617683Spst
70717683Spst	default:
70875107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE,
70998530Sfenner		    "recv_ack: %s: Unexpected primitive ack %s",
71098530Sfenner		    what, dlprim(dlp->dl_primitive));
71117683Spst		return (-1);
71217683Spst	}
71317683Spst
71417683Spst	if (ctl.len < size) {
71575107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE,
71698530Sfenner		    "recv_ack: %s: Ack too small (%d < %d)",
71717683Spst		    what, ctl.len, size);
71817683Spst		return (-1);
71917683Spst	}
72017683Spst	return (ctl.len);
72117683Spst}
72217683Spst
72398530Sfennerstatic char *
72498530Sfennerdlstrerror(bpf_u_int32 dl_errno)
72598530Sfenner{
72698530Sfenner	static char errstring[6+2+8+1];
72798530Sfenner
72898530Sfenner	switch (dl_errno) {
72998530Sfenner
73098530Sfenner	case DL_ACCESS:
73198530Sfenner		return ("Improper permissions for request");
73298530Sfenner
73398530Sfenner	case DL_BADADDR:
73498530Sfenner		return ("DLSAP addr in improper format or invalid");
73598530Sfenner
73698530Sfenner	case DL_BADCORR:
73798530Sfenner		return ("Seq number not from outstand DL_CONN_IND");
73898530Sfenner
73998530Sfenner	case DL_BADDATA:
74098530Sfenner		return ("User data exceeded provider limit");
74198530Sfenner
74298530Sfenner	case DL_BADPPA:
74398530Sfenner#ifdef HAVE_DEV_DLPI
74498530Sfenner		/*
74598530Sfenner		 * With a single "/dev/dlpi" device used for all
74698530Sfenner		 * DLPI providers, PPAs have nothing to do with
74798530Sfenner		 * unit numbers.
74898530Sfenner		 */
74998530Sfenner		return ("Specified PPA was invalid");
75098530Sfenner#else
75198530Sfenner		/*
75298530Sfenner		 * We have separate devices for separate devices;
75398530Sfenner		 * the PPA is just the unit number.
75498530Sfenner		 */
75598530Sfenner		return ("Specified PPA (device unit) was invalid");
75698530Sfenner#endif
75798530Sfenner
75898530Sfenner	case DL_BADPRIM:
75998530Sfenner		return ("Primitive received not known by provider");
76098530Sfenner
76198530Sfenner	case DL_BADQOSPARAM:
76298530Sfenner		return ("QOS parameters contained invalid values");
76398530Sfenner
76498530Sfenner	case DL_BADQOSTYPE:
76598530Sfenner		return ("QOS structure type is unknown/unsupported");
76698530Sfenner
76798530Sfenner	case DL_BADSAP:
76898530Sfenner		return ("Bad LSAP selector");
76998530Sfenner
77098530Sfenner	case DL_BADTOKEN:
77198530Sfenner		return ("Token used not an active stream");
77298530Sfenner
77398530Sfenner	case DL_BOUND:
77498530Sfenner		return ("Attempted second bind with dl_max_conind");
77598530Sfenner
77698530Sfenner	case DL_INITFAILED:
77798530Sfenner		return ("Physical link initialization failed");
77898530Sfenner
77998530Sfenner	case DL_NOADDR:
78098530Sfenner		return ("Provider couldn't allocate alternate address");
78198530Sfenner
78298530Sfenner	case DL_NOTINIT:
78398530Sfenner		return ("Physical link not initialized");
78498530Sfenner
78598530Sfenner	case DL_OUTSTATE:
78698530Sfenner		return ("Primitive issued in improper state");
78798530Sfenner
78898530Sfenner	case DL_SYSERR:
78998530Sfenner		return ("UNIX system error occurred");
79098530Sfenner
79198530Sfenner	case DL_UNSUPPORTED:
79298530Sfenner		return ("Requested service not supplied by provider");
79398530Sfenner
79498530Sfenner	case DL_UNDELIVERABLE:
79598530Sfenner		return ("Previous data unit could not be delivered");
79698530Sfenner
79798530Sfenner	case DL_NOTSUPPORTED:
79898530Sfenner		return ("Primitive is known but not supported");
79998530Sfenner
80098530Sfenner	case DL_TOOMANY:
80198530Sfenner		return ("Limit exceeded");
80298530Sfenner
80398530Sfenner	case DL_NOTENAB:
80498530Sfenner		return ("Promiscuous mode not enabled");
80598530Sfenner
80698530Sfenner	case DL_BUSY:
80798530Sfenner		return ("Other streams for PPA in post-attached");
80898530Sfenner
80998530Sfenner	case DL_NOAUTO:
81098530Sfenner		return ("Automatic handling XID&TEST not supported");
81198530Sfenner
81298530Sfenner	case DL_NOXIDAUTO:
81398530Sfenner		return ("Automatic handling of XID not supported");
81498530Sfenner
81598530Sfenner	case DL_NOTESTAUTO:
81698530Sfenner		return ("Automatic handling of TEST not supported");
81798530Sfenner
81898530Sfenner	case DL_XIDAUTO:
81998530Sfenner		return ("Automatic handling of XID response");
82098530Sfenner
82198530Sfenner	case DL_TESTAUTO:
82298530Sfenner		return ("Automatic handling of TEST response");
82398530Sfenner
82498530Sfenner	case DL_PENDING:
82598530Sfenner		return ("Pending outstanding connect indications");
82698530Sfenner
82798530Sfenner	default:
82898530Sfenner		sprintf(errstring, "Error %02x", dl_errno);
82998530Sfenner		return (errstring);
83098530Sfenner	}
83198530Sfenner}
83298530Sfenner
83398530Sfennerstatic char *
83498530Sfennerdlprim(bpf_u_int32 prim)
83598530Sfenner{
83698530Sfenner	static char primbuf[80];
83798530Sfenner
83898530Sfenner	switch (prim) {
83998530Sfenner
84098530Sfenner	case DL_INFO_REQ:
84198530Sfenner		return ("DL_INFO_REQ");
84298530Sfenner
84398530Sfenner	case DL_INFO_ACK:
84498530Sfenner		return ("DL_INFO_ACK");
84598530Sfenner
84698530Sfenner	case DL_ATTACH_REQ:
84798530Sfenner		return ("DL_ATTACH_REQ");
84898530Sfenner
84998530Sfenner	case DL_DETACH_REQ:
85098530Sfenner		return ("DL_DETACH_REQ");
85198530Sfenner
85298530Sfenner	case DL_BIND_REQ:
85398530Sfenner		return ("DL_BIND_REQ");
85498530Sfenner
85598530Sfenner	case DL_BIND_ACK:
85698530Sfenner		return ("DL_BIND_ACK");
85798530Sfenner
85898530Sfenner	case DL_UNBIND_REQ:
85998530Sfenner		return ("DL_UNBIND_REQ");
86098530Sfenner
86198530Sfenner	case DL_OK_ACK:
86298530Sfenner		return ("DL_OK_ACK");
86398530Sfenner
86498530Sfenner	case DL_ERROR_ACK:
86598530Sfenner		return ("DL_ERROR_ACK");
86698530Sfenner
86798530Sfenner	case DL_SUBS_BIND_REQ:
86898530Sfenner		return ("DL_SUBS_BIND_REQ");
86998530Sfenner
87098530Sfenner	case DL_SUBS_BIND_ACK:
87198530Sfenner		return ("DL_SUBS_BIND_ACK");
87298530Sfenner
87398530Sfenner	case DL_UNITDATA_REQ:
87498530Sfenner		return ("DL_UNITDATA_REQ");
87598530Sfenner
87698530Sfenner	case DL_UNITDATA_IND:
87798530Sfenner		return ("DL_UNITDATA_IND");
87898530Sfenner
87998530Sfenner	case DL_UDERROR_IND:
88098530Sfenner		return ("DL_UDERROR_IND");
88198530Sfenner
88298530Sfenner	case DL_UDQOS_REQ:
88398530Sfenner		return ("DL_UDQOS_REQ");
88498530Sfenner
88598530Sfenner	case DL_CONNECT_REQ:
88698530Sfenner		return ("DL_CONNECT_REQ");
88798530Sfenner
88898530Sfenner	case DL_CONNECT_IND:
88998530Sfenner		return ("DL_CONNECT_IND");
89098530Sfenner
89198530Sfenner	case DL_CONNECT_RES:
89298530Sfenner		return ("DL_CONNECT_RES");
89398530Sfenner
89498530Sfenner	case DL_CONNECT_CON:
89598530Sfenner		return ("DL_CONNECT_CON");
89698530Sfenner
89798530Sfenner	case DL_TOKEN_REQ:
89898530Sfenner		return ("DL_TOKEN_REQ");
89998530Sfenner
90098530Sfenner	case DL_TOKEN_ACK:
90198530Sfenner		return ("DL_TOKEN_ACK");
90298530Sfenner
90398530Sfenner	case DL_DISCONNECT_REQ:
90498530Sfenner		return ("DL_DISCONNECT_REQ");
90598530Sfenner
90698530Sfenner	case DL_DISCONNECT_IND:
90798530Sfenner		return ("DL_DISCONNECT_IND");
90898530Sfenner
90998530Sfenner	case DL_RESET_REQ:
91098530Sfenner		return ("DL_RESET_REQ");
91198530Sfenner
91298530Sfenner	case DL_RESET_IND:
91398530Sfenner		return ("DL_RESET_IND");
91498530Sfenner
91598530Sfenner	case DL_RESET_RES:
91698530Sfenner		return ("DL_RESET_RES");
91798530Sfenner
91898530Sfenner	case DL_RESET_CON:
91998530Sfenner		return ("DL_RESET_CON");
92098530Sfenner
92198530Sfenner	default:
92298530Sfenner		(void) sprintf(primbuf, "unknown primitive 0x%x", prim);
92398530Sfenner		return (primbuf);
92498530Sfenner	}
92598530Sfenner}
92698530Sfenner
92717683Spststatic int
92817683Spstdlattachreq(int fd, bpf_u_int32 ppa, char *ebuf)
92917683Spst{
93017683Spst	dl_attach_req_t	req;
93117683Spst
93217683Spst	req.dl_primitive = DL_ATTACH_REQ;
93317683Spst	req.dl_ppa = ppa;
93417683Spst
93517683Spst	return (send_request(fd, (char *)&req, sizeof(req), "attach", ebuf));
93617683Spst}
93717683Spst
93817683Spststatic int
93917683Spstdlbindreq(int fd, bpf_u_int32 sap, char *ebuf)
94017683Spst{
94117683Spst
94217683Spst	dl_bind_req_t	req;
94317683Spst
94417683Spst	memset((char *)&req, 0, sizeof(req));
94517683Spst	req.dl_primitive = DL_BIND_REQ;
94617683Spst#ifdef DL_HP_RAWDLS
94717683Spst	req.dl_max_conind = 1;			/* XXX magic number */
94817683Spst	/* 22 is INSAP as per the HP-UX DLPI Programmer's Guide */
94917683Spst	req.dl_sap = 22;
95017683Spst	req.dl_service_mode = DL_HP_RAWDLS;
95117683Spst#else
95217683Spst	req.dl_sap = sap;
95326175Sfenner#ifdef DL_CLDLS
95426175Sfenner	req.dl_service_mode = DL_CLDLS;
95517683Spst#endif
95626175Sfenner#endif
95717683Spst
95817683Spst	return (send_request(fd, (char *)&req, sizeof(req), "bind", ebuf));
95917683Spst}
96017683Spst
96117683Spststatic int
96217683Spstdlbindack(int fd, char *bufp, char *ebuf)
96317683Spst{
96417683Spst
96517683Spst	return (recv_ack(fd, DL_BIND_ACK_SIZE, "bind", bufp, ebuf));
96617683Spst}
96717683Spst
96817683Spststatic int
96917683Spstdlpromisconreq(int fd, bpf_u_int32 level, char *ebuf)
97017683Spst{
97117683Spst	dl_promiscon_req_t req;
97217683Spst
97317683Spst	req.dl_primitive = DL_PROMISCON_REQ;
97417683Spst	req.dl_level = level;
97517683Spst
97617683Spst	return (send_request(fd, (char *)&req, sizeof(req), "promiscon", ebuf));
97717683Spst}
97817683Spst
97917683Spststatic int
98017683Spstdlokack(int fd, const char *what, char *bufp, char *ebuf)
98117683Spst{
98217683Spst
98317683Spst	return (recv_ack(fd, DL_OK_ACK_SIZE, what, bufp, ebuf));
98417683Spst}
98517683Spst
98617683Spst
98717683Spststatic int
98817683Spstdlinforeq(int fd, char *ebuf)
98917683Spst{
99017683Spst	dl_info_req_t req;
99117683Spst
99217683Spst	req.dl_primitive = DL_INFO_REQ;
99317683Spst
99417683Spst	return (send_request(fd, (char *)&req, sizeof(req), "info", ebuf));
99517683Spst}
99617683Spst
99717683Spststatic int
99817683Spstdlinfoack(int fd, char *bufp, char *ebuf)
99917683Spst{
100017683Spst
100117683Spst	return (recv_ack(fd, DL_INFO_ACK_SIZE, "info", bufp, ebuf));
100217683Spst}
100317683Spst
100417683Spst#ifdef HAVE_SYS_BUFMOD_H
100517683Spststatic int
100617683Spststrioctl(int fd, int cmd, int len, char *dp)
100717683Spst{
100817683Spst	struct strioctl str;
100917683Spst	int rc;
101017683Spst
101117683Spst	str.ic_cmd = cmd;
101217683Spst	str.ic_timout = -1;
101317683Spst	str.ic_len = len;
101417683Spst	str.ic_dp = dp;
101517683Spst	rc = ioctl(fd, I_STR, &str);
101617683Spst
101717683Spst	if (rc < 0)
101817683Spst		return (rc);
101917683Spst	else
102017683Spst		return (str.ic_len);
102117683Spst}
102217683Spst#endif
102317683Spst
102417683Spst#if defined(HAVE_SOLARIS) && defined(HAVE_SYS_BUFMOD_H)
102517683Spststatic char *
102617683Spstget_release(bpf_u_int32 *majorp, bpf_u_int32 *minorp, bpf_u_int32 *microp)
102717683Spst{
102817683Spst	char *cp;
102917683Spst	static char buf[32];
103017683Spst
103117683Spst	*majorp = 0;
103217683Spst	*minorp = 0;
103317683Spst	*microp = 0;
103417683Spst	if (sysinfo(SI_RELEASE, buf, sizeof(buf)) < 0)
103517683Spst		return ("?");
103617683Spst	cp = buf;
103798530Sfenner	if (!isdigit((unsigned char)*cp))
103817683Spst		return (buf);
103917683Spst	*majorp = strtol(cp, &cp, 10);
104017683Spst	if (*cp++ != '.')
104117683Spst		return (buf);
104217683Spst	*minorp =  strtol(cp, &cp, 10);
104317683Spst	if (*cp++ != '.')
104417683Spst		return (buf);
104517683Spst	*microp =  strtol(cp, &cp, 10);
104617683Spst	return (buf);
104717683Spst}
104817683Spst#endif
104917683Spst
105017683Spst#ifdef DL_HP_PPA_ACK_OBS
105117683Spst/*
105275107Sfenner * Under HP-UX 10 and HP-UX 11, we can ask for the ppa
105317683Spst */
105417683Spst
105517683Spst
105675107Sfenner/*
105775107Sfenner * Determine ppa number that specifies ifname.
105875107Sfenner *
105975107Sfenner * If the "dl_hp_ppa_info_t" doesn't have a "dl_module_id_1" member,
106075107Sfenner * the code that's used here is the old code for HP-UX 10.x.
106175107Sfenner *
106275107Sfenner * However, HP-UX 10.20, at least, appears to have such a member
106375107Sfenner * in its "dl_hp_ppa_info_t" structure, so the new code is used.
106475107Sfenner * The new code didn't work on an old 10.20 system on which Rick
106575107Sfenner * Jones of HP tried it, but with later patches installed, it
106675107Sfenner * worked - it appears that the older system had those members but
106775107Sfenner * didn't put anything in them, so, if the search by name fails, we
106875107Sfenner * do the old search.
106975107Sfenner *
107075107Sfenner * Rick suggests that making sure your system is "up on the latest
107175107Sfenner * lancommon/DLPI/driver patches" is probably a good idea; it'd fix
107275107Sfenner * that problem, as well as allowing libpcap to see packets sent
107375107Sfenner * from the system on which the libpcap application is being run.
107475107Sfenner * (On 10.20, in addition to getting the latest patches, you need
107575107Sfenner * to turn the kernel "lanc_outbound_promisc_flag" flag on with ADB;
107675107Sfenner * a posting to "comp.sys.hp.hpux" at
107775107Sfenner *
107875107Sfenner *	http://www.deja.com/[ST_rn=ps]/getdoc.xp?AN=558092266
107975107Sfenner *
108075107Sfenner * says that, to see the machine's outgoing traffic, you'd need to
108175107Sfenner * apply the right patches to your system, and also set that variable
108275107Sfenner * with:
108375107Sfenner
108475107Sfennerecho 'lanc_outbound_promisc_flag/W1' | /usr/bin/adb -w /stand/vmunix /dev/kmem
108575107Sfenner
108675107Sfenner * which could be put in, for example, "/sbin/init.d/lan".
108775107Sfenner *
108875107Sfenner * Setting the variable is not necessary on HP-UX 11.x.
108975107Sfenner */
109017683Spststatic int
109117683Spstget_dlpi_ppa(register int fd, register const char *device, register int unit,
109217683Spst    register char *ebuf)
109317683Spst{
109417683Spst	register dl_hp_ppa_ack_t *ap;
109575107Sfenner	register dl_hp_ppa_info_t *ipstart, *ip;
109617683Spst	register int i;
109775107Sfenner	char dname[100];
109817683Spst	register u_long majdev;
109975107Sfenner	struct stat statbuf;
110017683Spst	dl_hp_ppa_req_t	req;
110198530Sfenner	char buf[MAXDLBUF];
110298530Sfenner	char *ppa_data_buf;
110398530Sfenner	dl_hp_ppa_ack_t	*dlp;
110498530Sfenner	struct strbuf ctl;
110598530Sfenner	int flags;
110698530Sfenner	int ppa;
110717683Spst
110817683Spst	memset((char *)&req, 0, sizeof(req));
110917683Spst	req.dl_primitive = DL_HP_PPA_REQ;
111017683Spst
111117683Spst	memset((char *)buf, 0, sizeof(buf));
111298530Sfenner	if (send_request(fd, (char *)&req, sizeof(req), "hpppa", ebuf) < 0)
111317683Spst		return (-1);
111417683Spst
111598530Sfenner	ctl.maxlen = DL_HP_PPA_ACK_SIZE;
111698530Sfenner	ctl.len = 0;
111798530Sfenner	ctl.buf = (char *)buf;
111898530Sfenner
111998530Sfenner	flags = 0;
112098530Sfenner	/*
112198530Sfenner	 * DLPI may return a big chunk of data for a DL_HP_PPA_REQ. The normal
112298530Sfenner	 * recv_ack will fail because it set the maxlen to MAXDLBUF (8192)
112398530Sfenner	 * which is NOT big enough for a DL_HP_PPA_REQ.
112498530Sfenner	 *
112598530Sfenner	 * This causes libpcap applications to fail on a system with HP-APA
112698530Sfenner	 * installed.
112798530Sfenner	 *
112898530Sfenner	 * To figure out how big the returned data is, we first call getmsg
112998530Sfenner	 * to get the small head and peek at the head to get the actual data
113098530Sfenner	 * length, and  then issue another getmsg to get the actual PPA data.
113198530Sfenner	 */
113298530Sfenner	/* get the head first */
113398530Sfenner	if (getmsg(fd, &ctl, (struct strbuf *)NULL, &flags) < 0) {
113498530Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE,
113598530Sfenner		    "get_dlpi_ppa: hpppa getmsg: %s", pcap_strerror(errno));
113698530Sfenner		return (-1);
113798530Sfenner	}
113898530Sfenner
113998530Sfenner	dlp = (dl_hp_ppa_ack_t *)ctl.buf;
114098530Sfenner	if (dlp->dl_primitive != DL_HP_PPA_ACK) {
114198530Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE,
114298530Sfenner		    "get_dlpi_ppa: hpppa unexpected primitive ack 0x%x",
114398530Sfenner		    (bpf_u_int32)dlp->dl_primitive);
114498530Sfenner		return (-1);
114598530Sfenner	}
114698530Sfenner
114798530Sfenner	if (ctl.len < DL_HP_PPA_ACK_SIZE) {
114898530Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE,
114998530Sfenner		    "get_dlpi_ppa: hpppa ack too small (%d < %d)",
115098530Sfenner		     ctl.len, DL_HP_PPA_ACK_SIZE);
115198530Sfenner		return (-1);
115298530Sfenner	}
115398530Sfenner
115498530Sfenner	/* allocate buffer */
115598530Sfenner	if ((ppa_data_buf = (char *)malloc(dlp->dl_length)) == NULL) {
115698530Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE,
115798530Sfenner		    "get_dlpi_ppa: hpppa malloc: %s", pcap_strerror(errno));
115898530Sfenner		return (-1);
115998530Sfenner	}
116098530Sfenner	ctl.maxlen = dlp->dl_length;
116198530Sfenner	ctl.len = 0;
116298530Sfenner	ctl.buf = (char *)ppa_data_buf;
116398530Sfenner	/* get the data */
116498530Sfenner	if (getmsg(fd, &ctl, (struct strbuf *)NULL, &flags) < 0) {
116598530Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE,
116698530Sfenner		    "get_dlpi_ppa: hpppa getmsg: %s", pcap_strerror(errno));
116798530Sfenner		free(ppa_data_buf);
116898530Sfenner		return (-1);
116998530Sfenner	}
117098530Sfenner	if (ctl.len < dlp->dl_length) {
117198530Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE,
117298530Sfenner		    "get_dlpi_ppa: hpppa ack too small (%d < %d)",
117398530Sfenner		    ctl.len, dlp->dl_length);
117498530Sfenner		free(ppa_data_buf);
117598530Sfenner		return (-1);
117698530Sfenner	}
117798530Sfenner
117817683Spst	ap = (dl_hp_ppa_ack_t *)buf;
117998530Sfenner	ipstart = (dl_hp_ppa_info_t *)ppa_data_buf;
118075107Sfenner	ip = ipstart;
118117683Spst
118275107Sfenner#ifdef HAVE_HP_PPA_INFO_T_DL_MODULE_ID_1
118375107Sfenner	/*
118475107Sfenner	 * The "dl_hp_ppa_info_t" structure has a "dl_module_id_1"
118575107Sfenner	 * member that should, in theory, contain the part of the
118675107Sfenner	 * name for the device that comes before the unit number,
118775107Sfenner	 * and should also have a "dl_module_id_2" member that may
118875107Sfenner	 * contain an alternate name (e.g., I think Ethernet devices
118975107Sfenner	 * have both "lan", for "lanN", and "snap", for "snapN", with
119075107Sfenner	 * the former being for Ethernet packets and the latter being
119175107Sfenner	 * for 802.3/802.2 packets).
119275107Sfenner	 *
119375107Sfenner	 * Search for the device that has the specified name and
119475107Sfenner	 * instance number.
119575107Sfenner	 */
119675107Sfenner	for (i = 0; i < ap->dl_count; i++) {
119798530Sfenner		if ((strcmp((const char *)ip->dl_module_id_1, device) == 0 ||
119898530Sfenner		     strcmp((const char *)ip->dl_module_id_2, device) == 0) &&
119975107Sfenner		    ip->dl_instance_num == unit)
120075107Sfenner			break;
120117683Spst
120275107Sfenner		ip = (dl_hp_ppa_info_t *)((u_char *)ipstart + ip->dl_next_offset);
120375107Sfenner	}
120475107Sfenner#else
120575107Sfenner	/*
120675107Sfenner	 * We don't have that member, so the search is impossible; make it
120775107Sfenner	 * look as if the search failed.
120875107Sfenner	 */
120975107Sfenner	i = ap->dl_count;
121075107Sfenner#endif
121175107Sfenner
121275107Sfenner	if (i == ap->dl_count) {
121375107Sfenner		/*
121475107Sfenner		 * Well, we didn't, or can't, find the device by name.
121575107Sfenner		 *
121675107Sfenner		 * HP-UX 10.20, whilst it has "dl_module_id_1" and
121775107Sfenner		 * "dl_module_id_2" fields in the "dl_hp_ppa_info_t",
121875107Sfenner		 * doesn't seem to fill them in unless the system is
121975107Sfenner		 * at a reasonably up-to-date patch level.
122075107Sfenner		 *
122175107Sfenner		 * Older HP-UX 10.x systems might not have those fields
122275107Sfenner		 * at all.
122375107Sfenner		 *
122475107Sfenner		 * Therefore, we'll search for the entry with the major
122575107Sfenner		 * device number of a device with the name "/dev/<dev><unit>",
122675107Sfenner		 * if such a device exists, as the old code did.
122775107Sfenner		 */
122875107Sfenner		snprintf(dname, sizeof(dname), "/dev/%s%d", device, unit);
122975107Sfenner		if (stat(dname, &statbuf) < 0) {
123075107Sfenner			snprintf(ebuf, PCAP_ERRBUF_SIZE, "stat: %s: %s",
123175107Sfenner			    dname, pcap_strerror(errno));
123275107Sfenner			return (-1);
123375107Sfenner		}
123475107Sfenner		majdev = major(statbuf.st_rdev);
123575107Sfenner
123675107Sfenner		ip = ipstart;
123775107Sfenner
123875107Sfenner		for (i = 0; i < ap->dl_count; i++) {
123975107Sfenner			if (ip->dl_mjr_num == majdev &&
124075107Sfenner			    ip->dl_instance_num == unit)
124175107Sfenner				break;
124275107Sfenner
124375107Sfenner			ip = (dl_hp_ppa_info_t *)((u_char *)ipstart + ip->dl_next_offset);
124475107Sfenner		}
124575107Sfenner	}
124617683Spst        if (i == ap->dl_count) {
124775107Sfenner                snprintf(ebuf, PCAP_ERRBUF_SIZE,
124875107Sfenner		    "can't find /dev/dlpi PPA for %s%d", device, unit);
124917683Spst		return (-1);
125017683Spst        }
125117683Spst        if (ip->dl_hdw_state == HDW_DEAD) {
125275107Sfenner                snprintf(ebuf, PCAP_ERRBUF_SIZE,
125375107Sfenner		    "%s%d: hardware state: DOWN\n", device, unit);
125498530Sfenner		free(ppa_data_buf);
125517683Spst		return (-1);
125617683Spst        }
125798530Sfenner        ppa = ip->dl_ppa;
125898530Sfenner        free(ppa_data_buf);
125998530Sfenner        return (ppa);
126017683Spst}
126117683Spst#endif
126217683Spst
126317683Spst#ifdef HAVE_HPUX9
126417683Spst/*
126517683Spst * Under HP-UX 9, there is no good way to determine the ppa.
126617683Spst * So punt and read it from /dev/kmem.
126717683Spst */
126817683Spststatic struct nlist nl[] = {
126917683Spst#define NL_IFNET 0
127017683Spst	{ "ifnet" },
127117683Spst	{ "" }
127217683Spst};
127317683Spst
127417683Spststatic char path_vmunix[] = "/hp-ux";
127517683Spst
127617683Spst/* Determine ppa number that specifies ifname */
127717683Spststatic int
127817683Spstget_dlpi_ppa(register int fd, register const char *ifname, register int unit,
127917683Spst    register char *ebuf)
128017683Spst{
128117683Spst	register const char *cp;
128217683Spst	register int kd;
128317683Spst	void *addr;
128417683Spst	struct ifnet ifnet;
128575107Sfenner	char if_name[sizeof(ifnet.if_name) + 1];
128617683Spst
128717683Spst	cp = strrchr(ifname, '/');
128817683Spst	if (cp != NULL)
128917683Spst		ifname = cp + 1;
129017683Spst	if (nlist(path_vmunix, &nl) < 0) {
129175107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE, "nlist %s failed",
129275107Sfenner		    path_vmunix);
129317683Spst		return (-1);
129417683Spst	}
129517683Spst	if (nl[NL_IFNET].n_value == 0) {
129675107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE,
129775107Sfenner		    "could't find %s kernel symbol",
129817683Spst		    nl[NL_IFNET].n_name);
129917683Spst		return (-1);
130017683Spst	}
130117683Spst	kd = open("/dev/kmem", O_RDONLY);
130217683Spst	if (kd < 0) {
130375107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE, "kmem open: %s",
130475107Sfenner		    pcap_strerror(errno));
130517683Spst		return (-1);
130617683Spst	}
130717683Spst	if (dlpi_kread(kd, nl[NL_IFNET].n_value,
130817683Spst	    &addr, sizeof(addr), ebuf) < 0) {
130917683Spst		close(kd);
131017683Spst		return (-1);
131117683Spst	}
131217683Spst	for (; addr != NULL; addr = ifnet.if_next) {
131317683Spst		if (dlpi_kread(kd, (off_t)addr,
131417683Spst		    &ifnet, sizeof(ifnet), ebuf) < 0 ||
131517683Spst		    dlpi_kread(kd, (off_t)ifnet.if_name,
131675107Sfenner		    if_name, sizeof(ifnet.if_name), ebuf) < 0) {
131717683Spst			(void)close(kd);
131817683Spst			return (-1);
131917683Spst		}
132075107Sfenner		if_name[sizeof(ifnet.if_name)] = '\0';
132175107Sfenner		if (strcmp(if_name, ifname) == 0 && ifnet.if_unit == unit)
132217683Spst			return (ifnet.if_index);
132317683Spst	}
132417683Spst
132575107Sfenner	snprintf(ebuf, PCAP_ERRBUF_SIZE, "Can't find %s", ifname);
132617683Spst	return (-1);
132717683Spst}
132817683Spst
132917683Spststatic int
133017683Spstdlpi_kread(register int fd, register off_t addr,
133117683Spst    register void *buf, register u_int len, register char *ebuf)
133217683Spst{
133317683Spst	register int cc;
133417683Spst
133539291Sfenner	if (lseek(fd, addr, SEEK_SET) < 0) {
133675107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE, "lseek: %s",
133775107Sfenner		    pcap_strerror(errno));
133817683Spst		return (-1);
133917683Spst	}
134017683Spst	cc = read(fd, buf, len);
134117683Spst	if (cc < 0) {
134275107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE, "read: %s",
134375107Sfenner		    pcap_strerror(errno));
134417683Spst		return (-1);
134517683Spst	} else if (cc != len) {
134675107Sfenner		snprintf(ebuf, PCAP_ERRBUF_SIZE, "short read (%d != %d)", cc,
134775107Sfenner		    len);
134817683Spst		return (-1);
134917683Spst	}
135017683Spst	return (cc);
135117683Spst}
135217683Spst#endif
1353