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