xref: /freebsd/contrib/libpcap/pcap-dlpi.c (revision 41466b50c1d5bfd1cf6adaae547a579a75d7c04e)
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.63 2000/11/22 05:32:55 guy Exp $ (LBL)";
42 #endif
43 
44 #ifdef HAVE_CONFIG_H
45 #include "config.h"
46 #endif
47 
48 #include <sys/types.h>
49 #include <sys/time.h>
50 #ifdef HAVE_SYS_BUFMOD_H
51 #include <sys/bufmod.h>
52 #endif
53 #include <sys/dlpi.h>
54 #ifdef HAVE_SYS_DLPI_EXT_H
55 #include <sys/dlpi_ext.h>
56 #endif
57 #ifdef HAVE_HPUX9
58 #include <sys/socket.h>
59 #endif
60 #ifdef DL_HP_PPA_ACK_OBS
61 #include <sys/stat.h>
62 #endif
63 #include <sys/stream.h>
64 #if defined(HAVE_SOLARIS) && defined(HAVE_SYS_BUFMOD_H)
65 #include <sys/systeminfo.h>
66 #endif
67 
68 #ifdef HAVE_HPUX9
69 #include <net/if.h>
70 #endif
71 
72 #include <ctype.h>
73 #ifdef HAVE_HPUX9
74 #include <nlist.h>
75 #endif
76 #include <errno.h>
77 #include <fcntl.h>
78 #include <memory.h>
79 #include <stdio.h>
80 #include <stdlib.h>
81 #include <string.h>
82 #include <stropts.h>
83 #include <unistd.h>
84 
85 #include "pcap-int.h"
86 
87 #ifdef HAVE_OS_PROTO_H
88 #include "os-proto.h"
89 #endif
90 
91 #ifndef PCAP_DEV_PREFIX
92 #define PCAP_DEV_PREFIX "/dev"
93 #endif
94 
95 #define	MAXDLBUF	8192
96 
97 /* Forwards */
98 static int dlattachreq(int, bpf_u_int32, char *);
99 static int dlbindack(int, char *, char *);
100 static int dlbindreq(int, bpf_u_int32, char *);
101 static int dlinfoack(int, char *, char *);
102 static int dlinforeq(int, char *);
103 static int dlokack(int, const char *, char *, char *);
104 static int recv_ack(int, int, const char *, char *, char *);
105 static int dlpromisconreq(int, bpf_u_int32, char *);
106 #if defined(HAVE_SOLARIS) && defined(HAVE_SYS_BUFMOD_H)
107 static char *get_release(bpf_u_int32 *, bpf_u_int32 *, bpf_u_int32 *);
108 #endif
109 static int send_request(int, char *, int, char *, char *);
110 #ifdef HAVE_SYS_BUFMOD_H
111 static int strioctl(int, int, int, char *);
112 #endif
113 #ifdef HAVE_HPUX9
114 static int dlpi_kread(int, off_t, void *, u_int, char *);
115 #endif
116 #ifdef HAVE_DEV_DLPI
117 static int get_dlpi_ppa(int, const char *, int, char *);
118 #endif
119 
120 int
121 pcap_stats(pcap_t *p, struct pcap_stat *ps)
122 {
123 
124 	*ps = p->md.stat;
125 	return (0);
126 }
127 
128 /* XXX Needed by HP-UX (at least) */
129 static bpf_u_int32 ctlbuf[MAXDLBUF];
130 static struct strbuf ctl = {
131 	MAXDLBUF,
132 	0,
133 	(char *)ctlbuf
134 };
135 
136 int
137 pcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
138 {
139 	register int cc, n, caplen, origlen;
140 	register u_char *bp, *ep, *pk;
141 	register struct bpf_insn *fcode;
142 #ifdef HAVE_SYS_BUFMOD_H
143 	register struct sb_hdr *sbp;
144 #ifdef LBL_ALIGN
145 	struct sb_hdr sbhdr;
146 #endif
147 #endif
148 	int flags;
149 	struct strbuf data;
150 	struct pcap_pkthdr pkthdr;
151 
152 	flags = 0;
153 	cc = p->cc;
154 	if (cc == 0) {
155 		data.buf = (char *)p->buffer + p->offset;
156 		data.maxlen = MAXDLBUF;
157 		data.len = 0;
158 		do {
159 			if (getmsg(p->fd, &ctl, &data, &flags) < 0) {
160 				/* Don't choke when we get ptraced */
161 				if (errno == EINTR) {
162 					cc = 0;
163 					continue;
164 				}
165 				strlcpy(p->errbuf, pcap_strerror(errno),
166 				    sizeof(p->errbuf));
167 				return (-1);
168 			}
169 			cc = data.len;
170 		} while (cc == 0);
171 		bp = p->buffer + p->offset;
172 	} else
173 		bp = p->bp;
174 
175 	/* Loop through packets */
176 	fcode = p->fcode.bf_insns;
177 	ep = bp + cc;
178 	n = 0;
179 #ifdef HAVE_SYS_BUFMOD_H
180 	while (bp < ep) {
181 #ifdef LBL_ALIGN
182 		if ((long)bp & 3) {
183 			sbp = &sbhdr;
184 			memcpy(sbp, bp, sizeof(*sbp));
185 		} else
186 #endif
187 			sbp = (struct sb_hdr *)bp;
188 		p->md.stat.ps_drop += sbp->sbh_drops;
189 		pk = bp + sizeof(*sbp);
190 		bp += sbp->sbh_totlen;
191 		origlen = sbp->sbh_origlen;
192 		caplen = sbp->sbh_msglen;
193 #else
194 		origlen = cc;
195 		caplen = min(p->snapshot, cc);
196 		pk = bp;
197 		bp += caplen;
198 #endif
199 		++p->md.stat.ps_recv;
200 		if (bpf_filter(fcode, pk, origlen, caplen)) {
201 #ifdef HAVE_SYS_BUFMOD_H
202 			pkthdr.ts = sbp->sbh_timestamp;
203 #else
204 			(void)gettimeofday(&pkthdr.ts, NULL);
205 #endif
206 			pkthdr.len = origlen;
207 			pkthdr.caplen = caplen;
208 			/* Insure caplen does not exceed snapshot */
209 			if (pkthdr.caplen > p->snapshot)
210 				pkthdr.caplen = p->snapshot;
211 			(*callback)(user, &pkthdr, pk);
212 			if (++n >= cnt && cnt >= 0) {
213 				p->cc = ep - bp;
214 				p->bp = bp;
215 				return (n);
216 			}
217 		}
218 #ifdef HAVE_SYS_BUFMOD_H
219 	}
220 #endif
221 	p->cc = 0;
222 	return (n);
223 }
224 
225 pcap_t *
226 pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)
227 {
228 	register char *cp;
229 	char *eos;
230 	register pcap_t *p;
231 	register int ppa;
232 	register dl_info_ack_t *infop;
233 #ifdef HAVE_SYS_BUFMOD_H
234 	bpf_u_int32 ss, flag;
235 #ifdef HAVE_SOLARIS
236 	register char *release;
237 	bpf_u_int32 osmajor, osminor, osmicro;
238 #endif
239 #endif
240 	bpf_u_int32 buf[MAXDLBUF];
241 	char dname[100];
242 #ifndef HAVE_DEV_DLPI
243 	char dname2[100];
244 #endif
245 
246 	p = (pcap_t *)malloc(sizeof(*p));
247 	if (p == NULL) {
248 		strlcpy(ebuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE);
249 		return (NULL);
250 	}
251 	memset(p, 0, sizeof(*p));
252 
253 #ifdef HAVE_DEV_DLPI
254 	/*
255 	** Remove any "/dev/" on the front of the device.
256 	*/
257 	cp = strrchr(device, '/');
258 	if (cp == NULL)
259 		cp = device;
260 	else
261 		cp++;
262 	strlcpy(dname, cp, sizeof(dname));
263 
264 	/*
265 	 * Split the name into a device type and a unit number.
266 	 */
267 	cp = strpbrk(dname, "0123456789");
268 	if (cp == NULL) {
269 		snprintf(ebuf, PCAP_ERRBUF_SIZE,
270 		    "%s missing unit number", device);
271 		goto bad;
272 	}
273 	ppa = strtol(cp, &eos, 10);
274 	if (*eos != '\0') {
275 		snprintf(ebuf, PCAP_ERRBUF_SIZE,
276 		    "%s bad unit number", device);
277 		goto bad;
278 	}
279 	*cp = '\0';
280 
281 	/*
282 	 * Use "/dev/dlpi" as the device.
283 	 *
284 	 * XXX - HP's DLPI Programmer's Guide for HP-UX 11.00 says that
285 	 * the "dl_mjr_num" field is for the "major number of interface
286 	 * driver"; that's the major of "/dev/dlpi" on the system on
287 	 * which I tried this, but there may be DLPI devices that
288 	 * use a different driver, in which case we may need to
289 	 * search "/dev" for the appropriate device with that major
290 	 * device number, rather than hardwiring "/dev/dlpi".
291 	 */
292 	cp = "/dev/dlpi";
293 	if ((p->fd = open(cp, O_RDWR)) < 0) {
294 		snprintf(ebuf, PCAP_ERRBUF_SIZE,
295 		    "%s: %s", cp, pcap_strerror(errno));
296 		goto bad;
297 	}
298 
299 	/*
300 	 * Get a table of all PPAs for that device, and search that
301 	 * table for the specified device type name and unit number.
302 	 */
303 	ppa = get_dlpi_ppa(p->fd, dname, ppa, ebuf);
304 	if (ppa < 0)
305 		goto bad;
306 #else
307 	/*
308 	** Determine device and ppa
309 	*/
310 	cp = strpbrk(device, "0123456789");
311 	if (cp == NULL) {
312 		snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s missing unit number",
313 		    device);
314 		goto bad;
315 	}
316 	ppa = strtol(cp, &eos, 10);
317 	if (*eos != '\0') {
318 		snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s bad unit number", device);
319 		goto bad;
320 	}
321 
322 	if (*device == '/')
323 		strlcpy(dname, device, sizeof(dname));
324 	else
325 		snprintf(dname, sizeof(dname), "%s/%s", PCAP_DEV_PREFIX,
326 		    device);
327 
328 	/* Try device without unit number */
329 	strlcpy(dname2, dname, sizeof(dname2));
330 	cp = strchr(dname, *cp);
331 	*cp = '\0';
332 	if ((p->fd = open(dname, O_RDWR)) < 0) {
333 		if (errno != ENOENT) {
334 			snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s: %s", dname,
335 			    pcap_strerror(errno));
336 			goto bad;
337 		}
338 
339 		/* Try again with unit number */
340 		if ((p->fd = open(dname2, O_RDWR)) < 0) {
341 			snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s: %s", dname2,
342 			    pcap_strerror(errno));
343 			goto bad;
344 		}
345 		/* XXX Assume unit zero */
346 		ppa = 0;
347 	}
348 #endif
349 
350 	p->snapshot = snaplen;
351 
352 	/*
353 	** Attach if "style 2" provider
354 	*/
355 	if (dlinforeq(p->fd, ebuf) < 0 ||
356 	    dlinfoack(p->fd, (char *)buf, ebuf) < 0)
357 		goto bad;
358 	infop = &((union DL_primitives *)buf)->info_ack;
359 	if (infop->dl_provider_style == DL_STYLE2 &&
360 	    (dlattachreq(p->fd, ppa, ebuf) < 0 ||
361 	    dlokack(p->fd, "attach", (char *)buf, ebuf) < 0))
362 		goto bad;
363 	/*
364 	** Bind (defer if using HP-UX 9 or HP-UX 10.20, totally skip if
365 	** using SINIX)
366 	*/
367 #if !defined(HAVE_HPUX9) && !defined(HAVE_HPUX10_20) && !defined(sinix)
368 #ifdef _AIX
369         /* According to IBM's AIX Support Line, the dl_sap value
370         ** should not be less than 0x600 (1536) for standard ethernet
371          */
372 	if (dlbindreq(p->fd, 1537, ebuf) < 0 ||
373 #else
374 	if (dlbindreq(p->fd, 0, ebuf) < 0 ||
375 #endif
376 	    dlbindack(p->fd, (char *)buf, ebuf) < 0)
377 		goto bad;
378 #endif
379 
380 	if (promisc) {
381 		/*
382 		** Enable promiscuous
383 		*/
384 		if (dlpromisconreq(p->fd, DL_PROMISC_PHYS, ebuf) < 0 ||
385 		    dlokack(p->fd, "promisc_phys", (char *)buf, ebuf) < 0)
386 			goto bad;
387 
388 		/*
389 		** Try to enable multicast (you would have thought
390 		** promiscuous would be sufficient). (Skip if using
391 		** HP-UX or SINIX)
392 		*/
393 #if !defined(__hpux) && !defined(sinix)
394 		if (dlpromisconreq(p->fd, DL_PROMISC_MULTI, ebuf) < 0 ||
395 		    dlokack(p->fd, "promisc_multi", (char *)buf, ebuf) < 0)
396 			fprintf(stderr,
397 			    "WARNING: DL_PROMISC_MULTI failed (%s)\n", ebuf);
398 #endif
399 	}
400 	/*
401 	** Try to enable sap (when not in promiscuous mode when using
402 	** using HP-UX and never under SINIX)
403 	*/
404 #ifndef sinix
405 	if (
406 #ifdef __hpux
407 	    !promisc &&
408 #endif
409 	    (dlpromisconreq(p->fd, DL_PROMISC_SAP, ebuf) < 0 ||
410 	    dlokack(p->fd, "promisc_sap", (char *)buf, ebuf) < 0)) {
411 		/* Not fatal if promisc since the DL_PROMISC_PHYS worked */
412 		if (promisc)
413 			fprintf(stderr,
414 			    "WARNING: DL_PROMISC_SAP failed (%s)\n", ebuf);
415 		else
416 			goto bad;
417 	}
418 #endif
419 
420 	/*
421 	** HP-UX 9 and HP-UX 10.20 must bind after setting promiscuous
422 	** options)
423 	*/
424 #if defined(HAVE_HPUX9) || defined(HAVE_HPUX10_20)
425 	if (dlbindreq(p->fd, 0, ebuf) < 0 ||
426 	    dlbindack(p->fd, (char *)buf, ebuf) < 0)
427 		goto bad;
428 #endif
429 
430 	/*
431 	** Determine link type
432 	*/
433 	if (dlinforeq(p->fd, ebuf) < 0 ||
434 	    dlinfoack(p->fd, (char *)buf, ebuf) < 0)
435 		goto bad;
436 
437 	infop = &((union DL_primitives *)buf)->info_ack;
438 	switch (infop->dl_mac_type) {
439 
440 	case DL_CSMACD:
441 	case DL_ETHER:
442 		p->linktype = DLT_EN10MB;
443 		p->offset = 2;
444 		break;
445 
446 	case DL_FDDI:
447 		p->linktype = DLT_FDDI;
448 		p->offset = 3;
449 		break;
450 
451 	default:
452 		snprintf(ebuf, PCAP_ERRBUF_SIZE, "unknown mac type %lu",
453 		    infop->dl_mac_type);
454 		goto bad;
455 	}
456 
457 #ifdef	DLIOCRAW
458 	/*
459 	** This is a non standard SunOS hack to get the ethernet header.
460 	*/
461 	if (strioctl(p->fd, DLIOCRAW, 0, NULL) < 0) {
462 		snprintf(ebuf, PCAP_ERRBUF_SIZE, "DLIOCRAW: %s",
463 		    pcap_strerror(errno));
464 		goto bad;
465 	}
466 #endif
467 
468 #ifdef HAVE_SYS_BUFMOD_H
469 	/*
470 	** Another non standard call to get the data nicely buffered
471 	*/
472 	if (ioctl(p->fd, I_PUSH, "bufmod") != 0) {
473 		snprintf(ebuf, PCAP_ERRBUF_SIZE, "I_PUSH bufmod: %s",
474 		    pcap_strerror(errno));
475 		goto bad;
476 	}
477 
478 	/*
479 	** Now that the bufmod is pushed lets configure it.
480 	**
481 	** There is a bug in bufmod(7). When dealing with messages of
482 	** less than snaplen size it strips data from the beginning not
483 	** the end.
484 	**
485 	** This bug is supposed to be fixed in 5.3.2. Also, there is a
486 	** patch available. Ask for bugid 1149065.
487 	*/
488 	ss = snaplen;
489 #ifdef HAVE_SOLARIS
490 	release = get_release(&osmajor, &osminor, &osmicro);
491 	if (osmajor == 5 && (osminor <= 2 || (osminor == 3 && osmicro < 2)) &&
492 	    getenv("BUFMOD_FIXED") == NULL) {
493 		fprintf(stderr,
494 		"WARNING: bufmod is broken in SunOS %s; ignoring snaplen.\n",
495 		    release);
496 		ss = 0;
497 	}
498 #endif
499 	if (ss > 0 &&
500 	    strioctl(p->fd, SBIOCSSNAP, sizeof(ss), (char *)&ss) != 0) {
501 		snprintf(ebuf, PCAP_ERRBUF_SIZE, "SBIOCSSNAP: %s",
502 		    pcap_strerror(errno));
503 		goto bad;
504 	}
505 
506 	/*
507 	** Set up the bufmod flags
508 	*/
509 	if (strioctl(p->fd, SBIOCGFLAGS, sizeof(flag), (char *)&flag) < 0) {
510 		snprintf(ebuf, PCAP_ERRBUF_SIZE, "SBIOCGFLAGS: %s",
511 		    pcap_strerror(errno));
512 		goto bad;
513 	}
514 	flag |= SB_NO_DROPS;
515 	if (strioctl(p->fd, SBIOCSFLAGS, sizeof(flag), (char *)&flag) != 0) {
516 		snprintf(ebuf, PCAP_ERRBUF_SIZE, "SBIOCSFLAGS: %s",
517 		    pcap_strerror(errno));
518 		goto bad;
519 	}
520 	/*
521 	** Set up the bufmod timeout
522 	*/
523 	if (to_ms != 0) {
524 		struct timeval to;
525 
526 		to.tv_sec = to_ms / 1000;
527 		to.tv_usec = (to_ms * 1000) % 1000000;
528 		if (strioctl(p->fd, SBIOCSTIME, sizeof(to), (char *)&to) != 0) {
529 			snprintf(ebuf, PCAP_ERRBUF_SIZE, "SBIOCSTIME: %s",
530 			    pcap_strerror(errno));
531 			goto bad;
532 		}
533 	}
534 #endif
535 
536 	/*
537 	** As the last operation flush the read side.
538 	*/
539 	if (ioctl(p->fd, I_FLUSH, FLUSHR) != 0) {
540 		snprintf(ebuf, PCAP_ERRBUF_SIZE, "FLUSHR: %s",
541 		    pcap_strerror(errno));
542 		goto bad;
543 	}
544 	/* Allocate data buffer */
545 	p->bufsize = MAXDLBUF * sizeof(bpf_u_int32);
546 	p->buffer = (u_char *)malloc(p->bufsize + p->offset);
547 
548 	return (p);
549 bad:
550 	free(p);
551 	return (NULL);
552 }
553 
554 int
555 pcap_setfilter(pcap_t *p, struct bpf_program *fp)
556 {
557 
558 	if (install_bpf_program(p, fp) < 0)
559 		return (-1);
560 	return (0);
561 }
562 
563 static int
564 send_request(int fd, char *ptr, int len, char *what, char *ebuf)
565 {
566 	struct	strbuf	ctl;
567 	int	flags;
568 
569 	ctl.maxlen = 0;
570 	ctl.len = len;
571 	ctl.buf = ptr;
572 
573 	flags = 0;
574 	if (putmsg(fd, &ctl, (struct strbuf *) NULL, flags) < 0) {
575 		snprintf(ebuf, PCAP_ERRBUF_SIZE,
576 		    "send_request: putmsg \"%s\": %s",
577 		    what, pcap_strerror(errno));
578 		return (-1);
579 	}
580 	return (0);
581 }
582 
583 static int
584 recv_ack(int fd, int size, const char *what, char *bufp, char *ebuf)
585 {
586 	union	DL_primitives	*dlp;
587 	struct	strbuf	ctl;
588 	int	flags;
589 
590 	ctl.maxlen = MAXDLBUF;
591 	ctl.len = 0;
592 	ctl.buf = bufp;
593 
594 	flags = 0;
595 	if (getmsg(fd, &ctl, (struct strbuf*)NULL, &flags) < 0) {
596 		snprintf(ebuf, PCAP_ERRBUF_SIZE, "recv_ack: %s getmsg: %s",
597 		    what, pcap_strerror(errno));
598 		return (-1);
599 	}
600 
601 	dlp = (union DL_primitives *) ctl.buf;
602 	switch (dlp->dl_primitive) {
603 
604 	case DL_INFO_ACK:
605 	case DL_BIND_ACK:
606 	case DL_OK_ACK:
607 #ifdef DL_HP_PPA_ACK
608 	case DL_HP_PPA_ACK:
609 #endif
610 
611 		/* These are OK */
612 		break;
613 
614 	case DL_ERROR_ACK:
615 		switch (dlp->error_ack.dl_errno) {
616 
617 		case DL_BADPPA:
618 			snprintf(ebuf, PCAP_ERRBUF_SIZE,
619 			    "recv_ack: %s bad ppa (device unit)", what);
620 			break;
621 
622 
623 		case DL_SYSERR:
624 			snprintf(ebuf, PCAP_ERRBUF_SIZE, "recv_ack: %s: %s",
625 			    what, pcap_strerror(dlp->error_ack.dl_unix_errno));
626 			break;
627 
628 		case DL_UNSUPPORTED:
629 			snprintf(ebuf, PCAP_ERRBUF_SIZE,
630 			    "recv_ack: %s: Service not supplied by provider",
631 			    what);
632 			break;
633 
634 		default:
635 			snprintf(ebuf, PCAP_ERRBUF_SIZE,
636 			    "recv_ack: %s error 0x%x",
637 			    what, (bpf_u_int32)dlp->error_ack.dl_errno);
638 			break;
639 		}
640 		return (-1);
641 
642 	default:
643 		snprintf(ebuf, PCAP_ERRBUF_SIZE,
644 		    "recv_ack: %s unexpected primitive ack 0x%x ",
645 		    what, (bpf_u_int32)dlp->dl_primitive);
646 		return (-1);
647 	}
648 
649 	if (ctl.len < size) {
650 		snprintf(ebuf, PCAP_ERRBUF_SIZE,
651 		    "recv_ack: %s ack too small (%d < %d)",
652 		    what, ctl.len, size);
653 		return (-1);
654 	}
655 	return (ctl.len);
656 }
657 
658 static int
659 dlattachreq(int fd, bpf_u_int32 ppa, char *ebuf)
660 {
661 	dl_attach_req_t	req;
662 
663 	req.dl_primitive = DL_ATTACH_REQ;
664 	req.dl_ppa = ppa;
665 
666 	return (send_request(fd, (char *)&req, sizeof(req), "attach", ebuf));
667 }
668 
669 static int
670 dlbindreq(int fd, bpf_u_int32 sap, char *ebuf)
671 {
672 
673 	dl_bind_req_t	req;
674 
675 	memset((char *)&req, 0, sizeof(req));
676 	req.dl_primitive = DL_BIND_REQ;
677 #ifdef DL_HP_RAWDLS
678 	req.dl_max_conind = 1;			/* XXX magic number */
679 	/* 22 is INSAP as per the HP-UX DLPI Programmer's Guide */
680 	req.dl_sap = 22;
681 	req.dl_service_mode = DL_HP_RAWDLS;
682 #else
683 	req.dl_sap = sap;
684 #ifdef DL_CLDLS
685 	req.dl_service_mode = DL_CLDLS;
686 #endif
687 #endif
688 
689 	return (send_request(fd, (char *)&req, sizeof(req), "bind", ebuf));
690 }
691 
692 static int
693 dlbindack(int fd, char *bufp, char *ebuf)
694 {
695 
696 	return (recv_ack(fd, DL_BIND_ACK_SIZE, "bind", bufp, ebuf));
697 }
698 
699 static int
700 dlpromisconreq(int fd, bpf_u_int32 level, char *ebuf)
701 {
702 	dl_promiscon_req_t req;
703 
704 	req.dl_primitive = DL_PROMISCON_REQ;
705 	req.dl_level = level;
706 
707 	return (send_request(fd, (char *)&req, sizeof(req), "promiscon", ebuf));
708 }
709 
710 static int
711 dlokack(int fd, const char *what, char *bufp, char *ebuf)
712 {
713 
714 	return (recv_ack(fd, DL_OK_ACK_SIZE, what, bufp, ebuf));
715 }
716 
717 
718 static int
719 dlinforeq(int fd, char *ebuf)
720 {
721 	dl_info_req_t req;
722 
723 	req.dl_primitive = DL_INFO_REQ;
724 
725 	return (send_request(fd, (char *)&req, sizeof(req), "info", ebuf));
726 }
727 
728 static int
729 dlinfoack(int fd, char *bufp, char *ebuf)
730 {
731 
732 	return (recv_ack(fd, DL_INFO_ACK_SIZE, "info", bufp, ebuf));
733 }
734 
735 #ifdef HAVE_SYS_BUFMOD_H
736 static int
737 strioctl(int fd, int cmd, int len, char *dp)
738 {
739 	struct strioctl str;
740 	int rc;
741 
742 	str.ic_cmd = cmd;
743 	str.ic_timout = -1;
744 	str.ic_len = len;
745 	str.ic_dp = dp;
746 	rc = ioctl(fd, I_STR, &str);
747 
748 	if (rc < 0)
749 		return (rc);
750 	else
751 		return (str.ic_len);
752 }
753 #endif
754 
755 #if defined(HAVE_SOLARIS) && defined(HAVE_SYS_BUFMOD_H)
756 static char *
757 get_release(bpf_u_int32 *majorp, bpf_u_int32 *minorp, bpf_u_int32 *microp)
758 {
759 	char *cp;
760 	static char buf[32];
761 
762 	*majorp = 0;
763 	*minorp = 0;
764 	*microp = 0;
765 	if (sysinfo(SI_RELEASE, buf, sizeof(buf)) < 0)
766 		return ("?");
767 	cp = buf;
768 	if (!isdigit(*cp))
769 		return (buf);
770 	*majorp = strtol(cp, &cp, 10);
771 	if (*cp++ != '.')
772 		return (buf);
773 	*minorp =  strtol(cp, &cp, 10);
774 	if (*cp++ != '.')
775 		return (buf);
776 	*microp =  strtol(cp, &cp, 10);
777 	return (buf);
778 }
779 #endif
780 
781 #ifdef DL_HP_PPA_ACK_OBS
782 /*
783  * Under HP-UX 10 and HP-UX 11, we can ask for the ppa
784  */
785 
786 
787 /*
788  * Determine ppa number that specifies ifname.
789  *
790  * If the "dl_hp_ppa_info_t" doesn't have a "dl_module_id_1" member,
791  * the code that's used here is the old code for HP-UX 10.x.
792  *
793  * However, HP-UX 10.20, at least, appears to have such a member
794  * in its "dl_hp_ppa_info_t" structure, so the new code is used.
795  * The new code didn't work on an old 10.20 system on which Rick
796  * Jones of HP tried it, but with later patches installed, it
797  * worked - it appears that the older system had those members but
798  * didn't put anything in them, so, if the search by name fails, we
799  * do the old search.
800  *
801  * Rick suggests that making sure your system is "up on the latest
802  * lancommon/DLPI/driver patches" is probably a good idea; it'd fix
803  * that problem, as well as allowing libpcap to see packets sent
804  * from the system on which the libpcap application is being run.
805  * (On 10.20, in addition to getting the latest patches, you need
806  * to turn the kernel "lanc_outbound_promisc_flag" flag on with ADB;
807  * a posting to "comp.sys.hp.hpux" at
808  *
809  *	http://www.deja.com/[ST_rn=ps]/getdoc.xp?AN=558092266
810  *
811  * says that, to see the machine's outgoing traffic, you'd need to
812  * apply the right patches to your system, and also set that variable
813  * with:
814 
815 echo 'lanc_outbound_promisc_flag/W1' | /usr/bin/adb -w /stand/vmunix /dev/kmem
816 
817  * which could be put in, for example, "/sbin/init.d/lan".
818  *
819  * Setting the variable is not necessary on HP-UX 11.x.
820  */
821 static int
822 get_dlpi_ppa(register int fd, register const char *device, register int unit,
823     register char *ebuf)
824 {
825 	register dl_hp_ppa_ack_t *ap;
826 	register dl_hp_ppa_info_t *ipstart, *ip;
827 	register int i;
828 	char dname[100];
829 	register u_long majdev;
830 	struct stat statbuf;
831 	dl_hp_ppa_req_t	req;
832 	bpf_u_int32 buf[MAXDLBUF];
833 
834 	memset((char *)&req, 0, sizeof(req));
835 	req.dl_primitive = DL_HP_PPA_REQ;
836 
837 	memset((char *)buf, 0, sizeof(buf));
838 	if (send_request(fd, (char *)&req, sizeof(req), "hpppa", ebuf) < 0 ||
839 	    recv_ack(fd, DL_HP_PPA_ACK_SIZE, "hpppa", (char *)buf, ebuf) < 0)
840 		return (-1);
841 
842 	ap = (dl_hp_ppa_ack_t *)buf;
843 	ipstart = (dl_hp_ppa_info_t *)((u_char *)ap + ap->dl_offset);
844 	ip = ipstart;
845 
846 #ifdef HAVE_HP_PPA_INFO_T_DL_MODULE_ID_1
847 	/*
848 	 * The "dl_hp_ppa_info_t" structure has a "dl_module_id_1"
849 	 * member that should, in theory, contain the part of the
850 	 * name for the device that comes before the unit number,
851 	 * and should also have a "dl_module_id_2" member that may
852 	 * contain an alternate name (e.g., I think Ethernet devices
853 	 * have both "lan", for "lanN", and "snap", for "snapN", with
854 	 * the former being for Ethernet packets and the latter being
855 	 * for 802.3/802.2 packets).
856 	 *
857 	 * Search for the device that has the specified name and
858 	 * instance number.
859 	 */
860 	for (i = 0; i < ap->dl_count; i++) {
861 		if ((strcmp(ip->dl_module_id_1, device) == 0 ||
862 		     strcmp(ip->dl_module_id_2, device) == 0) &&
863 		    ip->dl_instance_num == unit)
864 			break;
865 
866 		ip = (dl_hp_ppa_info_t *)((u_char *)ipstart + ip->dl_next_offset);
867 	}
868 #else
869 	/*
870 	 * We don't have that member, so the search is impossible; make it
871 	 * look as if the search failed.
872 	 */
873 	i = ap->dl_count;
874 #endif
875 
876 	if (i == ap->dl_count) {
877 		/*
878 		 * Well, we didn't, or can't, find the device by name.
879 		 *
880 		 * HP-UX 10.20, whilst it has "dl_module_id_1" and
881 		 * "dl_module_id_2" fields in the "dl_hp_ppa_info_t",
882 		 * doesn't seem to fill them in unless the system is
883 		 * at a reasonably up-to-date patch level.
884 		 *
885 		 * Older HP-UX 10.x systems might not have those fields
886 		 * at all.
887 		 *
888 		 * Therefore, we'll search for the entry with the major
889 		 * device number of a device with the name "/dev/<dev><unit>",
890 		 * if such a device exists, as the old code did.
891 		 */
892 		snprintf(dname, sizeof(dname), "/dev/%s%d", device, unit);
893 		if (stat(dname, &statbuf) < 0) {
894 			snprintf(ebuf, PCAP_ERRBUF_SIZE, "stat: %s: %s",
895 			    dname, pcap_strerror(errno));
896 			return (-1);
897 		}
898 		majdev = major(statbuf.st_rdev);
899 
900 		ip = ipstart;
901 
902 		for (i = 0; i < ap->dl_count; i++) {
903 			if (ip->dl_mjr_num == majdev &&
904 			    ip->dl_instance_num == unit)
905 				break;
906 
907 			ip = (dl_hp_ppa_info_t *)((u_char *)ipstart + ip->dl_next_offset);
908 		}
909 	}
910         if (i == ap->dl_count) {
911                 snprintf(ebuf, PCAP_ERRBUF_SIZE,
912 		    "can't find /dev/dlpi PPA for %s%d", device, unit);
913 		return (-1);
914         }
915         if (ip->dl_hdw_state == HDW_DEAD) {
916                 snprintf(ebuf, PCAP_ERRBUF_SIZE,
917 		    "%s%d: hardware state: DOWN\n", device, unit);
918 		return (-1);
919         }
920         return ((int)ip->dl_ppa);
921 }
922 #endif
923 
924 #ifdef HAVE_HPUX9
925 /*
926  * Under HP-UX 9, there is no good way to determine the ppa.
927  * So punt and read it from /dev/kmem.
928  */
929 static struct nlist nl[] = {
930 #define NL_IFNET 0
931 	{ "ifnet" },
932 	{ "" }
933 };
934 
935 static char path_vmunix[] = "/hp-ux";
936 
937 /* Determine ppa number that specifies ifname */
938 static int
939 get_dlpi_ppa(register int fd, register const char *ifname, register int unit,
940     register char *ebuf)
941 {
942 	register const char *cp;
943 	register int kd;
944 	void *addr;
945 	struct ifnet ifnet;
946 	char if_name[sizeof(ifnet.if_name) + 1];
947 
948 	cp = strrchr(ifname, '/');
949 	if (cp != NULL)
950 		ifname = cp + 1;
951 	if (nlist(path_vmunix, &nl) < 0) {
952 		snprintf(ebuf, PCAP_ERRBUF_SIZE, "nlist %s failed",
953 		    path_vmunix);
954 		return (-1);
955 	}
956 	if (nl[NL_IFNET].n_value == 0) {
957 		snprintf(ebuf, PCAP_ERRBUF_SIZE,
958 		    "could't find %s kernel symbol",
959 		    nl[NL_IFNET].n_name);
960 		return (-1);
961 	}
962 	kd = open("/dev/kmem", O_RDONLY);
963 	if (kd < 0) {
964 		snprintf(ebuf, PCAP_ERRBUF_SIZE, "kmem open: %s",
965 		    pcap_strerror(errno));
966 		return (-1);
967 	}
968 	if (dlpi_kread(kd, nl[NL_IFNET].n_value,
969 	    &addr, sizeof(addr), ebuf) < 0) {
970 		close(kd);
971 		return (-1);
972 	}
973 	for (; addr != NULL; addr = ifnet.if_next) {
974 		if (dlpi_kread(kd, (off_t)addr,
975 		    &ifnet, sizeof(ifnet), ebuf) < 0 ||
976 		    dlpi_kread(kd, (off_t)ifnet.if_name,
977 		    if_name, sizeof(ifnet.if_name), ebuf) < 0) {
978 			(void)close(kd);
979 			return (-1);
980 		}
981 		if_name[sizeof(ifnet.if_name)] = '\0';
982 		if (strcmp(if_name, ifname) == 0 && ifnet.if_unit == unit)
983 			return (ifnet.if_index);
984 	}
985 
986 	snprintf(ebuf, PCAP_ERRBUF_SIZE, "Can't find %s", ifname);
987 	return (-1);
988 }
989 
990 static int
991 dlpi_kread(register int fd, register off_t addr,
992     register void *buf, register u_int len, register char *ebuf)
993 {
994 	register int cc;
995 
996 	if (lseek(fd, addr, SEEK_SET) < 0) {
997 		snprintf(ebuf, PCAP_ERRBUF_SIZE, "lseek: %s",
998 		    pcap_strerror(errno));
999 		return (-1);
1000 	}
1001 	cc = read(fd, buf, len);
1002 	if (cc < 0) {
1003 		snprintf(ebuf, PCAP_ERRBUF_SIZE, "read: %s",
1004 		    pcap_strerror(errno));
1005 		return (-1);
1006 	} else if (cc != len) {
1007 		snprintf(ebuf, PCAP_ERRBUF_SIZE, "short read (%d != %d)", cc,
1008 		    len);
1009 		return (-1);
1010 	}
1011 	return (cc);
1012 }
1013 #endif
1014