xref: /freebsd/contrib/libpcap/pcap-dlpi.c (revision 8e537d168674d6b65869f73c20813001af875738)
1 /*
2  * Copyright (c) 1993, 1994, 1995, 1996
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that: (1) source code distributions
7  * retain the above copyright notice and this paragraph in its entirety, (2)
8  * distributions including binary code include the above copyright notice and
9  * this paragraph in its entirety in the documentation or other materials
10  * provided with the distribution, and (3) all advertising materials mentioning
11  * features or use of this software display the following acknowledgement:
12  * ``This product includes software developed by the University of California,
13  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14  * the University nor the names of its contributors may be used to endorse
15  * or promote products derived from this software without specific prior
16  * written permission.
17  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20  *
21  * This code contributed by Atanu Ghosh (atanu@cs.ucl.ac.uk),
22  * University College London.
23  */
24 #ifndef lint
25 static  char rcsid[] =
26     "@(#)$Header: pcap-dlpi.c,v 1.42 96/07/23 14:20:32 leres Exp $ (LBL)";
27 #endif
28 
29 /*
30  * Packet capture routine for dlpi under SunOS 5
31  *
32  * Notes:
33  *
34  *    - Apparently the DLIOCRAW ioctl() is specific to SunOS.
35  *
36  *    - There is a bug in bufmod(7) such that setting the snapshot
37  *      length results in data being left of the front of the packet.
38  *
39  *    - It might be desirable to use pfmod(7) to filter packets in the
40  *      kernel.
41  */
42 
43 #include <sys/types.h>
44 #include <sys/time.h>
45 #ifdef HAVE_SYS_BUFMOD_H
46 #include <sys/bufmod.h>
47 #endif
48 #include <sys/dlpi.h>
49 #ifdef HAVE_SYS_DLPI_EXT_H
50 #include <sys/dlpi_ext.h>
51 #endif
52 #ifdef HAVE_HPUX9
53 #include <sys/socket.h>
54 #endif
55 #ifdef DL_HP_PPA_ACK_OBS
56 #include <sys/stat.h>
57 #endif
58 #include <sys/stream.h>
59 #if defined(HAVE_SOLARIS) && defined(HAVE_SYS_BUFMOD_H)
60 #include <sys/systeminfo.h>
61 #endif
62 
63 #ifdef HAVE_HPUX9
64 #include <net/if.h>
65 #endif
66 
67 #include <ctype.h>
68 #ifdef HAVE_HPUX9
69 #include <nlist.h>
70 #endif
71 #include <errno.h>
72 #include <fcntl.h>
73 #include <memory.h>
74 #include <stdio.h>
75 #include <stdlib.h>
76 #include <string.h>
77 #include <stropts.h>
78 #include <unistd.h>
79 
80 #include "pcap-int.h"
81 
82 #include "gnuc.h"
83 #ifdef HAVE_OS_PROTO_H
84 #include "os-proto.h"
85 #endif
86 
87 #ifndef PCAP_DEV_PREFIX
88 #define PCAP_DEV_PREFIX "/dev"
89 #endif
90 
91 #define	MAXDLBUF	8192
92 
93 /* Forwards */
94 static int dlattachreq(int, bpf_u_int32, char *);
95 static int dlbindack(int, char *, char *);
96 static int dlbindreq(int, bpf_u_int32, char *);
97 static int dlinfoack(int, char *, char *);
98 static int dlinforeq(int, char *);
99 static int dlokack(int, const char *, char *, char *);
100 static int recv_ack(int, int, const char *, char *, char *);
101 static int dlpromisconreq(int, bpf_u_int32, char *);
102 #if defined(HAVE_SOLARIS) && defined(HAVE_SYS_BUFMOD_H)
103 static char *get_release(bpf_u_int32 *, bpf_u_int32 *, bpf_u_int32 *);
104 #endif
105 static int send_request(int, char *, int, char *, char *);
106 #ifdef HAVE_SYS_BUFMOD_H
107 static int strioctl(int, int, int, char *);
108 #endif
109 #ifdef HAVE_HPUX9
110 static int dlpi_kread(int, off_t, void *, u_int, char *);
111 #endif
112 #ifdef HAVE_DEV_DLPI
113 static int get_dlpi_ppa(int, const char *, int, char *);
114 #endif
115 
116 int
117 pcap_stats(pcap_t *p, struct pcap_stat *ps)
118 {
119 
120 	*ps = p->md.stat;
121 	return (0);
122 }
123 
124 /* XXX Needed by HP-UX (at least) */
125 static bpf_u_int32 ctlbuf[MAXDLBUF];
126 static struct strbuf ctl = {
127 	MAXDLBUF,
128 	0,
129 	(char *)ctlbuf
130 };
131 
132 int
133 pcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
134 {
135 	register int cc, n, caplen, origlen;
136 	register u_char *bp, *ep, *pk;
137 	register struct bpf_insn *fcode;
138 #ifdef HAVE_SYS_BUFMOD_H
139 	register struct sb_hdr *sbp;
140 #ifdef LBL_ALIGN
141 	struct sb_hdr sbhdr;
142 #endif
143 #endif
144 	int flags;
145 	struct strbuf data;
146 	struct pcap_pkthdr pkthdr;
147 
148 	flags = 0;
149 	cc = p->cc;
150 	if (cc == 0) {
151 		data.buf = (char *)p->buffer + p->offset;
152 		data.maxlen = MAXDLBUF;
153 		data.len = 0;
154 		do {
155 			if (getmsg(p->fd, &ctl, &data, &flags) < 0) {
156 				/* Don't choke when we get ptraced */
157 				if (errno == EINTR) {
158 					cc = 0;
159 					continue;
160 				}
161 				strcpy(p->errbuf, pcap_strerror(errno));
162 				return (-1);
163 			}
164 			cc = data.len;
165 		} while (cc == 0);
166 		bp = p->buffer + p->offset;
167 	} else
168 		bp = p->bp;
169 
170 	/* Loop through packets */
171 	fcode = p->fcode.bf_insns;
172 	ep = bp + cc;
173 	n = 0;
174 #ifdef HAVE_SYS_BUFMOD_H
175 	while (bp < ep) {
176 #ifdef LBL_ALIGN
177 		if ((long)bp & 3) {
178 			sbp = &sbhdr;
179 			memcpy(sbp, bp, sizeof(*sbp));
180 		} else
181 #endif
182 			sbp = (struct sb_hdr *)bp;
183 		p->md.stat.ps_drop += sbp->sbh_drops;
184 		pk = bp + sizeof(*sbp);
185 		bp += sbp->sbh_totlen;
186 		origlen = sbp->sbh_origlen;
187 		caplen = sbp->sbh_msglen;
188 #else
189 		origlen = cc;
190 		caplen = min(p->snapshot, cc);
191 		pk = bp;
192 		bp += caplen;
193 #endif
194 		++p->md.stat.ps_recv;
195 		if (bpf_filter(fcode, pk, origlen, caplen)) {
196 #ifdef HAVE_SYS_BUFMOD_H
197 			pkthdr.ts = sbp->sbh_timestamp;
198 #else
199 			(void)gettimeofday(&pkthdr.ts, NULL);
200 #endif
201 			pkthdr.len = origlen;
202 			pkthdr.caplen = caplen;
203 			/* Insure caplen does not exceed snapshot */
204 			if (pkthdr.caplen > p->snapshot)
205 				pkthdr.caplen = p->snapshot;
206 			(*callback)(user, &pkthdr, pk);
207 			if (++n >= cnt && cnt >= 0) {
208 				p->cc = ep - bp;
209 				p->bp = bp;
210 				return (n);
211 			}
212 		}
213 #ifdef HAVE_SYS_BUFMOD_H
214 	}
215 #endif
216 	p->cc = 0;
217 	return (n);
218 }
219 
220 pcap_t *
221 pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)
222 {
223 	register char *cp;
224 	char *eos;
225 	register pcap_t *p;
226 	register int ppa;
227 	register dl_info_ack_t *infop;
228 #ifdef HAVE_SYS_BUFMOD_H
229 	bpf_u_int32 ss, flag;
230 #ifdef HAVE_SOLARIS
231 	register char *release;
232 	bpf_u_int32 osmajor, osminor, osmicro;
233 #endif
234 #endif
235 	bpf_u_int32 buf[MAXDLBUF];
236 	char dname[100];
237 #ifndef HAVE_DEV_DLPI
238 	char dname2[100];
239 #endif
240 
241 	p = (pcap_t *)malloc(sizeof(*p));
242 	if (p == NULL) {
243 		strcpy(ebuf, pcap_strerror(errno));
244 		return (NULL);
245 	}
246 	memset(p, 0, sizeof(*p));
247 
248 	/*
249 	** Determine device and ppa
250 	*/
251 	cp = strpbrk(device, "0123456789");
252 	if (cp == NULL) {
253 		sprintf(ebuf, "%s missing unit number", device);
254 		goto bad;
255 	}
256 	ppa = strtol(cp, &eos, 10);
257 	if (*eos != '\0') {
258 		sprintf(ebuf, "%s bad unit number", device);
259 		goto bad;
260 	}
261 
262 	if (*device == '/')
263 		strcpy(dname, device);
264 	else
265 		sprintf(dname, "%s/%s", PCAP_DEV_PREFIX, device);
266 #ifdef HAVE_DEV_DLPI
267 	/* Map network device to /dev/dlpi unit */
268 	cp = "/dev/dlpi";
269 	if ((p->fd = open(cp, O_RDWR)) < 0) {
270 		sprintf(ebuf, "%s: %s", cp, pcap_strerror(errno));
271 		goto bad;
272 	}
273 	/* Map network interface to /dev/dlpi unit */
274 	ppa = get_dlpi_ppa(p->fd, dname, ppa, ebuf);
275 	if (ppa < 0)
276 		goto bad;
277 #else
278 	/* Try device without unit number */
279 	strcpy(dname2, dname);
280 	cp = strchr(dname, *cp);
281 	*cp = '\0';
282 	if ((p->fd = open(dname, O_RDWR)) < 0) {
283 		if (errno != ENOENT) {
284 			sprintf(ebuf, "%s: %s", dname, pcap_strerror(errno));
285 			goto bad;
286 		}
287 
288 		/* Try again with unit number */
289 		if ((p->fd = open(dname2, O_RDWR)) < 0) {
290 			sprintf(ebuf, "%s: %s", dname2, pcap_strerror(errno));
291 			goto bad;
292 		}
293 		/* XXX Assume unit zero */
294 		ppa = 0;
295 	}
296 #endif
297 
298 	p->snapshot = snaplen;
299 
300 	/*
301 	** Attach if "style 2" provider
302 	*/
303 	if (dlinforeq(p->fd, ebuf) < 0 ||
304 	    dlinfoack(p->fd, (char *)buf, ebuf) < 0)
305 		goto bad;
306 	infop = &((union DL_primitives *)buf)->info_ack;
307 	if (infop->dl_provider_style == DL_STYLE2 &&
308 	    (dlattachreq(p->fd, ppa, ebuf) < 0 ||
309 	    dlokack(p->fd, "attach", (char *)buf, ebuf) < 0))
310 		goto bad;
311 	/*
312 	** Bind (defer if using HP-UX 9, totally skip if using SINIX)
313 	*/
314 #if !defined(HAVE_HPUX9) && !defined(sinix)
315 	if (dlbindreq(p->fd, 0, ebuf) < 0 ||
316 	    dlbindack(p->fd, (char *)buf, ebuf) < 0)
317 		goto bad;
318 #endif
319 
320 	if (promisc) {
321 		/*
322 		** Enable promiscuous
323 		*/
324 		if (dlpromisconreq(p->fd, DL_PROMISC_PHYS, ebuf) < 0 ||
325 		    dlokack(p->fd, "promisc_phys", (char *)buf, ebuf) < 0)
326 			goto bad;
327 
328 		/*
329 		** Try to enable multicast (you would have thought
330 		** promiscuous would be sufficient). Skip if SINIX.
331 		*/
332 #ifndef sinix
333 		if (dlpromisconreq(p->fd, DL_PROMISC_MULTI, ebuf) < 0 ||
334 		    dlokack(p->fd, "promisc_multi", (char *)buf, ebuf) < 0)
335 			fprintf(stderr,
336 			    "WARNING: DL_PROMISC_MULTI failed (%s)\n", ebuf);
337 #endif
338 	}
339 	/*
340 	** Always try to enable sap (except if SINIX)
341 	*/
342 #ifndef sinix
343 	if (dlpromisconreq(p->fd, DL_PROMISC_SAP, ebuf) < 0 ||
344 	    dlokack(p->fd, "promisc_sap", (char *)buf, ebuf) < 0) {
345 		/* Not fatal if promisc since the DL_PROMISC_PHYS worked */
346 		if (promisc)
347 			fprintf(stderr,
348 			    "WARNING: DL_PROMISC_SAP failed (%s)\n", ebuf);
349 		else
350 			goto bad;
351 	}
352 #endif
353 
354 	/*
355 	** Bind (HP-UX 9 must bind after setting promiscuous options)
356 	*/
357 #ifdef HAVE_HPUX9
358 	if (dlbindreq(p->fd, 0, ebuf) < 0 ||
359 	    dlbindack(p->fd, (char *)buf, ebuf) < 0)
360 		goto bad;
361 #endif
362 
363 	/*
364 	** Determine link type
365 	*/
366 	if (dlinforeq(p->fd, ebuf) < 0 ||
367 	    dlinfoack(p->fd, (char *)buf, ebuf) < 0)
368 		goto bad;
369 
370 	infop = &((union DL_primitives *)buf)->info_ack;
371 	switch (infop->dl_mac_type) {
372 
373 	case DL_CSMACD:
374 	case DL_ETHER:
375 		p->linktype = DLT_EN10MB;
376 		p->offset = 2;
377 		break;
378 
379 	case DL_FDDI:
380 		p->linktype = DLT_FDDI;
381 		break;
382 
383 	default:
384 		sprintf(ebuf, "unknown mac type 0x%lu", infop->dl_mac_type);
385 		goto bad;
386 	}
387 
388 #ifdef	DLIOCRAW
389 	/*
390 	** This is a non standard SunOS hack to get the ethernet header.
391 	*/
392 	if (strioctl(p->fd, DLIOCRAW, 0, NULL) < 0) {
393 		sprintf(ebuf, "DLIOCRAW: %s", pcap_strerror(errno));
394 		goto bad;
395 	}
396 #endif
397 
398 #ifdef HAVE_SYS_BUFMOD_H
399 	/*
400 	** Another non standard call to get the data nicely buffered
401 	*/
402 	if (ioctl(p->fd, I_PUSH, "bufmod") != 0) {
403 		sprintf(ebuf, "I_PUSH bufmod: %s", pcap_strerror(errno));
404 		goto bad;
405 	}
406 
407 	/*
408 	** Now that the bufmod is pushed lets configure it.
409 	**
410 	** There is a bug in bufmod(7). When dealing with messages of
411 	** less than snaplen size it strips data from the beginning not
412 	** the end.
413 	**
414 	** This bug is supposed to be fixed in 5.3.2. Also, there is a
415 	** patch available. Ask for bugid 1149065.
416 	*/
417 	ss = snaplen;
418 #ifdef HAVE_SOLARIS
419 	release = get_release(&osmajor, &osminor, &osmicro);
420 	if (osmajor == 5 && (osminor <= 2 || (osminor == 3 && osmicro < 2)) &&
421 	    getenv("BUFMOD_FIXED") == NULL) {
422 		fprintf(stderr,
423 		"WARNING: bufmod is broken in SunOS %s; ignoring snaplen.\n",
424 		    release);
425 		ss = 0;
426 	}
427 #endif
428 	if (ss > 0 &&
429 	    strioctl(p->fd, SBIOCSSNAP, sizeof(ss), (char *)&ss) != 0) {
430 		sprintf(ebuf, "SBIOCSSNAP: %s", pcap_strerror(errno));
431 		goto bad;
432 	}
433 
434 	/*
435 	** Set up the bufmod flags
436 	*/
437 	if (strioctl(p->fd, SBIOCGFLAGS, sizeof(flag), (char *)&flag) < 0) {
438 		sprintf(ebuf, "SBIOCGFLAGS: %s", pcap_strerror(errno));
439 		goto bad;
440 	}
441 	flag |= SB_NO_DROPS;
442 	if (strioctl(p->fd, SBIOCSFLAGS, sizeof(flag), (char *)&flag) != 0) {
443 		sprintf(ebuf, "SBIOCSFLAGS: %s", pcap_strerror(errno));
444 		goto bad;
445 	}
446 	/*
447 	** Set up the bufmod timeout
448 	*/
449 	if (to_ms != 0) {
450 		struct timeval to;
451 
452 		to.tv_sec = to_ms / 1000;
453 		to.tv_usec = (to_ms * 1000) % 1000000;
454 		if (strioctl(p->fd, SBIOCSTIME, sizeof(to), (char *)&to) != 0) {
455 			sprintf(ebuf, "SBIOCSTIME: %s", pcap_strerror(errno));
456 			goto bad;
457 		}
458 	}
459 #endif
460 
461 	/*
462 	** As the last operation flush the read side.
463 	*/
464 	if (ioctl(p->fd, I_FLUSH, FLUSHR) != 0) {
465 		sprintf(ebuf, "FLUSHR: %s", pcap_strerror(errno));
466 		goto bad;
467 	}
468 	/* Allocate data buffer */
469 	p->bufsize = MAXDLBUF * sizeof(bpf_u_int32);
470 	p->buffer = (u_char *)malloc(p->bufsize + p->offset);
471 
472 	return (p);
473 bad:
474 	free(p);
475 	return (NULL);
476 }
477 
478 int
479 pcap_setfilter(pcap_t *p, struct bpf_program *fp)
480 {
481 
482 	p->fcode = *fp;
483 	return (0);
484 }
485 
486 static int
487 send_request(int fd, char *ptr, int len, char *what, char *ebuf)
488 {
489 	struct	strbuf	ctl;
490 	int	flags;
491 
492 	ctl.maxlen = 0;
493 	ctl.len = len;
494 	ctl.buf = ptr;
495 
496 	flags = 0;
497 	if (putmsg(fd, &ctl, (struct strbuf *) NULL, flags) < 0) {
498 		sprintf(ebuf, "send_request: putmsg \"%s\": %s",
499 		    what, pcap_strerror(errno));
500 		return (-1);
501 	}
502 	return (0);
503 }
504 
505 static int
506 recv_ack(int fd, int size, const char *what, char *bufp, char *ebuf)
507 {
508 	union	DL_primitives	*dlp;
509 	struct	strbuf	ctl;
510 	int	flags;
511 
512 	ctl.maxlen = MAXDLBUF;
513 	ctl.len = 0;
514 	ctl.buf = bufp;
515 
516 	flags = 0;
517 	if (getmsg(fd, &ctl, (struct strbuf*)NULL, &flags) < 0) {
518 		sprintf(ebuf, "recv_ack: %s getmsg: %s",
519 		    what, pcap_strerror(errno));
520 		return (-1);
521 	}
522 
523 	dlp = (union DL_primitives *) ctl.buf;
524 	switch (dlp->dl_primitive) {
525 
526 	case DL_INFO_ACK:
527 	case DL_BIND_ACK:
528 	case DL_OK_ACK:
529 #ifdef DL_HP_PPA_ACK
530 	case DL_HP_PPA_ACK:
531 #endif
532 
533 		/* These are OK */
534 		break;
535 
536 	case DL_ERROR_ACK:
537 		switch (dlp->error_ack.dl_errno) {
538 
539 		case DL_BADPPA:
540 			sprintf(ebuf, "recv_ack: %s bad ppa (device unit)",
541 			    what);
542 			break;
543 
544 		case DL_SYSERR:
545 			sprintf(ebuf, "recv_ack: %s: %s",
546 			    what, pcap_strerror(dlp->error_ack.dl_unix_errno));
547 			break;
548 
549 		default:
550 			sprintf(ebuf, "recv_ack: %s error 0x%x",
551 			    what, (bpf_u_int32)dlp->error_ack.dl_errno);
552 			break;
553 		}
554 		return (-1);
555 
556 	default:
557 		sprintf(ebuf, "recv_ack: %s unexpected primitive ack 0x%x ",
558 		    what, (bpf_u_int32)dlp->dl_primitive);
559 		return (-1);
560 	}
561 
562 	if (ctl.len < size) {
563 		sprintf(ebuf, "recv_ack: %s ack too small (%d < %d)",
564 		    what, ctl.len, size);
565 		return (-1);
566 	}
567 	return (ctl.len);
568 }
569 
570 static int
571 dlattachreq(int fd, bpf_u_int32 ppa, char *ebuf)
572 {
573 	dl_attach_req_t	req;
574 
575 	req.dl_primitive = DL_ATTACH_REQ;
576 	req.dl_ppa = ppa;
577 
578 	return (send_request(fd, (char *)&req, sizeof(req), "attach", ebuf));
579 }
580 
581 static int
582 dlbindreq(int fd, bpf_u_int32 sap, char *ebuf)
583 {
584 
585 	dl_bind_req_t	req;
586 
587 	memset((char *)&req, 0, sizeof(req));
588 	req.dl_primitive = DL_BIND_REQ;
589 #ifdef DL_HP_RAWDLS
590 	req.dl_max_conind = 1;			/* XXX magic number */
591 	/* 22 is INSAP as per the HP-UX DLPI Programmer's Guide */
592 	req.dl_sap = 22;
593 	req.dl_service_mode = DL_HP_RAWDLS;
594 #else
595 	req.dl_sap = sap;
596 #endif
597 
598 	return (send_request(fd, (char *)&req, sizeof(req), "bind", ebuf));
599 }
600 
601 static int
602 dlbindack(int fd, char *bufp, char *ebuf)
603 {
604 
605 	return (recv_ack(fd, DL_BIND_ACK_SIZE, "bind", bufp, ebuf));
606 }
607 
608 static int
609 dlpromisconreq(int fd, bpf_u_int32 level, char *ebuf)
610 {
611 	dl_promiscon_req_t req;
612 
613 	req.dl_primitive = DL_PROMISCON_REQ;
614 	req.dl_level = level;
615 
616 	return (send_request(fd, (char *)&req, sizeof(req), "promiscon", ebuf));
617 }
618 
619 static int
620 dlokack(int fd, const char *what, char *bufp, char *ebuf)
621 {
622 
623 	return (recv_ack(fd, DL_OK_ACK_SIZE, what, bufp, ebuf));
624 }
625 
626 
627 static int
628 dlinforeq(int fd, char *ebuf)
629 {
630 	dl_info_req_t req;
631 
632 	req.dl_primitive = DL_INFO_REQ;
633 
634 	return (send_request(fd, (char *)&req, sizeof(req), "info", ebuf));
635 }
636 
637 static int
638 dlinfoack(int fd, char *bufp, char *ebuf)
639 {
640 
641 	return (recv_ack(fd, DL_INFO_ACK_SIZE, "info", bufp, ebuf));
642 }
643 
644 #ifdef HAVE_SYS_BUFMOD_H
645 static int
646 strioctl(int fd, int cmd, int len, char *dp)
647 {
648 	struct strioctl str;
649 	int rc;
650 
651 	str.ic_cmd = cmd;
652 	str.ic_timout = -1;
653 	str.ic_len = len;
654 	str.ic_dp = dp;
655 	rc = ioctl(fd, I_STR, &str);
656 
657 	if (rc < 0)
658 		return (rc);
659 	else
660 		return (str.ic_len);
661 }
662 #endif
663 
664 #if defined(HAVE_SOLARIS) && defined(HAVE_SYS_BUFMOD_H)
665 static char *
666 get_release(bpf_u_int32 *majorp, bpf_u_int32 *minorp, bpf_u_int32 *microp)
667 {
668 	char *cp;
669 	static char buf[32];
670 
671 	*majorp = 0;
672 	*minorp = 0;
673 	*microp = 0;
674 	if (sysinfo(SI_RELEASE, buf, sizeof(buf)) < 0)
675 		return ("?");
676 	cp = buf;
677 	if (!isdigit(*cp))
678 		return (buf);
679 	*majorp = strtol(cp, &cp, 10);
680 	if (*cp++ != '.')
681 		return (buf);
682 	*minorp =  strtol(cp, &cp, 10);
683 	if (*cp++ != '.')
684 		return (buf);
685 	*microp =  strtol(cp, &cp, 10);
686 	return (buf);
687 }
688 #endif
689 
690 #ifdef DL_HP_PPA_ACK_OBS
691 /*
692  * Under HP-UX 10, we can ask for the ppa
693  */
694 
695 
696 /* Determine ppa number that specifies ifname */
697 static int
698 get_dlpi_ppa(register int fd, register const char *device, register int unit,
699     register char *ebuf)
700 {
701 	register dl_hp_ppa_ack_t *ap;
702 	register dl_hp_ppa_info_t *ip;
703 	register int i;
704 	register u_long majdev;
705 	dl_hp_ppa_req_t	req;
706 	struct stat statbuf;
707 	bpf_u_int32 buf[MAXDLBUF];
708 
709 	if (stat(device, &statbuf) < 0) {
710 		sprintf(ebuf, "stat: %s: %s", device, pcap_strerror(errno));
711 		return (-1);
712 	}
713 	majdev = major(statbuf.st_rdev);
714 
715 	memset((char *)&req, 0, sizeof(req));
716 	req.dl_primitive = DL_HP_PPA_REQ;
717 
718 	memset((char *)buf, 0, sizeof(buf));
719 	if (send_request(fd, (char *)&req, sizeof(req), "hpppa", ebuf) < 0 ||
720 	    recv_ack(fd, DL_HP_PPA_ACK_SIZE, "hpppa", (char *)buf, ebuf) < 0)
721 		return (-1);
722 
723 	ap = (dl_hp_ppa_ack_t *)buf;
724 	ip = (dl_hp_ppa_info_t *)((u_char *)ap + ap->dl_offset);
725 
726         for(i = 0; i < ap->dl_count; i++) {
727                 if (ip->dl_mjr_num == majdev && ip->dl_instance_num == unit)
728                         break;
729 
730                 ip = (dl_hp_ppa_info_t *)((u_char *)ip + ip->dl_next_offset);
731         }
732         if (i == ap->dl_count) {
733                 sprintf(ebuf, "can't find PPA for %s", device);
734 		return (-1);
735         }
736         if (ip->dl_hdw_state == HDW_DEAD) {
737                 sprintf(ebuf, "%s: hardware state: DOWN\n", device);
738 		return (-1);
739         }
740         return ((int)ip->dl_ppa);
741 }
742 #endif
743 
744 #ifdef HAVE_HPUX9
745 /*
746  * Under HP-UX 9, there is no good way to determine the ppa.
747  * So punt and read it from /dev/kmem.
748  */
749 static struct nlist nl[] = {
750 #define NL_IFNET 0
751 	{ "ifnet" },
752 	{ "" }
753 };
754 
755 static char path_vmunix[] = "/hp-ux";
756 
757 /* Determine ppa number that specifies ifname */
758 static int
759 get_dlpi_ppa(register int fd, register const char *ifname, register int unit,
760     register char *ebuf)
761 {
762 	register const char *cp;
763 	register int kd;
764 	void *addr;
765 	struct ifnet ifnet;
766 	char if_name[sizeof(ifnet.if_name)], tifname[32];
767 
768 	cp = strrchr(ifname, '/');
769 	if (cp != NULL)
770 		ifname = cp + 1;
771 	if (nlist(path_vmunix, &nl) < 0) {
772 		sprintf(ebuf, "nlist %s failed", path_vmunix);
773 		return (-1);
774 	}
775 	if (nl[NL_IFNET].n_value == 0) {
776 		sprintf(ebuf, "could't find %s kernel symbol",
777 		    nl[NL_IFNET].n_name);
778 		return (-1);
779 	}
780 	kd = open("/dev/kmem", O_RDONLY);
781 	if (kd < 0) {
782 		sprintf(ebuf, "kmem open: %s", pcap_strerror(errno));
783 		return (-1);
784 	}
785 	if (dlpi_kread(kd, nl[NL_IFNET].n_value,
786 	    &addr, sizeof(addr), ebuf) < 0) {
787 		close(kd);
788 		return (-1);
789 	}
790 	for (; addr != NULL; addr = ifnet.if_next) {
791 		if (dlpi_kread(kd, (off_t)addr,
792 		    &ifnet, sizeof(ifnet), ebuf) < 0 ||
793 		    dlpi_kread(kd, (off_t)ifnet.if_name,
794 		    if_name, sizeof(if_name), ebuf) < 0) {
795 			(void)close(kd);
796 			return (-1);
797 		}
798 		sprintf(tifname, "%.*s%d",
799 		    (int)sizeof(if_name), if_name, ifnet.if_unit);
800 		if (strcmp(tifname, ifname) == 0)
801 			return (ifnet.if_index);
802 	}
803 
804 	sprintf(ebuf, "Can't find %s", ifname);
805 	return (-1);
806 }
807 
808 static int
809 dlpi_kread(register int fd, register off_t addr,
810     register void *buf, register u_int len, register char *ebuf)
811 {
812 	register int cc;
813 
814 	if (lseek(fd, addr, L_SET) < 0) {
815 		sprintf(ebuf, "lseek: %s", pcap_strerror(errno));
816 		return (-1);
817 	}
818 	cc = read(fd, buf, len);
819 	if (cc < 0) {
820 		sprintf(ebuf, "read: %s", pcap_strerror(errno));
821 		return (-1);
822 	} else if (cc != len) {
823 		sprintf(ebuf, "short read (%d != %d)", cc, len);
824 		return (-1);
825 	}
826 	return (cc);
827 }
828 #endif
829