pcap-dlpi.c revision 172677
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_ = 73172677Smlaier "@(#) $Header: /tcpdump/master/libpcap/pcap-dlpi.c,v 1.108.2.7 2006/04/04 05:33:02 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 } 399172677Smlaier /* 400172677Smlaier * putmsg() returns either 0 or -1; it doesn't indicate how 401172677Smlaier * many bytes were written (presumably they were all written 402172677Smlaier * or none of them were written). OpenBSD's pcap_inject() 403172677Smlaier * returns the number of bytes written, so, for API compatibility, 404172677Smlaier * we return the number of bytes we were told to write. 405172677Smlaier */ 406172677Smlaier ret = size; 407146768Ssam#else /* no raw mode */ 408146768Ssam /* 409146768Ssam * XXX - this is a pain, because you might have to extract 410146768Ssam * the address from the packet and use it in a DL_UNITDATA_REQ 411146768Ssam * request. That would be dependent on the link-layer type. 412146768Ssam * 413146768Ssam * I also don't know what SAP you'd have to bind the descriptor 414146768Ssam * to, or whether you'd need separate "receive" and "send" FDs, 415146768Ssam * nor do I know whether you'd need different bindings for 416146768Ssam * D/I/X Ethernet and 802.3, or for {FDDI,Token Ring} plus 417146768Ssam * 802.2 and {FDDI,Token Ring} plus 802.2 plus SNAP. 418146768Ssam * 419146768Ssam * So, for now, we just return a "you can't send" indication, 420146768Ssam * and leave it up to somebody with a DLPI-based system lacking 421146768Ssam * both DLIOCRAW and DL_HP_RAWDLS to supply code to implement 422146768Ssam * packet transmission on that system. If they do, they should 423146768Ssam * send it to us - but should not send us code that assumes 424146768Ssam * Ethernet; if the code doesn't work on non-Ethernet interfaces, 425146768Ssam * it should check "p->linktype" and reject the send request if 426146768Ssam * it's anything other than DLT_EN10MB. 427146768Ssam */ 428146768Ssam strlcpy(p->errbuf, "send: Not supported on this version of this OS", 429146768Ssam PCAP_ERRBUF_SIZE); 430146768Ssam ret = -1; 431146768Ssam#endif /* raw mode */ 432146768Ssam return (ret); 433147894Ssam} 434146768Ssam 435127664Sbms#ifndef DL_IPATM 436127664Sbms#define DL_IPATM 0x12 /* ATM Classical IP interface */ 437127664Sbms#endif 438127664Sbms 439127664Sbms#ifdef HAVE_SOLARIS 440127664Sbms/* 441127664Sbms * For SunATM. 442127664Sbms */ 443127664Sbms#ifndef A_GET_UNITS 444127664Sbms#define A_GET_UNITS (('A'<<8)|118) 445127664Sbms#endif /* A_GET_UNITS */ 446127664Sbms#ifndef A_PROMISCON_REQ 447127664Sbms#define A_PROMISCON_REQ (('A'<<8)|121) 448127664Sbms#endif /* A_PROMISCON_REQ */ 449127664Sbms#endif /* HAVE_SOLARIS */ 450127664Sbms 451127664Sbmsstatic void 452127664Sbmspcap_close_dlpi(pcap_t *p) 453127664Sbms{ 454146768Ssam pcap_close_common(p); 455146768Ssam if (p->send_fd >= 0) 456146768Ssam close(p->send_fd); 457127664Sbms} 458127664Sbms 45917683Spstpcap_t * 460127664Sbmspcap_open_live(const char *device, int snaplen, int promisc, int to_ms, 461127664Sbms char *ebuf) 46217683Spst{ 46317683Spst register char *cp; 46417683Spst register pcap_t *p; 46598530Sfenner int ppa; 466127664Sbms#ifdef HAVE_SOLARIS 467127664Sbms int isatm = 0; 468127664Sbms#endif 46917683Spst register dl_info_ack_t *infop; 47017683Spst#ifdef HAVE_SYS_BUFMOD_H 471127664Sbms bpf_u_int32 ss, chunksize; 47217683Spst#ifdef HAVE_SOLARIS 47317683Spst register char *release; 47417683Spst bpf_u_int32 osmajor, osminor, osmicro; 47517683Spst#endif 47617683Spst#endif 47717683Spst bpf_u_int32 buf[MAXDLBUF]; 47817683Spst char dname[100]; 47917683Spst#ifndef HAVE_DEV_DLPI 48017683Spst char dname2[100]; 48117683Spst#endif 48217683Spst 48317683Spst p = (pcap_t *)malloc(sizeof(*p)); 48417683Spst if (p == NULL) { 48575107Sfenner strlcpy(ebuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE); 48617683Spst return (NULL); 48717683Spst } 48817683Spst memset(p, 0, sizeof(*p)); 48998530Sfenner p->fd = -1; /* indicate that it hasn't been opened yet */ 490146768Ssam p->send_fd = -1; 49117683Spst 49275107Sfenner#ifdef HAVE_DEV_DLPI 49317683Spst /* 49475107Sfenner ** Remove any "/dev/" on the front of the device. 49517683Spst */ 49675107Sfenner cp = strrchr(device, '/'); 49775107Sfenner if (cp == NULL) 498127664Sbms strlcpy(dname, device, sizeof(dname)); 49975107Sfenner else 500127664Sbms strlcpy(dname, cp + 1, sizeof(dname)); 50175107Sfenner 50275107Sfenner /* 50398530Sfenner * Split the device name into a device type name and a unit number; 50498530Sfenner * chop off the unit number, so "dname" is just a device type name. 50575107Sfenner */ 50698530Sfenner cp = split_dname(dname, &ppa, ebuf); 50798530Sfenner if (cp == NULL) 50817683Spst goto bad; 50975107Sfenner *cp = '\0'; 51017683Spst 51175107Sfenner /* 51275107Sfenner * Use "/dev/dlpi" as the device. 51375107Sfenner * 51475107Sfenner * XXX - HP's DLPI Programmer's Guide for HP-UX 11.00 says that 51575107Sfenner * the "dl_mjr_num" field is for the "major number of interface 51675107Sfenner * driver"; that's the major of "/dev/dlpi" on the system on 51775107Sfenner * which I tried this, but there may be DLPI devices that 51875107Sfenner * use a different driver, in which case we may need to 51975107Sfenner * search "/dev" for the appropriate device with that major 52075107Sfenner * device number, rather than hardwiring "/dev/dlpi". 52175107Sfenner */ 52217683Spst cp = "/dev/dlpi"; 52317683Spst if ((p->fd = open(cp, O_RDWR)) < 0) { 52475107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 52575107Sfenner "%s: %s", cp, pcap_strerror(errno)); 52617683Spst goto bad; 52717683Spst } 52875107Sfenner 529146768Ssam#ifdef DL_HP_RAWDLS 53075107Sfenner /* 531146768Ssam * XXX - HP-UX 10.20 and 11.xx don't appear to support sending and 532147894Ssam * receiving packets on the same descriptor - you need separate 533147894Ssam * descriptors for sending and receiving, bound to different SAPs. 534146768Ssam * 535146768Ssam * If the open fails, we just leave -1 in "p->send_fd" and reject 536146768Ssam * attempts to send packets, just as if, in pcap-bpf.c, we fail 537146768Ssam * to open the BPF device for reading and writing, we just try 538146768Ssam * to open it for reading only and, if that succeeds, just let 539146768Ssam * the send attempts fail. 540146768Ssam */ 541146768Ssam p->send_fd = open(cp, O_RDWR); 542146768Ssam#endif 543146768Ssam 544146768Ssam /* 54575107Sfenner * Get a table of all PPAs for that device, and search that 54675107Sfenner * table for the specified device type name and unit number. 54775107Sfenner */ 54817683Spst ppa = get_dlpi_ppa(p->fd, dname, ppa, ebuf); 54917683Spst if (ppa < 0) 55017683Spst goto bad; 55117683Spst#else 55275107Sfenner /* 55398530Sfenner * If the device name begins with "/", assume it begins with 55498530Sfenner * the pathname of the directory containing the device to open; 55598530Sfenner * otherwise, concatenate the device directory name and the 55698530Sfenner * device name. 55798530Sfenner */ 55875107Sfenner if (*device == '/') 55975107Sfenner strlcpy(dname, device, sizeof(dname)); 56075107Sfenner else 56175107Sfenner snprintf(dname, sizeof(dname), "%s/%s", PCAP_DEV_PREFIX, 56275107Sfenner device); 56375107Sfenner 56498530Sfenner /* 565127664Sbms * Get the unit number, and a pointer to the end of the device 566127664Sbms * type name. 567127664Sbms */ 568127664Sbms cp = split_dname(dname, &ppa, ebuf); 569127664Sbms if (cp == NULL) 570127664Sbms goto bad; 571127664Sbms 572127664Sbms /* 57398530Sfenner * Make a copy of the device pathname, and then remove the unit 57498530Sfenner * number from the device pathname. 57598530Sfenner */ 57698530Sfenner strlcpy(dname2, dname, sizeof(dname)); 577127664Sbms *cp = '\0'; 57898530Sfenner 57917683Spst /* Try device without unit number */ 58017683Spst if ((p->fd = open(dname, O_RDWR)) < 0) { 58117683Spst if (errno != ENOENT) { 58275107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s: %s", dname, 58375107Sfenner pcap_strerror(errno)); 58417683Spst goto bad; 58517683Spst } 58617683Spst 58717683Spst /* Try again with unit number */ 58817683Spst if ((p->fd = open(dname2, O_RDWR)) < 0) { 589146768Ssam if (errno == ENOENT) { 590146768Ssam /* 591146768Ssam * We just report "No DLPI device found" 592146768Ssam * with the device name, so people don't 593146768Ssam * get confused and think, for example, 594146768Ssam * that if they can't capture on "lo0" 595146768Ssam * on Solaris the fix is to change libpcap 596146768Ssam * (or the application that uses it) to 597146768Ssam * look for something other than "/dev/lo0", 598146768Ssam * as the fix is to look for an operating 599146768Ssam * system other than Solaris - you just 600146768Ssam * *can't* capture on a loopback interface 601146768Ssam * on Solaris, the lack of a DLPI device 602146768Ssam * for the loopback interface is just a 603146768Ssam * symptom of that inability. 604146768Ssam */ 605146768Ssam snprintf(ebuf, PCAP_ERRBUF_SIZE, 606146768Ssam "%s: No DLPI device found", device); 607146768Ssam } else { 608146768Ssam snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s: %s", 609146768Ssam dname2, pcap_strerror(errno)); 610146768Ssam } 61117683Spst goto bad; 61217683Spst } 61317683Spst /* XXX Assume unit zero */ 61417683Spst ppa = 0; 61517683Spst } 61617683Spst#endif 61717683Spst 61817683Spst p->snapshot = snaplen; 61917683Spst 62017683Spst /* 62117683Spst ** Attach if "style 2" provider 62217683Spst */ 62317683Spst if (dlinforeq(p->fd, ebuf) < 0 || 62417683Spst dlinfoack(p->fd, (char *)buf, ebuf) < 0) 62517683Spst goto bad; 62617683Spst infop = &((union DL_primitives *)buf)->info_ack; 627127664Sbms#ifdef HAVE_SOLARIS 628127664Sbms if (infop->dl_mac_type == DL_IPATM) 629127664Sbms isatm = 1; 630127664Sbms#endif 631146768Ssam if (infop->dl_provider_style == DL_STYLE2) { 632146768Ssam if (dl_doattach(p->fd, ppa, ebuf) < 0) 633146768Ssam goto bad; 634146768Ssam#ifdef DL_HP_RAWDLS 635146768Ssam if (p->send_fd >= 0) { 636146768Ssam if (dl_doattach(p->send_fd, ppa, ebuf) < 0) 637146768Ssam goto bad; 638146768Ssam } 639146768Ssam#endif 640146768Ssam } 641146768Ssam 64217683Spst /* 643147894Ssam ** Bind (defer if using HP-UX 9 or HP-UX 10.20 or later, totally 644147894Ssam ** skip if using SINIX) 64517683Spst */ 646147894Ssam#if !defined(HAVE_HPUX9) && !defined(HAVE_HPUX10_20_OR_LATER) && !defined(sinix) 64775107Sfenner#ifdef _AIX 648147894Ssam /* 649147894Ssam ** AIX. 650147894Ssam ** According to IBM's AIX Support Line, the dl_sap value 65198530Sfenner ** should not be less than 0x600 (1536) for standard Ethernet. 65298530Sfenner ** However, we seem to get DL_BADADDR - "DLSAP addr in improper 65398530Sfenner ** format or invalid" - errors if we use 1537 on the "tr0" 65498530Sfenner ** device, which, given that its name starts with "tr" and that 65598530Sfenner ** it's IBM, probably means a Token Ring device. (Perhaps we 65698530Sfenner ** need to use 1537 on "/dev/dlpi/en" because that device is for 65798530Sfenner ** D/I/X Ethernet, the "SAP" is actually an Ethernet type, and 65898530Sfenner ** it rejects invalid Ethernet types.) 65998530Sfenner ** 66098530Sfenner ** So if 1537 fails, we try 2, as Hyung Sik Yoon of IBM Korea 66198530Sfenner ** says that works on Token Ring (he says that 0 does *not* 66298530Sfenner ** work; perhaps that's considered an invalid LLC SAP value - I 66398530Sfenner ** assume the SAP value in a DLPI bind is an LLC SAP for network 66498530Sfenner ** types that use 802.2 LLC). 66598530Sfenner */ 66698530Sfenner if ((dlbindreq(p->fd, 1537, ebuf) < 0 && 66798530Sfenner dlbindreq(p->fd, 2, ebuf) < 0) || 668147894Ssam dlbindack(p->fd, (char *)buf, ebuf, NULL) < 0) 669146768Ssam goto bad; 670146768Ssam#elif defined(DL_HP_RAWDLS) 671146768Ssam /* 672147894Ssam ** HP-UX 10.0x and 10.1x. 673146768Ssam */ 674147894Ssam if (dl_dohpuxbind(p->fd, ebuf) < 0) 675146768Ssam goto bad; 676146768Ssam if (p->send_fd >= 0) { 677146768Ssam /* 678147894Ssam ** XXX - if this fails, just close send_fd and 679147894Ssam ** set it to -1, so that you can't send but can 680147894Ssam ** still receive? 681146768Ssam */ 682147894Ssam if (dl_dohpuxbind(p->send_fd, ebuf) < 0) 683146768Ssam goto bad; 684146768Ssam } 685146768Ssam#else /* neither AIX nor HP-UX */ 686147894Ssam /* 687147894Ssam ** Not Sinix, and neither AIX nor HP-UX - Solaris, and any other 688147894Ssam ** OS using DLPI. 689147894Ssam **/ 69017683Spst if (dlbindreq(p->fd, 0, ebuf) < 0 || 691147894Ssam dlbindack(p->fd, (char *)buf, ebuf, NULL) < 0) 69217683Spst goto bad; 693147894Ssam#endif /* AIX vs. HP-UX vs. other */ 694147894Ssam#endif /* !HP-UX 9 and !HP-UX 10.20 or later and !SINIX */ 69517683Spst 696127664Sbms#ifdef HAVE_SOLARIS 697127664Sbms if (isatm) { 698127664Sbms /* 699127664Sbms ** Have to turn on some special ATM promiscuous mode 700127664Sbms ** for SunATM. 701127664Sbms ** Do *NOT* turn regular promiscuous mode on; it doesn't 702127664Sbms ** help, and may break things. 703127664Sbms */ 704127664Sbms if (strioctl(p->fd, A_PROMISCON_REQ, 0, NULL) < 0) { 705127664Sbms snprintf(ebuf, PCAP_ERRBUF_SIZE, "A_PROMISCON_REQ: %s", 706127664Sbms pcap_strerror(errno)); 707127664Sbms goto bad; 708127664Sbms } 709127664Sbms } else 710127664Sbms#endif 71117683Spst if (promisc) { 71217683Spst /* 713146768Ssam ** Enable promiscuous (not necessary on send FD) 71417683Spst */ 71517683Spst if (dlpromisconreq(p->fd, DL_PROMISC_PHYS, ebuf) < 0 || 71617683Spst dlokack(p->fd, "promisc_phys", (char *)buf, ebuf) < 0) 71717683Spst goto bad; 71817683Spst 71917683Spst /* 72017683Spst ** Try to enable multicast (you would have thought 72139291Sfenner ** promiscuous would be sufficient). (Skip if using 722146768Ssam ** HP-UX or SINIX) (Not necessary on send FD) 72317683Spst */ 72439291Sfenner#if !defined(__hpux) && !defined(sinix) 72517683Spst if (dlpromisconreq(p->fd, DL_PROMISC_MULTI, ebuf) < 0 || 72617683Spst dlokack(p->fd, "promisc_multi", (char *)buf, ebuf) < 0) 72717683Spst fprintf(stderr, 72817683Spst "WARNING: DL_PROMISC_MULTI failed (%s)\n", ebuf); 72917683Spst#endif 73017683Spst } 73117683Spst /* 732147894Ssam ** Try to enable SAP promiscuity (when not in promiscuous mode 733147894Ssam ** when using HP-UX, when not doing SunATM on Solaris, and never 734146768Ssam ** under SINIX) (Not necessary on send FD) 73517683Spst */ 73617683Spst#ifndef sinix 73739291Sfenner if ( 73839291Sfenner#ifdef __hpux 73939291Sfenner !promisc && 74039291Sfenner#endif 741127664Sbms#ifdef HAVE_SOLARIS 742127664Sbms !isatm && 743127664Sbms#endif 74439291Sfenner (dlpromisconreq(p->fd, DL_PROMISC_SAP, ebuf) < 0 || 74539291Sfenner dlokack(p->fd, "promisc_sap", (char *)buf, ebuf) < 0)) { 74617683Spst /* Not fatal if promisc since the DL_PROMISC_PHYS worked */ 74717683Spst if (promisc) 74817683Spst fprintf(stderr, 74917683Spst "WARNING: DL_PROMISC_SAP failed (%s)\n", ebuf); 75017683Spst else 75117683Spst goto bad; 75217683Spst } 753147894Ssam#endif /* sinix */ 75417683Spst 75517683Spst /* 756147894Ssam ** HP-UX 9, and HP-UX 10.20 or later, must bind after setting 757147894Ssam ** promiscuous options. 75817683Spst */ 759147894Ssam#if defined(HAVE_HPUX9) || defined(HAVE_HPUX10_20_OR_LATER) 760147894Ssam if (dl_dohpuxbind(p->fd, ebuf) < 0) 76117683Spst goto bad; 762147894Ssam /* 763147894Ssam ** We don't set promiscuous mode on the send FD, but we'll defer 764147894Ssam ** binding it anyway, just to keep the HP-UX 9/10.20 or later 765147894Ssam ** code together. 766147894Ssam */ 767147894Ssam if (p->send_fd >= 0) { 768147894Ssam /* 769147894Ssam ** XXX - if this fails, just close send_fd and 770147894Ssam ** set it to -1, so that you can't send but can 771147894Ssam ** still receive? 772147894Ssam */ 773147894Ssam if (dl_dohpuxbind(p->send_fd, ebuf) < 0) 774147894Ssam goto bad; 775147894Ssam } 77617683Spst#endif 77717683Spst 77817683Spst /* 77917683Spst ** Determine link type 780146768Ssam ** XXX - get SAP length and address length as well, for use 781146768Ssam ** when sending packets. 78217683Spst */ 78317683Spst if (dlinforeq(p->fd, ebuf) < 0 || 78417683Spst dlinfoack(p->fd, (char *)buf, ebuf) < 0) 78517683Spst goto bad; 78617683Spst 78717683Spst infop = &((union DL_primitives *)buf)->info_ack; 78817683Spst switch (infop->dl_mac_type) { 78917683Spst 79017683Spst case DL_CSMACD: 79117683Spst case DL_ETHER: 79217683Spst p->linktype = DLT_EN10MB; 79317683Spst p->offset = 2; 794146768Ssam /* 795146768Ssam * This is (presumably) a real Ethernet capture; give it a 796146768Ssam * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so 797146768Ssam * that an application can let you choose it, in case you're 798146768Ssam * capturing DOCSIS traffic that a Cisco Cable Modem 799146768Ssam * Termination System is putting out onto an Ethernet (it 800146768Ssam * doesn't put an Ethernet header onto the wire, it puts raw 801146768Ssam * DOCSIS frames out on the wire inside the low-level 802146768Ssam * Ethernet framing). 803146768Ssam */ 804146768Ssam p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); 805146768Ssam /* 806146768Ssam * If that fails, just leave the list empty. 807146768Ssam */ 808146768Ssam if (p->dlt_list != NULL) { 809146768Ssam p->dlt_list[0] = DLT_EN10MB; 810146768Ssam p->dlt_list[1] = DLT_DOCSIS; 811146768Ssam p->dlt_count = 2; 812146768Ssam } 81317683Spst break; 81417683Spst 81517683Spst case DL_FDDI: 81617683Spst p->linktype = DLT_FDDI; 81739291Sfenner p->offset = 3; 81817683Spst break; 81917683Spst 82098530Sfenner case DL_TPR: 821146768Ssam /* 822146768Ssam * XXX - what about DL_TPB? Is that Token Bus? 823146768Ssam */ 82498530Sfenner p->linktype = DLT_IEEE802; 82598530Sfenner p->offset = 2; 82698530Sfenner break; 82798530Sfenner 828127664Sbms#ifdef HAVE_SOLARIS 829127664Sbms case DL_IPATM: 830127664Sbms p->linktype = DLT_SUNATM; 831127664Sbms p->offset = 0; /* works for LANE and LLC encapsulation */ 832127664Sbms break; 833127664Sbms#endif 834127664Sbms 83517683Spst default: 83675107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "unknown mac type %lu", 837127664Sbms (unsigned long)infop->dl_mac_type); 83817683Spst goto bad; 83917683Spst } 84017683Spst 84117683Spst#ifdef DLIOCRAW 84217683Spst /* 843127664Sbms ** This is a non standard SunOS hack to get the full raw link-layer 844127664Sbms ** header. 84517683Spst */ 84617683Spst if (strioctl(p->fd, DLIOCRAW, 0, NULL) < 0) { 84775107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "DLIOCRAW: %s", 84875107Sfenner pcap_strerror(errno)); 84917683Spst goto bad; 85017683Spst } 85117683Spst#endif 85217683Spst 85317683Spst#ifdef HAVE_SYS_BUFMOD_H 85417683Spst /* 85517683Spst ** Another non standard call to get the data nicely buffered 85617683Spst */ 85717683Spst if (ioctl(p->fd, I_PUSH, "bufmod") != 0) { 85875107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "I_PUSH bufmod: %s", 85975107Sfenner pcap_strerror(errno)); 86017683Spst goto bad; 86117683Spst } 86217683Spst 86317683Spst /* 86417683Spst ** Now that the bufmod is pushed lets configure it. 86517683Spst ** 86617683Spst ** There is a bug in bufmod(7). When dealing with messages of 86717683Spst ** less than snaplen size it strips data from the beginning not 86817683Spst ** the end. 86917683Spst ** 87017683Spst ** This bug is supposed to be fixed in 5.3.2. Also, there is a 87117683Spst ** patch available. Ask for bugid 1149065. 87217683Spst */ 87317683Spst ss = snaplen; 87417683Spst#ifdef HAVE_SOLARIS 87517683Spst release = get_release(&osmajor, &osminor, &osmicro); 87617683Spst if (osmajor == 5 && (osminor <= 2 || (osminor == 3 && osmicro < 2)) && 87717683Spst getenv("BUFMOD_FIXED") == NULL) { 87817683Spst fprintf(stderr, 87917683Spst "WARNING: bufmod is broken in SunOS %s; ignoring snaplen.\n", 88017683Spst release); 88117683Spst ss = 0; 88217683Spst } 88317683Spst#endif 88417683Spst if (ss > 0 && 88517683Spst strioctl(p->fd, SBIOCSSNAP, sizeof(ss), (char *)&ss) != 0) { 88675107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "SBIOCSSNAP: %s", 88775107Sfenner pcap_strerror(errno)); 88817683Spst goto bad; 88917683Spst } 89017683Spst 89117683Spst /* 89217683Spst ** Set up the bufmod timeout 89317683Spst */ 89417683Spst if (to_ms != 0) { 89517683Spst struct timeval to; 89617683Spst 89717683Spst to.tv_sec = to_ms / 1000; 89817683Spst to.tv_usec = (to_ms * 1000) % 1000000; 89917683Spst if (strioctl(p->fd, SBIOCSTIME, sizeof(to), (char *)&to) != 0) { 90075107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "SBIOCSTIME: %s", 90175107Sfenner pcap_strerror(errno)); 90217683Spst goto bad; 90317683Spst } 90417683Spst } 905127664Sbms 906127664Sbms /* 907127664Sbms ** Set the chunk length. 908127664Sbms */ 909127664Sbms chunksize = CHUNKSIZE; 910127664Sbms if (strioctl(p->fd, SBIOCSCHUNK, sizeof(chunksize), (char *)&chunksize) 911127664Sbms != 0) { 912127664Sbms snprintf(ebuf, PCAP_ERRBUF_SIZE, "SBIOCSCHUNKP: %s", 913127664Sbms pcap_strerror(errno)); 914127664Sbms goto bad; 915127664Sbms } 91617683Spst#endif 91717683Spst 91817683Spst /* 91917683Spst ** As the last operation flush the read side. 92017683Spst */ 92117683Spst if (ioctl(p->fd, I_FLUSH, FLUSHR) != 0) { 92275107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "FLUSHR: %s", 92375107Sfenner pcap_strerror(errno)); 92417683Spst goto bad; 92517683Spst } 926127664Sbms 92717683Spst /* Allocate data buffer */ 928127664Sbms p->bufsize = PKTBUFSIZE; 92917683Spst p->buffer = (u_char *)malloc(p->bufsize + p->offset); 930127664Sbms if (p->buffer == NULL) { 931127664Sbms strlcpy(ebuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE); 932127664Sbms goto bad; 933127664Sbms } 93417683Spst 935127664Sbms /* 936127664Sbms * "p->fd" is an FD for a STREAMS device, so "select()" and 937127664Sbms * "poll()" should work on it. 938127664Sbms */ 939127664Sbms p->selectable_fd = p->fd; 940127664Sbms 941127664Sbms p->read_op = pcap_read_dlpi; 942146768Ssam p->inject_op = pcap_inject_dlpi; 943127664Sbms p->setfilter_op = install_bpf_program; /* no kernel filtering */ 944147894Ssam p->setdirection_op = NULL; /* Not implemented.*/ 945127664Sbms p->set_datalink_op = NULL; /* can't change data link type */ 946127664Sbms p->getnonblock_op = pcap_getnonblock_fd; 947127664Sbms p->setnonblock_op = pcap_setnonblock_fd; 948127664Sbms p->stats_op = pcap_stats_dlpi; 949127664Sbms p->close_op = pcap_close_dlpi; 950127664Sbms 95117683Spst return (p); 95217683Spstbad: 95398530Sfenner if (p->fd >= 0) 95498530Sfenner close(p->fd); 955146768Ssam if (p->send_fd >= 0) 956146768Ssam close(p->send_fd); 957146768Ssam /* 958146768Ssam * Get rid of any link-layer type list we allocated. 959146768Ssam */ 960146768Ssam if (p->dlt_list != NULL) 961146768Ssam free(p->dlt_list); 96217683Spst free(p); 96317683Spst return (NULL); 96417683Spst} 96517683Spst 96698530Sfenner/* 96798530Sfenner * Split a device name into a device type name and a unit number; 96898530Sfenner * return the a pointer to the beginning of the unit number, which 96998530Sfenner * is the end of the device type name, and set "*unitp" to the unit 97098530Sfenner * number. 97198530Sfenner * 97298530Sfenner * Returns NULL on error, and fills "ebuf" with an error message. 97398530Sfenner */ 97498530Sfennerstatic char * 97598530Sfennersplit_dname(char *device, int *unitp, char *ebuf) 97698530Sfenner{ 97798530Sfenner char *cp; 97898530Sfenner char *eos; 979146768Ssam long unit; 98098530Sfenner 98198530Sfenner /* 98298530Sfenner * Look for a number at the end of the device name string. 98398530Sfenner */ 98498530Sfenner cp = device + strlen(device) - 1; 98598530Sfenner if (*cp < '0' || *cp > '9') { 98698530Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s missing unit number", 98798530Sfenner device); 98898530Sfenner return (NULL); 98998530Sfenner } 99098530Sfenner 99198530Sfenner /* Digits at end of string are unit number */ 99298530Sfenner while (cp-1 >= device && *(cp-1) >= '0' && *(cp-1) <= '9') 99398530Sfenner cp--; 99498530Sfenner 995146768Ssam errno = 0; 99698530Sfenner unit = strtol(cp, &eos, 10); 99798530Sfenner if (*eos != '\0') { 99898530Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s bad unit number", device); 99998530Sfenner return (NULL); 100098530Sfenner } 1001146768Ssam if (errno == ERANGE || unit > INT_MAX) { 1002146768Ssam snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s unit number too large", 1003146768Ssam device); 1004146768Ssam return (NULL); 1005146768Ssam } 1006146768Ssam if (unit < 0) { 1007146768Ssam snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s unit number is negative", 1008146768Ssam device); 1009146768Ssam return (NULL); 1010146768Ssam } 1011146768Ssam *unitp = (int)unit; 101298530Sfenner return (cp); 101398530Sfenner} 101498530Sfenner 1015146768Ssamstatic int 1016146768Ssamdl_doattach(int fd, int ppa, char *ebuf) 1017146768Ssam{ 1018146768Ssam bpf_u_int32 buf[MAXDLBUF]; 1019146768Ssam 1020146768Ssam if (dlattachreq(fd, ppa, ebuf) < 0 || 1021146768Ssam dlokack(fd, "attach", (char *)buf, ebuf) < 0) 1022146768Ssam return (-1); 1023146768Ssam return (0); 1024146768Ssam} 1025146768Ssam 1026147894Ssam#ifdef DL_HP_RAWDLS 1027147894Ssamstatic int 1028147894Ssamdl_dohpuxbind(int fd, char *ebuf) 1029147894Ssam{ 1030147894Ssam int hpsap; 1031147894Ssam int uerror; 1032147894Ssam bpf_u_int32 buf[MAXDLBUF]; 1033147894Ssam 1034147894Ssam /* 1035147894Ssam * XXX - we start at 22 because we used to use only 22, but 1036147894Ssam * that was just because that was the value used in some 1037147894Ssam * sample code from HP. With what value *should* we start? 1038147894Ssam * Does it matter, given that we're enabling SAP promiscuity 1039147894Ssam * on the input FD? 1040147894Ssam */ 1041147894Ssam hpsap = 22; 1042147894Ssam for (;;) { 1043147894Ssam if (dlbindreq(fd, hpsap, ebuf) < 0) 1044147894Ssam return (-1); 1045147894Ssam if (dlbindack(fd, (char *)buf, ebuf, &uerror) >= 0) 1046147894Ssam break; 1047147894Ssam /* 1048147894Ssam * For any error other than a UNIX EBUSY, give up. 1049147894Ssam */ 1050162012Ssam if (uerror != EBUSY) { 1051162012Ssam /* 1052162012Ssam * dlbindack() has already filled in ebuf for 1053162012Ssam * this error. 1054162012Ssam */ 1055147894Ssam return (-1); 1056162012Ssam } 1057147894Ssam 1058147894Ssam /* 1059147894Ssam * For EBUSY, try the next SAP value; that means that 1060147894Ssam * somebody else is using that SAP. Clear ebuf so 1061147894Ssam * that application doesn't report the "Device busy" 1062147894Ssam * error as a warning. 1063147894Ssam */ 1064147894Ssam *ebuf = '\0'; 1065147894Ssam hpsap++; 1066162012Ssam if (hpsap > 100) { 1067162012Ssam strlcpy(ebuf, 1068162012Ssam "All SAPs from 22 through 100 are in use", 1069162012Ssam PCAP_ERRBUF_SIZE); 1070147894Ssam return (-1); 1071162012Ssam } 1072147894Ssam } 1073162012Ssam return (0); 1074147894Ssam} 1075147894Ssam#endif 1076147894Ssam 107717683Spstint 1078127664Sbmspcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf) 107917683Spst{ 1080127664Sbms#ifdef HAVE_SOLARIS 1081127664Sbms int fd; 1082127664Sbms union { 1083127664Sbms u_int nunits; 1084127664Sbms char pad[516]; /* XXX - must be at least 513; is 516 1085127664Sbms in "atmgetunits" */ 1086127664Sbms } buf; 1087127664Sbms char baname[2+1+1]; 1088127664Sbms u_int i; 108917683Spst 1090127664Sbms /* 1091127664Sbms * We may have to do special magic to get ATM devices. 1092127664Sbms */ 1093127664Sbms if ((fd = open("/dev/ba", O_RDWR)) < 0) { 1094127664Sbms /* 1095127664Sbms * We couldn't open the "ba" device. 1096127664Sbms * For now, just give up; perhaps we should 1097127664Sbms * return an error if the problem is neither 1098127664Sbms * a "that device doesn't exist" error (ENOENT, 1099127664Sbms * ENXIO, etc.) or a "you're not allowed to do 1100127664Sbms * that" error (EPERM, EACCES). 1101127664Sbms */ 1102127664Sbms return (0); 1103127664Sbms } 1104127664Sbms 1105127664Sbms if (strioctl(fd, A_GET_UNITS, sizeof(buf), (char *)&buf) < 0) { 1106127664Sbms snprintf(errbuf, PCAP_ERRBUF_SIZE, "A_GET_UNITS: %s", 1107127664Sbms pcap_strerror(errno)); 110875107Sfenner return (-1); 1109127664Sbms } 1110127664Sbms for (i = 0; i < buf.nunits; i++) { 1111127664Sbms snprintf(baname, sizeof baname, "ba%u", i); 1112127664Sbms if (pcap_add_if(alldevsp, baname, 0, NULL, errbuf) < 0) 1113127664Sbms return (-1); 1114127664Sbms } 1115127664Sbms#endif 1116127664Sbms 111717683Spst return (0); 111817683Spst} 111917683Spst 112017683Spststatic int 112117683Spstsend_request(int fd, char *ptr, int len, char *what, char *ebuf) 112217683Spst{ 112317683Spst struct strbuf ctl; 112417683Spst int flags; 112517683Spst 112617683Spst ctl.maxlen = 0; 112717683Spst ctl.len = len; 112817683Spst ctl.buf = ptr; 112917683Spst 113017683Spst flags = 0; 113117683Spst if (putmsg(fd, &ctl, (struct strbuf *) NULL, flags) < 0) { 113275107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 113375107Sfenner "send_request: putmsg \"%s\": %s", 113417683Spst what, pcap_strerror(errno)); 113517683Spst return (-1); 113617683Spst } 113717683Spst return (0); 113817683Spst} 113917683Spst 114017683Spststatic int 1141147894Ssamrecv_ack(int fd, int size, const char *what, char *bufp, char *ebuf, int *uerror) 114217683Spst{ 114317683Spst union DL_primitives *dlp; 114417683Spst struct strbuf ctl; 114517683Spst int flags; 114617683Spst 1147162012Ssam /* 1148162012Ssam * Clear out "*uerror", so it's only set for DL_ERROR_ACK/DL_SYSERR, 1149162012Ssam * making that the only place where EBUSY is treated specially. 1150162012Ssam */ 1151162012Ssam if (uerror != NULL) 1152162012Ssam *uerror = 0; 1153162012Ssam 115417683Spst ctl.maxlen = MAXDLBUF; 115517683Spst ctl.len = 0; 115617683Spst ctl.buf = bufp; 115717683Spst 115817683Spst flags = 0; 115917683Spst if (getmsg(fd, &ctl, (struct strbuf*)NULL, &flags) < 0) { 116075107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "recv_ack: %s getmsg: %s", 116117683Spst what, pcap_strerror(errno)); 116217683Spst return (-1); 116317683Spst } 116417683Spst 116517683Spst dlp = (union DL_primitives *) ctl.buf; 116617683Spst switch (dlp->dl_primitive) { 116717683Spst 116817683Spst case DL_INFO_ACK: 116917683Spst case DL_BIND_ACK: 117017683Spst case DL_OK_ACK: 117117683Spst#ifdef DL_HP_PPA_ACK 117217683Spst case DL_HP_PPA_ACK: 117317683Spst#endif 117417683Spst /* These are OK */ 117517683Spst break; 117617683Spst 117717683Spst case DL_ERROR_ACK: 117817683Spst switch (dlp->error_ack.dl_errno) { 117917683Spst 118098530Sfenner case DL_SYSERR: 1181147894Ssam if (uerror != NULL) 1182147894Ssam *uerror = dlp->error_ack.dl_unix_errno; 118375107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 118498530Sfenner "recv_ack: %s: UNIX error - %s", 118517683Spst what, pcap_strerror(dlp->error_ack.dl_unix_errno)); 118617683Spst break; 118717683Spst 118817683Spst default: 118998530Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "recv_ack: %s: %s", 119098530Sfenner what, dlstrerror(dlp->error_ack.dl_errno)); 119117683Spst break; 119217683Spst } 119317683Spst return (-1); 119417683Spst 119517683Spst default: 119675107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 119798530Sfenner "recv_ack: %s: Unexpected primitive ack %s", 119898530Sfenner what, dlprim(dlp->dl_primitive)); 119917683Spst return (-1); 120017683Spst } 120117683Spst 120217683Spst if (ctl.len < size) { 120375107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 120498530Sfenner "recv_ack: %s: Ack too small (%d < %d)", 120517683Spst what, ctl.len, size); 120617683Spst return (-1); 120717683Spst } 120817683Spst return (ctl.len); 120917683Spst} 121017683Spst 121198530Sfennerstatic char * 121298530Sfennerdlstrerror(bpf_u_int32 dl_errno) 121398530Sfenner{ 121498530Sfenner static char errstring[6+2+8+1]; 121598530Sfenner 121698530Sfenner switch (dl_errno) { 121798530Sfenner 121898530Sfenner case DL_ACCESS: 121998530Sfenner return ("Improper permissions for request"); 122098530Sfenner 122198530Sfenner case DL_BADADDR: 122298530Sfenner return ("DLSAP addr in improper format or invalid"); 122398530Sfenner 122498530Sfenner case DL_BADCORR: 122598530Sfenner return ("Seq number not from outstand DL_CONN_IND"); 122698530Sfenner 122798530Sfenner case DL_BADDATA: 122898530Sfenner return ("User data exceeded provider limit"); 122998530Sfenner 123098530Sfenner case DL_BADPPA: 123198530Sfenner#ifdef HAVE_DEV_DLPI 123298530Sfenner /* 123398530Sfenner * With a single "/dev/dlpi" device used for all 123498530Sfenner * DLPI providers, PPAs have nothing to do with 123598530Sfenner * unit numbers. 123698530Sfenner */ 123798530Sfenner return ("Specified PPA was invalid"); 123898530Sfenner#else 123998530Sfenner /* 124098530Sfenner * We have separate devices for separate devices; 124198530Sfenner * the PPA is just the unit number. 124298530Sfenner */ 124398530Sfenner return ("Specified PPA (device unit) was invalid"); 124498530Sfenner#endif 124598530Sfenner 124698530Sfenner case DL_BADPRIM: 124798530Sfenner return ("Primitive received not known by provider"); 124898530Sfenner 124998530Sfenner case DL_BADQOSPARAM: 125098530Sfenner return ("QOS parameters contained invalid values"); 125198530Sfenner 125298530Sfenner case DL_BADQOSTYPE: 125398530Sfenner return ("QOS structure type is unknown/unsupported"); 125498530Sfenner 125598530Sfenner case DL_BADSAP: 125698530Sfenner return ("Bad LSAP selector"); 125798530Sfenner 125898530Sfenner case DL_BADTOKEN: 125998530Sfenner return ("Token used not an active stream"); 126098530Sfenner 126198530Sfenner case DL_BOUND: 126298530Sfenner return ("Attempted second bind with dl_max_conind"); 126398530Sfenner 126498530Sfenner case DL_INITFAILED: 126598530Sfenner return ("Physical link initialization failed"); 126698530Sfenner 126798530Sfenner case DL_NOADDR: 126898530Sfenner return ("Provider couldn't allocate alternate address"); 126998530Sfenner 127098530Sfenner case DL_NOTINIT: 127198530Sfenner return ("Physical link not initialized"); 127298530Sfenner 127398530Sfenner case DL_OUTSTATE: 127498530Sfenner return ("Primitive issued in improper state"); 127598530Sfenner 127698530Sfenner case DL_SYSERR: 127798530Sfenner return ("UNIX system error occurred"); 127898530Sfenner 127998530Sfenner case DL_UNSUPPORTED: 128098530Sfenner return ("Requested service not supplied by provider"); 128198530Sfenner 128298530Sfenner case DL_UNDELIVERABLE: 128398530Sfenner return ("Previous data unit could not be delivered"); 128498530Sfenner 128598530Sfenner case DL_NOTSUPPORTED: 128698530Sfenner return ("Primitive is known but not supported"); 128798530Sfenner 128898530Sfenner case DL_TOOMANY: 128998530Sfenner return ("Limit exceeded"); 129098530Sfenner 129198530Sfenner case DL_NOTENAB: 129298530Sfenner return ("Promiscuous mode not enabled"); 129398530Sfenner 129498530Sfenner case DL_BUSY: 129598530Sfenner return ("Other streams for PPA in post-attached"); 129698530Sfenner 129798530Sfenner case DL_NOAUTO: 129898530Sfenner return ("Automatic handling XID&TEST not supported"); 129998530Sfenner 130098530Sfenner case DL_NOXIDAUTO: 130198530Sfenner return ("Automatic handling of XID not supported"); 130298530Sfenner 130398530Sfenner case DL_NOTESTAUTO: 130498530Sfenner return ("Automatic handling of TEST not supported"); 130598530Sfenner 130698530Sfenner case DL_XIDAUTO: 130798530Sfenner return ("Automatic handling of XID response"); 130898530Sfenner 130998530Sfenner case DL_TESTAUTO: 131098530Sfenner return ("Automatic handling of TEST response"); 131198530Sfenner 131298530Sfenner case DL_PENDING: 131398530Sfenner return ("Pending outstanding connect indications"); 131498530Sfenner 131598530Sfenner default: 131698530Sfenner sprintf(errstring, "Error %02x", dl_errno); 131798530Sfenner return (errstring); 131898530Sfenner } 131998530Sfenner} 132098530Sfenner 132198530Sfennerstatic char * 132298530Sfennerdlprim(bpf_u_int32 prim) 132398530Sfenner{ 132498530Sfenner static char primbuf[80]; 132598530Sfenner 132698530Sfenner switch (prim) { 132798530Sfenner 132898530Sfenner case DL_INFO_REQ: 132998530Sfenner return ("DL_INFO_REQ"); 133098530Sfenner 133198530Sfenner case DL_INFO_ACK: 133298530Sfenner return ("DL_INFO_ACK"); 133398530Sfenner 133498530Sfenner case DL_ATTACH_REQ: 133598530Sfenner return ("DL_ATTACH_REQ"); 133698530Sfenner 133798530Sfenner case DL_DETACH_REQ: 133898530Sfenner return ("DL_DETACH_REQ"); 133998530Sfenner 134098530Sfenner case DL_BIND_REQ: 134198530Sfenner return ("DL_BIND_REQ"); 134298530Sfenner 134398530Sfenner case DL_BIND_ACK: 134498530Sfenner return ("DL_BIND_ACK"); 134598530Sfenner 134698530Sfenner case DL_UNBIND_REQ: 134798530Sfenner return ("DL_UNBIND_REQ"); 134898530Sfenner 134998530Sfenner case DL_OK_ACK: 135098530Sfenner return ("DL_OK_ACK"); 135198530Sfenner 135298530Sfenner case DL_ERROR_ACK: 135398530Sfenner return ("DL_ERROR_ACK"); 135498530Sfenner 135598530Sfenner case DL_SUBS_BIND_REQ: 135698530Sfenner return ("DL_SUBS_BIND_REQ"); 135798530Sfenner 135898530Sfenner case DL_SUBS_BIND_ACK: 135998530Sfenner return ("DL_SUBS_BIND_ACK"); 136098530Sfenner 136198530Sfenner case DL_UNITDATA_REQ: 136298530Sfenner return ("DL_UNITDATA_REQ"); 136398530Sfenner 136498530Sfenner case DL_UNITDATA_IND: 136598530Sfenner return ("DL_UNITDATA_IND"); 136698530Sfenner 136798530Sfenner case DL_UDERROR_IND: 136898530Sfenner return ("DL_UDERROR_IND"); 136998530Sfenner 137098530Sfenner case DL_UDQOS_REQ: 137198530Sfenner return ("DL_UDQOS_REQ"); 137298530Sfenner 137398530Sfenner case DL_CONNECT_REQ: 137498530Sfenner return ("DL_CONNECT_REQ"); 137598530Sfenner 137698530Sfenner case DL_CONNECT_IND: 137798530Sfenner return ("DL_CONNECT_IND"); 137898530Sfenner 137998530Sfenner case DL_CONNECT_RES: 138098530Sfenner return ("DL_CONNECT_RES"); 138198530Sfenner 138298530Sfenner case DL_CONNECT_CON: 138398530Sfenner return ("DL_CONNECT_CON"); 138498530Sfenner 138598530Sfenner case DL_TOKEN_REQ: 138698530Sfenner return ("DL_TOKEN_REQ"); 138798530Sfenner 138898530Sfenner case DL_TOKEN_ACK: 138998530Sfenner return ("DL_TOKEN_ACK"); 139098530Sfenner 139198530Sfenner case DL_DISCONNECT_REQ: 139298530Sfenner return ("DL_DISCONNECT_REQ"); 139398530Sfenner 139498530Sfenner case DL_DISCONNECT_IND: 139598530Sfenner return ("DL_DISCONNECT_IND"); 139698530Sfenner 139798530Sfenner case DL_RESET_REQ: 139898530Sfenner return ("DL_RESET_REQ"); 139998530Sfenner 140098530Sfenner case DL_RESET_IND: 140198530Sfenner return ("DL_RESET_IND"); 140298530Sfenner 140398530Sfenner case DL_RESET_RES: 140498530Sfenner return ("DL_RESET_RES"); 140598530Sfenner 140698530Sfenner case DL_RESET_CON: 140798530Sfenner return ("DL_RESET_CON"); 140898530Sfenner 140998530Sfenner default: 141098530Sfenner (void) sprintf(primbuf, "unknown primitive 0x%x", prim); 141198530Sfenner return (primbuf); 141298530Sfenner } 141398530Sfenner} 141498530Sfenner 141517683Spststatic int 141617683Spstdlattachreq(int fd, bpf_u_int32 ppa, char *ebuf) 141717683Spst{ 141817683Spst dl_attach_req_t req; 141917683Spst 142017683Spst req.dl_primitive = DL_ATTACH_REQ; 142117683Spst req.dl_ppa = ppa; 142217683Spst 142317683Spst return (send_request(fd, (char *)&req, sizeof(req), "attach", ebuf)); 142417683Spst} 142517683Spst 142617683Spststatic int 142717683Spstdlbindreq(int fd, bpf_u_int32 sap, char *ebuf) 142817683Spst{ 142917683Spst 143017683Spst dl_bind_req_t req; 143117683Spst 143217683Spst memset((char *)&req, 0, sizeof(req)); 143317683Spst req.dl_primitive = DL_BIND_REQ; 1434147894Ssam /* XXX - what if neither of these are defined? */ 1435147894Ssam#if defined(DL_HP_RAWDLS) 143617683Spst req.dl_max_conind = 1; /* XXX magic number */ 143717683Spst req.dl_service_mode = DL_HP_RAWDLS; 1438147894Ssam#elif defined(DL_CLDLS) 143926175Sfenner req.dl_service_mode = DL_CLDLS; 144017683Spst#endif 1441147894Ssam req.dl_sap = sap; 144217683Spst 144317683Spst return (send_request(fd, (char *)&req, sizeof(req), "bind", ebuf)); 144417683Spst} 144517683Spst 144617683Spststatic int 1447147894Ssamdlbindack(int fd, char *bufp, char *ebuf, int *uerror) 144817683Spst{ 144917683Spst 1450147894Ssam return (recv_ack(fd, DL_BIND_ACK_SIZE, "bind", bufp, ebuf, uerror)); 145117683Spst} 145217683Spst 145317683Spststatic int 145417683Spstdlpromisconreq(int fd, bpf_u_int32 level, char *ebuf) 145517683Spst{ 145617683Spst dl_promiscon_req_t req; 145717683Spst 145817683Spst req.dl_primitive = DL_PROMISCON_REQ; 145917683Spst req.dl_level = level; 146017683Spst 146117683Spst return (send_request(fd, (char *)&req, sizeof(req), "promiscon", ebuf)); 146217683Spst} 146317683Spst 146417683Spststatic int 146517683Spstdlokack(int fd, const char *what, char *bufp, char *ebuf) 146617683Spst{ 146717683Spst 1468147894Ssam return (recv_ack(fd, DL_OK_ACK_SIZE, what, bufp, ebuf, NULL)); 146917683Spst} 147017683Spst 147117683Spst 147217683Spststatic int 147317683Spstdlinforeq(int fd, char *ebuf) 147417683Spst{ 147517683Spst dl_info_req_t req; 147617683Spst 147717683Spst req.dl_primitive = DL_INFO_REQ; 147817683Spst 147917683Spst return (send_request(fd, (char *)&req, sizeof(req), "info", ebuf)); 148017683Spst} 148117683Spst 148217683Spststatic int 148317683Spstdlinfoack(int fd, char *bufp, char *ebuf) 148417683Spst{ 148517683Spst 1486147894Ssam return (recv_ack(fd, DL_INFO_ACK_SIZE, "info", bufp, ebuf, NULL)); 148717683Spst} 148817683Spst 1489146768Ssam#ifdef DL_HP_RAWDLS 1490146768Ssam/* 1491146768Ssam * There's an ack *if* there's an error. 1492146768Ssam */ 1493146768Ssamstatic int 1494146768Ssamdlrawdatareq(int fd, const u_char *datap, int datalen) 1495146768Ssam{ 1496146768Ssam struct strbuf ctl, data; 1497146768Ssam long buf[MAXDLBUF]; /* XXX - char? */ 1498146768Ssam union DL_primitives *dlp; 1499146768Ssam int dlen; 1500146768Ssam 1501146768Ssam dlp = (union DL_primitives*) buf; 1502146768Ssam 1503146768Ssam dlp->dl_primitive = DL_HP_RAWDATA_REQ; 1504146768Ssam dlen = DL_HP_RAWDATA_REQ_SIZE; 1505146768Ssam 1506146768Ssam /* 1507146768Ssam * HP's documentation doesn't appear to show us supplying any 1508146768Ssam * address pointed to by the control part of the message. 1509146768Ssam * I think that's what raw mode means - you just send the raw 1510146768Ssam * packet, you don't specify where to send it to, as that's 1511146768Ssam * implied by the destination address. 1512146768Ssam */ 1513146768Ssam ctl.maxlen = 0; 1514146768Ssam ctl.len = dlen; 1515146768Ssam ctl.buf = (void *)buf; 1516146768Ssam 1517146768Ssam data.maxlen = 0; 1518146768Ssam data.len = datalen; 1519146768Ssam data.buf = (void *)datap; 1520146768Ssam 1521146768Ssam return (putmsg(fd, &ctl, &data, 0)); 1522146768Ssam} 1523146768Ssam#endif /* DL_HP_RAWDLS */ 1524146768Ssam 152517683Spst#ifdef HAVE_SYS_BUFMOD_H 152617683Spststatic int 152717683Spststrioctl(int fd, int cmd, int len, char *dp) 152817683Spst{ 152917683Spst struct strioctl str; 153017683Spst int rc; 153117683Spst 153217683Spst str.ic_cmd = cmd; 153317683Spst str.ic_timout = -1; 153417683Spst str.ic_len = len; 153517683Spst str.ic_dp = dp; 153617683Spst rc = ioctl(fd, I_STR, &str); 153717683Spst 153817683Spst if (rc < 0) 153917683Spst return (rc); 154017683Spst else 154117683Spst return (str.ic_len); 154217683Spst} 154317683Spst#endif 154417683Spst 154517683Spst#if defined(HAVE_SOLARIS) && defined(HAVE_SYS_BUFMOD_H) 154617683Spststatic char * 154717683Spstget_release(bpf_u_int32 *majorp, bpf_u_int32 *minorp, bpf_u_int32 *microp) 154817683Spst{ 154917683Spst char *cp; 155017683Spst static char buf[32]; 155117683Spst 155217683Spst *majorp = 0; 155317683Spst *minorp = 0; 155417683Spst *microp = 0; 155517683Spst if (sysinfo(SI_RELEASE, buf, sizeof(buf)) < 0) 155617683Spst return ("?"); 155717683Spst cp = buf; 155898530Sfenner if (!isdigit((unsigned char)*cp)) 155917683Spst return (buf); 156017683Spst *majorp = strtol(cp, &cp, 10); 156117683Spst if (*cp++ != '.') 156217683Spst return (buf); 156317683Spst *minorp = strtol(cp, &cp, 10); 156417683Spst if (*cp++ != '.') 156517683Spst return (buf); 156617683Spst *microp = strtol(cp, &cp, 10); 156717683Spst return (buf); 156817683Spst} 156917683Spst#endif 157017683Spst 1571146768Ssam#ifdef DL_HP_PPA_REQ 157217683Spst/* 157375107Sfenner * Under HP-UX 10 and HP-UX 11, we can ask for the ppa 157417683Spst */ 157517683Spst 157617683Spst 157775107Sfenner/* 157875107Sfenner * Determine ppa number that specifies ifname. 157975107Sfenner * 158075107Sfenner * If the "dl_hp_ppa_info_t" doesn't have a "dl_module_id_1" member, 158175107Sfenner * the code that's used here is the old code for HP-UX 10.x. 158275107Sfenner * 158375107Sfenner * However, HP-UX 10.20, at least, appears to have such a member 158475107Sfenner * in its "dl_hp_ppa_info_t" structure, so the new code is used. 158575107Sfenner * The new code didn't work on an old 10.20 system on which Rick 158675107Sfenner * Jones of HP tried it, but with later patches installed, it 158775107Sfenner * worked - it appears that the older system had those members but 158875107Sfenner * didn't put anything in them, so, if the search by name fails, we 158975107Sfenner * do the old search. 159075107Sfenner * 159175107Sfenner * Rick suggests that making sure your system is "up on the latest 159275107Sfenner * lancommon/DLPI/driver patches" is probably a good idea; it'd fix 159375107Sfenner * that problem, as well as allowing libpcap to see packets sent 159475107Sfenner * from the system on which the libpcap application is being run. 159575107Sfenner * (On 10.20, in addition to getting the latest patches, you need 159675107Sfenner * to turn the kernel "lanc_outbound_promisc_flag" flag on with ADB; 159775107Sfenner * a posting to "comp.sys.hp.hpux" at 159875107Sfenner * 159975107Sfenner * http://www.deja.com/[ST_rn=ps]/getdoc.xp?AN=558092266 160075107Sfenner * 160175107Sfenner * says that, to see the machine's outgoing traffic, you'd need to 160275107Sfenner * apply the right patches to your system, and also set that variable 160375107Sfenner * with: 1604127664Sbms 160575107Sfennerecho 'lanc_outbound_promisc_flag/W1' | /usr/bin/adb -w /stand/vmunix /dev/kmem 160675107Sfenner 160775107Sfenner * which could be put in, for example, "/sbin/init.d/lan". 160875107Sfenner * 160975107Sfenner * Setting the variable is not necessary on HP-UX 11.x. 161075107Sfenner */ 161117683Spststatic int 161217683Spstget_dlpi_ppa(register int fd, register const char *device, register int unit, 161317683Spst register char *ebuf) 161417683Spst{ 161517683Spst register dl_hp_ppa_ack_t *ap; 161675107Sfenner register dl_hp_ppa_info_t *ipstart, *ip; 161717683Spst register int i; 161875107Sfenner char dname[100]; 161917683Spst register u_long majdev; 162075107Sfenner struct stat statbuf; 162117683Spst dl_hp_ppa_req_t req; 162298530Sfenner char buf[MAXDLBUF]; 162398530Sfenner char *ppa_data_buf; 162498530Sfenner dl_hp_ppa_ack_t *dlp; 162598530Sfenner struct strbuf ctl; 162698530Sfenner int flags; 162798530Sfenner int ppa; 162817683Spst 162917683Spst memset((char *)&req, 0, sizeof(req)); 163017683Spst req.dl_primitive = DL_HP_PPA_REQ; 163117683Spst 163217683Spst memset((char *)buf, 0, sizeof(buf)); 163398530Sfenner if (send_request(fd, (char *)&req, sizeof(req), "hpppa", ebuf) < 0) 163417683Spst return (-1); 163517683Spst 163698530Sfenner ctl.maxlen = DL_HP_PPA_ACK_SIZE; 163798530Sfenner ctl.len = 0; 163898530Sfenner ctl.buf = (char *)buf; 163998530Sfenner 164098530Sfenner flags = 0; 164198530Sfenner /* 164298530Sfenner * DLPI may return a big chunk of data for a DL_HP_PPA_REQ. The normal 164398530Sfenner * recv_ack will fail because it set the maxlen to MAXDLBUF (8192) 164498530Sfenner * which is NOT big enough for a DL_HP_PPA_REQ. 164598530Sfenner * 164698530Sfenner * This causes libpcap applications to fail on a system with HP-APA 164798530Sfenner * installed. 164898530Sfenner * 164998530Sfenner * To figure out how big the returned data is, we first call getmsg 165098530Sfenner * to get the small head and peek at the head to get the actual data 165198530Sfenner * length, and then issue another getmsg to get the actual PPA data. 165298530Sfenner */ 165398530Sfenner /* get the head first */ 165498530Sfenner if (getmsg(fd, &ctl, (struct strbuf *)NULL, &flags) < 0) { 165598530Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 165698530Sfenner "get_dlpi_ppa: hpppa getmsg: %s", pcap_strerror(errno)); 165798530Sfenner return (-1); 165898530Sfenner } 165998530Sfenner 166098530Sfenner dlp = (dl_hp_ppa_ack_t *)ctl.buf; 166198530Sfenner if (dlp->dl_primitive != DL_HP_PPA_ACK) { 166298530Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 166398530Sfenner "get_dlpi_ppa: hpppa unexpected primitive ack 0x%x", 166498530Sfenner (bpf_u_int32)dlp->dl_primitive); 166598530Sfenner return (-1); 166698530Sfenner } 1667127664Sbms 166898530Sfenner if (ctl.len < DL_HP_PPA_ACK_SIZE) { 166998530Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 1670127664Sbms "get_dlpi_ppa: hpppa ack too small (%d < %lu)", 1671127664Sbms ctl.len, (unsigned long)DL_HP_PPA_ACK_SIZE); 167298530Sfenner return (-1); 167398530Sfenner } 1674127664Sbms 167598530Sfenner /* allocate buffer */ 167698530Sfenner if ((ppa_data_buf = (char *)malloc(dlp->dl_length)) == NULL) { 167798530Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 167898530Sfenner "get_dlpi_ppa: hpppa malloc: %s", pcap_strerror(errno)); 167998530Sfenner return (-1); 168098530Sfenner } 168198530Sfenner ctl.maxlen = dlp->dl_length; 168298530Sfenner ctl.len = 0; 168398530Sfenner ctl.buf = (char *)ppa_data_buf; 168498530Sfenner /* get the data */ 168598530Sfenner if (getmsg(fd, &ctl, (struct strbuf *)NULL, &flags) < 0) { 168698530Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 168798530Sfenner "get_dlpi_ppa: hpppa getmsg: %s", pcap_strerror(errno)); 168898530Sfenner free(ppa_data_buf); 168998530Sfenner return (-1); 169098530Sfenner } 169198530Sfenner if (ctl.len < dlp->dl_length) { 169298530Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 169398530Sfenner "get_dlpi_ppa: hpppa ack too small (%d < %d)", 169498530Sfenner ctl.len, dlp->dl_length); 169598530Sfenner free(ppa_data_buf); 169698530Sfenner return (-1); 169798530Sfenner } 169898530Sfenner 169917683Spst ap = (dl_hp_ppa_ack_t *)buf; 170098530Sfenner ipstart = (dl_hp_ppa_info_t *)ppa_data_buf; 170175107Sfenner ip = ipstart; 170217683Spst 170375107Sfenner#ifdef HAVE_HP_PPA_INFO_T_DL_MODULE_ID_1 170475107Sfenner /* 170575107Sfenner * The "dl_hp_ppa_info_t" structure has a "dl_module_id_1" 170675107Sfenner * member that should, in theory, contain the part of the 170775107Sfenner * name for the device that comes before the unit number, 170875107Sfenner * and should also have a "dl_module_id_2" member that may 170975107Sfenner * contain an alternate name (e.g., I think Ethernet devices 171075107Sfenner * have both "lan", for "lanN", and "snap", for "snapN", with 171175107Sfenner * the former being for Ethernet packets and the latter being 171275107Sfenner * for 802.3/802.2 packets). 171375107Sfenner * 171475107Sfenner * Search for the device that has the specified name and 171575107Sfenner * instance number. 171675107Sfenner */ 171775107Sfenner for (i = 0; i < ap->dl_count; i++) { 171898530Sfenner if ((strcmp((const char *)ip->dl_module_id_1, device) == 0 || 171998530Sfenner strcmp((const char *)ip->dl_module_id_2, device) == 0) && 172075107Sfenner ip->dl_instance_num == unit) 172175107Sfenner break; 172217683Spst 172375107Sfenner ip = (dl_hp_ppa_info_t *)((u_char *)ipstart + ip->dl_next_offset); 172475107Sfenner } 172575107Sfenner#else 172675107Sfenner /* 172775107Sfenner * We don't have that member, so the search is impossible; make it 172875107Sfenner * look as if the search failed. 172975107Sfenner */ 173075107Sfenner i = ap->dl_count; 173175107Sfenner#endif 173275107Sfenner 173375107Sfenner if (i == ap->dl_count) { 173475107Sfenner /* 173575107Sfenner * Well, we didn't, or can't, find the device by name. 173675107Sfenner * 173775107Sfenner * HP-UX 10.20, whilst it has "dl_module_id_1" and 173875107Sfenner * "dl_module_id_2" fields in the "dl_hp_ppa_info_t", 173975107Sfenner * doesn't seem to fill them in unless the system is 174075107Sfenner * at a reasonably up-to-date patch level. 174175107Sfenner * 174275107Sfenner * Older HP-UX 10.x systems might not have those fields 174375107Sfenner * at all. 174475107Sfenner * 174575107Sfenner * Therefore, we'll search for the entry with the major 174675107Sfenner * device number of a device with the name "/dev/<dev><unit>", 174775107Sfenner * if such a device exists, as the old code did. 174875107Sfenner */ 174975107Sfenner snprintf(dname, sizeof(dname), "/dev/%s%d", device, unit); 175075107Sfenner if (stat(dname, &statbuf) < 0) { 175175107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "stat: %s: %s", 175275107Sfenner dname, pcap_strerror(errno)); 175375107Sfenner return (-1); 175475107Sfenner } 175575107Sfenner majdev = major(statbuf.st_rdev); 175675107Sfenner 175775107Sfenner ip = ipstart; 175875107Sfenner 175975107Sfenner for (i = 0; i < ap->dl_count; i++) { 176075107Sfenner if (ip->dl_mjr_num == majdev && 176175107Sfenner ip->dl_instance_num == unit) 176275107Sfenner break; 176375107Sfenner 176475107Sfenner ip = (dl_hp_ppa_info_t *)((u_char *)ipstart + ip->dl_next_offset); 176575107Sfenner } 176675107Sfenner } 1767147894Ssam if (i == ap->dl_count) { 1768147894Ssam snprintf(ebuf, PCAP_ERRBUF_SIZE, 176975107Sfenner "can't find /dev/dlpi PPA for %s%d", device, unit); 177017683Spst return (-1); 1771147894Ssam } 1772147894Ssam if (ip->dl_hdw_state == HDW_DEAD) { 1773147894Ssam snprintf(ebuf, PCAP_ERRBUF_SIZE, 177475107Sfenner "%s%d: hardware state: DOWN\n", device, unit); 177598530Sfenner free(ppa_data_buf); 177617683Spst return (-1); 1777147894Ssam } 1778147894Ssam ppa = ip->dl_ppa; 1779147894Ssam free(ppa_data_buf); 1780147894Ssam return (ppa); 178117683Spst} 178217683Spst#endif 178317683Spst 178417683Spst#ifdef HAVE_HPUX9 178517683Spst/* 178617683Spst * Under HP-UX 9, there is no good way to determine the ppa. 178717683Spst * So punt and read it from /dev/kmem. 178817683Spst */ 178917683Spststatic struct nlist nl[] = { 179017683Spst#define NL_IFNET 0 179117683Spst { "ifnet" }, 179217683Spst { "" } 179317683Spst}; 179417683Spst 179517683Spststatic char path_vmunix[] = "/hp-ux"; 179617683Spst 179717683Spst/* Determine ppa number that specifies ifname */ 179817683Spststatic int 179917683Spstget_dlpi_ppa(register int fd, register const char *ifname, register int unit, 180017683Spst register char *ebuf) 180117683Spst{ 180217683Spst register const char *cp; 180317683Spst register int kd; 180417683Spst void *addr; 180517683Spst struct ifnet ifnet; 180675107Sfenner char if_name[sizeof(ifnet.if_name) + 1]; 180717683Spst 180817683Spst cp = strrchr(ifname, '/'); 180917683Spst if (cp != NULL) 181017683Spst ifname = cp + 1; 181117683Spst if (nlist(path_vmunix, &nl) < 0) { 181275107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "nlist %s failed", 181375107Sfenner path_vmunix); 181417683Spst return (-1); 181517683Spst } 181617683Spst if (nl[NL_IFNET].n_value == 0) { 181775107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 181875107Sfenner "could't find %s kernel symbol", 181917683Spst nl[NL_IFNET].n_name); 182017683Spst return (-1); 182117683Spst } 182217683Spst kd = open("/dev/kmem", O_RDONLY); 182317683Spst if (kd < 0) { 182475107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "kmem open: %s", 182575107Sfenner pcap_strerror(errno)); 182617683Spst return (-1); 182717683Spst } 182817683Spst if (dlpi_kread(kd, nl[NL_IFNET].n_value, 182917683Spst &addr, sizeof(addr), ebuf) < 0) { 183017683Spst close(kd); 183117683Spst return (-1); 183217683Spst } 183317683Spst for (; addr != NULL; addr = ifnet.if_next) { 183417683Spst if (dlpi_kread(kd, (off_t)addr, 183517683Spst &ifnet, sizeof(ifnet), ebuf) < 0 || 183617683Spst dlpi_kread(kd, (off_t)ifnet.if_name, 183775107Sfenner if_name, sizeof(ifnet.if_name), ebuf) < 0) { 183817683Spst (void)close(kd); 183917683Spst return (-1); 184017683Spst } 184175107Sfenner if_name[sizeof(ifnet.if_name)] = '\0'; 184275107Sfenner if (strcmp(if_name, ifname) == 0 && ifnet.if_unit == unit) 184317683Spst return (ifnet.if_index); 184417683Spst } 184517683Spst 184675107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "Can't find %s", ifname); 184717683Spst return (-1); 184817683Spst} 184917683Spst 185017683Spststatic int 185117683Spstdlpi_kread(register int fd, register off_t addr, 185217683Spst register void *buf, register u_int len, register char *ebuf) 185317683Spst{ 185417683Spst register int cc; 185517683Spst 185639291Sfenner if (lseek(fd, addr, SEEK_SET) < 0) { 185775107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "lseek: %s", 185875107Sfenner pcap_strerror(errno)); 185917683Spst return (-1); 186017683Spst } 186117683Spst cc = read(fd, buf, len); 186217683Spst if (cc < 0) { 186375107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "read: %s", 186475107Sfenner pcap_strerror(errno)); 186517683Spst return (-1); 186617683Spst } else if (cc != len) { 186775107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "short read (%d != %d)", cc, 186875107Sfenner len); 186917683Spst return (-1); 187017683Spst } 187117683Spst return (cc); 187217683Spst} 187317683Spst#endif 1874