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