pcap-dlpi.c revision 98530
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), 2217683Spst * University College London. 2317683Spst */ 2417683Spst 2517683Spst/* 2617683Spst * Packet capture routine for dlpi under SunOS 5 2717683Spst * 2817683Spst * Notes: 2917683Spst * 3017683Spst * - Apparently the DLIOCRAW ioctl() is specific to SunOS. 3117683Spst * 3217683Spst * - There is a bug in bufmod(7) such that setting the snapshot 3317683Spst * length results in data being left of the front of the packet. 3417683Spst * 3517683Spst * - It might be desirable to use pfmod(7) to filter packets in the 3617683Spst * kernel. 3717683Spst */ 3817683Spst 3926175Sfenner#ifndef lint 4026175Sfennerstatic const char rcsid[] = 4198530Sfenner "@(#) $Header: /tcpdump/master/libpcap/pcap-dlpi.c,v 1.74 2001/12/10 07:14:15 guy Exp $ (LBL)"; 4226175Sfenner#endif 4326175Sfenner 4475107Sfenner#ifdef HAVE_CONFIG_H 4575107Sfenner#include "config.h" 4675107Sfenner#endif 4775107Sfenner 4817683Spst#include <sys/types.h> 4917683Spst#include <sys/time.h> 5017683Spst#ifdef HAVE_SYS_BUFMOD_H 5117683Spst#include <sys/bufmod.h> 5217683Spst#endif 5317683Spst#include <sys/dlpi.h> 5417683Spst#ifdef HAVE_SYS_DLPI_EXT_H 5517683Spst#include <sys/dlpi_ext.h> 5617683Spst#endif 5717683Spst#ifdef HAVE_HPUX9 5817683Spst#include <sys/socket.h> 5917683Spst#endif 6017683Spst#ifdef DL_HP_PPA_ACK_OBS 6117683Spst#include <sys/stat.h> 6217683Spst#endif 6317683Spst#include <sys/stream.h> 6417683Spst#if defined(HAVE_SOLARIS) && defined(HAVE_SYS_BUFMOD_H) 6517683Spst#include <sys/systeminfo.h> 6617683Spst#endif 6717683Spst 6817683Spst#ifdef HAVE_HPUX9 6917683Spst#include <net/if.h> 7017683Spst#endif 7117683Spst 7217683Spst#include <ctype.h> 7317683Spst#ifdef HAVE_HPUX9 7417683Spst#include <nlist.h> 7517683Spst#endif 7617683Spst#include <errno.h> 7717683Spst#include <fcntl.h> 7817683Spst#include <memory.h> 7917683Spst#include <stdio.h> 8017683Spst#include <stdlib.h> 8117683Spst#include <string.h> 8217683Spst#include <stropts.h> 8317683Spst#include <unistd.h> 8417683Spst 8517683Spst#include "pcap-int.h" 8617683Spst 8717683Spst#ifdef HAVE_OS_PROTO_H 8817683Spst#include "os-proto.h" 8917683Spst#endif 9017683Spst 9117683Spst#ifndef PCAP_DEV_PREFIX 9298530Sfenner#ifdef _AIX 9398530Sfenner#define PCAP_DEV_PREFIX "/dev/dlpi" 9498530Sfenner#else 9517683Spst#define PCAP_DEV_PREFIX "/dev" 9617683Spst#endif 9798530Sfenner#endif 9817683Spst 9917683Spst#define MAXDLBUF 8192 10017683Spst 10117683Spst/* Forwards */ 10298530Sfennerstatic char *split_dname(char *, int *, char *); 10317683Spststatic int dlattachreq(int, bpf_u_int32, char *); 10417683Spststatic int dlbindack(int, char *, char *); 10517683Spststatic int dlbindreq(int, bpf_u_int32, char *); 10617683Spststatic int dlinfoack(int, char *, char *); 10717683Spststatic int dlinforeq(int, char *); 10817683Spststatic int dlokack(int, const char *, char *, char *); 10917683Spststatic int recv_ack(int, int, const char *, char *, char *); 11098530Sfennerstatic char *dlstrerror(bpf_u_int32); 11198530Sfennerstatic char *dlprim(bpf_u_int32); 11217683Spststatic int dlpromisconreq(int, bpf_u_int32, char *); 11317683Spst#if defined(HAVE_SOLARIS) && defined(HAVE_SYS_BUFMOD_H) 11417683Spststatic char *get_release(bpf_u_int32 *, bpf_u_int32 *, bpf_u_int32 *); 11517683Spst#endif 11617683Spststatic int send_request(int, char *, int, char *, char *); 11717683Spst#ifdef HAVE_SYS_BUFMOD_H 11817683Spststatic int strioctl(int, int, int, char *); 11917683Spst#endif 12017683Spst#ifdef HAVE_HPUX9 12117683Spststatic int dlpi_kread(int, off_t, void *, u_int, char *); 12217683Spst#endif 12317683Spst#ifdef HAVE_DEV_DLPI 12417683Spststatic int get_dlpi_ppa(int, const char *, int, char *); 12517683Spst#endif 12617683Spst 12717683Spstint 12817683Spstpcap_stats(pcap_t *p, struct pcap_stat *ps) 12917683Spst{ 13017683Spst 13198530Sfenner /* 13298530Sfenner * "ps_recv" counts packets handed to the filter, not packets 13398530Sfenner * that passed the filter. As filtering is done in userland, 13498530Sfenner * this does not include packets dropped because we ran out 13598530Sfenner * of buffer space. 13698530Sfenner * 13798530Sfenner * "ps_drop" counts packets dropped inside the DLPI service 13898530Sfenner * provider device device because of flow control requirements 13998530Sfenner * or resource exhaustion; it doesn't count packets dropped by 14098530Sfenner * the interface driver, or packets dropped upstream. As 14198530Sfenner * filtering is done in userland, it counts packets regardless 14298530Sfenner * of whether they would've passed the filter. 14398530Sfenner * 14498530Sfenner * These statistics don't include packets not yet read from 14598530Sfenner * the kernel by libpcap, but they may include packets not 14698530Sfenner * yet read from libpcap by the application. 14798530Sfenner */ 14817683Spst *ps = p->md.stat; 14917683Spst return (0); 15017683Spst} 15117683Spst 15217683Spst/* XXX Needed by HP-UX (at least) */ 15317683Spststatic bpf_u_int32 ctlbuf[MAXDLBUF]; 15417683Spststatic struct strbuf ctl = { 15517683Spst MAXDLBUF, 15617683Spst 0, 15717683Spst (char *)ctlbuf 15817683Spst}; 15917683Spst 16017683Spstint 16117683Spstpcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) 16217683Spst{ 16317683Spst register int cc, n, caplen, origlen; 16417683Spst register u_char *bp, *ep, *pk; 16517683Spst register struct bpf_insn *fcode; 16617683Spst#ifdef HAVE_SYS_BUFMOD_H 16717683Spst register struct sb_hdr *sbp; 16817683Spst#ifdef LBL_ALIGN 16917683Spst struct sb_hdr sbhdr; 17017683Spst#endif 17117683Spst#endif 17217683Spst int flags; 17317683Spst struct strbuf data; 17417683Spst struct pcap_pkthdr pkthdr; 17517683Spst 17617683Spst flags = 0; 17717683Spst cc = p->cc; 17817683Spst if (cc == 0) { 17917683Spst data.buf = (char *)p->buffer + p->offset; 18017683Spst data.maxlen = MAXDLBUF; 18117683Spst data.len = 0; 18217683Spst do { 18317683Spst if (getmsg(p->fd, &ctl, &data, &flags) < 0) { 18417683Spst /* Don't choke when we get ptraced */ 18517683Spst if (errno == EINTR) { 18617683Spst cc = 0; 18717683Spst continue; 18817683Spst } 18975107Sfenner strlcpy(p->errbuf, pcap_strerror(errno), 19075107Sfenner sizeof(p->errbuf)); 19117683Spst return (-1); 19217683Spst } 19317683Spst cc = data.len; 19417683Spst } while (cc == 0); 19517683Spst bp = p->buffer + p->offset; 19617683Spst } else 19717683Spst bp = p->bp; 19817683Spst 19917683Spst /* Loop through packets */ 20017683Spst fcode = p->fcode.bf_insns; 20117683Spst ep = bp + cc; 20217683Spst n = 0; 20317683Spst#ifdef HAVE_SYS_BUFMOD_H 20417683Spst while (bp < ep) { 20517683Spst#ifdef LBL_ALIGN 20617683Spst if ((long)bp & 3) { 20717683Spst sbp = &sbhdr; 20817683Spst memcpy(sbp, bp, sizeof(*sbp)); 20917683Spst } else 21017683Spst#endif 21117683Spst sbp = (struct sb_hdr *)bp; 21217683Spst p->md.stat.ps_drop += sbp->sbh_drops; 21317683Spst pk = bp + sizeof(*sbp); 21417683Spst bp += sbp->sbh_totlen; 21517683Spst origlen = sbp->sbh_origlen; 21617683Spst caplen = sbp->sbh_msglen; 21717683Spst#else 21817683Spst origlen = cc; 21917683Spst caplen = min(p->snapshot, cc); 22017683Spst pk = bp; 22117683Spst bp += caplen; 22217683Spst#endif 22317683Spst ++p->md.stat.ps_recv; 22417683Spst if (bpf_filter(fcode, pk, origlen, caplen)) { 22517683Spst#ifdef HAVE_SYS_BUFMOD_H 22617683Spst pkthdr.ts = sbp->sbh_timestamp; 22717683Spst#else 22817683Spst (void)gettimeofday(&pkthdr.ts, NULL); 22917683Spst#endif 23017683Spst pkthdr.len = origlen; 23117683Spst pkthdr.caplen = caplen; 23217683Spst /* Insure caplen does not exceed snapshot */ 23317683Spst if (pkthdr.caplen > p->snapshot) 23417683Spst pkthdr.caplen = p->snapshot; 23517683Spst (*callback)(user, &pkthdr, pk); 23617683Spst if (++n >= cnt && cnt >= 0) { 23717683Spst p->cc = ep - bp; 23817683Spst p->bp = bp; 23917683Spst return (n); 24017683Spst } 24117683Spst } 24217683Spst#ifdef HAVE_SYS_BUFMOD_H 24317683Spst } 24417683Spst#endif 24517683Spst p->cc = 0; 24617683Spst return (n); 24717683Spst} 24817683Spst 24917683Spstpcap_t * 25017683Spstpcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf) 25117683Spst{ 25217683Spst register char *cp; 25317683Spst register pcap_t *p; 25498530Sfenner int ppa; 25517683Spst register dl_info_ack_t *infop; 25617683Spst#ifdef HAVE_SYS_BUFMOD_H 25717683Spst bpf_u_int32 ss, flag; 25817683Spst#ifdef HAVE_SOLARIS 25917683Spst register char *release; 26017683Spst bpf_u_int32 osmajor, osminor, osmicro; 26117683Spst#endif 26217683Spst#endif 26317683Spst bpf_u_int32 buf[MAXDLBUF]; 26417683Spst char dname[100]; 26517683Spst#ifndef HAVE_DEV_DLPI 26617683Spst char dname2[100]; 26717683Spst#endif 26817683Spst 26917683Spst p = (pcap_t *)malloc(sizeof(*p)); 27017683Spst if (p == NULL) { 27175107Sfenner strlcpy(ebuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE); 27217683Spst return (NULL); 27317683Spst } 27417683Spst memset(p, 0, sizeof(*p)); 27598530Sfenner p->fd = -1; /* indicate that it hasn't been opened yet */ 27617683Spst 27775107Sfenner#ifdef HAVE_DEV_DLPI 27817683Spst /* 27975107Sfenner ** Remove any "/dev/" on the front of the device. 28017683Spst */ 28175107Sfenner cp = strrchr(device, '/'); 28275107Sfenner if (cp == NULL) 28375107Sfenner cp = device; 28475107Sfenner else 28575107Sfenner cp++; 28675107Sfenner strlcpy(dname, cp, sizeof(dname)); 28775107Sfenner 28875107Sfenner /* 28998530Sfenner * Split the device name into a device type name and a unit number; 29098530Sfenner * chop off the unit number, so "dname" is just a device type name. 29175107Sfenner */ 29298530Sfenner cp = split_dname(dname, &ppa, ebuf); 29398530Sfenner if (cp == NULL) 29417683Spst goto bad; 29575107Sfenner *cp = '\0'; 29617683Spst 29775107Sfenner /* 29875107Sfenner * Use "/dev/dlpi" as the device. 29975107Sfenner * 30075107Sfenner * XXX - HP's DLPI Programmer's Guide for HP-UX 11.00 says that 30175107Sfenner * the "dl_mjr_num" field is for the "major number of interface 30275107Sfenner * driver"; that's the major of "/dev/dlpi" on the system on 30375107Sfenner * which I tried this, but there may be DLPI devices that 30475107Sfenner * use a different driver, in which case we may need to 30575107Sfenner * search "/dev" for the appropriate device with that major 30675107Sfenner * device number, rather than hardwiring "/dev/dlpi". 30775107Sfenner */ 30817683Spst cp = "/dev/dlpi"; 30917683Spst if ((p->fd = open(cp, O_RDWR)) < 0) { 31075107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 31175107Sfenner "%s: %s", cp, pcap_strerror(errno)); 31217683Spst goto bad; 31317683Spst } 31475107Sfenner 31575107Sfenner /* 31675107Sfenner * Get a table of all PPAs for that device, and search that 31775107Sfenner * table for the specified device type name and unit number. 31875107Sfenner */ 31917683Spst ppa = get_dlpi_ppa(p->fd, dname, ppa, ebuf); 32017683Spst if (ppa < 0) 32117683Spst goto bad; 32217683Spst#else 32375107Sfenner /* 32498530Sfenner * Get the unit number, and a pointer to the end of the device 32598530Sfenner * type name. 32698530Sfenner */ 32798530Sfenner cp = split_dname(device, &ppa, ebuf); 32898530Sfenner if (cp == NULL) 32975107Sfenner goto bad; 33075107Sfenner 33198530Sfenner /* 33298530Sfenner * If the device name begins with "/", assume it begins with 33398530Sfenner * the pathname of the directory containing the device to open; 33498530Sfenner * otherwise, concatenate the device directory name and the 33598530Sfenner * device name. 33698530Sfenner */ 33775107Sfenner if (*device == '/') 33875107Sfenner strlcpy(dname, device, sizeof(dname)); 33975107Sfenner else 34075107Sfenner snprintf(dname, sizeof(dname), "%s/%s", PCAP_DEV_PREFIX, 34175107Sfenner device); 34275107Sfenner 34398530Sfenner /* 34498530Sfenner * Make a copy of the device pathname, and then remove the unit 34598530Sfenner * number from the device pathname. 34698530Sfenner */ 34798530Sfenner strlcpy(dname2, dname, sizeof(dname)); 34898530Sfenner *(dname + strlen(dname) - strlen(cp)) = '\0'; 34998530Sfenner 35017683Spst /* Try device without unit number */ 35117683Spst if ((p->fd = open(dname, O_RDWR)) < 0) { 35217683Spst if (errno != ENOENT) { 35375107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s: %s", dname, 35475107Sfenner pcap_strerror(errno)); 35517683Spst goto bad; 35617683Spst } 35717683Spst 35817683Spst /* Try again with unit number */ 35917683Spst if ((p->fd = open(dname2, O_RDWR)) < 0) { 36075107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s: %s", dname2, 36175107Sfenner pcap_strerror(errno)); 36217683Spst goto bad; 36317683Spst } 36417683Spst /* XXX Assume unit zero */ 36517683Spst ppa = 0; 36617683Spst } 36717683Spst#endif 36817683Spst 36917683Spst p->snapshot = snaplen; 37017683Spst 37117683Spst /* 37217683Spst ** Attach if "style 2" provider 37317683Spst */ 37417683Spst if (dlinforeq(p->fd, ebuf) < 0 || 37517683Spst dlinfoack(p->fd, (char *)buf, ebuf) < 0) 37617683Spst goto bad; 37717683Spst infop = &((union DL_primitives *)buf)->info_ack; 37817683Spst if (infop->dl_provider_style == DL_STYLE2 && 37917683Spst (dlattachreq(p->fd, ppa, ebuf) < 0 || 38017683Spst dlokack(p->fd, "attach", (char *)buf, ebuf) < 0)) 38117683Spst goto bad; 38217683Spst /* 38339291Sfenner ** Bind (defer if using HP-UX 9 or HP-UX 10.20, totally skip if 38439291Sfenner ** using SINIX) 38517683Spst */ 38639291Sfenner#if !defined(HAVE_HPUX9) && !defined(HAVE_HPUX10_20) && !defined(sinix) 38775107Sfenner#ifdef _AIX 38898530Sfenner /* According to IBM's AIX Support Line, the dl_sap value 38998530Sfenner ** should not be less than 0x600 (1536) for standard Ethernet. 39098530Sfenner ** However, we seem to get DL_BADADDR - "DLSAP addr in improper 39198530Sfenner ** format or invalid" - errors if we use 1537 on the "tr0" 39298530Sfenner ** device, which, given that its name starts with "tr" and that 39398530Sfenner ** it's IBM, probably means a Token Ring device. (Perhaps we 39498530Sfenner ** need to use 1537 on "/dev/dlpi/en" because that device is for 39598530Sfenner ** D/I/X Ethernet, the "SAP" is actually an Ethernet type, and 39698530Sfenner ** it rejects invalid Ethernet types.) 39798530Sfenner ** 39898530Sfenner ** So if 1537 fails, we try 2, as Hyung Sik Yoon of IBM Korea 39998530Sfenner ** says that works on Token Ring (he says that 0 does *not* 40098530Sfenner ** work; perhaps that's considered an invalid LLC SAP value - I 40198530Sfenner ** assume the SAP value in a DLPI bind is an LLC SAP for network 40298530Sfenner ** types that use 802.2 LLC). 40398530Sfenner */ 40498530Sfenner if ((dlbindreq(p->fd, 1537, ebuf) < 0 && 40598530Sfenner dlbindreq(p->fd, 2, ebuf) < 0) || 40675107Sfenner#else 40717683Spst if (dlbindreq(p->fd, 0, ebuf) < 0 || 40875107Sfenner#endif 40917683Spst dlbindack(p->fd, (char *)buf, ebuf) < 0) 41017683Spst goto bad; 41117683Spst#endif 41217683Spst 41317683Spst if (promisc) { 41417683Spst /* 41517683Spst ** Enable promiscuous 41617683Spst */ 41717683Spst if (dlpromisconreq(p->fd, DL_PROMISC_PHYS, ebuf) < 0 || 41817683Spst dlokack(p->fd, "promisc_phys", (char *)buf, ebuf) < 0) 41917683Spst goto bad; 42017683Spst 42117683Spst /* 42217683Spst ** Try to enable multicast (you would have thought 42339291Sfenner ** promiscuous would be sufficient). (Skip if using 42439291Sfenner ** HP-UX or SINIX) 42517683Spst */ 42639291Sfenner#if !defined(__hpux) && !defined(sinix) 42717683Spst if (dlpromisconreq(p->fd, DL_PROMISC_MULTI, ebuf) < 0 || 42817683Spst dlokack(p->fd, "promisc_multi", (char *)buf, ebuf) < 0) 42917683Spst fprintf(stderr, 43017683Spst "WARNING: DL_PROMISC_MULTI failed (%s)\n", ebuf); 43117683Spst#endif 43217683Spst } 43317683Spst /* 43439291Sfenner ** Try to enable sap (when not in promiscuous mode when using 43539291Sfenner ** using HP-UX and never under SINIX) 43617683Spst */ 43717683Spst#ifndef sinix 43839291Sfenner if ( 43939291Sfenner#ifdef __hpux 44039291Sfenner !promisc && 44139291Sfenner#endif 44239291Sfenner (dlpromisconreq(p->fd, DL_PROMISC_SAP, ebuf) < 0 || 44339291Sfenner dlokack(p->fd, "promisc_sap", (char *)buf, ebuf) < 0)) { 44417683Spst /* Not fatal if promisc since the DL_PROMISC_PHYS worked */ 44517683Spst if (promisc) 44617683Spst fprintf(stderr, 44717683Spst "WARNING: DL_PROMISC_SAP failed (%s)\n", ebuf); 44817683Spst else 44917683Spst goto bad; 45017683Spst } 45117683Spst#endif 45217683Spst 45317683Spst /* 45439291Sfenner ** HP-UX 9 and HP-UX 10.20 must bind after setting promiscuous 45539291Sfenner ** options) 45617683Spst */ 45739291Sfenner#if defined(HAVE_HPUX9) || defined(HAVE_HPUX10_20) 45817683Spst if (dlbindreq(p->fd, 0, ebuf) < 0 || 45917683Spst dlbindack(p->fd, (char *)buf, ebuf) < 0) 46017683Spst goto bad; 46117683Spst#endif 46217683Spst 46317683Spst /* 46417683Spst ** Determine link type 46517683Spst */ 46617683Spst if (dlinforeq(p->fd, ebuf) < 0 || 46717683Spst dlinfoack(p->fd, (char *)buf, ebuf) < 0) 46817683Spst goto bad; 46917683Spst 47017683Spst infop = &((union DL_primitives *)buf)->info_ack; 47117683Spst switch (infop->dl_mac_type) { 47217683Spst 47317683Spst case DL_CSMACD: 47417683Spst case DL_ETHER: 47517683Spst p->linktype = DLT_EN10MB; 47617683Spst p->offset = 2; 47717683Spst break; 47817683Spst 47917683Spst case DL_FDDI: 48017683Spst p->linktype = DLT_FDDI; 48139291Sfenner p->offset = 3; 48217683Spst break; 48317683Spst 48498530Sfenner case DL_TPR: 48598530Sfenner p->linktype = DLT_IEEE802; 48698530Sfenner p->offset = 2; 48798530Sfenner break; 48898530Sfenner 48917683Spst default: 49075107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "unknown mac type %lu", 49175107Sfenner infop->dl_mac_type); 49217683Spst goto bad; 49317683Spst } 49417683Spst 49517683Spst#ifdef DLIOCRAW 49617683Spst /* 49717683Spst ** This is a non standard SunOS hack to get the ethernet header. 49817683Spst */ 49917683Spst if (strioctl(p->fd, DLIOCRAW, 0, NULL) < 0) { 50075107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "DLIOCRAW: %s", 50175107Sfenner pcap_strerror(errno)); 50217683Spst goto bad; 50317683Spst } 50417683Spst#endif 50517683Spst 50617683Spst#ifdef HAVE_SYS_BUFMOD_H 50717683Spst /* 50817683Spst ** Another non standard call to get the data nicely buffered 50917683Spst */ 51017683Spst if (ioctl(p->fd, I_PUSH, "bufmod") != 0) { 51175107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "I_PUSH bufmod: %s", 51275107Sfenner pcap_strerror(errno)); 51317683Spst goto bad; 51417683Spst } 51517683Spst 51617683Spst /* 51717683Spst ** Now that the bufmod is pushed lets configure it. 51817683Spst ** 51917683Spst ** There is a bug in bufmod(7). When dealing with messages of 52017683Spst ** less than snaplen size it strips data from the beginning not 52117683Spst ** the end. 52217683Spst ** 52317683Spst ** This bug is supposed to be fixed in 5.3.2. Also, there is a 52417683Spst ** patch available. Ask for bugid 1149065. 52517683Spst */ 52617683Spst ss = snaplen; 52717683Spst#ifdef HAVE_SOLARIS 52817683Spst release = get_release(&osmajor, &osminor, &osmicro); 52917683Spst if (osmajor == 5 && (osminor <= 2 || (osminor == 3 && osmicro < 2)) && 53017683Spst getenv("BUFMOD_FIXED") == NULL) { 53117683Spst fprintf(stderr, 53217683Spst "WARNING: bufmod is broken in SunOS %s; ignoring snaplen.\n", 53317683Spst release); 53417683Spst ss = 0; 53517683Spst } 53617683Spst#endif 53717683Spst if (ss > 0 && 53817683Spst strioctl(p->fd, SBIOCSSNAP, sizeof(ss), (char *)&ss) != 0) { 53975107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "SBIOCSSNAP: %s", 54075107Sfenner pcap_strerror(errno)); 54117683Spst goto bad; 54217683Spst } 54317683Spst 54417683Spst /* 54517683Spst ** Set up the bufmod flags 54617683Spst */ 54717683Spst if (strioctl(p->fd, SBIOCGFLAGS, sizeof(flag), (char *)&flag) < 0) { 54875107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "SBIOCGFLAGS: %s", 54975107Sfenner pcap_strerror(errno)); 55017683Spst goto bad; 55117683Spst } 55217683Spst flag |= SB_NO_DROPS; 55317683Spst if (strioctl(p->fd, SBIOCSFLAGS, sizeof(flag), (char *)&flag) != 0) { 55475107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "SBIOCSFLAGS: %s", 55575107Sfenner pcap_strerror(errno)); 55617683Spst goto bad; 55717683Spst } 55817683Spst /* 55917683Spst ** Set up the bufmod timeout 56017683Spst */ 56117683Spst if (to_ms != 0) { 56217683Spst struct timeval to; 56317683Spst 56417683Spst to.tv_sec = to_ms / 1000; 56517683Spst to.tv_usec = (to_ms * 1000) % 1000000; 56617683Spst if (strioctl(p->fd, SBIOCSTIME, sizeof(to), (char *)&to) != 0) { 56775107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "SBIOCSTIME: %s", 56875107Sfenner pcap_strerror(errno)); 56917683Spst goto bad; 57017683Spst } 57117683Spst } 57217683Spst#endif 57317683Spst 57417683Spst /* 57517683Spst ** As the last operation flush the read side. 57617683Spst */ 57717683Spst if (ioctl(p->fd, I_FLUSH, FLUSHR) != 0) { 57875107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "FLUSHR: %s", 57975107Sfenner pcap_strerror(errno)); 58017683Spst goto bad; 58117683Spst } 58217683Spst /* Allocate data buffer */ 58317683Spst p->bufsize = MAXDLBUF * sizeof(bpf_u_int32); 58417683Spst p->buffer = (u_char *)malloc(p->bufsize + p->offset); 58517683Spst 58617683Spst return (p); 58717683Spstbad: 58898530Sfenner if (p->fd >= 0) 58998530Sfenner close(p->fd); 59017683Spst free(p); 59117683Spst return (NULL); 59217683Spst} 59317683Spst 59498530Sfenner/* 59598530Sfenner * Split a device name into a device type name and a unit number; 59698530Sfenner * return the a pointer to the beginning of the unit number, which 59798530Sfenner * is the end of the device type name, and set "*unitp" to the unit 59898530Sfenner * number. 59998530Sfenner * 60098530Sfenner * Returns NULL on error, and fills "ebuf" with an error message. 60198530Sfenner */ 60298530Sfennerstatic char * 60398530Sfennersplit_dname(char *device, int *unitp, char *ebuf) 60498530Sfenner{ 60598530Sfenner char *cp; 60698530Sfenner char *eos; 60798530Sfenner int unit; 60898530Sfenner 60998530Sfenner /* 61098530Sfenner * Look for a number at the end of the device name string. 61198530Sfenner */ 61298530Sfenner cp = device + strlen(device) - 1; 61398530Sfenner if (*cp < '0' || *cp > '9') { 61498530Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s missing unit number", 61598530Sfenner device); 61698530Sfenner return (NULL); 61798530Sfenner } 61898530Sfenner 61998530Sfenner /* Digits at end of string are unit number */ 62098530Sfenner while (cp-1 >= device && *(cp-1) >= '0' && *(cp-1) <= '9') 62198530Sfenner cp--; 62298530Sfenner 62398530Sfenner unit = strtol(cp, &eos, 10); 62498530Sfenner if (*eos != '\0') { 62598530Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s bad unit number", device); 62698530Sfenner return (NULL); 62798530Sfenner } 62898530Sfenner *unitp = unit; 62998530Sfenner return (cp); 63098530Sfenner} 63198530Sfenner 63217683Spstint 63317683Spstpcap_setfilter(pcap_t *p, struct bpf_program *fp) 63417683Spst{ 63517683Spst 63675107Sfenner if (install_bpf_program(p, fp) < 0) 63775107Sfenner return (-1); 63817683Spst return (0); 63917683Spst} 64017683Spst 64117683Spststatic int 64217683Spstsend_request(int fd, char *ptr, int len, char *what, char *ebuf) 64317683Spst{ 64417683Spst struct strbuf ctl; 64517683Spst int flags; 64617683Spst 64717683Spst ctl.maxlen = 0; 64817683Spst ctl.len = len; 64917683Spst ctl.buf = ptr; 65017683Spst 65117683Spst flags = 0; 65217683Spst if (putmsg(fd, &ctl, (struct strbuf *) NULL, flags) < 0) { 65375107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 65475107Sfenner "send_request: putmsg \"%s\": %s", 65517683Spst what, pcap_strerror(errno)); 65617683Spst return (-1); 65717683Spst } 65817683Spst return (0); 65917683Spst} 66017683Spst 66117683Spststatic int 66217683Spstrecv_ack(int fd, int size, const char *what, char *bufp, char *ebuf) 66317683Spst{ 66417683Spst union DL_primitives *dlp; 66517683Spst struct strbuf ctl; 66617683Spst int flags; 66717683Spst 66817683Spst ctl.maxlen = MAXDLBUF; 66917683Spst ctl.len = 0; 67017683Spst ctl.buf = bufp; 67117683Spst 67217683Spst flags = 0; 67317683Spst if (getmsg(fd, &ctl, (struct strbuf*)NULL, &flags) < 0) { 67475107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "recv_ack: %s getmsg: %s", 67517683Spst what, pcap_strerror(errno)); 67617683Spst return (-1); 67717683Spst } 67817683Spst 67917683Spst dlp = (union DL_primitives *) ctl.buf; 68017683Spst switch (dlp->dl_primitive) { 68117683Spst 68217683Spst case DL_INFO_ACK: 68317683Spst case DL_BIND_ACK: 68417683Spst case DL_OK_ACK: 68517683Spst#ifdef DL_HP_PPA_ACK 68617683Spst case DL_HP_PPA_ACK: 68717683Spst#endif 68817683Spst /* These are OK */ 68917683Spst break; 69017683Spst 69117683Spst case DL_ERROR_ACK: 69217683Spst switch (dlp->error_ack.dl_errno) { 69317683Spst 69498530Sfenner case DL_SYSERR: 69575107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 69698530Sfenner "recv_ack: %s: UNIX error - %s", 69717683Spst what, pcap_strerror(dlp->error_ack.dl_unix_errno)); 69817683Spst break; 69917683Spst 70017683Spst default: 70198530Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "recv_ack: %s: %s", 70298530Sfenner what, dlstrerror(dlp->error_ack.dl_errno)); 70317683Spst break; 70417683Spst } 70517683Spst return (-1); 70617683Spst 70717683Spst default: 70875107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 70998530Sfenner "recv_ack: %s: Unexpected primitive ack %s", 71098530Sfenner what, dlprim(dlp->dl_primitive)); 71117683Spst return (-1); 71217683Spst } 71317683Spst 71417683Spst if (ctl.len < size) { 71575107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 71698530Sfenner "recv_ack: %s: Ack too small (%d < %d)", 71717683Spst what, ctl.len, size); 71817683Spst return (-1); 71917683Spst } 72017683Spst return (ctl.len); 72117683Spst} 72217683Spst 72398530Sfennerstatic char * 72498530Sfennerdlstrerror(bpf_u_int32 dl_errno) 72598530Sfenner{ 72698530Sfenner static char errstring[6+2+8+1]; 72798530Sfenner 72898530Sfenner switch (dl_errno) { 72998530Sfenner 73098530Sfenner case DL_ACCESS: 73198530Sfenner return ("Improper permissions for request"); 73298530Sfenner 73398530Sfenner case DL_BADADDR: 73498530Sfenner return ("DLSAP addr in improper format or invalid"); 73598530Sfenner 73698530Sfenner case DL_BADCORR: 73798530Sfenner return ("Seq number not from outstand DL_CONN_IND"); 73898530Sfenner 73998530Sfenner case DL_BADDATA: 74098530Sfenner return ("User data exceeded provider limit"); 74198530Sfenner 74298530Sfenner case DL_BADPPA: 74398530Sfenner#ifdef HAVE_DEV_DLPI 74498530Sfenner /* 74598530Sfenner * With a single "/dev/dlpi" device used for all 74698530Sfenner * DLPI providers, PPAs have nothing to do with 74798530Sfenner * unit numbers. 74898530Sfenner */ 74998530Sfenner return ("Specified PPA was invalid"); 75098530Sfenner#else 75198530Sfenner /* 75298530Sfenner * We have separate devices for separate devices; 75398530Sfenner * the PPA is just the unit number. 75498530Sfenner */ 75598530Sfenner return ("Specified PPA (device unit) was invalid"); 75698530Sfenner#endif 75798530Sfenner 75898530Sfenner case DL_BADPRIM: 75998530Sfenner return ("Primitive received not known by provider"); 76098530Sfenner 76198530Sfenner case DL_BADQOSPARAM: 76298530Sfenner return ("QOS parameters contained invalid values"); 76398530Sfenner 76498530Sfenner case DL_BADQOSTYPE: 76598530Sfenner return ("QOS structure type is unknown/unsupported"); 76698530Sfenner 76798530Sfenner case DL_BADSAP: 76898530Sfenner return ("Bad LSAP selector"); 76998530Sfenner 77098530Sfenner case DL_BADTOKEN: 77198530Sfenner return ("Token used not an active stream"); 77298530Sfenner 77398530Sfenner case DL_BOUND: 77498530Sfenner return ("Attempted second bind with dl_max_conind"); 77598530Sfenner 77698530Sfenner case DL_INITFAILED: 77798530Sfenner return ("Physical link initialization failed"); 77898530Sfenner 77998530Sfenner case DL_NOADDR: 78098530Sfenner return ("Provider couldn't allocate alternate address"); 78198530Sfenner 78298530Sfenner case DL_NOTINIT: 78398530Sfenner return ("Physical link not initialized"); 78498530Sfenner 78598530Sfenner case DL_OUTSTATE: 78698530Sfenner return ("Primitive issued in improper state"); 78798530Sfenner 78898530Sfenner case DL_SYSERR: 78998530Sfenner return ("UNIX system error occurred"); 79098530Sfenner 79198530Sfenner case DL_UNSUPPORTED: 79298530Sfenner return ("Requested service not supplied by provider"); 79398530Sfenner 79498530Sfenner case DL_UNDELIVERABLE: 79598530Sfenner return ("Previous data unit could not be delivered"); 79698530Sfenner 79798530Sfenner case DL_NOTSUPPORTED: 79898530Sfenner return ("Primitive is known but not supported"); 79998530Sfenner 80098530Sfenner case DL_TOOMANY: 80198530Sfenner return ("Limit exceeded"); 80298530Sfenner 80398530Sfenner case DL_NOTENAB: 80498530Sfenner return ("Promiscuous mode not enabled"); 80598530Sfenner 80698530Sfenner case DL_BUSY: 80798530Sfenner return ("Other streams for PPA in post-attached"); 80898530Sfenner 80998530Sfenner case DL_NOAUTO: 81098530Sfenner return ("Automatic handling XID&TEST not supported"); 81198530Sfenner 81298530Sfenner case DL_NOXIDAUTO: 81398530Sfenner return ("Automatic handling of XID not supported"); 81498530Sfenner 81598530Sfenner case DL_NOTESTAUTO: 81698530Sfenner return ("Automatic handling of TEST not supported"); 81798530Sfenner 81898530Sfenner case DL_XIDAUTO: 81998530Sfenner return ("Automatic handling of XID response"); 82098530Sfenner 82198530Sfenner case DL_TESTAUTO: 82298530Sfenner return ("Automatic handling of TEST response"); 82398530Sfenner 82498530Sfenner case DL_PENDING: 82598530Sfenner return ("Pending outstanding connect indications"); 82698530Sfenner 82798530Sfenner default: 82898530Sfenner sprintf(errstring, "Error %02x", dl_errno); 82998530Sfenner return (errstring); 83098530Sfenner } 83198530Sfenner} 83298530Sfenner 83398530Sfennerstatic char * 83498530Sfennerdlprim(bpf_u_int32 prim) 83598530Sfenner{ 83698530Sfenner static char primbuf[80]; 83798530Sfenner 83898530Sfenner switch (prim) { 83998530Sfenner 84098530Sfenner case DL_INFO_REQ: 84198530Sfenner return ("DL_INFO_REQ"); 84298530Sfenner 84398530Sfenner case DL_INFO_ACK: 84498530Sfenner return ("DL_INFO_ACK"); 84598530Sfenner 84698530Sfenner case DL_ATTACH_REQ: 84798530Sfenner return ("DL_ATTACH_REQ"); 84898530Sfenner 84998530Sfenner case DL_DETACH_REQ: 85098530Sfenner return ("DL_DETACH_REQ"); 85198530Sfenner 85298530Sfenner case DL_BIND_REQ: 85398530Sfenner return ("DL_BIND_REQ"); 85498530Sfenner 85598530Sfenner case DL_BIND_ACK: 85698530Sfenner return ("DL_BIND_ACK"); 85798530Sfenner 85898530Sfenner case DL_UNBIND_REQ: 85998530Sfenner return ("DL_UNBIND_REQ"); 86098530Sfenner 86198530Sfenner case DL_OK_ACK: 86298530Sfenner return ("DL_OK_ACK"); 86398530Sfenner 86498530Sfenner case DL_ERROR_ACK: 86598530Sfenner return ("DL_ERROR_ACK"); 86698530Sfenner 86798530Sfenner case DL_SUBS_BIND_REQ: 86898530Sfenner return ("DL_SUBS_BIND_REQ"); 86998530Sfenner 87098530Sfenner case DL_SUBS_BIND_ACK: 87198530Sfenner return ("DL_SUBS_BIND_ACK"); 87298530Sfenner 87398530Sfenner case DL_UNITDATA_REQ: 87498530Sfenner return ("DL_UNITDATA_REQ"); 87598530Sfenner 87698530Sfenner case DL_UNITDATA_IND: 87798530Sfenner return ("DL_UNITDATA_IND"); 87898530Sfenner 87998530Sfenner case DL_UDERROR_IND: 88098530Sfenner return ("DL_UDERROR_IND"); 88198530Sfenner 88298530Sfenner case DL_UDQOS_REQ: 88398530Sfenner return ("DL_UDQOS_REQ"); 88498530Sfenner 88598530Sfenner case DL_CONNECT_REQ: 88698530Sfenner return ("DL_CONNECT_REQ"); 88798530Sfenner 88898530Sfenner case DL_CONNECT_IND: 88998530Sfenner return ("DL_CONNECT_IND"); 89098530Sfenner 89198530Sfenner case DL_CONNECT_RES: 89298530Sfenner return ("DL_CONNECT_RES"); 89398530Sfenner 89498530Sfenner case DL_CONNECT_CON: 89598530Sfenner return ("DL_CONNECT_CON"); 89698530Sfenner 89798530Sfenner case DL_TOKEN_REQ: 89898530Sfenner return ("DL_TOKEN_REQ"); 89998530Sfenner 90098530Sfenner case DL_TOKEN_ACK: 90198530Sfenner return ("DL_TOKEN_ACK"); 90298530Sfenner 90398530Sfenner case DL_DISCONNECT_REQ: 90498530Sfenner return ("DL_DISCONNECT_REQ"); 90598530Sfenner 90698530Sfenner case DL_DISCONNECT_IND: 90798530Sfenner return ("DL_DISCONNECT_IND"); 90898530Sfenner 90998530Sfenner case DL_RESET_REQ: 91098530Sfenner return ("DL_RESET_REQ"); 91198530Sfenner 91298530Sfenner case DL_RESET_IND: 91398530Sfenner return ("DL_RESET_IND"); 91498530Sfenner 91598530Sfenner case DL_RESET_RES: 91698530Sfenner return ("DL_RESET_RES"); 91798530Sfenner 91898530Sfenner case DL_RESET_CON: 91998530Sfenner return ("DL_RESET_CON"); 92098530Sfenner 92198530Sfenner default: 92298530Sfenner (void) sprintf(primbuf, "unknown primitive 0x%x", prim); 92398530Sfenner return (primbuf); 92498530Sfenner } 92598530Sfenner} 92698530Sfenner 92717683Spststatic int 92817683Spstdlattachreq(int fd, bpf_u_int32 ppa, char *ebuf) 92917683Spst{ 93017683Spst dl_attach_req_t req; 93117683Spst 93217683Spst req.dl_primitive = DL_ATTACH_REQ; 93317683Spst req.dl_ppa = ppa; 93417683Spst 93517683Spst return (send_request(fd, (char *)&req, sizeof(req), "attach", ebuf)); 93617683Spst} 93717683Spst 93817683Spststatic int 93917683Spstdlbindreq(int fd, bpf_u_int32 sap, char *ebuf) 94017683Spst{ 94117683Spst 94217683Spst dl_bind_req_t req; 94317683Spst 94417683Spst memset((char *)&req, 0, sizeof(req)); 94517683Spst req.dl_primitive = DL_BIND_REQ; 94617683Spst#ifdef DL_HP_RAWDLS 94717683Spst req.dl_max_conind = 1; /* XXX magic number */ 94817683Spst /* 22 is INSAP as per the HP-UX DLPI Programmer's Guide */ 94917683Spst req.dl_sap = 22; 95017683Spst req.dl_service_mode = DL_HP_RAWDLS; 95117683Spst#else 95217683Spst req.dl_sap = sap; 95326175Sfenner#ifdef DL_CLDLS 95426175Sfenner req.dl_service_mode = DL_CLDLS; 95517683Spst#endif 95626175Sfenner#endif 95717683Spst 95817683Spst return (send_request(fd, (char *)&req, sizeof(req), "bind", ebuf)); 95917683Spst} 96017683Spst 96117683Spststatic int 96217683Spstdlbindack(int fd, char *bufp, char *ebuf) 96317683Spst{ 96417683Spst 96517683Spst return (recv_ack(fd, DL_BIND_ACK_SIZE, "bind", bufp, ebuf)); 96617683Spst} 96717683Spst 96817683Spststatic int 96917683Spstdlpromisconreq(int fd, bpf_u_int32 level, char *ebuf) 97017683Spst{ 97117683Spst dl_promiscon_req_t req; 97217683Spst 97317683Spst req.dl_primitive = DL_PROMISCON_REQ; 97417683Spst req.dl_level = level; 97517683Spst 97617683Spst return (send_request(fd, (char *)&req, sizeof(req), "promiscon", ebuf)); 97717683Spst} 97817683Spst 97917683Spststatic int 98017683Spstdlokack(int fd, const char *what, char *bufp, char *ebuf) 98117683Spst{ 98217683Spst 98317683Spst return (recv_ack(fd, DL_OK_ACK_SIZE, what, bufp, ebuf)); 98417683Spst} 98517683Spst 98617683Spst 98717683Spststatic int 98817683Spstdlinforeq(int fd, char *ebuf) 98917683Spst{ 99017683Spst dl_info_req_t req; 99117683Spst 99217683Spst req.dl_primitive = DL_INFO_REQ; 99317683Spst 99417683Spst return (send_request(fd, (char *)&req, sizeof(req), "info", ebuf)); 99517683Spst} 99617683Spst 99717683Spststatic int 99817683Spstdlinfoack(int fd, char *bufp, char *ebuf) 99917683Spst{ 100017683Spst 100117683Spst return (recv_ack(fd, DL_INFO_ACK_SIZE, "info", bufp, ebuf)); 100217683Spst} 100317683Spst 100417683Spst#ifdef HAVE_SYS_BUFMOD_H 100517683Spststatic int 100617683Spststrioctl(int fd, int cmd, int len, char *dp) 100717683Spst{ 100817683Spst struct strioctl str; 100917683Spst int rc; 101017683Spst 101117683Spst str.ic_cmd = cmd; 101217683Spst str.ic_timout = -1; 101317683Spst str.ic_len = len; 101417683Spst str.ic_dp = dp; 101517683Spst rc = ioctl(fd, I_STR, &str); 101617683Spst 101717683Spst if (rc < 0) 101817683Spst return (rc); 101917683Spst else 102017683Spst return (str.ic_len); 102117683Spst} 102217683Spst#endif 102317683Spst 102417683Spst#if defined(HAVE_SOLARIS) && defined(HAVE_SYS_BUFMOD_H) 102517683Spststatic char * 102617683Spstget_release(bpf_u_int32 *majorp, bpf_u_int32 *minorp, bpf_u_int32 *microp) 102717683Spst{ 102817683Spst char *cp; 102917683Spst static char buf[32]; 103017683Spst 103117683Spst *majorp = 0; 103217683Spst *minorp = 0; 103317683Spst *microp = 0; 103417683Spst if (sysinfo(SI_RELEASE, buf, sizeof(buf)) < 0) 103517683Spst return ("?"); 103617683Spst cp = buf; 103798530Sfenner if (!isdigit((unsigned char)*cp)) 103817683Spst return (buf); 103917683Spst *majorp = strtol(cp, &cp, 10); 104017683Spst if (*cp++ != '.') 104117683Spst return (buf); 104217683Spst *minorp = strtol(cp, &cp, 10); 104317683Spst if (*cp++ != '.') 104417683Spst return (buf); 104517683Spst *microp = strtol(cp, &cp, 10); 104617683Spst return (buf); 104717683Spst} 104817683Spst#endif 104917683Spst 105017683Spst#ifdef DL_HP_PPA_ACK_OBS 105117683Spst/* 105275107Sfenner * Under HP-UX 10 and HP-UX 11, we can ask for the ppa 105317683Spst */ 105417683Spst 105517683Spst 105675107Sfenner/* 105775107Sfenner * Determine ppa number that specifies ifname. 105875107Sfenner * 105975107Sfenner * If the "dl_hp_ppa_info_t" doesn't have a "dl_module_id_1" member, 106075107Sfenner * the code that's used here is the old code for HP-UX 10.x. 106175107Sfenner * 106275107Sfenner * However, HP-UX 10.20, at least, appears to have such a member 106375107Sfenner * in its "dl_hp_ppa_info_t" structure, so the new code is used. 106475107Sfenner * The new code didn't work on an old 10.20 system on which Rick 106575107Sfenner * Jones of HP tried it, but with later patches installed, it 106675107Sfenner * worked - it appears that the older system had those members but 106775107Sfenner * didn't put anything in them, so, if the search by name fails, we 106875107Sfenner * do the old search. 106975107Sfenner * 107075107Sfenner * Rick suggests that making sure your system is "up on the latest 107175107Sfenner * lancommon/DLPI/driver patches" is probably a good idea; it'd fix 107275107Sfenner * that problem, as well as allowing libpcap to see packets sent 107375107Sfenner * from the system on which the libpcap application is being run. 107475107Sfenner * (On 10.20, in addition to getting the latest patches, you need 107575107Sfenner * to turn the kernel "lanc_outbound_promisc_flag" flag on with ADB; 107675107Sfenner * a posting to "comp.sys.hp.hpux" at 107775107Sfenner * 107875107Sfenner * http://www.deja.com/[ST_rn=ps]/getdoc.xp?AN=558092266 107975107Sfenner * 108075107Sfenner * says that, to see the machine's outgoing traffic, you'd need to 108175107Sfenner * apply the right patches to your system, and also set that variable 108275107Sfenner * with: 108375107Sfenner 108475107Sfennerecho 'lanc_outbound_promisc_flag/W1' | /usr/bin/adb -w /stand/vmunix /dev/kmem 108575107Sfenner 108675107Sfenner * which could be put in, for example, "/sbin/init.d/lan". 108775107Sfenner * 108875107Sfenner * Setting the variable is not necessary on HP-UX 11.x. 108975107Sfenner */ 109017683Spststatic int 109117683Spstget_dlpi_ppa(register int fd, register const char *device, register int unit, 109217683Spst register char *ebuf) 109317683Spst{ 109417683Spst register dl_hp_ppa_ack_t *ap; 109575107Sfenner register dl_hp_ppa_info_t *ipstart, *ip; 109617683Spst register int i; 109775107Sfenner char dname[100]; 109817683Spst register u_long majdev; 109975107Sfenner struct stat statbuf; 110017683Spst dl_hp_ppa_req_t req; 110198530Sfenner char buf[MAXDLBUF]; 110298530Sfenner char *ppa_data_buf; 110398530Sfenner dl_hp_ppa_ack_t *dlp; 110498530Sfenner struct strbuf ctl; 110598530Sfenner int flags; 110698530Sfenner int ppa; 110717683Spst 110817683Spst memset((char *)&req, 0, sizeof(req)); 110917683Spst req.dl_primitive = DL_HP_PPA_REQ; 111017683Spst 111117683Spst memset((char *)buf, 0, sizeof(buf)); 111298530Sfenner if (send_request(fd, (char *)&req, sizeof(req), "hpppa", ebuf) < 0) 111317683Spst return (-1); 111417683Spst 111598530Sfenner ctl.maxlen = DL_HP_PPA_ACK_SIZE; 111698530Sfenner ctl.len = 0; 111798530Sfenner ctl.buf = (char *)buf; 111898530Sfenner 111998530Sfenner flags = 0; 112098530Sfenner /* 112198530Sfenner * DLPI may return a big chunk of data for a DL_HP_PPA_REQ. The normal 112298530Sfenner * recv_ack will fail because it set the maxlen to MAXDLBUF (8192) 112398530Sfenner * which is NOT big enough for a DL_HP_PPA_REQ. 112498530Sfenner * 112598530Sfenner * This causes libpcap applications to fail on a system with HP-APA 112698530Sfenner * installed. 112798530Sfenner * 112898530Sfenner * To figure out how big the returned data is, we first call getmsg 112998530Sfenner * to get the small head and peek at the head to get the actual data 113098530Sfenner * length, and then issue another getmsg to get the actual PPA data. 113198530Sfenner */ 113298530Sfenner /* get the head first */ 113398530Sfenner if (getmsg(fd, &ctl, (struct strbuf *)NULL, &flags) < 0) { 113498530Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 113598530Sfenner "get_dlpi_ppa: hpppa getmsg: %s", pcap_strerror(errno)); 113698530Sfenner return (-1); 113798530Sfenner } 113898530Sfenner 113998530Sfenner dlp = (dl_hp_ppa_ack_t *)ctl.buf; 114098530Sfenner if (dlp->dl_primitive != DL_HP_PPA_ACK) { 114198530Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 114298530Sfenner "get_dlpi_ppa: hpppa unexpected primitive ack 0x%x", 114398530Sfenner (bpf_u_int32)dlp->dl_primitive); 114498530Sfenner return (-1); 114598530Sfenner } 114698530Sfenner 114798530Sfenner if (ctl.len < DL_HP_PPA_ACK_SIZE) { 114898530Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 114998530Sfenner "get_dlpi_ppa: hpppa ack too small (%d < %d)", 115098530Sfenner ctl.len, DL_HP_PPA_ACK_SIZE); 115198530Sfenner return (-1); 115298530Sfenner } 115398530Sfenner 115498530Sfenner /* allocate buffer */ 115598530Sfenner if ((ppa_data_buf = (char *)malloc(dlp->dl_length)) == NULL) { 115698530Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 115798530Sfenner "get_dlpi_ppa: hpppa malloc: %s", pcap_strerror(errno)); 115898530Sfenner return (-1); 115998530Sfenner } 116098530Sfenner ctl.maxlen = dlp->dl_length; 116198530Sfenner ctl.len = 0; 116298530Sfenner ctl.buf = (char *)ppa_data_buf; 116398530Sfenner /* get the data */ 116498530Sfenner if (getmsg(fd, &ctl, (struct strbuf *)NULL, &flags) < 0) { 116598530Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 116698530Sfenner "get_dlpi_ppa: hpppa getmsg: %s", pcap_strerror(errno)); 116798530Sfenner free(ppa_data_buf); 116898530Sfenner return (-1); 116998530Sfenner } 117098530Sfenner if (ctl.len < dlp->dl_length) { 117198530Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 117298530Sfenner "get_dlpi_ppa: hpppa ack too small (%d < %d)", 117398530Sfenner ctl.len, dlp->dl_length); 117498530Sfenner free(ppa_data_buf); 117598530Sfenner return (-1); 117698530Sfenner } 117798530Sfenner 117817683Spst ap = (dl_hp_ppa_ack_t *)buf; 117998530Sfenner ipstart = (dl_hp_ppa_info_t *)ppa_data_buf; 118075107Sfenner ip = ipstart; 118117683Spst 118275107Sfenner#ifdef HAVE_HP_PPA_INFO_T_DL_MODULE_ID_1 118375107Sfenner /* 118475107Sfenner * The "dl_hp_ppa_info_t" structure has a "dl_module_id_1" 118575107Sfenner * member that should, in theory, contain the part of the 118675107Sfenner * name for the device that comes before the unit number, 118775107Sfenner * and should also have a "dl_module_id_2" member that may 118875107Sfenner * contain an alternate name (e.g., I think Ethernet devices 118975107Sfenner * have both "lan", for "lanN", and "snap", for "snapN", with 119075107Sfenner * the former being for Ethernet packets and the latter being 119175107Sfenner * for 802.3/802.2 packets). 119275107Sfenner * 119375107Sfenner * Search for the device that has the specified name and 119475107Sfenner * instance number. 119575107Sfenner */ 119675107Sfenner for (i = 0; i < ap->dl_count; i++) { 119798530Sfenner if ((strcmp((const char *)ip->dl_module_id_1, device) == 0 || 119898530Sfenner strcmp((const char *)ip->dl_module_id_2, device) == 0) && 119975107Sfenner ip->dl_instance_num == unit) 120075107Sfenner break; 120117683Spst 120275107Sfenner ip = (dl_hp_ppa_info_t *)((u_char *)ipstart + ip->dl_next_offset); 120375107Sfenner } 120475107Sfenner#else 120575107Sfenner /* 120675107Sfenner * We don't have that member, so the search is impossible; make it 120775107Sfenner * look as if the search failed. 120875107Sfenner */ 120975107Sfenner i = ap->dl_count; 121075107Sfenner#endif 121175107Sfenner 121275107Sfenner if (i == ap->dl_count) { 121375107Sfenner /* 121475107Sfenner * Well, we didn't, or can't, find the device by name. 121575107Sfenner * 121675107Sfenner * HP-UX 10.20, whilst it has "dl_module_id_1" and 121775107Sfenner * "dl_module_id_2" fields in the "dl_hp_ppa_info_t", 121875107Sfenner * doesn't seem to fill them in unless the system is 121975107Sfenner * at a reasonably up-to-date patch level. 122075107Sfenner * 122175107Sfenner * Older HP-UX 10.x systems might not have those fields 122275107Sfenner * at all. 122375107Sfenner * 122475107Sfenner * Therefore, we'll search for the entry with the major 122575107Sfenner * device number of a device with the name "/dev/<dev><unit>", 122675107Sfenner * if such a device exists, as the old code did. 122775107Sfenner */ 122875107Sfenner snprintf(dname, sizeof(dname), "/dev/%s%d", device, unit); 122975107Sfenner if (stat(dname, &statbuf) < 0) { 123075107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "stat: %s: %s", 123175107Sfenner dname, pcap_strerror(errno)); 123275107Sfenner return (-1); 123375107Sfenner } 123475107Sfenner majdev = major(statbuf.st_rdev); 123575107Sfenner 123675107Sfenner ip = ipstart; 123775107Sfenner 123875107Sfenner for (i = 0; i < ap->dl_count; i++) { 123975107Sfenner if (ip->dl_mjr_num == majdev && 124075107Sfenner ip->dl_instance_num == unit) 124175107Sfenner break; 124275107Sfenner 124375107Sfenner ip = (dl_hp_ppa_info_t *)((u_char *)ipstart + ip->dl_next_offset); 124475107Sfenner } 124575107Sfenner } 124617683Spst if (i == ap->dl_count) { 124775107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 124875107Sfenner "can't find /dev/dlpi PPA for %s%d", device, unit); 124917683Spst return (-1); 125017683Spst } 125117683Spst if (ip->dl_hdw_state == HDW_DEAD) { 125275107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 125375107Sfenner "%s%d: hardware state: DOWN\n", device, unit); 125498530Sfenner free(ppa_data_buf); 125517683Spst return (-1); 125617683Spst } 125798530Sfenner ppa = ip->dl_ppa; 125898530Sfenner free(ppa_data_buf); 125998530Sfenner return (ppa); 126017683Spst} 126117683Spst#endif 126217683Spst 126317683Spst#ifdef HAVE_HPUX9 126417683Spst/* 126517683Spst * Under HP-UX 9, there is no good way to determine the ppa. 126617683Spst * So punt and read it from /dev/kmem. 126717683Spst */ 126817683Spststatic struct nlist nl[] = { 126917683Spst#define NL_IFNET 0 127017683Spst { "ifnet" }, 127117683Spst { "" } 127217683Spst}; 127317683Spst 127417683Spststatic char path_vmunix[] = "/hp-ux"; 127517683Spst 127617683Spst/* Determine ppa number that specifies ifname */ 127717683Spststatic int 127817683Spstget_dlpi_ppa(register int fd, register const char *ifname, register int unit, 127917683Spst register char *ebuf) 128017683Spst{ 128117683Spst register const char *cp; 128217683Spst register int kd; 128317683Spst void *addr; 128417683Spst struct ifnet ifnet; 128575107Sfenner char if_name[sizeof(ifnet.if_name) + 1]; 128617683Spst 128717683Spst cp = strrchr(ifname, '/'); 128817683Spst if (cp != NULL) 128917683Spst ifname = cp + 1; 129017683Spst if (nlist(path_vmunix, &nl) < 0) { 129175107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "nlist %s failed", 129275107Sfenner path_vmunix); 129317683Spst return (-1); 129417683Spst } 129517683Spst if (nl[NL_IFNET].n_value == 0) { 129675107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 129775107Sfenner "could't find %s kernel symbol", 129817683Spst nl[NL_IFNET].n_name); 129917683Spst return (-1); 130017683Spst } 130117683Spst kd = open("/dev/kmem", O_RDONLY); 130217683Spst if (kd < 0) { 130375107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "kmem open: %s", 130475107Sfenner pcap_strerror(errno)); 130517683Spst return (-1); 130617683Spst } 130717683Spst if (dlpi_kread(kd, nl[NL_IFNET].n_value, 130817683Spst &addr, sizeof(addr), ebuf) < 0) { 130917683Spst close(kd); 131017683Spst return (-1); 131117683Spst } 131217683Spst for (; addr != NULL; addr = ifnet.if_next) { 131317683Spst if (dlpi_kread(kd, (off_t)addr, 131417683Spst &ifnet, sizeof(ifnet), ebuf) < 0 || 131517683Spst dlpi_kread(kd, (off_t)ifnet.if_name, 131675107Sfenner if_name, sizeof(ifnet.if_name), ebuf) < 0) { 131717683Spst (void)close(kd); 131817683Spst return (-1); 131917683Spst } 132075107Sfenner if_name[sizeof(ifnet.if_name)] = '\0'; 132175107Sfenner if (strcmp(if_name, ifname) == 0 && ifnet.if_unit == unit) 132217683Spst return (ifnet.if_index); 132317683Spst } 132417683Spst 132575107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "Can't find %s", ifname); 132617683Spst return (-1); 132717683Spst} 132817683Spst 132917683Spststatic int 133017683Spstdlpi_kread(register int fd, register off_t addr, 133117683Spst register void *buf, register u_int len, register char *ebuf) 133217683Spst{ 133317683Spst register int cc; 133417683Spst 133539291Sfenner if (lseek(fd, addr, SEEK_SET) < 0) { 133675107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "lseek: %s", 133775107Sfenner pcap_strerror(errno)); 133817683Spst return (-1); 133917683Spst } 134017683Spst cc = read(fd, buf, len); 134117683Spst if (cc < 0) { 134275107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "read: %s", 134375107Sfenner pcap_strerror(errno)); 134417683Spst return (-1); 134517683Spst } else if (cc != len) { 134675107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "short read (%d != %d)", cc, 134775107Sfenner len); 134817683Spst return (-1); 134917683Spst } 135017683Spst return (cc); 135117683Spst} 135217683Spst#endif 1353