pcap-dlpi.c revision 147894
117683Spst/* 239291Sfenner * Copyright (c) 1993, 1994, 1995, 1996, 1997 317683Spst * The Regents of the University of California. All rights reserved. 417683Spst * 517683Spst * Redistribution and use in source and binary forms, with or without 617683Spst * modification, are permitted provided that: (1) source code distributions 717683Spst * retain the above copyright notice and this paragraph in its entirety, (2) 817683Spst * distributions including binary code include the above copyright notice and 917683Spst * this paragraph in its entirety in the documentation or other materials 1017683Spst * provided with the distribution, and (3) all advertising materials mentioning 1117683Spst * features or use of this software display the following acknowledgement: 1217683Spst * ``This product includes software developed by the University of California, 1317683Spst * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 1417683Spst * the University nor the names of its contributors may be used to endorse 1517683Spst * or promote products derived from this software without specific prior 1617683Spst * written permission. 1717683Spst * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 1817683Spst * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 1917683Spst * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 2017683Spst * 2117683Spst * This code contributed by Atanu Ghosh (atanu@cs.ucl.ac.uk), 22146768Ssam * University College London, and subsequently modified by 23147894Ssam * Guy Harris (guy@alum.mit.edu), Mark Pizzolato 24147894Ssam * <List-tcpdump-workers@subscriptions.pizzolato.net>, 25147894Ssam * and Mark C. Brown (mbrown@hp.com). 2617683Spst */ 2717683Spst 2817683Spst/* 29127664Sbms * Packet capture routine for DLPI under SunOS 5, HP-UX 9/10/11, and AIX. 3017683Spst * 3117683Spst * Notes: 3217683Spst * 33146768Ssam * - The DLIOCRAW ioctl() is specific to SunOS. 3417683Spst * 3517683Spst * - There is a bug in bufmod(7) such that setting the snapshot 3617683Spst * length results in data being left of the front of the packet. 3717683Spst * 3817683Spst * - It might be desirable to use pfmod(7) to filter packets in the 39127664Sbms * kernel when possible. 40146768Ssam * 41147894Ssam * - An older version of the HP-UX DLPI Programmer's Guide, which 42147894Ssam * I think was advertised as the 10.20 version, used to be available 43146768Ssam * at 44146768Ssam * 45146768Ssam * http://docs.hp.com/hpux/onlinedocs/B2355-90093/B2355-90093.html 46146768Ssam * 47146768Ssam * but is no longer available; it can still be found at 48146768Ssam * 49146768Ssam * http://h21007.www2.hp.com/dspp/files/unprotected/Drivers/Docs/Refs/B2355-90093.pdf 50146768Ssam * 51146768Ssam * in PDF form. 52146768Ssam * 53147894Ssam * - The HP-UX 10.x, 11.0, and 11i v1.6 version of the HP-UX DLPI 54147894Ssam * Programmer's Guide, which I think was once advertised as the 55147894Ssam * 11.00 version is available at 56146768Ssam * 57147894Ssam * http://docs.hp.com/en/B2355-90139/index.html 58146768Ssam * 59147894Ssam * - The HP-UX 11i v2 version of the HP-UX DLPI Programmer's Guide 60147894Ssam * is available at 61146768Ssam * 62147894Ssam * http://docs.hp.com/en/B2355-90871/index.html 63146768Ssam * 64147894Ssam * - All of the HP documents describe raw-mode services, which are 65147894Ssam * what we use if DL_HP_RAWDLS is defined. XXX - we use __hpux 66147894Ssam * in some places to test for HP-UX, but use DL_HP_RAWDLS in 67147894Ssam * other places; do we support any versions of HP-UX without 68147894Ssam * DL_HP_RAWDLS? 6917683Spst */ 7017683Spst 7126175Sfenner#ifndef lint 72127664Sbmsstatic const char rcsid[] _U_ = 73147894Ssam "@(#) $Header: /tcpdump/master/libpcap/pcap-dlpi.c,v 1.108.2.5 2005/05/03 18:54:35 guy Exp $ (LBL)"; 7426175Sfenner#endif 7526175Sfenner 7675107Sfenner#ifdef HAVE_CONFIG_H 7775107Sfenner#include "config.h" 7875107Sfenner#endif 7975107Sfenner 8017683Spst#include <sys/types.h> 8117683Spst#include <sys/time.h> 8217683Spst#ifdef HAVE_SYS_BUFMOD_H 8317683Spst#include <sys/bufmod.h> 8417683Spst#endif 8517683Spst#include <sys/dlpi.h> 8617683Spst#ifdef HAVE_SYS_DLPI_EXT_H 8717683Spst#include <sys/dlpi_ext.h> 8817683Spst#endif 8917683Spst#ifdef HAVE_HPUX9 9017683Spst#include <sys/socket.h> 9117683Spst#endif 92146768Ssam#ifdef DL_HP_PPA_REQ 9317683Spst#include <sys/stat.h> 9417683Spst#endif 9517683Spst#include <sys/stream.h> 9617683Spst#if defined(HAVE_SOLARIS) && defined(HAVE_SYS_BUFMOD_H) 9717683Spst#include <sys/systeminfo.h> 9817683Spst#endif 9917683Spst 10017683Spst#ifdef HAVE_HPUX9 10117683Spst#include <net/if.h> 10217683Spst#endif 10317683Spst 10417683Spst#include <ctype.h> 10517683Spst#ifdef HAVE_HPUX9 10617683Spst#include <nlist.h> 10717683Spst#endif 10817683Spst#include <errno.h> 10917683Spst#include <fcntl.h> 11017683Spst#include <memory.h> 11117683Spst#include <stdio.h> 11217683Spst#include <stdlib.h> 11317683Spst#include <string.h> 11417683Spst#include <stropts.h> 11517683Spst#include <unistd.h> 11617683Spst 117146768Ssam#ifdef HAVE_LIMITS_H 118146768Ssam#include <limits.h> 119146768Ssam#else 120146768Ssam#define INT_MAX 2147483647 121146768Ssam#endif 122146768Ssam 12317683Spst#include "pcap-int.h" 12417683Spst 12517683Spst#ifdef HAVE_OS_PROTO_H 12617683Spst#include "os-proto.h" 12717683Spst#endif 12817683Spst 12917683Spst#ifndef PCAP_DEV_PREFIX 13098530Sfenner#ifdef _AIX 13198530Sfenner#define PCAP_DEV_PREFIX "/dev/dlpi" 13298530Sfenner#else 13317683Spst#define PCAP_DEV_PREFIX "/dev" 13417683Spst#endif 13598530Sfenner#endif 13617683Spst 13717683Spst#define MAXDLBUF 8192 13817683Spst 139127664Sbms#ifdef HAVE_SYS_BUFMOD_H 140127664Sbms 141127664Sbms/* 142127664Sbms * Size of a bufmod chunk to pass upstream; that appears to be the biggest 143127664Sbms * value to which you can set it, and setting it to that value (which 144127664Sbms * is bigger than what appears to be the Solaris default of 8192) 145127664Sbms * reduces the number of packet drops. 146127664Sbms */ 147127664Sbms#define CHUNKSIZE 65536 148127664Sbms 149127664Sbms/* 150127664Sbms * Size of the buffer to allocate for packet data we read; it must be 151127664Sbms * large enough to hold a chunk. 152127664Sbms */ 153127664Sbms#define PKTBUFSIZE CHUNKSIZE 154127664Sbms 155127664Sbms#else /* HAVE_SYS_BUFMOD_H */ 156127664Sbms 157127664Sbms/* 158127664Sbms * Size of the buffer to allocate for packet data we read; this is 159127664Sbms * what the value used to be - there's no particular reason why it 160127664Sbms * should be tied to MAXDLBUF, but we'll leave it as this for now. 161127664Sbms */ 162127664Sbms#define PKTBUFSIZE (MAXDLBUF * sizeof(bpf_u_int32)) 163127664Sbms 164127664Sbms#endif 165127664Sbms 16617683Spst/* Forwards */ 16798530Sfennerstatic char *split_dname(char *, int *, char *); 168146768Ssamstatic int dl_doattach(int, int, char *); 169147894Ssam#ifdef DL_HP_RAWDLS 170147894Ssamstatic int dl_dohpuxbind(int, char *); 171147894Ssam#endif 17217683Spststatic int dlattachreq(int, bpf_u_int32, char *); 173146768Ssamstatic int dlbindreq(int, bpf_u_int32, char *); 174147894Ssamstatic int dlbindack(int, char *, char *, int *); 175146768Ssamstatic int dlpromisconreq(int, bpf_u_int32, char *); 176146768Ssamstatic int dlokack(int, const char *, char *, char *); 177146768Ssamstatic int dlinforeq(int, char *); 17817683Spststatic int dlinfoack(int, char *, char *); 179146768Ssam#ifdef DL_HP_RAWDLS 180146768Ssamstatic int dlrawdatareq(int, const u_char *, int); 181146768Ssam#endif 182147894Ssamstatic int recv_ack(int, int, const char *, char *, char *, int *); 18398530Sfennerstatic char *dlstrerror(bpf_u_int32); 18498530Sfennerstatic char *dlprim(bpf_u_int32); 18517683Spst#if defined(HAVE_SOLARIS) && defined(HAVE_SYS_BUFMOD_H) 18617683Spststatic char *get_release(bpf_u_int32 *, bpf_u_int32 *, bpf_u_int32 *); 18717683Spst#endif 18817683Spststatic int send_request(int, char *, int, char *, char *); 18917683Spst#ifdef HAVE_SYS_BUFMOD_H 19017683Spststatic int strioctl(int, int, int, char *); 19117683Spst#endif 19217683Spst#ifdef HAVE_HPUX9 19317683Spststatic int dlpi_kread(int, off_t, void *, u_int, char *); 19417683Spst#endif 19517683Spst#ifdef HAVE_DEV_DLPI 19617683Spststatic int get_dlpi_ppa(int, const char *, int, char *); 19717683Spst#endif 19817683Spst 199127664Sbmsstatic int 200127664Sbmspcap_stats_dlpi(pcap_t *p, struct pcap_stat *ps) 20117683Spst{ 20217683Spst 20398530Sfenner /* 20498530Sfenner * "ps_recv" counts packets handed to the filter, not packets 20598530Sfenner * that passed the filter. As filtering is done in userland, 206146768Ssam * this would not include packets dropped because we ran out 207146768Ssam * of buffer space; in order to make this more like other 208146768Ssam * platforms (Linux 2.4 and later, BSDs with BPF), where the 209146768Ssam * "packets received" count includes packets received but dropped 210146768Ssam * due to running out of buffer space, and to keep from confusing 211146768Ssam * applications that, for example, compute packet drop percentages, 212146768Ssam * we also make it count packets dropped by "bufmod" (otherwise we 213146768Ssam * might run the risk of the packet drop count being bigger than 214146768Ssam * the received-packet count). 21598530Sfenner * 216146768Ssam * "ps_drop" counts packets dropped by "bufmod" because of 217146768Ssam * flow control requirements or resource exhaustion; it doesn't 218146768Ssam * count packets dropped by the interface driver, or packets 219146768Ssam * dropped upstream. As filtering is done in userland, it counts 220146768Ssam * packets regardless of whether they would've passed the filter. 22198530Sfenner * 22298530Sfenner * These statistics don't include packets not yet read from 22398530Sfenner * the kernel by libpcap, but they may include packets not 22498530Sfenner * yet read from libpcap by the application. 22598530Sfenner */ 22617683Spst *ps = p->md.stat; 227146768Ssam 228146768Ssam /* 229146768Ssam * Add in the drop count, as per the above comment. 230146768Ssam */ 231146768Ssam ps->ps_recv += ps->ps_drop; 23217683Spst return (0); 23317683Spst} 23417683Spst 23517683Spst/* XXX Needed by HP-UX (at least) */ 23617683Spststatic bpf_u_int32 ctlbuf[MAXDLBUF]; 23717683Spststatic struct strbuf ctl = { 23817683Spst MAXDLBUF, 23917683Spst 0, 24017683Spst (char *)ctlbuf 24117683Spst}; 24217683Spst 243127664Sbmsstatic int 244127664Sbmspcap_read_dlpi(pcap_t *p, int cnt, pcap_handler callback, u_char *user) 24517683Spst{ 24617683Spst register int cc, n, caplen, origlen; 24717683Spst register u_char *bp, *ep, *pk; 24817683Spst register struct bpf_insn *fcode; 24917683Spst#ifdef HAVE_SYS_BUFMOD_H 25017683Spst register struct sb_hdr *sbp; 25117683Spst#ifdef LBL_ALIGN 25217683Spst struct sb_hdr sbhdr; 25317683Spst#endif 25417683Spst#endif 25517683Spst int flags; 25617683Spst struct strbuf data; 25717683Spst struct pcap_pkthdr pkthdr; 25817683Spst 25917683Spst flags = 0; 26017683Spst cc = p->cc; 26117683Spst if (cc == 0) { 26217683Spst data.buf = (char *)p->buffer + p->offset; 263127664Sbms data.maxlen = p->bufsize; 26417683Spst data.len = 0; 26517683Spst do { 266127664Sbms /* 267127664Sbms * Has "pcap_breakloop()" been called? 268127664Sbms */ 269127664Sbms if (p->break_loop) { 270127664Sbms /* 271127664Sbms * Yes - clear the flag that indicates 272127664Sbms * that it has, and return -2 to 273127664Sbms * indicate that we were told to 274127664Sbms * break out of the loop. 275127664Sbms */ 276127664Sbms p->break_loop = 0; 277127664Sbms return (-2); 278127664Sbms } 279146768Ssam /* 280146768Ssam * XXX - check for the DLPI primitive, which 281146768Ssam * would be DL_HP_RAWDATA_IND on HP-UX 282146768Ssam * if we're in raw mode? 283146768Ssam */ 28417683Spst if (getmsg(p->fd, &ctl, &data, &flags) < 0) { 28517683Spst /* Don't choke when we get ptraced */ 286146768Ssam switch (errno) { 287146768Ssam 288146768Ssam case EINTR: 28917683Spst cc = 0; 29017683Spst continue; 291146768Ssam 292146768Ssam case EAGAIN: 293146768Ssam return (0); 29417683Spst } 29575107Sfenner strlcpy(p->errbuf, pcap_strerror(errno), 29675107Sfenner sizeof(p->errbuf)); 29717683Spst return (-1); 29817683Spst } 29917683Spst cc = data.len; 30017683Spst } while (cc == 0); 30117683Spst bp = p->buffer + p->offset; 30217683Spst } else 30317683Spst bp = p->bp; 30417683Spst 30517683Spst /* Loop through packets */ 30617683Spst fcode = p->fcode.bf_insns; 30717683Spst ep = bp + cc; 30817683Spst n = 0; 30917683Spst#ifdef HAVE_SYS_BUFMOD_H 31017683Spst while (bp < ep) { 311127664Sbms /* 312127664Sbms * Has "pcap_breakloop()" been called? 313127664Sbms * If so, return immediately - if we haven't read any 314127664Sbms * packets, clear the flag and return -2 to indicate 315127664Sbms * that we were told to break out of the loop, otherwise 316127664Sbms * leave the flag set, so that the *next* call will break 317127664Sbms * out of the loop without having read any packets, and 318127664Sbms * return the number of packets we've processed so far. 319127664Sbms */ 320127664Sbms if (p->break_loop) { 321127664Sbms if (n == 0) { 322127664Sbms p->break_loop = 0; 323127664Sbms return (-2); 324127664Sbms } else { 325127664Sbms p->bp = bp; 326127664Sbms p->cc = ep - bp; 327127664Sbms return (n); 328127664Sbms } 329127664Sbms } 33017683Spst#ifdef LBL_ALIGN 33117683Spst if ((long)bp & 3) { 33217683Spst sbp = &sbhdr; 33317683Spst memcpy(sbp, bp, sizeof(*sbp)); 33417683Spst } else 33517683Spst#endif 33617683Spst sbp = (struct sb_hdr *)bp; 337127664Sbms p->md.stat.ps_drop = sbp->sbh_drops; 33817683Spst pk = bp + sizeof(*sbp); 33917683Spst bp += sbp->sbh_totlen; 34017683Spst origlen = sbp->sbh_origlen; 34117683Spst caplen = sbp->sbh_msglen; 34217683Spst#else 34317683Spst origlen = cc; 34417683Spst caplen = min(p->snapshot, cc); 34517683Spst pk = bp; 34617683Spst bp += caplen; 34717683Spst#endif 34817683Spst ++p->md.stat.ps_recv; 34917683Spst if (bpf_filter(fcode, pk, origlen, caplen)) { 35017683Spst#ifdef HAVE_SYS_BUFMOD_H 351127664Sbms pkthdr.ts.tv_sec = sbp->sbh_timestamp.tv_sec; 352127664Sbms pkthdr.ts.tv_usec = sbp->sbh_timestamp.tv_usec; 35317683Spst#else 35417683Spst (void)gettimeofday(&pkthdr.ts, NULL); 35517683Spst#endif 35617683Spst pkthdr.len = origlen; 35717683Spst pkthdr.caplen = caplen; 35817683Spst /* Insure caplen does not exceed snapshot */ 35917683Spst if (pkthdr.caplen > p->snapshot) 36017683Spst pkthdr.caplen = p->snapshot; 36117683Spst (*callback)(user, &pkthdr, pk); 36217683Spst if (++n >= cnt && cnt >= 0) { 36317683Spst p->cc = ep - bp; 36417683Spst p->bp = bp; 36517683Spst return (n); 36617683Spst } 36717683Spst } 36817683Spst#ifdef HAVE_SYS_BUFMOD_H 36917683Spst } 37017683Spst#endif 37117683Spst p->cc = 0; 37217683Spst return (n); 37317683Spst} 37417683Spst 375146768Ssamstatic int 376146768Ssampcap_inject_dlpi(pcap_t *p, const void *buf, size_t size) 377146768Ssam{ 378146768Ssam int ret; 379146768Ssam 380146768Ssam#if defined(DLIOCRAW) 381146768Ssam ret = write(p->fd, buf, size); 382146768Ssam if (ret == -1) { 383146768Ssam snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: %s", 384146768Ssam pcap_strerror(errno)); 385146768Ssam return (-1); 386146768Ssam } 387146768Ssam#elif defined(DL_HP_RAWDLS) 388146768Ssam if (p->send_fd < 0) { 389146768Ssam snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 390146768Ssam "send: Output FD couldn't be opened"); 391146768Ssam return (-1); 392146768Ssam } 393146768Ssam ret = dlrawdatareq(p->send_fd, buf, size); 394146768Ssam if (ret == -1) { 395146768Ssam snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: %s", 396146768Ssam pcap_strerror(errno)); 397146768Ssam return (-1); 398146768Ssam } 399146768Ssam#else /* no raw mode */ 400146768Ssam /* 401146768Ssam * XXX - this is a pain, because you might have to extract 402146768Ssam * the address from the packet and use it in a DL_UNITDATA_REQ 403146768Ssam * request. That would be dependent on the link-layer type. 404146768Ssam * 405146768Ssam * I also don't know what SAP you'd have to bind the descriptor 406146768Ssam * to, or whether you'd need separate "receive" and "send" FDs, 407146768Ssam * nor do I know whether you'd need different bindings for 408146768Ssam * D/I/X Ethernet and 802.3, or for {FDDI,Token Ring} plus 409146768Ssam * 802.2 and {FDDI,Token Ring} plus 802.2 plus SNAP. 410146768Ssam * 411146768Ssam * So, for now, we just return a "you can't send" indication, 412146768Ssam * and leave it up to somebody with a DLPI-based system lacking 413146768Ssam * both DLIOCRAW and DL_HP_RAWDLS to supply code to implement 414146768Ssam * packet transmission on that system. If they do, they should 415146768Ssam * send it to us - but should not send us code that assumes 416146768Ssam * Ethernet; if the code doesn't work on non-Ethernet interfaces, 417146768Ssam * it should check "p->linktype" and reject the send request if 418146768Ssam * it's anything other than DLT_EN10MB. 419146768Ssam */ 420146768Ssam strlcpy(p->errbuf, "send: Not supported on this version of this OS", 421146768Ssam PCAP_ERRBUF_SIZE); 422146768Ssam ret = -1; 423146768Ssam#endif /* raw mode */ 424146768Ssam return (ret); 425147894Ssam} 426146768Ssam 427127664Sbms#ifndef DL_IPATM 428127664Sbms#define DL_IPATM 0x12 /* ATM Classical IP interface */ 429127664Sbms#endif 430127664Sbms 431127664Sbms#ifdef HAVE_SOLARIS 432127664Sbms/* 433127664Sbms * For SunATM. 434127664Sbms */ 435127664Sbms#ifndef A_GET_UNITS 436127664Sbms#define A_GET_UNITS (('A'<<8)|118) 437127664Sbms#endif /* A_GET_UNITS */ 438127664Sbms#ifndef A_PROMISCON_REQ 439127664Sbms#define A_PROMISCON_REQ (('A'<<8)|121) 440127664Sbms#endif /* A_PROMISCON_REQ */ 441127664Sbms#endif /* HAVE_SOLARIS */ 442127664Sbms 443127664Sbmsstatic void 444127664Sbmspcap_close_dlpi(pcap_t *p) 445127664Sbms{ 446146768Ssam pcap_close_common(p); 447146768Ssam if (p->send_fd >= 0) 448146768Ssam close(p->send_fd); 449127664Sbms} 450127664Sbms 45117683Spstpcap_t * 452127664Sbmspcap_open_live(const char *device, int snaplen, int promisc, int to_ms, 453127664Sbms char *ebuf) 45417683Spst{ 45517683Spst register char *cp; 45617683Spst register pcap_t *p; 45798530Sfenner int ppa; 458127664Sbms#ifdef HAVE_SOLARIS 459127664Sbms int isatm = 0; 460127664Sbms#endif 46117683Spst register dl_info_ack_t *infop; 46217683Spst#ifdef HAVE_SYS_BUFMOD_H 463127664Sbms bpf_u_int32 ss, chunksize; 46417683Spst#ifdef HAVE_SOLARIS 46517683Spst register char *release; 46617683Spst bpf_u_int32 osmajor, osminor, osmicro; 46717683Spst#endif 46817683Spst#endif 46917683Spst bpf_u_int32 buf[MAXDLBUF]; 47017683Spst char dname[100]; 47117683Spst#ifndef HAVE_DEV_DLPI 47217683Spst char dname2[100]; 47317683Spst#endif 47417683Spst 47517683Spst p = (pcap_t *)malloc(sizeof(*p)); 47617683Spst if (p == NULL) { 47775107Sfenner strlcpy(ebuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE); 47817683Spst return (NULL); 47917683Spst } 48017683Spst memset(p, 0, sizeof(*p)); 48198530Sfenner p->fd = -1; /* indicate that it hasn't been opened yet */ 482146768Ssam p->send_fd = -1; 48317683Spst 48475107Sfenner#ifdef HAVE_DEV_DLPI 48517683Spst /* 48675107Sfenner ** Remove any "/dev/" on the front of the device. 48717683Spst */ 48875107Sfenner cp = strrchr(device, '/'); 48975107Sfenner if (cp == NULL) 490127664Sbms strlcpy(dname, device, sizeof(dname)); 49175107Sfenner else 492127664Sbms strlcpy(dname, cp + 1, sizeof(dname)); 49375107Sfenner 49475107Sfenner /* 49598530Sfenner * Split the device name into a device type name and a unit number; 49698530Sfenner * chop off the unit number, so "dname" is just a device type name. 49775107Sfenner */ 49898530Sfenner cp = split_dname(dname, &ppa, ebuf); 49998530Sfenner if (cp == NULL) 50017683Spst goto bad; 50175107Sfenner *cp = '\0'; 50217683Spst 50375107Sfenner /* 50475107Sfenner * Use "/dev/dlpi" as the device. 50575107Sfenner * 50675107Sfenner * XXX - HP's DLPI Programmer's Guide for HP-UX 11.00 says that 50775107Sfenner * the "dl_mjr_num" field is for the "major number of interface 50875107Sfenner * driver"; that's the major of "/dev/dlpi" on the system on 50975107Sfenner * which I tried this, but there may be DLPI devices that 51075107Sfenner * use a different driver, in which case we may need to 51175107Sfenner * search "/dev" for the appropriate device with that major 51275107Sfenner * device number, rather than hardwiring "/dev/dlpi". 51375107Sfenner */ 51417683Spst cp = "/dev/dlpi"; 51517683Spst if ((p->fd = open(cp, O_RDWR)) < 0) { 51675107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 51775107Sfenner "%s: %s", cp, pcap_strerror(errno)); 51817683Spst goto bad; 51917683Spst } 52075107Sfenner 521146768Ssam#ifdef DL_HP_RAWDLS 52275107Sfenner /* 523146768Ssam * XXX - HP-UX 10.20 and 11.xx don't appear to support sending and 524147894Ssam * receiving packets on the same descriptor - you need separate 525147894Ssam * descriptors for sending and receiving, bound to different SAPs. 526146768Ssam * 527146768Ssam * If the open fails, we just leave -1 in "p->send_fd" and reject 528146768Ssam * attempts to send packets, just as if, in pcap-bpf.c, we fail 529146768Ssam * to open the BPF device for reading and writing, we just try 530146768Ssam * to open it for reading only and, if that succeeds, just let 531146768Ssam * the send attempts fail. 532146768Ssam */ 533146768Ssam p->send_fd = open(cp, O_RDWR); 534146768Ssam#endif 535146768Ssam 536146768Ssam /* 53775107Sfenner * Get a table of all PPAs for that device, and search that 53875107Sfenner * table for the specified device type name and unit number. 53975107Sfenner */ 54017683Spst ppa = get_dlpi_ppa(p->fd, dname, ppa, ebuf); 54117683Spst if (ppa < 0) 54217683Spst goto bad; 54317683Spst#else 54475107Sfenner /* 54598530Sfenner * If the device name begins with "/", assume it begins with 54698530Sfenner * the pathname of the directory containing the device to open; 54798530Sfenner * otherwise, concatenate the device directory name and the 54898530Sfenner * device name. 54998530Sfenner */ 55075107Sfenner if (*device == '/') 55175107Sfenner strlcpy(dname, device, sizeof(dname)); 55275107Sfenner else 55375107Sfenner snprintf(dname, sizeof(dname), "%s/%s", PCAP_DEV_PREFIX, 55475107Sfenner device); 55575107Sfenner 55698530Sfenner /* 557127664Sbms * Get the unit number, and a pointer to the end of the device 558127664Sbms * type name. 559127664Sbms */ 560127664Sbms cp = split_dname(dname, &ppa, ebuf); 561127664Sbms if (cp == NULL) 562127664Sbms goto bad; 563127664Sbms 564127664Sbms /* 56598530Sfenner * Make a copy of the device pathname, and then remove the unit 56698530Sfenner * number from the device pathname. 56798530Sfenner */ 56898530Sfenner strlcpy(dname2, dname, sizeof(dname)); 569127664Sbms *cp = '\0'; 57098530Sfenner 57117683Spst /* Try device without unit number */ 57217683Spst if ((p->fd = open(dname, O_RDWR)) < 0) { 57317683Spst if (errno != ENOENT) { 57475107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s: %s", dname, 57575107Sfenner pcap_strerror(errno)); 57617683Spst goto bad; 57717683Spst } 57817683Spst 57917683Spst /* Try again with unit number */ 58017683Spst if ((p->fd = open(dname2, O_RDWR)) < 0) { 581146768Ssam if (errno == ENOENT) { 582146768Ssam /* 583146768Ssam * We just report "No DLPI device found" 584146768Ssam * with the device name, so people don't 585146768Ssam * get confused and think, for example, 586146768Ssam * that if they can't capture on "lo0" 587146768Ssam * on Solaris the fix is to change libpcap 588146768Ssam * (or the application that uses it) to 589146768Ssam * look for something other than "/dev/lo0", 590146768Ssam * as the fix is to look for an operating 591146768Ssam * system other than Solaris - you just 592146768Ssam * *can't* capture on a loopback interface 593146768Ssam * on Solaris, the lack of a DLPI device 594146768Ssam * for the loopback interface is just a 595146768Ssam * symptom of that inability. 596146768Ssam */ 597146768Ssam snprintf(ebuf, PCAP_ERRBUF_SIZE, 598146768Ssam "%s: No DLPI device found", device); 599146768Ssam } else { 600146768Ssam snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s: %s", 601146768Ssam dname2, pcap_strerror(errno)); 602146768Ssam } 60317683Spst goto bad; 60417683Spst } 60517683Spst /* XXX Assume unit zero */ 60617683Spst ppa = 0; 60717683Spst } 60817683Spst#endif 60917683Spst 61017683Spst p->snapshot = snaplen; 61117683Spst 61217683Spst /* 61317683Spst ** Attach if "style 2" provider 61417683Spst */ 61517683Spst if (dlinforeq(p->fd, ebuf) < 0 || 61617683Spst dlinfoack(p->fd, (char *)buf, ebuf) < 0) 61717683Spst goto bad; 61817683Spst infop = &((union DL_primitives *)buf)->info_ack; 619127664Sbms#ifdef HAVE_SOLARIS 620127664Sbms if (infop->dl_mac_type == DL_IPATM) 621127664Sbms isatm = 1; 622127664Sbms#endif 623146768Ssam if (infop->dl_provider_style == DL_STYLE2) { 624146768Ssam if (dl_doattach(p->fd, ppa, ebuf) < 0) 625146768Ssam goto bad; 626146768Ssam#ifdef DL_HP_RAWDLS 627146768Ssam if (p->send_fd >= 0) { 628146768Ssam if (dl_doattach(p->send_fd, ppa, ebuf) < 0) 629146768Ssam goto bad; 630146768Ssam } 631146768Ssam#endif 632146768Ssam } 633146768Ssam 63417683Spst /* 635147894Ssam ** Bind (defer if using HP-UX 9 or HP-UX 10.20 or later, totally 636147894Ssam ** skip if using SINIX) 63717683Spst */ 638147894Ssam#if !defined(HAVE_HPUX9) && !defined(HAVE_HPUX10_20_OR_LATER) && !defined(sinix) 63975107Sfenner#ifdef _AIX 640147894Ssam /* 641147894Ssam ** AIX. 642147894Ssam ** According to IBM's AIX Support Line, the dl_sap value 64398530Sfenner ** should not be less than 0x600 (1536) for standard Ethernet. 64498530Sfenner ** However, we seem to get DL_BADADDR - "DLSAP addr in improper 64598530Sfenner ** format or invalid" - errors if we use 1537 on the "tr0" 64698530Sfenner ** device, which, given that its name starts with "tr" and that 64798530Sfenner ** it's IBM, probably means a Token Ring device. (Perhaps we 64898530Sfenner ** need to use 1537 on "/dev/dlpi/en" because that device is for 64998530Sfenner ** D/I/X Ethernet, the "SAP" is actually an Ethernet type, and 65098530Sfenner ** it rejects invalid Ethernet types.) 65198530Sfenner ** 65298530Sfenner ** So if 1537 fails, we try 2, as Hyung Sik Yoon of IBM Korea 65398530Sfenner ** says that works on Token Ring (he says that 0 does *not* 65498530Sfenner ** work; perhaps that's considered an invalid LLC SAP value - I 65598530Sfenner ** assume the SAP value in a DLPI bind is an LLC SAP for network 65698530Sfenner ** types that use 802.2 LLC). 65798530Sfenner */ 65898530Sfenner if ((dlbindreq(p->fd, 1537, ebuf) < 0 && 65998530Sfenner dlbindreq(p->fd, 2, ebuf) < 0) || 660147894Ssam dlbindack(p->fd, (char *)buf, ebuf, NULL) < 0) 661146768Ssam goto bad; 662146768Ssam#elif defined(DL_HP_RAWDLS) 663146768Ssam /* 664147894Ssam ** HP-UX 10.0x and 10.1x. 665146768Ssam */ 666147894Ssam if (dl_dohpuxbind(p->fd, ebuf) < 0) 667146768Ssam goto bad; 668146768Ssam if (p->send_fd >= 0) { 669146768Ssam /* 670147894Ssam ** XXX - if this fails, just close send_fd and 671147894Ssam ** set it to -1, so that you can't send but can 672147894Ssam ** still receive? 673146768Ssam */ 674147894Ssam if (dl_dohpuxbind(p->send_fd, ebuf) < 0) 675146768Ssam goto bad; 676146768Ssam } 677146768Ssam#else /* neither AIX nor HP-UX */ 678147894Ssam /* 679147894Ssam ** Not Sinix, and neither AIX nor HP-UX - Solaris, and any other 680147894Ssam ** OS using DLPI. 681147894Ssam **/ 68217683Spst if (dlbindreq(p->fd, 0, ebuf) < 0 || 683147894Ssam dlbindack(p->fd, (char *)buf, ebuf, NULL) < 0) 68417683Spst goto bad; 685147894Ssam#endif /* AIX vs. HP-UX vs. other */ 686147894Ssam#endif /* !HP-UX 9 and !HP-UX 10.20 or later and !SINIX */ 68717683Spst 688127664Sbms#ifdef HAVE_SOLARIS 689127664Sbms if (isatm) { 690127664Sbms /* 691127664Sbms ** Have to turn on some special ATM promiscuous mode 692127664Sbms ** for SunATM. 693127664Sbms ** Do *NOT* turn regular promiscuous mode on; it doesn't 694127664Sbms ** help, and may break things. 695127664Sbms */ 696127664Sbms if (strioctl(p->fd, A_PROMISCON_REQ, 0, NULL) < 0) { 697127664Sbms snprintf(ebuf, PCAP_ERRBUF_SIZE, "A_PROMISCON_REQ: %s", 698127664Sbms pcap_strerror(errno)); 699127664Sbms goto bad; 700127664Sbms } 701127664Sbms } else 702127664Sbms#endif 70317683Spst if (promisc) { 70417683Spst /* 705146768Ssam ** Enable promiscuous (not necessary on send FD) 70617683Spst */ 70717683Spst if (dlpromisconreq(p->fd, DL_PROMISC_PHYS, ebuf) < 0 || 70817683Spst dlokack(p->fd, "promisc_phys", (char *)buf, ebuf) < 0) 70917683Spst goto bad; 71017683Spst 71117683Spst /* 71217683Spst ** Try to enable multicast (you would have thought 71339291Sfenner ** promiscuous would be sufficient). (Skip if using 714146768Ssam ** HP-UX or SINIX) (Not necessary on send FD) 71517683Spst */ 71639291Sfenner#if !defined(__hpux) && !defined(sinix) 71717683Spst if (dlpromisconreq(p->fd, DL_PROMISC_MULTI, ebuf) < 0 || 71817683Spst dlokack(p->fd, "promisc_multi", (char *)buf, ebuf) < 0) 71917683Spst fprintf(stderr, 72017683Spst "WARNING: DL_PROMISC_MULTI failed (%s)\n", ebuf); 72117683Spst#endif 72217683Spst } 72317683Spst /* 724147894Ssam ** Try to enable SAP promiscuity (when not in promiscuous mode 725147894Ssam ** when using HP-UX, when not doing SunATM on Solaris, and never 726146768Ssam ** under SINIX) (Not necessary on send FD) 72717683Spst */ 72817683Spst#ifndef sinix 72939291Sfenner if ( 73039291Sfenner#ifdef __hpux 73139291Sfenner !promisc && 73239291Sfenner#endif 733127664Sbms#ifdef HAVE_SOLARIS 734127664Sbms !isatm && 735127664Sbms#endif 73639291Sfenner (dlpromisconreq(p->fd, DL_PROMISC_SAP, ebuf) < 0 || 73739291Sfenner dlokack(p->fd, "promisc_sap", (char *)buf, ebuf) < 0)) { 73817683Spst /* Not fatal if promisc since the DL_PROMISC_PHYS worked */ 73917683Spst if (promisc) 74017683Spst fprintf(stderr, 74117683Spst "WARNING: DL_PROMISC_SAP failed (%s)\n", ebuf); 74217683Spst else 74317683Spst goto bad; 74417683Spst } 745147894Ssam#endif /* sinix */ 74617683Spst 74717683Spst /* 748147894Ssam ** HP-UX 9, and HP-UX 10.20 or later, must bind after setting 749147894Ssam ** promiscuous options. 75017683Spst */ 751147894Ssam#if defined(HAVE_HPUX9) || defined(HAVE_HPUX10_20_OR_LATER) 752147894Ssam if (dl_dohpuxbind(p->fd, ebuf) < 0) 75317683Spst goto bad; 754147894Ssam /* 755147894Ssam ** We don't set promiscuous mode on the send FD, but we'll defer 756147894Ssam ** binding it anyway, just to keep the HP-UX 9/10.20 or later 757147894Ssam ** code together. 758147894Ssam */ 759147894Ssam if (p->send_fd >= 0) { 760147894Ssam /* 761147894Ssam ** XXX - if this fails, just close send_fd and 762147894Ssam ** set it to -1, so that you can't send but can 763147894Ssam ** still receive? 764147894Ssam */ 765147894Ssam if (dl_dohpuxbind(p->send_fd, ebuf) < 0) 766147894Ssam goto bad; 767147894Ssam } 76817683Spst#endif 76917683Spst 77017683Spst /* 77117683Spst ** Determine link type 772146768Ssam ** XXX - get SAP length and address length as well, for use 773146768Ssam ** when sending packets. 77417683Spst */ 77517683Spst if (dlinforeq(p->fd, ebuf) < 0 || 77617683Spst dlinfoack(p->fd, (char *)buf, ebuf) < 0) 77717683Spst goto bad; 77817683Spst 77917683Spst infop = &((union DL_primitives *)buf)->info_ack; 78017683Spst switch (infop->dl_mac_type) { 78117683Spst 78217683Spst case DL_CSMACD: 78317683Spst case DL_ETHER: 78417683Spst p->linktype = DLT_EN10MB; 78517683Spst p->offset = 2; 786146768Ssam /* 787146768Ssam * This is (presumably) a real Ethernet capture; give it a 788146768Ssam * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so 789146768Ssam * that an application can let you choose it, in case you're 790146768Ssam * capturing DOCSIS traffic that a Cisco Cable Modem 791146768Ssam * Termination System is putting out onto an Ethernet (it 792146768Ssam * doesn't put an Ethernet header onto the wire, it puts raw 793146768Ssam * DOCSIS frames out on the wire inside the low-level 794146768Ssam * Ethernet framing). 795146768Ssam */ 796146768Ssam p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); 797146768Ssam /* 798146768Ssam * If that fails, just leave the list empty. 799146768Ssam */ 800146768Ssam if (p->dlt_list != NULL) { 801146768Ssam p->dlt_list[0] = DLT_EN10MB; 802146768Ssam p->dlt_list[1] = DLT_DOCSIS; 803146768Ssam p->dlt_count = 2; 804146768Ssam } 80517683Spst break; 80617683Spst 80717683Spst case DL_FDDI: 80817683Spst p->linktype = DLT_FDDI; 80939291Sfenner p->offset = 3; 81017683Spst break; 81117683Spst 81298530Sfenner case DL_TPR: 813146768Ssam /* 814146768Ssam * XXX - what about DL_TPB? Is that Token Bus? 815146768Ssam */ 81698530Sfenner p->linktype = DLT_IEEE802; 81798530Sfenner p->offset = 2; 81898530Sfenner break; 81998530Sfenner 820127664Sbms#ifdef HAVE_SOLARIS 821127664Sbms case DL_IPATM: 822127664Sbms p->linktype = DLT_SUNATM; 823127664Sbms p->offset = 0; /* works for LANE and LLC encapsulation */ 824127664Sbms break; 825127664Sbms#endif 826127664Sbms 82717683Spst default: 82875107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "unknown mac type %lu", 829127664Sbms (unsigned long)infop->dl_mac_type); 83017683Spst goto bad; 83117683Spst } 83217683Spst 83317683Spst#ifdef DLIOCRAW 83417683Spst /* 835127664Sbms ** This is a non standard SunOS hack to get the full raw link-layer 836127664Sbms ** header. 83717683Spst */ 83817683Spst if (strioctl(p->fd, DLIOCRAW, 0, NULL) < 0) { 83975107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "DLIOCRAW: %s", 84075107Sfenner pcap_strerror(errno)); 84117683Spst goto bad; 84217683Spst } 84317683Spst#endif 84417683Spst 84517683Spst#ifdef HAVE_SYS_BUFMOD_H 84617683Spst /* 84717683Spst ** Another non standard call to get the data nicely buffered 84817683Spst */ 84917683Spst if (ioctl(p->fd, I_PUSH, "bufmod") != 0) { 85075107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "I_PUSH bufmod: %s", 85175107Sfenner pcap_strerror(errno)); 85217683Spst goto bad; 85317683Spst } 85417683Spst 85517683Spst /* 85617683Spst ** Now that the bufmod is pushed lets configure it. 85717683Spst ** 85817683Spst ** There is a bug in bufmod(7). When dealing with messages of 85917683Spst ** less than snaplen size it strips data from the beginning not 86017683Spst ** the end. 86117683Spst ** 86217683Spst ** This bug is supposed to be fixed in 5.3.2. Also, there is a 86317683Spst ** patch available. Ask for bugid 1149065. 86417683Spst */ 86517683Spst ss = snaplen; 86617683Spst#ifdef HAVE_SOLARIS 86717683Spst release = get_release(&osmajor, &osminor, &osmicro); 86817683Spst if (osmajor == 5 && (osminor <= 2 || (osminor == 3 && osmicro < 2)) && 86917683Spst getenv("BUFMOD_FIXED") == NULL) { 87017683Spst fprintf(stderr, 87117683Spst "WARNING: bufmod is broken in SunOS %s; ignoring snaplen.\n", 87217683Spst release); 87317683Spst ss = 0; 87417683Spst } 87517683Spst#endif 87617683Spst if (ss > 0 && 87717683Spst strioctl(p->fd, SBIOCSSNAP, sizeof(ss), (char *)&ss) != 0) { 87875107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "SBIOCSSNAP: %s", 87975107Sfenner pcap_strerror(errno)); 88017683Spst goto bad; 88117683Spst } 88217683Spst 88317683Spst /* 88417683Spst ** Set up the bufmod timeout 88517683Spst */ 88617683Spst if (to_ms != 0) { 88717683Spst struct timeval to; 88817683Spst 88917683Spst to.tv_sec = to_ms / 1000; 89017683Spst to.tv_usec = (to_ms * 1000) % 1000000; 89117683Spst if (strioctl(p->fd, SBIOCSTIME, sizeof(to), (char *)&to) != 0) { 89275107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "SBIOCSTIME: %s", 89375107Sfenner pcap_strerror(errno)); 89417683Spst goto bad; 89517683Spst } 89617683Spst } 897127664Sbms 898127664Sbms /* 899127664Sbms ** Set the chunk length. 900127664Sbms */ 901127664Sbms chunksize = CHUNKSIZE; 902127664Sbms if (strioctl(p->fd, SBIOCSCHUNK, sizeof(chunksize), (char *)&chunksize) 903127664Sbms != 0) { 904127664Sbms snprintf(ebuf, PCAP_ERRBUF_SIZE, "SBIOCSCHUNKP: %s", 905127664Sbms pcap_strerror(errno)); 906127664Sbms goto bad; 907127664Sbms } 90817683Spst#endif 90917683Spst 91017683Spst /* 91117683Spst ** As the last operation flush the read side. 91217683Spst */ 91317683Spst if (ioctl(p->fd, I_FLUSH, FLUSHR) != 0) { 91475107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "FLUSHR: %s", 91575107Sfenner pcap_strerror(errno)); 91617683Spst goto bad; 91717683Spst } 918127664Sbms 91917683Spst /* Allocate data buffer */ 920127664Sbms p->bufsize = PKTBUFSIZE; 92117683Spst p->buffer = (u_char *)malloc(p->bufsize + p->offset); 922127664Sbms if (p->buffer == NULL) { 923127664Sbms strlcpy(ebuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE); 924127664Sbms goto bad; 925127664Sbms } 92617683Spst 927127664Sbms /* 928127664Sbms * "p->fd" is an FD for a STREAMS device, so "select()" and 929127664Sbms * "poll()" should work on it. 930127664Sbms */ 931127664Sbms p->selectable_fd = p->fd; 932127664Sbms 933127664Sbms p->read_op = pcap_read_dlpi; 934146768Ssam p->inject_op = pcap_inject_dlpi; 935127664Sbms p->setfilter_op = install_bpf_program; /* no kernel filtering */ 936147894Ssam p->setdirection_op = NULL; /* Not implemented.*/ 937127664Sbms p->set_datalink_op = NULL; /* can't change data link type */ 938127664Sbms p->getnonblock_op = pcap_getnonblock_fd; 939127664Sbms p->setnonblock_op = pcap_setnonblock_fd; 940127664Sbms p->stats_op = pcap_stats_dlpi; 941127664Sbms p->close_op = pcap_close_dlpi; 942127664Sbms 94317683Spst return (p); 94417683Spstbad: 94598530Sfenner if (p->fd >= 0) 94698530Sfenner close(p->fd); 947146768Ssam if (p->send_fd >= 0) 948146768Ssam close(p->send_fd); 949146768Ssam /* 950146768Ssam * Get rid of any link-layer type list we allocated. 951146768Ssam */ 952146768Ssam if (p->dlt_list != NULL) 953146768Ssam free(p->dlt_list); 95417683Spst free(p); 95517683Spst return (NULL); 95617683Spst} 95717683Spst 95898530Sfenner/* 95998530Sfenner * Split a device name into a device type name and a unit number; 96098530Sfenner * return the a pointer to the beginning of the unit number, which 96198530Sfenner * is the end of the device type name, and set "*unitp" to the unit 96298530Sfenner * number. 96398530Sfenner * 96498530Sfenner * Returns NULL on error, and fills "ebuf" with an error message. 96598530Sfenner */ 96698530Sfennerstatic char * 96798530Sfennersplit_dname(char *device, int *unitp, char *ebuf) 96898530Sfenner{ 96998530Sfenner char *cp; 97098530Sfenner char *eos; 971146768Ssam long unit; 97298530Sfenner 97398530Sfenner /* 97498530Sfenner * Look for a number at the end of the device name string. 97598530Sfenner */ 97698530Sfenner cp = device + strlen(device) - 1; 97798530Sfenner if (*cp < '0' || *cp > '9') { 97898530Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s missing unit number", 97998530Sfenner device); 98098530Sfenner return (NULL); 98198530Sfenner } 98298530Sfenner 98398530Sfenner /* Digits at end of string are unit number */ 98498530Sfenner while (cp-1 >= device && *(cp-1) >= '0' && *(cp-1) <= '9') 98598530Sfenner cp--; 98698530Sfenner 987146768Ssam errno = 0; 98898530Sfenner unit = strtol(cp, &eos, 10); 98998530Sfenner if (*eos != '\0') { 99098530Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s bad unit number", device); 99198530Sfenner return (NULL); 99298530Sfenner } 993146768Ssam if (errno == ERANGE || unit > INT_MAX) { 994146768Ssam snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s unit number too large", 995146768Ssam device); 996146768Ssam return (NULL); 997146768Ssam } 998146768Ssam if (unit < 0) { 999146768Ssam snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s unit number is negative", 1000146768Ssam device); 1001146768Ssam return (NULL); 1002146768Ssam } 1003146768Ssam *unitp = (int)unit; 100498530Sfenner return (cp); 100598530Sfenner} 100698530Sfenner 1007146768Ssamstatic int 1008146768Ssamdl_doattach(int fd, int ppa, char *ebuf) 1009146768Ssam{ 1010146768Ssam bpf_u_int32 buf[MAXDLBUF]; 1011146768Ssam 1012146768Ssam if (dlattachreq(fd, ppa, ebuf) < 0 || 1013146768Ssam dlokack(fd, "attach", (char *)buf, ebuf) < 0) 1014146768Ssam return (-1); 1015146768Ssam return (0); 1016146768Ssam} 1017146768Ssam 1018147894Ssam#ifdef DL_HP_RAWDLS 1019147894Ssamstatic int 1020147894Ssamdl_dohpuxbind(int fd, char *ebuf) 1021147894Ssam{ 1022147894Ssam int hpsap; 1023147894Ssam int uerror; 1024147894Ssam bpf_u_int32 buf[MAXDLBUF]; 1025147894Ssam 1026147894Ssam /* 1027147894Ssam * XXX - we start at 22 because we used to use only 22, but 1028147894Ssam * that was just because that was the value used in some 1029147894Ssam * sample code from HP. With what value *should* we start? 1030147894Ssam * Does it matter, given that we're enabling SAP promiscuity 1031147894Ssam * on the input FD? 1032147894Ssam */ 1033147894Ssam hpsap = 22; 1034147894Ssam for (;;) { 1035147894Ssam if (dlbindreq(fd, hpsap, ebuf) < 0) 1036147894Ssam return (-1); 1037147894Ssam if (dlbindack(fd, (char *)buf, ebuf, &uerror) >= 0) 1038147894Ssam break; 1039147894Ssam /* 1040147894Ssam * For any error other than a UNIX EBUSY, give up. 1041147894Ssam */ 1042147894Ssam if (uerror != EBUSY) 1043147894Ssam return (-1); 1044147894Ssam 1045147894Ssam /* 1046147894Ssam * For EBUSY, try the next SAP value; that means that 1047147894Ssam * somebody else is using that SAP. Clear ebuf so 1048147894Ssam * that application doesn't report the "Device busy" 1049147894Ssam * error as a warning. 1050147894Ssam */ 1051147894Ssam *ebuf = '\0'; 1052147894Ssam hpsap++; 1053147894Ssam if (hpsap > 100) 1054147894Ssam return (-1); 1055147894Ssam } 1056147894Ssam} 1057147894Ssam#endif 1058147894Ssam 105917683Spstint 1060127664Sbmspcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf) 106117683Spst{ 1062127664Sbms#ifdef HAVE_SOLARIS 1063127664Sbms int fd; 1064127664Sbms union { 1065127664Sbms u_int nunits; 1066127664Sbms char pad[516]; /* XXX - must be at least 513; is 516 1067127664Sbms in "atmgetunits" */ 1068127664Sbms } buf; 1069127664Sbms char baname[2+1+1]; 1070127664Sbms u_int i; 107117683Spst 1072127664Sbms /* 1073127664Sbms * We may have to do special magic to get ATM devices. 1074127664Sbms */ 1075127664Sbms if ((fd = open("/dev/ba", O_RDWR)) < 0) { 1076127664Sbms /* 1077127664Sbms * We couldn't open the "ba" device. 1078127664Sbms * For now, just give up; perhaps we should 1079127664Sbms * return an error if the problem is neither 1080127664Sbms * a "that device doesn't exist" error (ENOENT, 1081127664Sbms * ENXIO, etc.) or a "you're not allowed to do 1082127664Sbms * that" error (EPERM, EACCES). 1083127664Sbms */ 1084127664Sbms return (0); 1085127664Sbms } 1086127664Sbms 1087127664Sbms if (strioctl(fd, A_GET_UNITS, sizeof(buf), (char *)&buf) < 0) { 1088127664Sbms snprintf(errbuf, PCAP_ERRBUF_SIZE, "A_GET_UNITS: %s", 1089127664Sbms pcap_strerror(errno)); 109075107Sfenner return (-1); 1091127664Sbms } 1092127664Sbms for (i = 0; i < buf.nunits; i++) { 1093127664Sbms snprintf(baname, sizeof baname, "ba%u", i); 1094127664Sbms if (pcap_add_if(alldevsp, baname, 0, NULL, errbuf) < 0) 1095127664Sbms return (-1); 1096127664Sbms } 1097127664Sbms#endif 1098127664Sbms 109917683Spst return (0); 110017683Spst} 110117683Spst 110217683Spststatic int 110317683Spstsend_request(int fd, char *ptr, int len, char *what, char *ebuf) 110417683Spst{ 110517683Spst struct strbuf ctl; 110617683Spst int flags; 110717683Spst 110817683Spst ctl.maxlen = 0; 110917683Spst ctl.len = len; 111017683Spst ctl.buf = ptr; 111117683Spst 111217683Spst flags = 0; 111317683Spst if (putmsg(fd, &ctl, (struct strbuf *) NULL, flags) < 0) { 111475107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 111575107Sfenner "send_request: putmsg \"%s\": %s", 111617683Spst what, pcap_strerror(errno)); 111717683Spst return (-1); 111817683Spst } 111917683Spst return (0); 112017683Spst} 112117683Spst 112217683Spststatic int 1123147894Ssamrecv_ack(int fd, int size, const char *what, char *bufp, char *ebuf, int *uerror) 112417683Spst{ 112517683Spst union DL_primitives *dlp; 112617683Spst struct strbuf ctl; 112717683Spst int flags; 112817683Spst 112917683Spst ctl.maxlen = MAXDLBUF; 113017683Spst ctl.len = 0; 113117683Spst ctl.buf = bufp; 113217683Spst 113317683Spst flags = 0; 113417683Spst if (getmsg(fd, &ctl, (struct strbuf*)NULL, &flags) < 0) { 113575107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "recv_ack: %s getmsg: %s", 113617683Spst what, pcap_strerror(errno)); 113717683Spst return (-1); 113817683Spst } 113917683Spst 114017683Spst dlp = (union DL_primitives *) ctl.buf; 114117683Spst switch (dlp->dl_primitive) { 114217683Spst 114317683Spst case DL_INFO_ACK: 114417683Spst case DL_BIND_ACK: 114517683Spst case DL_OK_ACK: 114617683Spst#ifdef DL_HP_PPA_ACK 114717683Spst case DL_HP_PPA_ACK: 114817683Spst#endif 114917683Spst /* These are OK */ 115017683Spst break; 115117683Spst 115217683Spst case DL_ERROR_ACK: 115317683Spst switch (dlp->error_ack.dl_errno) { 115417683Spst 115598530Sfenner case DL_SYSERR: 1156147894Ssam if (uerror != NULL) 1157147894Ssam *uerror = dlp->error_ack.dl_unix_errno; 115875107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 115998530Sfenner "recv_ack: %s: UNIX error - %s", 116017683Spst what, pcap_strerror(dlp->error_ack.dl_unix_errno)); 116117683Spst break; 116217683Spst 116317683Spst default: 1164147894Ssam if (uerror != NULL) 1165147894Ssam *uerror = 0; 116698530Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "recv_ack: %s: %s", 116798530Sfenner what, dlstrerror(dlp->error_ack.dl_errno)); 116817683Spst break; 116917683Spst } 117017683Spst return (-1); 117117683Spst 117217683Spst default: 1173147894Ssam if (uerror != NULL) 1174147894Ssam *uerror = 0; 117575107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 117698530Sfenner "recv_ack: %s: Unexpected primitive ack %s", 117798530Sfenner what, dlprim(dlp->dl_primitive)); 117817683Spst return (-1); 117917683Spst } 118017683Spst 118117683Spst if (ctl.len < size) { 1182147894Ssam if (uerror != NULL) 1183147894Ssam *uerror = 0; 118475107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 118598530Sfenner "recv_ack: %s: Ack too small (%d < %d)", 118617683Spst what, ctl.len, size); 118717683Spst return (-1); 118817683Spst } 118917683Spst return (ctl.len); 119017683Spst} 119117683Spst 119298530Sfennerstatic char * 119398530Sfennerdlstrerror(bpf_u_int32 dl_errno) 119498530Sfenner{ 119598530Sfenner static char errstring[6+2+8+1]; 119698530Sfenner 119798530Sfenner switch (dl_errno) { 119898530Sfenner 119998530Sfenner case DL_ACCESS: 120098530Sfenner return ("Improper permissions for request"); 120198530Sfenner 120298530Sfenner case DL_BADADDR: 120398530Sfenner return ("DLSAP addr in improper format or invalid"); 120498530Sfenner 120598530Sfenner case DL_BADCORR: 120698530Sfenner return ("Seq number not from outstand DL_CONN_IND"); 120798530Sfenner 120898530Sfenner case DL_BADDATA: 120998530Sfenner return ("User data exceeded provider limit"); 121098530Sfenner 121198530Sfenner case DL_BADPPA: 121298530Sfenner#ifdef HAVE_DEV_DLPI 121398530Sfenner /* 121498530Sfenner * With a single "/dev/dlpi" device used for all 121598530Sfenner * DLPI providers, PPAs have nothing to do with 121698530Sfenner * unit numbers. 121798530Sfenner */ 121898530Sfenner return ("Specified PPA was invalid"); 121998530Sfenner#else 122098530Sfenner /* 122198530Sfenner * We have separate devices for separate devices; 122298530Sfenner * the PPA is just the unit number. 122398530Sfenner */ 122498530Sfenner return ("Specified PPA (device unit) was invalid"); 122598530Sfenner#endif 122698530Sfenner 122798530Sfenner case DL_BADPRIM: 122898530Sfenner return ("Primitive received not known by provider"); 122998530Sfenner 123098530Sfenner case DL_BADQOSPARAM: 123198530Sfenner return ("QOS parameters contained invalid values"); 123298530Sfenner 123398530Sfenner case DL_BADQOSTYPE: 123498530Sfenner return ("QOS structure type is unknown/unsupported"); 123598530Sfenner 123698530Sfenner case DL_BADSAP: 123798530Sfenner return ("Bad LSAP selector"); 123898530Sfenner 123998530Sfenner case DL_BADTOKEN: 124098530Sfenner return ("Token used not an active stream"); 124198530Sfenner 124298530Sfenner case DL_BOUND: 124398530Sfenner return ("Attempted second bind with dl_max_conind"); 124498530Sfenner 124598530Sfenner case DL_INITFAILED: 124698530Sfenner return ("Physical link initialization failed"); 124798530Sfenner 124898530Sfenner case DL_NOADDR: 124998530Sfenner return ("Provider couldn't allocate alternate address"); 125098530Sfenner 125198530Sfenner case DL_NOTINIT: 125298530Sfenner return ("Physical link not initialized"); 125398530Sfenner 125498530Sfenner case DL_OUTSTATE: 125598530Sfenner return ("Primitive issued in improper state"); 125698530Sfenner 125798530Sfenner case DL_SYSERR: 125898530Sfenner return ("UNIX system error occurred"); 125998530Sfenner 126098530Sfenner case DL_UNSUPPORTED: 126198530Sfenner return ("Requested service not supplied by provider"); 126298530Sfenner 126398530Sfenner case DL_UNDELIVERABLE: 126498530Sfenner return ("Previous data unit could not be delivered"); 126598530Sfenner 126698530Sfenner case DL_NOTSUPPORTED: 126798530Sfenner return ("Primitive is known but not supported"); 126898530Sfenner 126998530Sfenner case DL_TOOMANY: 127098530Sfenner return ("Limit exceeded"); 127198530Sfenner 127298530Sfenner case DL_NOTENAB: 127398530Sfenner return ("Promiscuous mode not enabled"); 127498530Sfenner 127598530Sfenner case DL_BUSY: 127698530Sfenner return ("Other streams for PPA in post-attached"); 127798530Sfenner 127898530Sfenner case DL_NOAUTO: 127998530Sfenner return ("Automatic handling XID&TEST not supported"); 128098530Sfenner 128198530Sfenner case DL_NOXIDAUTO: 128298530Sfenner return ("Automatic handling of XID not supported"); 128398530Sfenner 128498530Sfenner case DL_NOTESTAUTO: 128598530Sfenner return ("Automatic handling of TEST not supported"); 128698530Sfenner 128798530Sfenner case DL_XIDAUTO: 128898530Sfenner return ("Automatic handling of XID response"); 128998530Sfenner 129098530Sfenner case DL_TESTAUTO: 129198530Sfenner return ("Automatic handling of TEST response"); 129298530Sfenner 129398530Sfenner case DL_PENDING: 129498530Sfenner return ("Pending outstanding connect indications"); 129598530Sfenner 129698530Sfenner default: 129798530Sfenner sprintf(errstring, "Error %02x", dl_errno); 129898530Sfenner return (errstring); 129998530Sfenner } 130098530Sfenner} 130198530Sfenner 130298530Sfennerstatic char * 130398530Sfennerdlprim(bpf_u_int32 prim) 130498530Sfenner{ 130598530Sfenner static char primbuf[80]; 130698530Sfenner 130798530Sfenner switch (prim) { 130898530Sfenner 130998530Sfenner case DL_INFO_REQ: 131098530Sfenner return ("DL_INFO_REQ"); 131198530Sfenner 131298530Sfenner case DL_INFO_ACK: 131398530Sfenner return ("DL_INFO_ACK"); 131498530Sfenner 131598530Sfenner case DL_ATTACH_REQ: 131698530Sfenner return ("DL_ATTACH_REQ"); 131798530Sfenner 131898530Sfenner case DL_DETACH_REQ: 131998530Sfenner return ("DL_DETACH_REQ"); 132098530Sfenner 132198530Sfenner case DL_BIND_REQ: 132298530Sfenner return ("DL_BIND_REQ"); 132398530Sfenner 132498530Sfenner case DL_BIND_ACK: 132598530Sfenner return ("DL_BIND_ACK"); 132698530Sfenner 132798530Sfenner case DL_UNBIND_REQ: 132898530Sfenner return ("DL_UNBIND_REQ"); 132998530Sfenner 133098530Sfenner case DL_OK_ACK: 133198530Sfenner return ("DL_OK_ACK"); 133298530Sfenner 133398530Sfenner case DL_ERROR_ACK: 133498530Sfenner return ("DL_ERROR_ACK"); 133598530Sfenner 133698530Sfenner case DL_SUBS_BIND_REQ: 133798530Sfenner return ("DL_SUBS_BIND_REQ"); 133898530Sfenner 133998530Sfenner case DL_SUBS_BIND_ACK: 134098530Sfenner return ("DL_SUBS_BIND_ACK"); 134198530Sfenner 134298530Sfenner case DL_UNITDATA_REQ: 134398530Sfenner return ("DL_UNITDATA_REQ"); 134498530Sfenner 134598530Sfenner case DL_UNITDATA_IND: 134698530Sfenner return ("DL_UNITDATA_IND"); 134798530Sfenner 134898530Sfenner case DL_UDERROR_IND: 134998530Sfenner return ("DL_UDERROR_IND"); 135098530Sfenner 135198530Sfenner case DL_UDQOS_REQ: 135298530Sfenner return ("DL_UDQOS_REQ"); 135398530Sfenner 135498530Sfenner case DL_CONNECT_REQ: 135598530Sfenner return ("DL_CONNECT_REQ"); 135698530Sfenner 135798530Sfenner case DL_CONNECT_IND: 135898530Sfenner return ("DL_CONNECT_IND"); 135998530Sfenner 136098530Sfenner case DL_CONNECT_RES: 136198530Sfenner return ("DL_CONNECT_RES"); 136298530Sfenner 136398530Sfenner case DL_CONNECT_CON: 136498530Sfenner return ("DL_CONNECT_CON"); 136598530Sfenner 136698530Sfenner case DL_TOKEN_REQ: 136798530Sfenner return ("DL_TOKEN_REQ"); 136898530Sfenner 136998530Sfenner case DL_TOKEN_ACK: 137098530Sfenner return ("DL_TOKEN_ACK"); 137198530Sfenner 137298530Sfenner case DL_DISCONNECT_REQ: 137398530Sfenner return ("DL_DISCONNECT_REQ"); 137498530Sfenner 137598530Sfenner case DL_DISCONNECT_IND: 137698530Sfenner return ("DL_DISCONNECT_IND"); 137798530Sfenner 137898530Sfenner case DL_RESET_REQ: 137998530Sfenner return ("DL_RESET_REQ"); 138098530Sfenner 138198530Sfenner case DL_RESET_IND: 138298530Sfenner return ("DL_RESET_IND"); 138398530Sfenner 138498530Sfenner case DL_RESET_RES: 138598530Sfenner return ("DL_RESET_RES"); 138698530Sfenner 138798530Sfenner case DL_RESET_CON: 138898530Sfenner return ("DL_RESET_CON"); 138998530Sfenner 139098530Sfenner default: 139198530Sfenner (void) sprintf(primbuf, "unknown primitive 0x%x", prim); 139298530Sfenner return (primbuf); 139398530Sfenner } 139498530Sfenner} 139598530Sfenner 139617683Spststatic int 139717683Spstdlattachreq(int fd, bpf_u_int32 ppa, char *ebuf) 139817683Spst{ 139917683Spst dl_attach_req_t req; 140017683Spst 140117683Spst req.dl_primitive = DL_ATTACH_REQ; 140217683Spst req.dl_ppa = ppa; 140317683Spst 140417683Spst return (send_request(fd, (char *)&req, sizeof(req), "attach", ebuf)); 140517683Spst} 140617683Spst 140717683Spststatic int 140817683Spstdlbindreq(int fd, bpf_u_int32 sap, char *ebuf) 140917683Spst{ 141017683Spst 141117683Spst dl_bind_req_t req; 141217683Spst 141317683Spst memset((char *)&req, 0, sizeof(req)); 141417683Spst req.dl_primitive = DL_BIND_REQ; 1415147894Ssam /* XXX - what if neither of these are defined? */ 1416147894Ssam#if defined(DL_HP_RAWDLS) 141717683Spst req.dl_max_conind = 1; /* XXX magic number */ 141817683Spst req.dl_service_mode = DL_HP_RAWDLS; 1419147894Ssam#elif defined(DL_CLDLS) 142026175Sfenner req.dl_service_mode = DL_CLDLS; 142117683Spst#endif 1422147894Ssam req.dl_sap = sap; 142317683Spst 142417683Spst return (send_request(fd, (char *)&req, sizeof(req), "bind", ebuf)); 142517683Spst} 142617683Spst 142717683Spststatic int 1428147894Ssamdlbindack(int fd, char *bufp, char *ebuf, int *uerror) 142917683Spst{ 143017683Spst 1431147894Ssam return (recv_ack(fd, DL_BIND_ACK_SIZE, "bind", bufp, ebuf, uerror)); 143217683Spst} 143317683Spst 143417683Spststatic int 143517683Spstdlpromisconreq(int fd, bpf_u_int32 level, char *ebuf) 143617683Spst{ 143717683Spst dl_promiscon_req_t req; 143817683Spst 143917683Spst req.dl_primitive = DL_PROMISCON_REQ; 144017683Spst req.dl_level = level; 144117683Spst 144217683Spst return (send_request(fd, (char *)&req, sizeof(req), "promiscon", ebuf)); 144317683Spst} 144417683Spst 144517683Spststatic int 144617683Spstdlokack(int fd, const char *what, char *bufp, char *ebuf) 144717683Spst{ 144817683Spst 1449147894Ssam return (recv_ack(fd, DL_OK_ACK_SIZE, what, bufp, ebuf, NULL)); 145017683Spst} 145117683Spst 145217683Spst 145317683Spststatic int 145417683Spstdlinforeq(int fd, char *ebuf) 145517683Spst{ 145617683Spst dl_info_req_t req; 145717683Spst 145817683Spst req.dl_primitive = DL_INFO_REQ; 145917683Spst 146017683Spst return (send_request(fd, (char *)&req, sizeof(req), "info", ebuf)); 146117683Spst} 146217683Spst 146317683Spststatic int 146417683Spstdlinfoack(int fd, char *bufp, char *ebuf) 146517683Spst{ 146617683Spst 1467147894Ssam return (recv_ack(fd, DL_INFO_ACK_SIZE, "info", bufp, ebuf, NULL)); 146817683Spst} 146917683Spst 1470146768Ssam#ifdef DL_HP_RAWDLS 1471146768Ssam/* 1472146768Ssam * There's an ack *if* there's an error. 1473146768Ssam */ 1474146768Ssamstatic int 1475146768Ssamdlrawdatareq(int fd, const u_char *datap, int datalen) 1476146768Ssam{ 1477146768Ssam struct strbuf ctl, data; 1478146768Ssam long buf[MAXDLBUF]; /* XXX - char? */ 1479146768Ssam union DL_primitives *dlp; 1480146768Ssam int dlen; 1481146768Ssam 1482146768Ssam dlp = (union DL_primitives*) buf; 1483146768Ssam 1484146768Ssam dlp->dl_primitive = DL_HP_RAWDATA_REQ; 1485146768Ssam dlen = DL_HP_RAWDATA_REQ_SIZE; 1486146768Ssam 1487146768Ssam /* 1488146768Ssam * HP's documentation doesn't appear to show us supplying any 1489146768Ssam * address pointed to by the control part of the message. 1490146768Ssam * I think that's what raw mode means - you just send the raw 1491146768Ssam * packet, you don't specify where to send it to, as that's 1492146768Ssam * implied by the destination address. 1493146768Ssam */ 1494146768Ssam ctl.maxlen = 0; 1495146768Ssam ctl.len = dlen; 1496146768Ssam ctl.buf = (void *)buf; 1497146768Ssam 1498146768Ssam data.maxlen = 0; 1499146768Ssam data.len = datalen; 1500146768Ssam data.buf = (void *)datap; 1501146768Ssam 1502146768Ssam return (putmsg(fd, &ctl, &data, 0)); 1503146768Ssam} 1504146768Ssam#endif /* DL_HP_RAWDLS */ 1505146768Ssam 150617683Spst#ifdef HAVE_SYS_BUFMOD_H 150717683Spststatic int 150817683Spststrioctl(int fd, int cmd, int len, char *dp) 150917683Spst{ 151017683Spst struct strioctl str; 151117683Spst int rc; 151217683Spst 151317683Spst str.ic_cmd = cmd; 151417683Spst str.ic_timout = -1; 151517683Spst str.ic_len = len; 151617683Spst str.ic_dp = dp; 151717683Spst rc = ioctl(fd, I_STR, &str); 151817683Spst 151917683Spst if (rc < 0) 152017683Spst return (rc); 152117683Spst else 152217683Spst return (str.ic_len); 152317683Spst} 152417683Spst#endif 152517683Spst 152617683Spst#if defined(HAVE_SOLARIS) && defined(HAVE_SYS_BUFMOD_H) 152717683Spststatic char * 152817683Spstget_release(bpf_u_int32 *majorp, bpf_u_int32 *minorp, bpf_u_int32 *microp) 152917683Spst{ 153017683Spst char *cp; 153117683Spst static char buf[32]; 153217683Spst 153317683Spst *majorp = 0; 153417683Spst *minorp = 0; 153517683Spst *microp = 0; 153617683Spst if (sysinfo(SI_RELEASE, buf, sizeof(buf)) < 0) 153717683Spst return ("?"); 153817683Spst cp = buf; 153998530Sfenner if (!isdigit((unsigned char)*cp)) 154017683Spst return (buf); 154117683Spst *majorp = strtol(cp, &cp, 10); 154217683Spst if (*cp++ != '.') 154317683Spst return (buf); 154417683Spst *minorp = strtol(cp, &cp, 10); 154517683Spst if (*cp++ != '.') 154617683Spst return (buf); 154717683Spst *microp = strtol(cp, &cp, 10); 154817683Spst return (buf); 154917683Spst} 155017683Spst#endif 155117683Spst 1552146768Ssam#ifdef DL_HP_PPA_REQ 155317683Spst/* 155475107Sfenner * Under HP-UX 10 and HP-UX 11, we can ask for the ppa 155517683Spst */ 155617683Spst 155717683Spst 155875107Sfenner/* 155975107Sfenner * Determine ppa number that specifies ifname. 156075107Sfenner * 156175107Sfenner * If the "dl_hp_ppa_info_t" doesn't have a "dl_module_id_1" member, 156275107Sfenner * the code that's used here is the old code for HP-UX 10.x. 156375107Sfenner * 156475107Sfenner * However, HP-UX 10.20, at least, appears to have such a member 156575107Sfenner * in its "dl_hp_ppa_info_t" structure, so the new code is used. 156675107Sfenner * The new code didn't work on an old 10.20 system on which Rick 156775107Sfenner * Jones of HP tried it, but with later patches installed, it 156875107Sfenner * worked - it appears that the older system had those members but 156975107Sfenner * didn't put anything in them, so, if the search by name fails, we 157075107Sfenner * do the old search. 157175107Sfenner * 157275107Sfenner * Rick suggests that making sure your system is "up on the latest 157375107Sfenner * lancommon/DLPI/driver patches" is probably a good idea; it'd fix 157475107Sfenner * that problem, as well as allowing libpcap to see packets sent 157575107Sfenner * from the system on which the libpcap application is being run. 157675107Sfenner * (On 10.20, in addition to getting the latest patches, you need 157775107Sfenner * to turn the kernel "lanc_outbound_promisc_flag" flag on with ADB; 157875107Sfenner * a posting to "comp.sys.hp.hpux" at 157975107Sfenner * 158075107Sfenner * http://www.deja.com/[ST_rn=ps]/getdoc.xp?AN=558092266 158175107Sfenner * 158275107Sfenner * says that, to see the machine's outgoing traffic, you'd need to 158375107Sfenner * apply the right patches to your system, and also set that variable 158475107Sfenner * with: 1585127664Sbms 158675107Sfennerecho 'lanc_outbound_promisc_flag/W1' | /usr/bin/adb -w /stand/vmunix /dev/kmem 158775107Sfenner 158875107Sfenner * which could be put in, for example, "/sbin/init.d/lan". 158975107Sfenner * 159075107Sfenner * Setting the variable is not necessary on HP-UX 11.x. 159175107Sfenner */ 159217683Spststatic int 159317683Spstget_dlpi_ppa(register int fd, register const char *device, register int unit, 159417683Spst register char *ebuf) 159517683Spst{ 159617683Spst register dl_hp_ppa_ack_t *ap; 159775107Sfenner register dl_hp_ppa_info_t *ipstart, *ip; 159817683Spst register int i; 159975107Sfenner char dname[100]; 160017683Spst register u_long majdev; 160175107Sfenner struct stat statbuf; 160217683Spst dl_hp_ppa_req_t req; 160398530Sfenner char buf[MAXDLBUF]; 160498530Sfenner char *ppa_data_buf; 160598530Sfenner dl_hp_ppa_ack_t *dlp; 160698530Sfenner struct strbuf ctl; 160798530Sfenner int flags; 160898530Sfenner int ppa; 160917683Spst 161017683Spst memset((char *)&req, 0, sizeof(req)); 161117683Spst req.dl_primitive = DL_HP_PPA_REQ; 161217683Spst 161317683Spst memset((char *)buf, 0, sizeof(buf)); 161498530Sfenner if (send_request(fd, (char *)&req, sizeof(req), "hpppa", ebuf) < 0) 161517683Spst return (-1); 161617683Spst 161798530Sfenner ctl.maxlen = DL_HP_PPA_ACK_SIZE; 161898530Sfenner ctl.len = 0; 161998530Sfenner ctl.buf = (char *)buf; 162098530Sfenner 162198530Sfenner flags = 0; 162298530Sfenner /* 162398530Sfenner * DLPI may return a big chunk of data for a DL_HP_PPA_REQ. The normal 162498530Sfenner * recv_ack will fail because it set the maxlen to MAXDLBUF (8192) 162598530Sfenner * which is NOT big enough for a DL_HP_PPA_REQ. 162698530Sfenner * 162798530Sfenner * This causes libpcap applications to fail on a system with HP-APA 162898530Sfenner * installed. 162998530Sfenner * 163098530Sfenner * To figure out how big the returned data is, we first call getmsg 163198530Sfenner * to get the small head and peek at the head to get the actual data 163298530Sfenner * length, and then issue another getmsg to get the actual PPA data. 163398530Sfenner */ 163498530Sfenner /* get the head first */ 163598530Sfenner if (getmsg(fd, &ctl, (struct strbuf *)NULL, &flags) < 0) { 163698530Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 163798530Sfenner "get_dlpi_ppa: hpppa getmsg: %s", pcap_strerror(errno)); 163898530Sfenner return (-1); 163998530Sfenner } 164098530Sfenner 164198530Sfenner dlp = (dl_hp_ppa_ack_t *)ctl.buf; 164298530Sfenner if (dlp->dl_primitive != DL_HP_PPA_ACK) { 164398530Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 164498530Sfenner "get_dlpi_ppa: hpppa unexpected primitive ack 0x%x", 164598530Sfenner (bpf_u_int32)dlp->dl_primitive); 164698530Sfenner return (-1); 164798530Sfenner } 1648127664Sbms 164998530Sfenner if (ctl.len < DL_HP_PPA_ACK_SIZE) { 165098530Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 1651127664Sbms "get_dlpi_ppa: hpppa ack too small (%d < %lu)", 1652127664Sbms ctl.len, (unsigned long)DL_HP_PPA_ACK_SIZE); 165398530Sfenner return (-1); 165498530Sfenner } 1655127664Sbms 165698530Sfenner /* allocate buffer */ 165798530Sfenner if ((ppa_data_buf = (char *)malloc(dlp->dl_length)) == NULL) { 165898530Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 165998530Sfenner "get_dlpi_ppa: hpppa malloc: %s", pcap_strerror(errno)); 166098530Sfenner return (-1); 166198530Sfenner } 166298530Sfenner ctl.maxlen = dlp->dl_length; 166398530Sfenner ctl.len = 0; 166498530Sfenner ctl.buf = (char *)ppa_data_buf; 166598530Sfenner /* get the data */ 166698530Sfenner if (getmsg(fd, &ctl, (struct strbuf *)NULL, &flags) < 0) { 166798530Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 166898530Sfenner "get_dlpi_ppa: hpppa getmsg: %s", pcap_strerror(errno)); 166998530Sfenner free(ppa_data_buf); 167098530Sfenner return (-1); 167198530Sfenner } 167298530Sfenner if (ctl.len < dlp->dl_length) { 167398530Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 167498530Sfenner "get_dlpi_ppa: hpppa ack too small (%d < %d)", 167598530Sfenner ctl.len, dlp->dl_length); 167698530Sfenner free(ppa_data_buf); 167798530Sfenner return (-1); 167898530Sfenner } 167998530Sfenner 168017683Spst ap = (dl_hp_ppa_ack_t *)buf; 168198530Sfenner ipstart = (dl_hp_ppa_info_t *)ppa_data_buf; 168275107Sfenner ip = ipstart; 168317683Spst 168475107Sfenner#ifdef HAVE_HP_PPA_INFO_T_DL_MODULE_ID_1 168575107Sfenner /* 168675107Sfenner * The "dl_hp_ppa_info_t" structure has a "dl_module_id_1" 168775107Sfenner * member that should, in theory, contain the part of the 168875107Sfenner * name for the device that comes before the unit number, 168975107Sfenner * and should also have a "dl_module_id_2" member that may 169075107Sfenner * contain an alternate name (e.g., I think Ethernet devices 169175107Sfenner * have both "lan", for "lanN", and "snap", for "snapN", with 169275107Sfenner * the former being for Ethernet packets and the latter being 169375107Sfenner * for 802.3/802.2 packets). 169475107Sfenner * 169575107Sfenner * Search for the device that has the specified name and 169675107Sfenner * instance number. 169775107Sfenner */ 169875107Sfenner for (i = 0; i < ap->dl_count; i++) { 169998530Sfenner if ((strcmp((const char *)ip->dl_module_id_1, device) == 0 || 170098530Sfenner strcmp((const char *)ip->dl_module_id_2, device) == 0) && 170175107Sfenner ip->dl_instance_num == unit) 170275107Sfenner break; 170317683Spst 170475107Sfenner ip = (dl_hp_ppa_info_t *)((u_char *)ipstart + ip->dl_next_offset); 170575107Sfenner } 170675107Sfenner#else 170775107Sfenner /* 170875107Sfenner * We don't have that member, so the search is impossible; make it 170975107Sfenner * look as if the search failed. 171075107Sfenner */ 171175107Sfenner i = ap->dl_count; 171275107Sfenner#endif 171375107Sfenner 171475107Sfenner if (i == ap->dl_count) { 171575107Sfenner /* 171675107Sfenner * Well, we didn't, or can't, find the device by name. 171775107Sfenner * 171875107Sfenner * HP-UX 10.20, whilst it has "dl_module_id_1" and 171975107Sfenner * "dl_module_id_2" fields in the "dl_hp_ppa_info_t", 172075107Sfenner * doesn't seem to fill them in unless the system is 172175107Sfenner * at a reasonably up-to-date patch level. 172275107Sfenner * 172375107Sfenner * Older HP-UX 10.x systems might not have those fields 172475107Sfenner * at all. 172575107Sfenner * 172675107Sfenner * Therefore, we'll search for the entry with the major 172775107Sfenner * device number of a device with the name "/dev/<dev><unit>", 172875107Sfenner * if such a device exists, as the old code did. 172975107Sfenner */ 173075107Sfenner snprintf(dname, sizeof(dname), "/dev/%s%d", device, unit); 173175107Sfenner if (stat(dname, &statbuf) < 0) { 173275107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "stat: %s: %s", 173375107Sfenner dname, pcap_strerror(errno)); 173475107Sfenner return (-1); 173575107Sfenner } 173675107Sfenner majdev = major(statbuf.st_rdev); 173775107Sfenner 173875107Sfenner ip = ipstart; 173975107Sfenner 174075107Sfenner for (i = 0; i < ap->dl_count; i++) { 174175107Sfenner if (ip->dl_mjr_num == majdev && 174275107Sfenner ip->dl_instance_num == unit) 174375107Sfenner break; 174475107Sfenner 174575107Sfenner ip = (dl_hp_ppa_info_t *)((u_char *)ipstart + ip->dl_next_offset); 174675107Sfenner } 174775107Sfenner } 1748147894Ssam if (i == ap->dl_count) { 1749147894Ssam snprintf(ebuf, PCAP_ERRBUF_SIZE, 175075107Sfenner "can't find /dev/dlpi PPA for %s%d", device, unit); 175117683Spst return (-1); 1752147894Ssam } 1753147894Ssam if (ip->dl_hdw_state == HDW_DEAD) { 1754147894Ssam snprintf(ebuf, PCAP_ERRBUF_SIZE, 175575107Sfenner "%s%d: hardware state: DOWN\n", device, unit); 175698530Sfenner free(ppa_data_buf); 175717683Spst return (-1); 1758147894Ssam } 1759147894Ssam ppa = ip->dl_ppa; 1760147894Ssam free(ppa_data_buf); 1761147894Ssam return (ppa); 176217683Spst} 176317683Spst#endif 176417683Spst 176517683Spst#ifdef HAVE_HPUX9 176617683Spst/* 176717683Spst * Under HP-UX 9, there is no good way to determine the ppa. 176817683Spst * So punt and read it from /dev/kmem. 176917683Spst */ 177017683Spststatic struct nlist nl[] = { 177117683Spst#define NL_IFNET 0 177217683Spst { "ifnet" }, 177317683Spst { "" } 177417683Spst}; 177517683Spst 177617683Spststatic char path_vmunix[] = "/hp-ux"; 177717683Spst 177817683Spst/* Determine ppa number that specifies ifname */ 177917683Spststatic int 178017683Spstget_dlpi_ppa(register int fd, register const char *ifname, register int unit, 178117683Spst register char *ebuf) 178217683Spst{ 178317683Spst register const char *cp; 178417683Spst register int kd; 178517683Spst void *addr; 178617683Spst struct ifnet ifnet; 178775107Sfenner char if_name[sizeof(ifnet.if_name) + 1]; 178817683Spst 178917683Spst cp = strrchr(ifname, '/'); 179017683Spst if (cp != NULL) 179117683Spst ifname = cp + 1; 179217683Spst if (nlist(path_vmunix, &nl) < 0) { 179375107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "nlist %s failed", 179475107Sfenner path_vmunix); 179517683Spst return (-1); 179617683Spst } 179717683Spst if (nl[NL_IFNET].n_value == 0) { 179875107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 179975107Sfenner "could't find %s kernel symbol", 180017683Spst nl[NL_IFNET].n_name); 180117683Spst return (-1); 180217683Spst } 180317683Spst kd = open("/dev/kmem", O_RDONLY); 180417683Spst if (kd < 0) { 180575107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "kmem open: %s", 180675107Sfenner pcap_strerror(errno)); 180717683Spst return (-1); 180817683Spst } 180917683Spst if (dlpi_kread(kd, nl[NL_IFNET].n_value, 181017683Spst &addr, sizeof(addr), ebuf) < 0) { 181117683Spst close(kd); 181217683Spst return (-1); 181317683Spst } 181417683Spst for (; addr != NULL; addr = ifnet.if_next) { 181517683Spst if (dlpi_kread(kd, (off_t)addr, 181617683Spst &ifnet, sizeof(ifnet), ebuf) < 0 || 181717683Spst dlpi_kread(kd, (off_t)ifnet.if_name, 181875107Sfenner if_name, sizeof(ifnet.if_name), ebuf) < 0) { 181917683Spst (void)close(kd); 182017683Spst return (-1); 182117683Spst } 182275107Sfenner if_name[sizeof(ifnet.if_name)] = '\0'; 182375107Sfenner if (strcmp(if_name, ifname) == 0 && ifnet.if_unit == unit) 182417683Spst return (ifnet.if_index); 182517683Spst } 182617683Spst 182775107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "Can't find %s", ifname); 182817683Spst return (-1); 182917683Spst} 183017683Spst 183117683Spststatic int 183217683Spstdlpi_kread(register int fd, register off_t addr, 183317683Spst register void *buf, register u_int len, register char *ebuf) 183417683Spst{ 183517683Spst register int cc; 183617683Spst 183739291Sfenner if (lseek(fd, addr, SEEK_SET) < 0) { 183875107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "lseek: %s", 183975107Sfenner pcap_strerror(errno)); 184017683Spst return (-1); 184117683Spst } 184217683Spst cc = read(fd, buf, len); 184317683Spst if (cc < 0) { 184475107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "read: %s", 184575107Sfenner pcap_strerror(errno)); 184617683Spst return (-1); 184717683Spst } else if (cc != len) { 184875107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "short read (%d != %d)", cc, 184975107Sfenner len); 185017683Spst return (-1); 185117683Spst } 185217683Spst return (cc); 185317683Spst} 185417683Spst#endif 1855