pcap-dlpi.c revision 214518
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>, 25190225Srpaulo * Mark C. Brown (mbrown@hp.com), and Sagun Shakya <Sagun.Shakya@Sun.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_ = 73214518Srpaulo "@(#) $Header: /tcpdump/master/libpcap/pcap-dlpi.c,v 1.128 2008-12-02 16:20:23 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" 124190225Srpaulo#include "dlpisubs.h" 12517683Spst 12617683Spst#ifdef HAVE_OS_PROTO_H 12717683Spst#include "os-proto.h" 12817683Spst#endif 12917683Spst 13017683Spst#ifndef PCAP_DEV_PREFIX 13198530Sfenner#ifdef _AIX 13298530Sfenner#define PCAP_DEV_PREFIX "/dev/dlpi" 13398530Sfenner#else 13417683Spst#define PCAP_DEV_PREFIX "/dev" 13517683Spst#endif 13698530Sfenner#endif 13717683Spst 13817683Spst#define MAXDLBUF 8192 13917683Spst 14017683Spst/* Forwards */ 14198530Sfennerstatic char *split_dname(char *, int *, char *); 142146768Ssamstatic int dl_doattach(int, int, char *); 143147894Ssam#ifdef DL_HP_RAWDLS 144147894Ssamstatic int dl_dohpuxbind(int, char *); 145147894Ssam#endif 14617683Spststatic int dlattachreq(int, bpf_u_int32, char *); 147146768Ssamstatic int dlbindreq(int, bpf_u_int32, char *); 148147894Ssamstatic int dlbindack(int, char *, char *, int *); 149146768Ssamstatic int dlpromisconreq(int, bpf_u_int32, char *); 150146768Ssamstatic int dlokack(int, const char *, char *, char *); 151146768Ssamstatic int dlinforeq(int, char *); 15217683Spststatic int dlinfoack(int, char *, char *); 153190225Srpaulo 154190225Srpaulo#ifdef HAVE_DLPI_PASSIVE 155190225Srpaulostatic void dlpassive(int, char *); 156190225Srpaulo#endif 157190225Srpaulo 158146768Ssam#ifdef DL_HP_RAWDLS 159146768Ssamstatic int dlrawdatareq(int, const u_char *, int); 160146768Ssam#endif 161147894Ssamstatic int recv_ack(int, int, const char *, char *, char *, int *); 16298530Sfennerstatic char *dlstrerror(bpf_u_int32); 16398530Sfennerstatic char *dlprim(bpf_u_int32); 16417683Spst#if defined(HAVE_SOLARIS) && defined(HAVE_SYS_BUFMOD_H) 16517683Spststatic char *get_release(bpf_u_int32 *, bpf_u_int32 *, bpf_u_int32 *); 16617683Spst#endif 16717683Spststatic int send_request(int, char *, int, char *, char *); 16817683Spst#ifdef HAVE_HPUX9 16917683Spststatic int dlpi_kread(int, off_t, void *, u_int, char *); 17017683Spst#endif 17117683Spst#ifdef HAVE_DEV_DLPI 17217683Spststatic int get_dlpi_ppa(int, const char *, int, char *); 17317683Spst#endif 17417683Spst 17517683Spst/* XXX Needed by HP-UX (at least) */ 17617683Spststatic bpf_u_int32 ctlbuf[MAXDLBUF]; 17717683Spststatic struct strbuf ctl = { 17817683Spst MAXDLBUF, 17917683Spst 0, 18017683Spst (char *)ctlbuf 18117683Spst}; 18217683Spst 183214518Srpaulo/* 184214518Srpaulo * Cast a buffer to "union DL_primitives" without provoking warnings 185214518Srpaulo * from the compiler. 186214518Srpaulo */ 187214518Srpaulo#define MAKE_DL_PRIMITIVES(ptr) ((union DL_primitives *)(void *)(ptr)) 188214518Srpaulo 189127664Sbmsstatic int 190127664Sbmspcap_read_dlpi(pcap_t *p, int cnt, pcap_handler callback, u_char *user) 19117683Spst{ 192190225Srpaulo int cc; 193190225Srpaulo u_char *bp; 19417683Spst int flags; 19517683Spst struct strbuf data; 19617683Spst 19717683Spst flags = 0; 19817683Spst cc = p->cc; 19917683Spst if (cc == 0) { 20017683Spst data.buf = (char *)p->buffer + p->offset; 201127664Sbms data.maxlen = p->bufsize; 20217683Spst data.len = 0; 20317683Spst do { 204127664Sbms /* 205127664Sbms * Has "pcap_breakloop()" been called? 206127664Sbms */ 207127664Sbms if (p->break_loop) { 208127664Sbms /* 209127664Sbms * Yes - clear the flag that indicates 210127664Sbms * that it has, and return -2 to 211127664Sbms * indicate that we were told to 212127664Sbms * break out of the loop. 213127664Sbms */ 214127664Sbms p->break_loop = 0; 215127664Sbms return (-2); 216127664Sbms } 217146768Ssam /* 218146768Ssam * XXX - check for the DLPI primitive, which 219146768Ssam * would be DL_HP_RAWDATA_IND on HP-UX 220146768Ssam * if we're in raw mode? 221146768Ssam */ 22217683Spst if (getmsg(p->fd, &ctl, &data, &flags) < 0) { 22317683Spst /* Don't choke when we get ptraced */ 224146768Ssam switch (errno) { 225146768Ssam 226146768Ssam case EINTR: 22717683Spst cc = 0; 22817683Spst continue; 229146768Ssam 230146768Ssam case EAGAIN: 231146768Ssam return (0); 23217683Spst } 23375107Sfenner strlcpy(p->errbuf, pcap_strerror(errno), 23475107Sfenner sizeof(p->errbuf)); 23517683Spst return (-1); 23617683Spst } 23717683Spst cc = data.len; 23817683Spst } while (cc == 0); 23917683Spst bp = p->buffer + p->offset; 24017683Spst } else 24117683Spst bp = p->bp; 24217683Spst 243190225Srpaulo return (pcap_process_pkts(p, callback, user, cnt, bp, cc)); 24417683Spst} 24517683Spst 246146768Ssamstatic int 247146768Ssampcap_inject_dlpi(pcap_t *p, const void *buf, size_t size) 248146768Ssam{ 249146768Ssam int ret; 250146768Ssam 251146768Ssam#if defined(DLIOCRAW) 252146768Ssam ret = write(p->fd, buf, size); 253146768Ssam if (ret == -1) { 254146768Ssam snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: %s", 255146768Ssam pcap_strerror(errno)); 256146768Ssam return (-1); 257146768Ssam } 258146768Ssam#elif defined(DL_HP_RAWDLS) 259146768Ssam if (p->send_fd < 0) { 260146768Ssam snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 261146768Ssam "send: Output FD couldn't be opened"); 262146768Ssam return (-1); 263146768Ssam } 264146768Ssam ret = dlrawdatareq(p->send_fd, buf, size); 265146768Ssam if (ret == -1) { 266146768Ssam snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: %s", 267146768Ssam pcap_strerror(errno)); 268146768Ssam return (-1); 269146768Ssam } 270172677Smlaier /* 271172677Smlaier * putmsg() returns either 0 or -1; it doesn't indicate how 272172677Smlaier * many bytes were written (presumably they were all written 273172677Smlaier * or none of them were written). OpenBSD's pcap_inject() 274172677Smlaier * returns the number of bytes written, so, for API compatibility, 275172677Smlaier * we return the number of bytes we were told to write. 276172677Smlaier */ 277172677Smlaier ret = size; 278146768Ssam#else /* no raw mode */ 279146768Ssam /* 280146768Ssam * XXX - this is a pain, because you might have to extract 281146768Ssam * the address from the packet and use it in a DL_UNITDATA_REQ 282146768Ssam * request. That would be dependent on the link-layer type. 283146768Ssam * 284146768Ssam * I also don't know what SAP you'd have to bind the descriptor 285146768Ssam * to, or whether you'd need separate "receive" and "send" FDs, 286146768Ssam * nor do I know whether you'd need different bindings for 287146768Ssam * D/I/X Ethernet and 802.3, or for {FDDI,Token Ring} plus 288146768Ssam * 802.2 and {FDDI,Token Ring} plus 802.2 plus SNAP. 289146768Ssam * 290146768Ssam * So, for now, we just return a "you can't send" indication, 291146768Ssam * and leave it up to somebody with a DLPI-based system lacking 292146768Ssam * both DLIOCRAW and DL_HP_RAWDLS to supply code to implement 293146768Ssam * packet transmission on that system. If they do, they should 294146768Ssam * send it to us - but should not send us code that assumes 295146768Ssam * Ethernet; if the code doesn't work on non-Ethernet interfaces, 296146768Ssam * it should check "p->linktype" and reject the send request if 297146768Ssam * it's anything other than DLT_EN10MB. 298146768Ssam */ 299146768Ssam strlcpy(p->errbuf, "send: Not supported on this version of this OS", 300146768Ssam PCAP_ERRBUF_SIZE); 301146768Ssam ret = -1; 302146768Ssam#endif /* raw mode */ 303146768Ssam return (ret); 304147894Ssam} 305146768Ssam 306127664Sbms#ifndef DL_IPATM 307127664Sbms#define DL_IPATM 0x12 /* ATM Classical IP interface */ 308127664Sbms#endif 309127664Sbms 310127664Sbms#ifdef HAVE_SOLARIS 311127664Sbms/* 312127664Sbms * For SunATM. 313127664Sbms */ 314127664Sbms#ifndef A_GET_UNITS 315127664Sbms#define A_GET_UNITS (('A'<<8)|118) 316127664Sbms#endif /* A_GET_UNITS */ 317127664Sbms#ifndef A_PROMISCON_REQ 318127664Sbms#define A_PROMISCON_REQ (('A'<<8)|121) 319127664Sbms#endif /* A_PROMISCON_REQ */ 320127664Sbms#endif /* HAVE_SOLARIS */ 321127664Sbms 322127664Sbmsstatic void 323190225Srpaulopcap_cleanup_dlpi(pcap_t *p) 324127664Sbms{ 325190225Srpaulo if (p->send_fd >= 0) { 326146768Ssam close(p->send_fd); 327190225Srpaulo p->send_fd = -1; 328190225Srpaulo } 329190225Srpaulo pcap_cleanup_live_common(p); 330127664Sbms} 331127664Sbms 332190225Srpaulostatic int 333190225Srpaulopcap_activate_dlpi(pcap_t *p) 33417683Spst{ 33517683Spst register char *cp; 33698530Sfenner int ppa; 337127664Sbms#ifdef HAVE_SOLARIS 338127664Sbms int isatm = 0; 339127664Sbms#endif 34017683Spst register dl_info_ack_t *infop; 34117683Spst#ifdef HAVE_SYS_BUFMOD_H 342190225Srpaulo bpf_u_int32 ss; 34317683Spst#ifdef HAVE_SOLARIS 34417683Spst register char *release; 34517683Spst bpf_u_int32 osmajor, osminor, osmicro; 34617683Spst#endif 34717683Spst#endif 34817683Spst bpf_u_int32 buf[MAXDLBUF]; 34917683Spst char dname[100]; 35017683Spst#ifndef HAVE_DEV_DLPI 35117683Spst char dname2[100]; 35217683Spst#endif 353190225Srpaulo int status = PCAP_ERROR; 35417683Spst 35575107Sfenner#ifdef HAVE_DEV_DLPI 35617683Spst /* 35775107Sfenner ** Remove any "/dev/" on the front of the device. 35817683Spst */ 359190225Srpaulo cp = strrchr(p->opt.source, '/'); 36075107Sfenner if (cp == NULL) 361190225Srpaulo strlcpy(dname, p->opt.source, sizeof(dname)); 36275107Sfenner else 363127664Sbms strlcpy(dname, cp + 1, sizeof(dname)); 36475107Sfenner 36575107Sfenner /* 36698530Sfenner * Split the device name into a device type name and a unit number; 36798530Sfenner * chop off the unit number, so "dname" is just a device type name. 36875107Sfenner */ 369190225Srpaulo cp = split_dname(dname, &ppa, p->errbuf); 370190225Srpaulo if (cp == NULL) { 371190225Srpaulo status = PCAP_ERROR_NO_SUCH_DEVICE; 37217683Spst goto bad; 373190225Srpaulo } 37475107Sfenner *cp = '\0'; 37517683Spst 37675107Sfenner /* 37775107Sfenner * Use "/dev/dlpi" as the device. 37875107Sfenner * 37975107Sfenner * XXX - HP's DLPI Programmer's Guide for HP-UX 11.00 says that 38075107Sfenner * the "dl_mjr_num" field is for the "major number of interface 38175107Sfenner * driver"; that's the major of "/dev/dlpi" on the system on 38275107Sfenner * which I tried this, but there may be DLPI devices that 38375107Sfenner * use a different driver, in which case we may need to 38475107Sfenner * search "/dev" for the appropriate device with that major 38575107Sfenner * device number, rather than hardwiring "/dev/dlpi". 38675107Sfenner */ 38717683Spst cp = "/dev/dlpi"; 38817683Spst if ((p->fd = open(cp, O_RDWR)) < 0) { 389190225Srpaulo if (errno == EPERM || errno == EACCES) 390190225Srpaulo status = PCAP_ERROR_PERM_DENIED; 391190225Srpaulo snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 39275107Sfenner "%s: %s", cp, pcap_strerror(errno)); 39317683Spst goto bad; 39417683Spst } 39575107Sfenner 396146768Ssam#ifdef DL_HP_RAWDLS 39775107Sfenner /* 398146768Ssam * XXX - HP-UX 10.20 and 11.xx don't appear to support sending and 399147894Ssam * receiving packets on the same descriptor - you need separate 400147894Ssam * descriptors for sending and receiving, bound to different SAPs. 401146768Ssam * 402146768Ssam * If the open fails, we just leave -1 in "p->send_fd" and reject 403146768Ssam * attempts to send packets, just as if, in pcap-bpf.c, we fail 404146768Ssam * to open the BPF device for reading and writing, we just try 405146768Ssam * to open it for reading only and, if that succeeds, just let 406146768Ssam * the send attempts fail. 407146768Ssam */ 408146768Ssam p->send_fd = open(cp, O_RDWR); 409146768Ssam#endif 410146768Ssam 411146768Ssam /* 41275107Sfenner * Get a table of all PPAs for that device, and search that 41375107Sfenner * table for the specified device type name and unit number. 41475107Sfenner */ 415190225Srpaulo ppa = get_dlpi_ppa(p->fd, dname, ppa, p->errbuf); 416190225Srpaulo if (ppa < 0) { 417190225Srpaulo status = ppa; 41817683Spst goto bad; 419190225Srpaulo } 42017683Spst#else 42175107Sfenner /* 42298530Sfenner * If the device name begins with "/", assume it begins with 42398530Sfenner * the pathname of the directory containing the device to open; 42498530Sfenner * otherwise, concatenate the device directory name and the 42598530Sfenner * device name. 42698530Sfenner */ 427190225Srpaulo if (*p->opt.source == '/') 428190225Srpaulo strlcpy(dname, p->opt.source, sizeof(dname)); 42975107Sfenner else 43075107Sfenner snprintf(dname, sizeof(dname), "%s/%s", PCAP_DEV_PREFIX, 431190225Srpaulo p->opt.source); 43275107Sfenner 43398530Sfenner /* 434127664Sbms * Get the unit number, and a pointer to the end of the device 435127664Sbms * type name. 436127664Sbms */ 437190225Srpaulo cp = split_dname(dname, &ppa, p->errbuf); 438190225Srpaulo if (cp == NULL) { 439190225Srpaulo status = PCAP_ERROR_NO_SUCH_DEVICE; 440127664Sbms goto bad; 441190225Srpaulo } 442127664Sbms 443127664Sbms /* 44498530Sfenner * Make a copy of the device pathname, and then remove the unit 44598530Sfenner * number from the device pathname. 44698530Sfenner */ 44798530Sfenner strlcpy(dname2, dname, sizeof(dname)); 448127664Sbms *cp = '\0'; 44998530Sfenner 45017683Spst /* Try device without unit number */ 45117683Spst if ((p->fd = open(dname, O_RDWR)) < 0) { 45217683Spst if (errno != ENOENT) { 453190225Srpaulo if (errno == EACCES) 454190225Srpaulo status = PCAP_ERROR_PERM_DENIED; 455190225Srpaulo snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: %s", dname, 45675107Sfenner pcap_strerror(errno)); 45717683Spst goto bad; 45817683Spst } 45917683Spst 46017683Spst /* Try again with unit number */ 46117683Spst if ((p->fd = open(dname2, O_RDWR)) < 0) { 462146768Ssam if (errno == ENOENT) { 463190225Srpaulo status = PCAP_ERROR_NO_SUCH_DEVICE; 464190225Srpaulo 465146768Ssam /* 466190225Srpaulo * We provide an error message even 467190225Srpaulo * for this error, for diagnostic 468190225Srpaulo * purposes (so that, for example, 469190225Srpaulo * the app can show the message if the 470190225Srpaulo * user requests it). 471190225Srpaulo * 472190225Srpaulo * In it, we just report "No DLPI device 473190225Srpaulo * found" with the device name, so people 474190225Srpaulo * don't get confused and think, for example, 475146768Ssam * that if they can't capture on "lo0" 476146768Ssam * on Solaris the fix is to change libpcap 477146768Ssam * (or the application that uses it) to 478146768Ssam * look for something other than "/dev/lo0", 479146768Ssam * as the fix is to look for an operating 480146768Ssam * system other than Solaris - you just 481146768Ssam * *can't* capture on a loopback interface 482146768Ssam * on Solaris, the lack of a DLPI device 483146768Ssam * for the loopback interface is just a 484146768Ssam * symptom of that inability. 485146768Ssam */ 486190225Srpaulo snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 487190225Srpaulo "%s: No DLPI device found", p->opt.source); 488146768Ssam } else { 489190225Srpaulo if (errno == EACCES) 490190225Srpaulo status = PCAP_ERROR_PERM_DENIED; 491190225Srpaulo snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: %s", 492146768Ssam dname2, pcap_strerror(errno)); 493146768Ssam } 49417683Spst goto bad; 49517683Spst } 49617683Spst /* XXX Assume unit zero */ 49717683Spst ppa = 0; 49817683Spst } 49917683Spst#endif 50017683Spst 50117683Spst /* 50217683Spst ** Attach if "style 2" provider 50317683Spst */ 504190225Srpaulo if (dlinforeq(p->fd, p->errbuf) < 0 || 505190225Srpaulo dlinfoack(p->fd, (char *)buf, p->errbuf) < 0) 50617683Spst goto bad; 507214518Srpaulo infop = &(MAKE_DL_PRIMITIVES(buf))->info_ack; 508127664Sbms#ifdef HAVE_SOLARIS 509127664Sbms if (infop->dl_mac_type == DL_IPATM) 510127664Sbms isatm = 1; 511127664Sbms#endif 512146768Ssam if (infop->dl_provider_style == DL_STYLE2) { 513190225Srpaulo status = dl_doattach(p->fd, ppa, p->errbuf); 514190225Srpaulo if (status < 0) 515146768Ssam goto bad; 516146768Ssam#ifdef DL_HP_RAWDLS 517146768Ssam if (p->send_fd >= 0) { 518190225Srpaulo if (dl_doattach(p->send_fd, ppa, p->errbuf) < 0) 519146768Ssam goto bad; 520146768Ssam } 521146768Ssam#endif 522146768Ssam } 523146768Ssam 524190225Srpaulo if (p->opt.rfmon) { 525190225Srpaulo /* 526190225Srpaulo * This device exists, but we don't support monitor mode 527190225Srpaulo * any platforms that support DLPI. 528190225Srpaulo */ 529190225Srpaulo status = PCAP_ERROR_RFMON_NOTSUP; 530190225Srpaulo goto bad; 531190225Srpaulo } 532190225Srpaulo 533190225Srpaulo#ifdef HAVE_DLPI_PASSIVE 53417683Spst /* 535190225Srpaulo * Enable Passive mode to be able to capture on aggregated link. 536190225Srpaulo * Not supported in all Solaris versions. 537190225Srpaulo */ 538190225Srpaulo dlpassive(p->fd, p->errbuf); 539190225Srpaulo#endif 540190225Srpaulo /* 541147894Ssam ** Bind (defer if using HP-UX 9 or HP-UX 10.20 or later, totally 542147894Ssam ** skip if using SINIX) 54317683Spst */ 544147894Ssam#if !defined(HAVE_HPUX9) && !defined(HAVE_HPUX10_20_OR_LATER) && !defined(sinix) 54575107Sfenner#ifdef _AIX 546147894Ssam /* 547147894Ssam ** AIX. 548147894Ssam ** According to IBM's AIX Support Line, the dl_sap value 54998530Sfenner ** should not be less than 0x600 (1536) for standard Ethernet. 55098530Sfenner ** However, we seem to get DL_BADADDR - "DLSAP addr in improper 55198530Sfenner ** format or invalid" - errors if we use 1537 on the "tr0" 55298530Sfenner ** device, which, given that its name starts with "tr" and that 55398530Sfenner ** it's IBM, probably means a Token Ring device. (Perhaps we 55498530Sfenner ** need to use 1537 on "/dev/dlpi/en" because that device is for 55598530Sfenner ** D/I/X Ethernet, the "SAP" is actually an Ethernet type, and 55698530Sfenner ** it rejects invalid Ethernet types.) 55798530Sfenner ** 55898530Sfenner ** So if 1537 fails, we try 2, as Hyung Sik Yoon of IBM Korea 55998530Sfenner ** says that works on Token Ring (he says that 0 does *not* 56098530Sfenner ** work; perhaps that's considered an invalid LLC SAP value - I 56198530Sfenner ** assume the SAP value in a DLPI bind is an LLC SAP for network 56298530Sfenner ** types that use 802.2 LLC). 56398530Sfenner */ 564190225Srpaulo if ((dlbindreq(p->fd, 1537, p->errbuf) < 0 && 565190225Srpaulo dlbindreq(p->fd, 2, p->errbuf) < 0) || 566190225Srpaulo dlbindack(p->fd, (char *)buf, p->errbuf, NULL) < 0) 567146768Ssam goto bad; 568146768Ssam#elif defined(DL_HP_RAWDLS) 569146768Ssam /* 570147894Ssam ** HP-UX 10.0x and 10.1x. 571146768Ssam */ 572190225Srpaulo if (dl_dohpuxbind(p->fd, p->errbuf) < 0) 573146768Ssam goto bad; 574146768Ssam if (p->send_fd >= 0) { 575146768Ssam /* 576147894Ssam ** XXX - if this fails, just close send_fd and 577147894Ssam ** set it to -1, so that you can't send but can 578147894Ssam ** still receive? 579146768Ssam */ 580190225Srpaulo if (dl_dohpuxbind(p->send_fd, p->errbuf) < 0) 581146768Ssam goto bad; 582146768Ssam } 583146768Ssam#else /* neither AIX nor HP-UX */ 584147894Ssam /* 585147894Ssam ** Not Sinix, and neither AIX nor HP-UX - Solaris, and any other 586147894Ssam ** OS using DLPI. 587147894Ssam **/ 588190225Srpaulo if (dlbindreq(p->fd, 0, p->errbuf) < 0 || 589190225Srpaulo dlbindack(p->fd, (char *)buf, p->errbuf, NULL) < 0) 59017683Spst goto bad; 591147894Ssam#endif /* AIX vs. HP-UX vs. other */ 592147894Ssam#endif /* !HP-UX 9 and !HP-UX 10.20 or later and !SINIX */ 59317683Spst 594127664Sbms#ifdef HAVE_SOLARIS 595127664Sbms if (isatm) { 596127664Sbms /* 597127664Sbms ** Have to turn on some special ATM promiscuous mode 598127664Sbms ** for SunATM. 599127664Sbms ** Do *NOT* turn regular promiscuous mode on; it doesn't 600127664Sbms ** help, and may break things. 601127664Sbms */ 602127664Sbms if (strioctl(p->fd, A_PROMISCON_REQ, 0, NULL) < 0) { 603190225Srpaulo snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 604190225Srpaulo "A_PROMISCON_REQ: %s", pcap_strerror(errno)); 605127664Sbms goto bad; 606127664Sbms } 607127664Sbms } else 608127664Sbms#endif 609190225Srpaulo if (p->opt.promisc) { 61017683Spst /* 611146768Ssam ** Enable promiscuous (not necessary on send FD) 61217683Spst */ 613190225Srpaulo if (dlpromisconreq(p->fd, DL_PROMISC_PHYS, p->errbuf) < 0 || 614190225Srpaulo dlokack(p->fd, "promisc_phys", (char *)buf, p->errbuf) < 0) 61517683Spst goto bad; 61617683Spst 61717683Spst /* 61817683Spst ** Try to enable multicast (you would have thought 61939291Sfenner ** promiscuous would be sufficient). (Skip if using 620146768Ssam ** HP-UX or SINIX) (Not necessary on send FD) 62117683Spst */ 62239291Sfenner#if !defined(__hpux) && !defined(sinix) 623190225Srpaulo if (dlpromisconreq(p->fd, DL_PROMISC_MULTI, p->errbuf) < 0 || 624190225Srpaulo dlokack(p->fd, "promisc_multi", (char *)buf, p->errbuf) < 0) 625190225Srpaulo status = PCAP_WARNING; 62617683Spst#endif 62717683Spst } 62817683Spst /* 629147894Ssam ** Try to enable SAP promiscuity (when not in promiscuous mode 630147894Ssam ** when using HP-UX, when not doing SunATM on Solaris, and never 631146768Ssam ** under SINIX) (Not necessary on send FD) 63217683Spst */ 63317683Spst#ifndef sinix 63439291Sfenner if ( 63539291Sfenner#ifdef __hpux 636190225Srpaulo !p->opt.promisc && 63739291Sfenner#endif 638127664Sbms#ifdef HAVE_SOLARIS 639127664Sbms !isatm && 640127664Sbms#endif 641190225Srpaulo (dlpromisconreq(p->fd, DL_PROMISC_SAP, p->errbuf) < 0 || 642190225Srpaulo dlokack(p->fd, "promisc_sap", (char *)buf, p->errbuf) < 0)) { 64317683Spst /* Not fatal if promisc since the DL_PROMISC_PHYS worked */ 644190225Srpaulo if (p->opt.promisc) 645190225Srpaulo status = PCAP_WARNING; 64617683Spst else 64717683Spst goto bad; 64817683Spst } 649147894Ssam#endif /* sinix */ 65017683Spst 65117683Spst /* 652147894Ssam ** HP-UX 9, and HP-UX 10.20 or later, must bind after setting 653147894Ssam ** promiscuous options. 65417683Spst */ 655147894Ssam#if defined(HAVE_HPUX9) || defined(HAVE_HPUX10_20_OR_LATER) 656190225Srpaulo if (dl_dohpuxbind(p->fd, p->errbuf) < 0) 65717683Spst goto bad; 658147894Ssam /* 659147894Ssam ** We don't set promiscuous mode on the send FD, but we'll defer 660147894Ssam ** binding it anyway, just to keep the HP-UX 9/10.20 or later 661147894Ssam ** code together. 662147894Ssam */ 663147894Ssam if (p->send_fd >= 0) { 664147894Ssam /* 665147894Ssam ** XXX - if this fails, just close send_fd and 666147894Ssam ** set it to -1, so that you can't send but can 667147894Ssam ** still receive? 668147894Ssam */ 669190225Srpaulo if (dl_dohpuxbind(p->send_fd, p->errbuf) < 0) 670147894Ssam goto bad; 671147894Ssam } 67217683Spst#endif 67317683Spst 67417683Spst /* 67517683Spst ** Determine link type 676146768Ssam ** XXX - get SAP length and address length as well, for use 677146768Ssam ** when sending packets. 67817683Spst */ 679190225Srpaulo if (dlinforeq(p->fd, p->errbuf) < 0 || 680190225Srpaulo dlinfoack(p->fd, (char *)buf, p->errbuf) < 0) 68117683Spst goto bad; 68217683Spst 683214518Srpaulo infop = &(MAKE_DL_PRIMITIVES(buf))->info_ack; 684190225Srpaulo if (pcap_process_mactype(p, infop->dl_mac_type) != 0) 68517683Spst goto bad; 68617683Spst 68717683Spst#ifdef DLIOCRAW 68817683Spst /* 689127664Sbms ** This is a non standard SunOS hack to get the full raw link-layer 690127664Sbms ** header. 69117683Spst */ 69217683Spst if (strioctl(p->fd, DLIOCRAW, 0, NULL) < 0) { 693190225Srpaulo snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "DLIOCRAW: %s", 69475107Sfenner pcap_strerror(errno)); 69517683Spst goto bad; 69617683Spst } 69717683Spst#endif 69817683Spst 699214518Srpaulo#ifdef HAVE_SYS_BUFMOD_H 700190225Srpaulo ss = p->snapshot; 70117683Spst 70217683Spst /* 70317683Spst ** There is a bug in bufmod(7). When dealing with messages of 70417683Spst ** less than snaplen size it strips data from the beginning not 70517683Spst ** the end. 70617683Spst ** 707190225Srpaulo ** This bug is fixed in 5.3.2. Also, there is a patch available. 708190225Srpaulo ** Ask for bugid 1149065. 70917683Spst */ 71017683Spst#ifdef HAVE_SOLARIS 71117683Spst release = get_release(&osmajor, &osminor, &osmicro); 71217683Spst if (osmajor == 5 && (osminor <= 2 || (osminor == 3 && osmicro < 2)) && 71317683Spst getenv("BUFMOD_FIXED") == NULL) { 714190225Srpaulo snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 715190225Srpaulo "WARNING: bufmod is broken in SunOS %s; ignoring snaplen.", 71617683Spst release); 71717683Spst ss = 0; 718190225Srpaulo status = PCAP_WARNING; 71917683Spst } 72017683Spst#endif 72117683Spst 722190225Srpaulo /* Push and configure bufmod. */ 723190225Srpaulo if (pcap_conf_bufmod(p, ss, p->md.timeout) != 0) 724127664Sbms goto bad; 72517683Spst#endif 72617683Spst 72717683Spst /* 72817683Spst ** As the last operation flush the read side. 72917683Spst */ 73017683Spst if (ioctl(p->fd, I_FLUSH, FLUSHR) != 0) { 731190225Srpaulo snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "FLUSHR: %s", 73275107Sfenner pcap_strerror(errno)); 73317683Spst goto bad; 73417683Spst } 735127664Sbms 736190225Srpaulo /* Allocate data buffer. */ 737190225Srpaulo if (pcap_alloc_databuf(p) != 0) 738127664Sbms goto bad; 73917683Spst 740190225Srpaulo /* Success - but perhaps with a warning */ 741190225Srpaulo if (status < 0) 742190225Srpaulo status = 0; 743190225Srpaulo 744127664Sbms /* 745127664Sbms * "p->fd" is an FD for a STREAMS device, so "select()" and 746127664Sbms * "poll()" should work on it. 747127664Sbms */ 748127664Sbms p->selectable_fd = p->fd; 749127664Sbms 750127664Sbms p->read_op = pcap_read_dlpi; 751146768Ssam p->inject_op = pcap_inject_dlpi; 752127664Sbms p->setfilter_op = install_bpf_program; /* no kernel filtering */ 753147894Ssam p->setdirection_op = NULL; /* Not implemented.*/ 754127664Sbms p->set_datalink_op = NULL; /* can't change data link type */ 755127664Sbms p->getnonblock_op = pcap_getnonblock_fd; 756127664Sbms p->setnonblock_op = pcap_setnonblock_fd; 757127664Sbms p->stats_op = pcap_stats_dlpi; 758190225Srpaulo p->cleanup_op = pcap_cleanup_dlpi; 759127664Sbms 760190225Srpaulo return (status); 76117683Spstbad: 762190225Srpaulo pcap_cleanup_dlpi(p); 763190225Srpaulo return (status); 76417683Spst} 76517683Spst 76698530Sfenner/* 76798530Sfenner * Split a device name into a device type name and a unit number; 76898530Sfenner * return the a pointer to the beginning of the unit number, which 76998530Sfenner * is the end of the device type name, and set "*unitp" to the unit 77098530Sfenner * number. 77198530Sfenner * 77298530Sfenner * Returns NULL on error, and fills "ebuf" with an error message. 77398530Sfenner */ 77498530Sfennerstatic char * 77598530Sfennersplit_dname(char *device, int *unitp, char *ebuf) 77698530Sfenner{ 77798530Sfenner char *cp; 77898530Sfenner char *eos; 779146768Ssam long unit; 78098530Sfenner 78198530Sfenner /* 78298530Sfenner * Look for a number at the end of the device name string. 78398530Sfenner */ 78498530Sfenner cp = device + strlen(device) - 1; 78598530Sfenner if (*cp < '0' || *cp > '9') { 78698530Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s missing unit number", 78798530Sfenner device); 78898530Sfenner return (NULL); 78998530Sfenner } 79098530Sfenner 79198530Sfenner /* Digits at end of string are unit number */ 79298530Sfenner while (cp-1 >= device && *(cp-1) >= '0' && *(cp-1) <= '9') 79398530Sfenner cp--; 79498530Sfenner 795146768Ssam errno = 0; 79698530Sfenner unit = strtol(cp, &eos, 10); 79798530Sfenner if (*eos != '\0') { 79898530Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s bad unit number", device); 79998530Sfenner return (NULL); 80098530Sfenner } 801146768Ssam if (errno == ERANGE || unit > INT_MAX) { 802146768Ssam snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s unit number too large", 803146768Ssam device); 804146768Ssam return (NULL); 805146768Ssam } 806146768Ssam if (unit < 0) { 807146768Ssam snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s unit number is negative", 808146768Ssam device); 809146768Ssam return (NULL); 810146768Ssam } 811146768Ssam *unitp = (int)unit; 81298530Sfenner return (cp); 81398530Sfenner} 81498530Sfenner 815146768Ssamstatic int 816146768Ssamdl_doattach(int fd, int ppa, char *ebuf) 817146768Ssam{ 818146768Ssam bpf_u_int32 buf[MAXDLBUF]; 819190225Srpaulo int err; 820146768Ssam 821190225Srpaulo if (dlattachreq(fd, ppa, ebuf) < 0) 822190225Srpaulo return (PCAP_ERROR); 823190225Srpaulo err = dlokack(fd, "attach", (char *)buf, ebuf); 824190225Srpaulo if (err < 0) 825190225Srpaulo return (err); 826146768Ssam return (0); 827146768Ssam} 828146768Ssam 829147894Ssam#ifdef DL_HP_RAWDLS 830147894Ssamstatic int 831147894Ssamdl_dohpuxbind(int fd, char *ebuf) 832147894Ssam{ 833147894Ssam int hpsap; 834147894Ssam int uerror; 835147894Ssam bpf_u_int32 buf[MAXDLBUF]; 836147894Ssam 837147894Ssam /* 838147894Ssam * XXX - we start at 22 because we used to use only 22, but 839147894Ssam * that was just because that was the value used in some 840147894Ssam * sample code from HP. With what value *should* we start? 841147894Ssam * Does it matter, given that we're enabling SAP promiscuity 842147894Ssam * on the input FD? 843147894Ssam */ 844147894Ssam hpsap = 22; 845147894Ssam for (;;) { 846147894Ssam if (dlbindreq(fd, hpsap, ebuf) < 0) 847147894Ssam return (-1); 848147894Ssam if (dlbindack(fd, (char *)buf, ebuf, &uerror) >= 0) 849147894Ssam break; 850147894Ssam /* 851147894Ssam * For any error other than a UNIX EBUSY, give up. 852147894Ssam */ 853162012Ssam if (uerror != EBUSY) { 854162012Ssam /* 855162012Ssam * dlbindack() has already filled in ebuf for 856162012Ssam * this error. 857162012Ssam */ 858147894Ssam return (-1); 859162012Ssam } 860147894Ssam 861147894Ssam /* 862147894Ssam * For EBUSY, try the next SAP value; that means that 863147894Ssam * somebody else is using that SAP. Clear ebuf so 864147894Ssam * that application doesn't report the "Device busy" 865147894Ssam * error as a warning. 866147894Ssam */ 867147894Ssam *ebuf = '\0'; 868147894Ssam hpsap++; 869162012Ssam if (hpsap > 100) { 870162012Ssam strlcpy(ebuf, 871162012Ssam "All SAPs from 22 through 100 are in use", 872162012Ssam PCAP_ERRBUF_SIZE); 873147894Ssam return (-1); 874162012Ssam } 875147894Ssam } 876162012Ssam return (0); 877147894Ssam} 878147894Ssam#endif 879147894Ssam 88017683Spstint 881127664Sbmspcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf) 88217683Spst{ 883127664Sbms#ifdef HAVE_SOLARIS 884127664Sbms int fd; 885127664Sbms union { 886127664Sbms u_int nunits; 887127664Sbms char pad[516]; /* XXX - must be at least 513; is 516 888127664Sbms in "atmgetunits" */ 889127664Sbms } buf; 890127664Sbms char baname[2+1+1]; 891127664Sbms u_int i; 89217683Spst 893127664Sbms /* 894127664Sbms * We may have to do special magic to get ATM devices. 895127664Sbms */ 896127664Sbms if ((fd = open("/dev/ba", O_RDWR)) < 0) { 897127664Sbms /* 898127664Sbms * We couldn't open the "ba" device. 899127664Sbms * For now, just give up; perhaps we should 900127664Sbms * return an error if the problem is neither 901127664Sbms * a "that device doesn't exist" error (ENOENT, 902127664Sbms * ENXIO, etc.) or a "you're not allowed to do 903127664Sbms * that" error (EPERM, EACCES). 904127664Sbms */ 905127664Sbms return (0); 906127664Sbms } 907127664Sbms 908127664Sbms if (strioctl(fd, A_GET_UNITS, sizeof(buf), (char *)&buf) < 0) { 909127664Sbms snprintf(errbuf, PCAP_ERRBUF_SIZE, "A_GET_UNITS: %s", 910127664Sbms pcap_strerror(errno)); 91175107Sfenner return (-1); 912127664Sbms } 913127664Sbms for (i = 0; i < buf.nunits; i++) { 914127664Sbms snprintf(baname, sizeof baname, "ba%u", i); 915127664Sbms if (pcap_add_if(alldevsp, baname, 0, NULL, errbuf) < 0) 916127664Sbms return (-1); 917127664Sbms } 918127664Sbms#endif 919127664Sbms 92017683Spst return (0); 92117683Spst} 92217683Spst 92317683Spststatic int 92417683Spstsend_request(int fd, char *ptr, int len, char *what, char *ebuf) 92517683Spst{ 92617683Spst struct strbuf ctl; 92717683Spst int flags; 92817683Spst 92917683Spst ctl.maxlen = 0; 93017683Spst ctl.len = len; 93117683Spst ctl.buf = ptr; 93217683Spst 93317683Spst flags = 0; 93417683Spst if (putmsg(fd, &ctl, (struct strbuf *) NULL, flags) < 0) { 93575107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 93675107Sfenner "send_request: putmsg \"%s\": %s", 93717683Spst what, pcap_strerror(errno)); 93817683Spst return (-1); 93917683Spst } 94017683Spst return (0); 94117683Spst} 94217683Spst 94317683Spststatic int 944147894Ssamrecv_ack(int fd, int size, const char *what, char *bufp, char *ebuf, int *uerror) 94517683Spst{ 94617683Spst union DL_primitives *dlp; 94717683Spst struct strbuf ctl; 94817683Spst int flags; 94917683Spst 950162012Ssam /* 951162012Ssam * Clear out "*uerror", so it's only set for DL_ERROR_ACK/DL_SYSERR, 952162012Ssam * making that the only place where EBUSY is treated specially. 953162012Ssam */ 954162012Ssam if (uerror != NULL) 955162012Ssam *uerror = 0; 956162012Ssam 95717683Spst ctl.maxlen = MAXDLBUF; 95817683Spst ctl.len = 0; 95917683Spst ctl.buf = bufp; 96017683Spst 96117683Spst flags = 0; 96217683Spst if (getmsg(fd, &ctl, (struct strbuf*)NULL, &flags) < 0) { 96375107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "recv_ack: %s getmsg: %s", 96417683Spst what, pcap_strerror(errno)); 965190225Srpaulo return (PCAP_ERROR); 96617683Spst } 96717683Spst 968214518Srpaulo dlp = MAKE_DL_PRIMITIVES(ctl.buf); 96917683Spst switch (dlp->dl_primitive) { 97017683Spst 97117683Spst case DL_INFO_ACK: 97217683Spst case DL_BIND_ACK: 97317683Spst case DL_OK_ACK: 97417683Spst#ifdef DL_HP_PPA_ACK 97517683Spst case DL_HP_PPA_ACK: 97617683Spst#endif 97717683Spst /* These are OK */ 97817683Spst break; 97917683Spst 98017683Spst case DL_ERROR_ACK: 98117683Spst switch (dlp->error_ack.dl_errno) { 98217683Spst 98398530Sfenner case DL_SYSERR: 984147894Ssam if (uerror != NULL) 985147894Ssam *uerror = dlp->error_ack.dl_unix_errno; 98675107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 98798530Sfenner "recv_ack: %s: UNIX error - %s", 98817683Spst what, pcap_strerror(dlp->error_ack.dl_unix_errno)); 989190225Srpaulo if (dlp->error_ack.dl_unix_errno == EACCES) 990190225Srpaulo return (PCAP_ERROR_PERM_DENIED); 99117683Spst break; 99217683Spst 99317683Spst default: 99498530Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "recv_ack: %s: %s", 99598530Sfenner what, dlstrerror(dlp->error_ack.dl_errno)); 996190225Srpaulo if (dlp->error_ack.dl_errno == DL_BADPPA) 997190225Srpaulo return (PCAP_ERROR_NO_SUCH_DEVICE); 998190225Srpaulo else if (dlp->error_ack.dl_errno == DL_ACCESS) 999190225Srpaulo return (PCAP_ERROR_PERM_DENIED); 100017683Spst break; 100117683Spst } 1002190225Srpaulo return (PCAP_ERROR); 100317683Spst 100417683Spst default: 100575107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 100698530Sfenner "recv_ack: %s: Unexpected primitive ack %s", 100798530Sfenner what, dlprim(dlp->dl_primitive)); 1008190225Srpaulo return (PCAP_ERROR); 100917683Spst } 101017683Spst 101117683Spst if (ctl.len < size) { 101275107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 101398530Sfenner "recv_ack: %s: Ack too small (%d < %d)", 101417683Spst what, ctl.len, size); 1015190225Srpaulo return (PCAP_ERROR); 101617683Spst } 101717683Spst return (ctl.len); 101817683Spst} 101917683Spst 102098530Sfennerstatic char * 102198530Sfennerdlstrerror(bpf_u_int32 dl_errno) 102298530Sfenner{ 102398530Sfenner static char errstring[6+2+8+1]; 102498530Sfenner 102598530Sfenner switch (dl_errno) { 102698530Sfenner 102798530Sfenner case DL_ACCESS: 102898530Sfenner return ("Improper permissions for request"); 102998530Sfenner 103098530Sfenner case DL_BADADDR: 103198530Sfenner return ("DLSAP addr in improper format or invalid"); 103298530Sfenner 103398530Sfenner case DL_BADCORR: 103498530Sfenner return ("Seq number not from outstand DL_CONN_IND"); 103598530Sfenner 103698530Sfenner case DL_BADDATA: 103798530Sfenner return ("User data exceeded provider limit"); 103898530Sfenner 103998530Sfenner case DL_BADPPA: 104098530Sfenner#ifdef HAVE_DEV_DLPI 104198530Sfenner /* 104298530Sfenner * With a single "/dev/dlpi" device used for all 104398530Sfenner * DLPI providers, PPAs have nothing to do with 104498530Sfenner * unit numbers. 104598530Sfenner */ 104698530Sfenner return ("Specified PPA was invalid"); 104798530Sfenner#else 104898530Sfenner /* 104998530Sfenner * We have separate devices for separate devices; 105098530Sfenner * the PPA is just the unit number. 105198530Sfenner */ 105298530Sfenner return ("Specified PPA (device unit) was invalid"); 105398530Sfenner#endif 105498530Sfenner 105598530Sfenner case DL_BADPRIM: 105698530Sfenner return ("Primitive received not known by provider"); 105798530Sfenner 105898530Sfenner case DL_BADQOSPARAM: 105998530Sfenner return ("QOS parameters contained invalid values"); 106098530Sfenner 106198530Sfenner case DL_BADQOSTYPE: 106298530Sfenner return ("QOS structure type is unknown/unsupported"); 106398530Sfenner 106498530Sfenner case DL_BADSAP: 106598530Sfenner return ("Bad LSAP selector"); 106698530Sfenner 106798530Sfenner case DL_BADTOKEN: 106898530Sfenner return ("Token used not an active stream"); 106998530Sfenner 107098530Sfenner case DL_BOUND: 107198530Sfenner return ("Attempted second bind with dl_max_conind"); 107298530Sfenner 107398530Sfenner case DL_INITFAILED: 107498530Sfenner return ("Physical link initialization failed"); 107598530Sfenner 107698530Sfenner case DL_NOADDR: 107798530Sfenner return ("Provider couldn't allocate alternate address"); 107898530Sfenner 107998530Sfenner case DL_NOTINIT: 108098530Sfenner return ("Physical link not initialized"); 108198530Sfenner 108298530Sfenner case DL_OUTSTATE: 108398530Sfenner return ("Primitive issued in improper state"); 108498530Sfenner 108598530Sfenner case DL_SYSERR: 108698530Sfenner return ("UNIX system error occurred"); 108798530Sfenner 108898530Sfenner case DL_UNSUPPORTED: 108998530Sfenner return ("Requested service not supplied by provider"); 109098530Sfenner 109198530Sfenner case DL_UNDELIVERABLE: 109298530Sfenner return ("Previous data unit could not be delivered"); 109398530Sfenner 109498530Sfenner case DL_NOTSUPPORTED: 109598530Sfenner return ("Primitive is known but not supported"); 109698530Sfenner 109798530Sfenner case DL_TOOMANY: 109898530Sfenner return ("Limit exceeded"); 109998530Sfenner 110098530Sfenner case DL_NOTENAB: 110198530Sfenner return ("Promiscuous mode not enabled"); 110298530Sfenner 110398530Sfenner case DL_BUSY: 110498530Sfenner return ("Other streams for PPA in post-attached"); 110598530Sfenner 110698530Sfenner case DL_NOAUTO: 110798530Sfenner return ("Automatic handling XID&TEST not supported"); 110898530Sfenner 110998530Sfenner case DL_NOXIDAUTO: 111098530Sfenner return ("Automatic handling of XID not supported"); 111198530Sfenner 111298530Sfenner case DL_NOTESTAUTO: 111398530Sfenner return ("Automatic handling of TEST not supported"); 111498530Sfenner 111598530Sfenner case DL_XIDAUTO: 111698530Sfenner return ("Automatic handling of XID response"); 111798530Sfenner 111898530Sfenner case DL_TESTAUTO: 111998530Sfenner return ("Automatic handling of TEST response"); 112098530Sfenner 112198530Sfenner case DL_PENDING: 112298530Sfenner return ("Pending outstanding connect indications"); 112398530Sfenner 112498530Sfenner default: 112598530Sfenner sprintf(errstring, "Error %02x", dl_errno); 112698530Sfenner return (errstring); 112798530Sfenner } 112898530Sfenner} 112998530Sfenner 113098530Sfennerstatic char * 113198530Sfennerdlprim(bpf_u_int32 prim) 113298530Sfenner{ 113398530Sfenner static char primbuf[80]; 113498530Sfenner 113598530Sfenner switch (prim) { 113698530Sfenner 113798530Sfenner case DL_INFO_REQ: 113898530Sfenner return ("DL_INFO_REQ"); 113998530Sfenner 114098530Sfenner case DL_INFO_ACK: 114198530Sfenner return ("DL_INFO_ACK"); 114298530Sfenner 114398530Sfenner case DL_ATTACH_REQ: 114498530Sfenner return ("DL_ATTACH_REQ"); 114598530Sfenner 114698530Sfenner case DL_DETACH_REQ: 114798530Sfenner return ("DL_DETACH_REQ"); 114898530Sfenner 114998530Sfenner case DL_BIND_REQ: 115098530Sfenner return ("DL_BIND_REQ"); 115198530Sfenner 115298530Sfenner case DL_BIND_ACK: 115398530Sfenner return ("DL_BIND_ACK"); 115498530Sfenner 115598530Sfenner case DL_UNBIND_REQ: 115698530Sfenner return ("DL_UNBIND_REQ"); 115798530Sfenner 115898530Sfenner case DL_OK_ACK: 115998530Sfenner return ("DL_OK_ACK"); 116098530Sfenner 116198530Sfenner case DL_ERROR_ACK: 116298530Sfenner return ("DL_ERROR_ACK"); 116398530Sfenner 116498530Sfenner case DL_SUBS_BIND_REQ: 116598530Sfenner return ("DL_SUBS_BIND_REQ"); 116698530Sfenner 116798530Sfenner case DL_SUBS_BIND_ACK: 116898530Sfenner return ("DL_SUBS_BIND_ACK"); 116998530Sfenner 117098530Sfenner case DL_UNITDATA_REQ: 117198530Sfenner return ("DL_UNITDATA_REQ"); 117298530Sfenner 117398530Sfenner case DL_UNITDATA_IND: 117498530Sfenner return ("DL_UNITDATA_IND"); 117598530Sfenner 117698530Sfenner case DL_UDERROR_IND: 117798530Sfenner return ("DL_UDERROR_IND"); 117898530Sfenner 117998530Sfenner case DL_UDQOS_REQ: 118098530Sfenner return ("DL_UDQOS_REQ"); 118198530Sfenner 118298530Sfenner case DL_CONNECT_REQ: 118398530Sfenner return ("DL_CONNECT_REQ"); 118498530Sfenner 118598530Sfenner case DL_CONNECT_IND: 118698530Sfenner return ("DL_CONNECT_IND"); 118798530Sfenner 118898530Sfenner case DL_CONNECT_RES: 118998530Sfenner return ("DL_CONNECT_RES"); 119098530Sfenner 119198530Sfenner case DL_CONNECT_CON: 119298530Sfenner return ("DL_CONNECT_CON"); 119398530Sfenner 119498530Sfenner case DL_TOKEN_REQ: 119598530Sfenner return ("DL_TOKEN_REQ"); 119698530Sfenner 119798530Sfenner case DL_TOKEN_ACK: 119898530Sfenner return ("DL_TOKEN_ACK"); 119998530Sfenner 120098530Sfenner case DL_DISCONNECT_REQ: 120198530Sfenner return ("DL_DISCONNECT_REQ"); 120298530Sfenner 120398530Sfenner case DL_DISCONNECT_IND: 120498530Sfenner return ("DL_DISCONNECT_IND"); 120598530Sfenner 120698530Sfenner case DL_RESET_REQ: 120798530Sfenner return ("DL_RESET_REQ"); 120898530Sfenner 120998530Sfenner case DL_RESET_IND: 121098530Sfenner return ("DL_RESET_IND"); 121198530Sfenner 121298530Sfenner case DL_RESET_RES: 121398530Sfenner return ("DL_RESET_RES"); 121498530Sfenner 121598530Sfenner case DL_RESET_CON: 121698530Sfenner return ("DL_RESET_CON"); 121798530Sfenner 121898530Sfenner default: 121998530Sfenner (void) sprintf(primbuf, "unknown primitive 0x%x", prim); 122098530Sfenner return (primbuf); 122198530Sfenner } 122298530Sfenner} 122398530Sfenner 122417683Spststatic int 122517683Spstdlattachreq(int fd, bpf_u_int32 ppa, char *ebuf) 122617683Spst{ 122717683Spst dl_attach_req_t req; 122817683Spst 122917683Spst req.dl_primitive = DL_ATTACH_REQ; 123017683Spst req.dl_ppa = ppa; 123117683Spst 123217683Spst return (send_request(fd, (char *)&req, sizeof(req), "attach", ebuf)); 123317683Spst} 123417683Spst 123517683Spststatic int 123617683Spstdlbindreq(int fd, bpf_u_int32 sap, char *ebuf) 123717683Spst{ 123817683Spst 123917683Spst dl_bind_req_t req; 124017683Spst 124117683Spst memset((char *)&req, 0, sizeof(req)); 124217683Spst req.dl_primitive = DL_BIND_REQ; 1243147894Ssam /* XXX - what if neither of these are defined? */ 1244147894Ssam#if defined(DL_HP_RAWDLS) 124517683Spst req.dl_max_conind = 1; /* XXX magic number */ 124617683Spst req.dl_service_mode = DL_HP_RAWDLS; 1247147894Ssam#elif defined(DL_CLDLS) 124826175Sfenner req.dl_service_mode = DL_CLDLS; 124917683Spst#endif 1250147894Ssam req.dl_sap = sap; 125117683Spst 125217683Spst return (send_request(fd, (char *)&req, sizeof(req), "bind", ebuf)); 125317683Spst} 125417683Spst 125517683Spststatic int 1256147894Ssamdlbindack(int fd, char *bufp, char *ebuf, int *uerror) 125717683Spst{ 125817683Spst 1259147894Ssam return (recv_ack(fd, DL_BIND_ACK_SIZE, "bind", bufp, ebuf, uerror)); 126017683Spst} 126117683Spst 126217683Spststatic int 126317683Spstdlpromisconreq(int fd, bpf_u_int32 level, char *ebuf) 126417683Spst{ 126517683Spst dl_promiscon_req_t req; 126617683Spst 126717683Spst req.dl_primitive = DL_PROMISCON_REQ; 126817683Spst req.dl_level = level; 126917683Spst 127017683Spst return (send_request(fd, (char *)&req, sizeof(req), "promiscon", ebuf)); 127117683Spst} 127217683Spst 127317683Spststatic int 127417683Spstdlokack(int fd, const char *what, char *bufp, char *ebuf) 127517683Spst{ 127617683Spst 1277147894Ssam return (recv_ack(fd, DL_OK_ACK_SIZE, what, bufp, ebuf, NULL)); 127817683Spst} 127917683Spst 128017683Spst 128117683Spststatic int 128217683Spstdlinforeq(int fd, char *ebuf) 128317683Spst{ 128417683Spst dl_info_req_t req; 128517683Spst 128617683Spst req.dl_primitive = DL_INFO_REQ; 128717683Spst 128817683Spst return (send_request(fd, (char *)&req, sizeof(req), "info", ebuf)); 128917683Spst} 129017683Spst 129117683Spststatic int 129217683Spstdlinfoack(int fd, char *bufp, char *ebuf) 129317683Spst{ 129417683Spst 1295147894Ssam return (recv_ack(fd, DL_INFO_ACK_SIZE, "info", bufp, ebuf, NULL)); 129617683Spst} 129717683Spst 1298190225Srpaulo#ifdef HAVE_DLPI_PASSIVE 1299190225Srpaulo/* 1300190225Srpaulo * Enable DLPI passive mode. We do not care if this request fails, as this 1301190225Srpaulo * indicates the underlying DLPI device does not support link aggregation. 1302190225Srpaulo */ 1303190225Srpaulostatic void 1304190225Srpaulodlpassive(int fd, char *ebuf) 1305190225Srpaulo{ 1306190225Srpaulo dl_passive_req_t req; 1307190225Srpaulo bpf_u_int32 buf[MAXDLBUF]; 1308190225Srpaulo 1309190225Srpaulo req.dl_primitive = DL_PASSIVE_REQ; 1310190225Srpaulo 1311190225Srpaulo if (send_request(fd, (char *)&req, sizeof(req), "dlpassive", ebuf) == 0) 1312190225Srpaulo (void) dlokack(fd, "dlpassive", (char *)buf, ebuf); 1313190225Srpaulo} 1314190225Srpaulo#endif 1315190225Srpaulo 1316146768Ssam#ifdef DL_HP_RAWDLS 1317146768Ssam/* 1318146768Ssam * There's an ack *if* there's an error. 1319146768Ssam */ 1320146768Ssamstatic int 1321146768Ssamdlrawdatareq(int fd, const u_char *datap, int datalen) 1322146768Ssam{ 1323146768Ssam struct strbuf ctl, data; 1324146768Ssam long buf[MAXDLBUF]; /* XXX - char? */ 1325146768Ssam union DL_primitives *dlp; 1326146768Ssam int dlen; 1327146768Ssam 1328214518Srpaulo dlp = MAKE_DL_PRIMITIVES(buf); 1329146768Ssam 1330146768Ssam dlp->dl_primitive = DL_HP_RAWDATA_REQ; 1331146768Ssam dlen = DL_HP_RAWDATA_REQ_SIZE; 1332146768Ssam 1333146768Ssam /* 1334146768Ssam * HP's documentation doesn't appear to show us supplying any 1335146768Ssam * address pointed to by the control part of the message. 1336146768Ssam * I think that's what raw mode means - you just send the raw 1337146768Ssam * packet, you don't specify where to send it to, as that's 1338146768Ssam * implied by the destination address. 1339146768Ssam */ 1340146768Ssam ctl.maxlen = 0; 1341146768Ssam ctl.len = dlen; 1342146768Ssam ctl.buf = (void *)buf; 1343146768Ssam 1344146768Ssam data.maxlen = 0; 1345146768Ssam data.len = datalen; 1346146768Ssam data.buf = (void *)datap; 1347146768Ssam 1348146768Ssam return (putmsg(fd, &ctl, &data, 0)); 1349146768Ssam} 1350146768Ssam#endif /* DL_HP_RAWDLS */ 1351146768Ssam 135217683Spst#if defined(HAVE_SOLARIS) && defined(HAVE_SYS_BUFMOD_H) 135317683Spststatic char * 135417683Spstget_release(bpf_u_int32 *majorp, bpf_u_int32 *minorp, bpf_u_int32 *microp) 135517683Spst{ 135617683Spst char *cp; 135717683Spst static char buf[32]; 135817683Spst 135917683Spst *majorp = 0; 136017683Spst *minorp = 0; 136117683Spst *microp = 0; 136217683Spst if (sysinfo(SI_RELEASE, buf, sizeof(buf)) < 0) 136317683Spst return ("?"); 136417683Spst cp = buf; 136598530Sfenner if (!isdigit((unsigned char)*cp)) 136617683Spst return (buf); 136717683Spst *majorp = strtol(cp, &cp, 10); 136817683Spst if (*cp++ != '.') 136917683Spst return (buf); 137017683Spst *minorp = strtol(cp, &cp, 10); 137117683Spst if (*cp++ != '.') 137217683Spst return (buf); 137317683Spst *microp = strtol(cp, &cp, 10); 137417683Spst return (buf); 137517683Spst} 137617683Spst#endif 137717683Spst 1378146768Ssam#ifdef DL_HP_PPA_REQ 137917683Spst/* 138075107Sfenner * Under HP-UX 10 and HP-UX 11, we can ask for the ppa 138117683Spst */ 138217683Spst 138317683Spst 138475107Sfenner/* 138575107Sfenner * Determine ppa number that specifies ifname. 138675107Sfenner * 138775107Sfenner * If the "dl_hp_ppa_info_t" doesn't have a "dl_module_id_1" member, 138875107Sfenner * the code that's used here is the old code for HP-UX 10.x. 138975107Sfenner * 139075107Sfenner * However, HP-UX 10.20, at least, appears to have such a member 139175107Sfenner * in its "dl_hp_ppa_info_t" structure, so the new code is used. 139275107Sfenner * The new code didn't work on an old 10.20 system on which Rick 139375107Sfenner * Jones of HP tried it, but with later patches installed, it 139475107Sfenner * worked - it appears that the older system had those members but 139575107Sfenner * didn't put anything in them, so, if the search by name fails, we 139675107Sfenner * do the old search. 139775107Sfenner * 139875107Sfenner * Rick suggests that making sure your system is "up on the latest 139975107Sfenner * lancommon/DLPI/driver patches" is probably a good idea; it'd fix 140075107Sfenner * that problem, as well as allowing libpcap to see packets sent 140175107Sfenner * from the system on which the libpcap application is being run. 140275107Sfenner * (On 10.20, in addition to getting the latest patches, you need 140375107Sfenner * to turn the kernel "lanc_outbound_promisc_flag" flag on with ADB; 140475107Sfenner * a posting to "comp.sys.hp.hpux" at 140575107Sfenner * 140675107Sfenner * http://www.deja.com/[ST_rn=ps]/getdoc.xp?AN=558092266 140775107Sfenner * 140875107Sfenner * says that, to see the machine's outgoing traffic, you'd need to 140975107Sfenner * apply the right patches to your system, and also set that variable 141075107Sfenner * with: 1411127664Sbms 141275107Sfennerecho 'lanc_outbound_promisc_flag/W1' | /usr/bin/adb -w /stand/vmunix /dev/kmem 141375107Sfenner 141475107Sfenner * which could be put in, for example, "/sbin/init.d/lan". 141575107Sfenner * 141675107Sfenner * Setting the variable is not necessary on HP-UX 11.x. 141775107Sfenner */ 141817683Spststatic int 141917683Spstget_dlpi_ppa(register int fd, register const char *device, register int unit, 142017683Spst register char *ebuf) 142117683Spst{ 142217683Spst register dl_hp_ppa_ack_t *ap; 142375107Sfenner register dl_hp_ppa_info_t *ipstart, *ip; 142417683Spst register int i; 142575107Sfenner char dname[100]; 142617683Spst register u_long majdev; 142775107Sfenner struct stat statbuf; 142817683Spst dl_hp_ppa_req_t req; 142998530Sfenner char buf[MAXDLBUF]; 143098530Sfenner char *ppa_data_buf; 143198530Sfenner dl_hp_ppa_ack_t *dlp; 143298530Sfenner struct strbuf ctl; 143398530Sfenner int flags; 143498530Sfenner int ppa; 143517683Spst 143617683Spst memset((char *)&req, 0, sizeof(req)); 143717683Spst req.dl_primitive = DL_HP_PPA_REQ; 143817683Spst 143917683Spst memset((char *)buf, 0, sizeof(buf)); 144098530Sfenner if (send_request(fd, (char *)&req, sizeof(req), "hpppa", ebuf) < 0) 1441190225Srpaulo return (PCAP_ERROR); 144217683Spst 144398530Sfenner ctl.maxlen = DL_HP_PPA_ACK_SIZE; 144498530Sfenner ctl.len = 0; 144598530Sfenner ctl.buf = (char *)buf; 144698530Sfenner 144798530Sfenner flags = 0; 144898530Sfenner /* 144998530Sfenner * DLPI may return a big chunk of data for a DL_HP_PPA_REQ. The normal 145098530Sfenner * recv_ack will fail because it set the maxlen to MAXDLBUF (8192) 145198530Sfenner * which is NOT big enough for a DL_HP_PPA_REQ. 145298530Sfenner * 145398530Sfenner * This causes libpcap applications to fail on a system with HP-APA 145498530Sfenner * installed. 145598530Sfenner * 145698530Sfenner * To figure out how big the returned data is, we first call getmsg 145798530Sfenner * to get the small head and peek at the head to get the actual data 145898530Sfenner * length, and then issue another getmsg to get the actual PPA data. 145998530Sfenner */ 146098530Sfenner /* get the head first */ 146198530Sfenner if (getmsg(fd, &ctl, (struct strbuf *)NULL, &flags) < 0) { 146298530Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 146398530Sfenner "get_dlpi_ppa: hpppa getmsg: %s", pcap_strerror(errno)); 1464190225Srpaulo return (PCAP_ERROR); 146598530Sfenner } 146698530Sfenner 146798530Sfenner dlp = (dl_hp_ppa_ack_t *)ctl.buf; 146898530Sfenner if (dlp->dl_primitive != DL_HP_PPA_ACK) { 146998530Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 147098530Sfenner "get_dlpi_ppa: hpppa unexpected primitive ack 0x%x", 147198530Sfenner (bpf_u_int32)dlp->dl_primitive); 1472190225Srpaulo return (PCAP_ERROR); 147398530Sfenner } 1474127664Sbms 147598530Sfenner if (ctl.len < DL_HP_PPA_ACK_SIZE) { 147698530Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 1477127664Sbms "get_dlpi_ppa: hpppa ack too small (%d < %lu)", 1478127664Sbms ctl.len, (unsigned long)DL_HP_PPA_ACK_SIZE); 1479190225Srpaulo return (PCAP_ERROR); 148098530Sfenner } 1481127664Sbms 148298530Sfenner /* allocate buffer */ 148398530Sfenner if ((ppa_data_buf = (char *)malloc(dlp->dl_length)) == NULL) { 148498530Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 148598530Sfenner "get_dlpi_ppa: hpppa malloc: %s", pcap_strerror(errno)); 1486190225Srpaulo return (PCAP_ERROR); 148798530Sfenner } 148898530Sfenner ctl.maxlen = dlp->dl_length; 148998530Sfenner ctl.len = 0; 149098530Sfenner ctl.buf = (char *)ppa_data_buf; 149198530Sfenner /* get the data */ 149298530Sfenner if (getmsg(fd, &ctl, (struct strbuf *)NULL, &flags) < 0) { 149398530Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 149498530Sfenner "get_dlpi_ppa: hpppa getmsg: %s", pcap_strerror(errno)); 149598530Sfenner free(ppa_data_buf); 1496190225Srpaulo return (PCAP_ERROR); 149798530Sfenner } 149898530Sfenner if (ctl.len < dlp->dl_length) { 149998530Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 1500214518Srpaulo "get_dlpi_ppa: hpppa ack too small (%d < %lu)", 1501214518Srpaulo ctl.len, (unsigned long)dlp->dl_length); 150298530Sfenner free(ppa_data_buf); 1503190225Srpaulo return (PCAP_ERROR); 150498530Sfenner } 150598530Sfenner 150617683Spst ap = (dl_hp_ppa_ack_t *)buf; 150798530Sfenner ipstart = (dl_hp_ppa_info_t *)ppa_data_buf; 150875107Sfenner ip = ipstart; 150917683Spst 151075107Sfenner#ifdef HAVE_HP_PPA_INFO_T_DL_MODULE_ID_1 151175107Sfenner /* 151275107Sfenner * The "dl_hp_ppa_info_t" structure has a "dl_module_id_1" 151375107Sfenner * member that should, in theory, contain the part of the 151475107Sfenner * name for the device that comes before the unit number, 151575107Sfenner * and should also have a "dl_module_id_2" member that may 151675107Sfenner * contain an alternate name (e.g., I think Ethernet devices 151775107Sfenner * have both "lan", for "lanN", and "snap", for "snapN", with 151875107Sfenner * the former being for Ethernet packets and the latter being 151975107Sfenner * for 802.3/802.2 packets). 152075107Sfenner * 152175107Sfenner * Search for the device that has the specified name and 152275107Sfenner * instance number. 152375107Sfenner */ 152475107Sfenner for (i = 0; i < ap->dl_count; i++) { 152598530Sfenner if ((strcmp((const char *)ip->dl_module_id_1, device) == 0 || 152698530Sfenner strcmp((const char *)ip->dl_module_id_2, device) == 0) && 152775107Sfenner ip->dl_instance_num == unit) 152875107Sfenner break; 152917683Spst 153075107Sfenner ip = (dl_hp_ppa_info_t *)((u_char *)ipstart + ip->dl_next_offset); 153175107Sfenner } 153275107Sfenner#else 153375107Sfenner /* 153475107Sfenner * We don't have that member, so the search is impossible; make it 153575107Sfenner * look as if the search failed. 153675107Sfenner */ 153775107Sfenner i = ap->dl_count; 153875107Sfenner#endif 153975107Sfenner 154075107Sfenner if (i == ap->dl_count) { 154175107Sfenner /* 154275107Sfenner * Well, we didn't, or can't, find the device by name. 154375107Sfenner * 154475107Sfenner * HP-UX 10.20, whilst it has "dl_module_id_1" and 154575107Sfenner * "dl_module_id_2" fields in the "dl_hp_ppa_info_t", 154675107Sfenner * doesn't seem to fill them in unless the system is 154775107Sfenner * at a reasonably up-to-date patch level. 154875107Sfenner * 154975107Sfenner * Older HP-UX 10.x systems might not have those fields 155075107Sfenner * at all. 155175107Sfenner * 155275107Sfenner * Therefore, we'll search for the entry with the major 155375107Sfenner * device number of a device with the name "/dev/<dev><unit>", 155475107Sfenner * if such a device exists, as the old code did. 155575107Sfenner */ 155675107Sfenner snprintf(dname, sizeof(dname), "/dev/%s%d", device, unit); 155775107Sfenner if (stat(dname, &statbuf) < 0) { 155875107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "stat: %s: %s", 155975107Sfenner dname, pcap_strerror(errno)); 1560190225Srpaulo return (PCAP_ERROR); 156175107Sfenner } 156275107Sfenner majdev = major(statbuf.st_rdev); 156375107Sfenner 156475107Sfenner ip = ipstart; 156575107Sfenner 156675107Sfenner for (i = 0; i < ap->dl_count; i++) { 156775107Sfenner if (ip->dl_mjr_num == majdev && 156875107Sfenner ip->dl_instance_num == unit) 156975107Sfenner break; 157075107Sfenner 157175107Sfenner ip = (dl_hp_ppa_info_t *)((u_char *)ipstart + ip->dl_next_offset); 157275107Sfenner } 157375107Sfenner } 1574147894Ssam if (i == ap->dl_count) { 1575147894Ssam snprintf(ebuf, PCAP_ERRBUF_SIZE, 157675107Sfenner "can't find /dev/dlpi PPA for %s%d", device, unit); 1577190225Srpaulo return (PCAP_ERROR_NO_SUCH_DEVICE); 1578147894Ssam } 1579147894Ssam if (ip->dl_hdw_state == HDW_DEAD) { 1580147894Ssam snprintf(ebuf, PCAP_ERRBUF_SIZE, 158175107Sfenner "%s%d: hardware state: DOWN\n", device, unit); 158298530Sfenner free(ppa_data_buf); 1583190225Srpaulo return (PCAP_ERROR); 1584147894Ssam } 1585147894Ssam ppa = ip->dl_ppa; 1586147894Ssam free(ppa_data_buf); 1587147894Ssam return (ppa); 158817683Spst} 158917683Spst#endif 159017683Spst 159117683Spst#ifdef HAVE_HPUX9 159217683Spst/* 159317683Spst * Under HP-UX 9, there is no good way to determine the ppa. 159417683Spst * So punt and read it from /dev/kmem. 159517683Spst */ 159617683Spststatic struct nlist nl[] = { 159717683Spst#define NL_IFNET 0 159817683Spst { "ifnet" }, 159917683Spst { "" } 160017683Spst}; 160117683Spst 160217683Spststatic char path_vmunix[] = "/hp-ux"; 160317683Spst 160417683Spst/* Determine ppa number that specifies ifname */ 160517683Spststatic int 160617683Spstget_dlpi_ppa(register int fd, register const char *ifname, register int unit, 160717683Spst register char *ebuf) 160817683Spst{ 160917683Spst register const char *cp; 161017683Spst register int kd; 161117683Spst void *addr; 161217683Spst struct ifnet ifnet; 161375107Sfenner char if_name[sizeof(ifnet.if_name) + 1]; 161417683Spst 161517683Spst cp = strrchr(ifname, '/'); 161617683Spst if (cp != NULL) 161717683Spst ifname = cp + 1; 161817683Spst if (nlist(path_vmunix, &nl) < 0) { 161975107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "nlist %s failed", 162075107Sfenner path_vmunix); 162117683Spst return (-1); 162217683Spst } 162317683Spst if (nl[NL_IFNET].n_value == 0) { 162475107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 162575107Sfenner "could't find %s kernel symbol", 162617683Spst nl[NL_IFNET].n_name); 162717683Spst return (-1); 162817683Spst } 162917683Spst kd = open("/dev/kmem", O_RDONLY); 163017683Spst if (kd < 0) { 163175107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "kmem open: %s", 163275107Sfenner pcap_strerror(errno)); 163317683Spst return (-1); 163417683Spst } 163517683Spst if (dlpi_kread(kd, nl[NL_IFNET].n_value, 163617683Spst &addr, sizeof(addr), ebuf) < 0) { 163717683Spst close(kd); 163817683Spst return (-1); 163917683Spst } 164017683Spst for (; addr != NULL; addr = ifnet.if_next) { 164117683Spst if (dlpi_kread(kd, (off_t)addr, 164217683Spst &ifnet, sizeof(ifnet), ebuf) < 0 || 164317683Spst dlpi_kread(kd, (off_t)ifnet.if_name, 164475107Sfenner if_name, sizeof(ifnet.if_name), ebuf) < 0) { 164517683Spst (void)close(kd); 164617683Spst return (-1); 164717683Spst } 164875107Sfenner if_name[sizeof(ifnet.if_name)] = '\0'; 164975107Sfenner if (strcmp(if_name, ifname) == 0 && ifnet.if_unit == unit) 165017683Spst return (ifnet.if_index); 165117683Spst } 165217683Spst 165375107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "Can't find %s", ifname); 165417683Spst return (-1); 165517683Spst} 165617683Spst 165717683Spststatic int 165817683Spstdlpi_kread(register int fd, register off_t addr, 165917683Spst register void *buf, register u_int len, register char *ebuf) 166017683Spst{ 166117683Spst register int cc; 166217683Spst 166339291Sfenner if (lseek(fd, addr, SEEK_SET) < 0) { 166475107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "lseek: %s", 166575107Sfenner pcap_strerror(errno)); 166617683Spst return (-1); 166717683Spst } 166817683Spst cc = read(fd, buf, len); 166917683Spst if (cc < 0) { 167075107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "read: %s", 167175107Sfenner pcap_strerror(errno)); 167217683Spst return (-1); 167317683Spst } else if (cc != len) { 167475107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "short read (%d != %d)", cc, 167575107Sfenner len); 167617683Spst return (-1); 167717683Spst } 167817683Spst return (cc); 167917683Spst} 168017683Spst#endif 1681190225Srpaulo 1682190225Srpaulopcap_t * 1683190225Srpaulopcap_create(const char *device, char *ebuf) 1684190225Srpaulo{ 1685190225Srpaulo pcap_t *p; 1686190225Srpaulo 1687190225Srpaulo p = pcap_create_common(device, ebuf); 1688190225Srpaulo if (p == NULL) 1689190225Srpaulo return (NULL); 1690190225Srpaulo 1691190225Srpaulo p->send_fd = -1; /* it hasn't been opened yet */ 1692190225Srpaulo 1693190225Srpaulo p->activate_op = pcap_activate_dlpi; 1694190225Srpaulo return (p); 1695190225Srpaulo} 1696