pcap-dlpi.c revision 75107
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[] = 4175107Sfenner "@(#) $Header: /tcpdump/master/libpcap/pcap-dlpi.c,v 1.63 2000/11/22 05:32:55 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 9217683Spst#define PCAP_DEV_PREFIX "/dev" 9317683Spst#endif 9417683Spst 9517683Spst#define MAXDLBUF 8192 9617683Spst 9717683Spst/* Forwards */ 9817683Spststatic int dlattachreq(int, bpf_u_int32, char *); 9917683Spststatic int dlbindack(int, char *, char *); 10017683Spststatic int dlbindreq(int, bpf_u_int32, char *); 10117683Spststatic int dlinfoack(int, char *, char *); 10217683Spststatic int dlinforeq(int, char *); 10317683Spststatic int dlokack(int, const char *, char *, char *); 10417683Spststatic int recv_ack(int, int, const char *, char *, char *); 10517683Spststatic int dlpromisconreq(int, bpf_u_int32, char *); 10617683Spst#if defined(HAVE_SOLARIS) && defined(HAVE_SYS_BUFMOD_H) 10717683Spststatic char *get_release(bpf_u_int32 *, bpf_u_int32 *, bpf_u_int32 *); 10817683Spst#endif 10917683Spststatic int send_request(int, char *, int, char *, char *); 11017683Spst#ifdef HAVE_SYS_BUFMOD_H 11117683Spststatic int strioctl(int, int, int, char *); 11217683Spst#endif 11317683Spst#ifdef HAVE_HPUX9 11417683Spststatic int dlpi_kread(int, off_t, void *, u_int, char *); 11517683Spst#endif 11617683Spst#ifdef HAVE_DEV_DLPI 11717683Spststatic int get_dlpi_ppa(int, const char *, int, char *); 11817683Spst#endif 11917683Spst 12017683Spstint 12117683Spstpcap_stats(pcap_t *p, struct pcap_stat *ps) 12217683Spst{ 12317683Spst 12417683Spst *ps = p->md.stat; 12517683Spst return (0); 12617683Spst} 12717683Spst 12817683Spst/* XXX Needed by HP-UX (at least) */ 12917683Spststatic bpf_u_int32 ctlbuf[MAXDLBUF]; 13017683Spststatic struct strbuf ctl = { 13117683Spst MAXDLBUF, 13217683Spst 0, 13317683Spst (char *)ctlbuf 13417683Spst}; 13517683Spst 13617683Spstint 13717683Spstpcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) 13817683Spst{ 13917683Spst register int cc, n, caplen, origlen; 14017683Spst register u_char *bp, *ep, *pk; 14117683Spst register struct bpf_insn *fcode; 14217683Spst#ifdef HAVE_SYS_BUFMOD_H 14317683Spst register struct sb_hdr *sbp; 14417683Spst#ifdef LBL_ALIGN 14517683Spst struct sb_hdr sbhdr; 14617683Spst#endif 14717683Spst#endif 14817683Spst int flags; 14917683Spst struct strbuf data; 15017683Spst struct pcap_pkthdr pkthdr; 15117683Spst 15217683Spst flags = 0; 15317683Spst cc = p->cc; 15417683Spst if (cc == 0) { 15517683Spst data.buf = (char *)p->buffer + p->offset; 15617683Spst data.maxlen = MAXDLBUF; 15717683Spst data.len = 0; 15817683Spst do { 15917683Spst if (getmsg(p->fd, &ctl, &data, &flags) < 0) { 16017683Spst /* Don't choke when we get ptraced */ 16117683Spst if (errno == EINTR) { 16217683Spst cc = 0; 16317683Spst continue; 16417683Spst } 16575107Sfenner strlcpy(p->errbuf, pcap_strerror(errno), 16675107Sfenner sizeof(p->errbuf)); 16717683Spst return (-1); 16817683Spst } 16917683Spst cc = data.len; 17017683Spst } while (cc == 0); 17117683Spst bp = p->buffer + p->offset; 17217683Spst } else 17317683Spst bp = p->bp; 17417683Spst 17517683Spst /* Loop through packets */ 17617683Spst fcode = p->fcode.bf_insns; 17717683Spst ep = bp + cc; 17817683Spst n = 0; 17917683Spst#ifdef HAVE_SYS_BUFMOD_H 18017683Spst while (bp < ep) { 18117683Spst#ifdef LBL_ALIGN 18217683Spst if ((long)bp & 3) { 18317683Spst sbp = &sbhdr; 18417683Spst memcpy(sbp, bp, sizeof(*sbp)); 18517683Spst } else 18617683Spst#endif 18717683Spst sbp = (struct sb_hdr *)bp; 18817683Spst p->md.stat.ps_drop += sbp->sbh_drops; 18917683Spst pk = bp + sizeof(*sbp); 19017683Spst bp += sbp->sbh_totlen; 19117683Spst origlen = sbp->sbh_origlen; 19217683Spst caplen = sbp->sbh_msglen; 19317683Spst#else 19417683Spst origlen = cc; 19517683Spst caplen = min(p->snapshot, cc); 19617683Spst pk = bp; 19717683Spst bp += caplen; 19817683Spst#endif 19917683Spst ++p->md.stat.ps_recv; 20017683Spst if (bpf_filter(fcode, pk, origlen, caplen)) { 20117683Spst#ifdef HAVE_SYS_BUFMOD_H 20217683Spst pkthdr.ts = sbp->sbh_timestamp; 20317683Spst#else 20417683Spst (void)gettimeofday(&pkthdr.ts, NULL); 20517683Spst#endif 20617683Spst pkthdr.len = origlen; 20717683Spst pkthdr.caplen = caplen; 20817683Spst /* Insure caplen does not exceed snapshot */ 20917683Spst if (pkthdr.caplen > p->snapshot) 21017683Spst pkthdr.caplen = p->snapshot; 21117683Spst (*callback)(user, &pkthdr, pk); 21217683Spst if (++n >= cnt && cnt >= 0) { 21317683Spst p->cc = ep - bp; 21417683Spst p->bp = bp; 21517683Spst return (n); 21617683Spst } 21717683Spst } 21817683Spst#ifdef HAVE_SYS_BUFMOD_H 21917683Spst } 22017683Spst#endif 22117683Spst p->cc = 0; 22217683Spst return (n); 22317683Spst} 22417683Spst 22517683Spstpcap_t * 22617683Spstpcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf) 22717683Spst{ 22817683Spst register char *cp; 22917683Spst char *eos; 23017683Spst register pcap_t *p; 23117683Spst register int ppa; 23217683Spst register dl_info_ack_t *infop; 23317683Spst#ifdef HAVE_SYS_BUFMOD_H 23417683Spst bpf_u_int32 ss, flag; 23517683Spst#ifdef HAVE_SOLARIS 23617683Spst register char *release; 23717683Spst bpf_u_int32 osmajor, osminor, osmicro; 23817683Spst#endif 23917683Spst#endif 24017683Spst bpf_u_int32 buf[MAXDLBUF]; 24117683Spst char dname[100]; 24217683Spst#ifndef HAVE_DEV_DLPI 24317683Spst char dname2[100]; 24417683Spst#endif 24517683Spst 24617683Spst p = (pcap_t *)malloc(sizeof(*p)); 24717683Spst if (p == NULL) { 24875107Sfenner strlcpy(ebuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE); 24917683Spst return (NULL); 25017683Spst } 25117683Spst memset(p, 0, sizeof(*p)); 25217683Spst 25375107Sfenner#ifdef HAVE_DEV_DLPI 25417683Spst /* 25575107Sfenner ** Remove any "/dev/" on the front of the device. 25617683Spst */ 25775107Sfenner cp = strrchr(device, '/'); 25875107Sfenner if (cp == NULL) 25975107Sfenner cp = device; 26075107Sfenner else 26175107Sfenner cp++; 26275107Sfenner strlcpy(dname, cp, sizeof(dname)); 26375107Sfenner 26475107Sfenner /* 26575107Sfenner * Split the name into a device type and a unit number. 26675107Sfenner */ 26775107Sfenner cp = strpbrk(dname, "0123456789"); 26817683Spst if (cp == NULL) { 26975107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 27075107Sfenner "%s missing unit number", device); 27117683Spst goto bad; 27217683Spst } 27317683Spst ppa = strtol(cp, &eos, 10); 27417683Spst if (*eos != '\0') { 27575107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 27675107Sfenner "%s bad unit number", device); 27717683Spst goto bad; 27817683Spst } 27975107Sfenner *cp = '\0'; 28017683Spst 28175107Sfenner /* 28275107Sfenner * Use "/dev/dlpi" as the device. 28375107Sfenner * 28475107Sfenner * XXX - HP's DLPI Programmer's Guide for HP-UX 11.00 says that 28575107Sfenner * the "dl_mjr_num" field is for the "major number of interface 28675107Sfenner * driver"; that's the major of "/dev/dlpi" on the system on 28775107Sfenner * which I tried this, but there may be DLPI devices that 28875107Sfenner * use a different driver, in which case we may need to 28975107Sfenner * search "/dev" for the appropriate device with that major 29075107Sfenner * device number, rather than hardwiring "/dev/dlpi". 29175107Sfenner */ 29217683Spst cp = "/dev/dlpi"; 29317683Spst if ((p->fd = open(cp, O_RDWR)) < 0) { 29475107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 29575107Sfenner "%s: %s", cp, pcap_strerror(errno)); 29617683Spst goto bad; 29717683Spst } 29875107Sfenner 29975107Sfenner /* 30075107Sfenner * Get a table of all PPAs for that device, and search that 30175107Sfenner * table for the specified device type name and unit number. 30275107Sfenner */ 30317683Spst ppa = get_dlpi_ppa(p->fd, dname, ppa, ebuf); 30417683Spst if (ppa < 0) 30517683Spst goto bad; 30617683Spst#else 30775107Sfenner /* 30875107Sfenner ** Determine device and ppa 30975107Sfenner */ 31075107Sfenner cp = strpbrk(device, "0123456789"); 31175107Sfenner if (cp == NULL) { 31275107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s missing unit number", 31375107Sfenner device); 31475107Sfenner goto bad; 31575107Sfenner } 31675107Sfenner ppa = strtol(cp, &eos, 10); 31775107Sfenner if (*eos != '\0') { 31875107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s bad unit number", device); 31975107Sfenner goto bad; 32075107Sfenner } 32175107Sfenner 32275107Sfenner if (*device == '/') 32375107Sfenner strlcpy(dname, device, sizeof(dname)); 32475107Sfenner else 32575107Sfenner snprintf(dname, sizeof(dname), "%s/%s", PCAP_DEV_PREFIX, 32675107Sfenner device); 32775107Sfenner 32817683Spst /* Try device without unit number */ 32975107Sfenner strlcpy(dname2, dname, sizeof(dname2)); 33017683Spst cp = strchr(dname, *cp); 33117683Spst *cp = '\0'; 33217683Spst if ((p->fd = open(dname, O_RDWR)) < 0) { 33317683Spst if (errno != ENOENT) { 33475107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s: %s", dname, 33575107Sfenner pcap_strerror(errno)); 33617683Spst goto bad; 33717683Spst } 33817683Spst 33917683Spst /* Try again with unit number */ 34017683Spst if ((p->fd = open(dname2, O_RDWR)) < 0) { 34175107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s: %s", dname2, 34275107Sfenner pcap_strerror(errno)); 34317683Spst goto bad; 34417683Spst } 34517683Spst /* XXX Assume unit zero */ 34617683Spst ppa = 0; 34717683Spst } 34817683Spst#endif 34917683Spst 35017683Spst p->snapshot = snaplen; 35117683Spst 35217683Spst /* 35317683Spst ** Attach if "style 2" provider 35417683Spst */ 35517683Spst if (dlinforeq(p->fd, ebuf) < 0 || 35617683Spst dlinfoack(p->fd, (char *)buf, ebuf) < 0) 35717683Spst goto bad; 35817683Spst infop = &((union DL_primitives *)buf)->info_ack; 35917683Spst if (infop->dl_provider_style == DL_STYLE2 && 36017683Spst (dlattachreq(p->fd, ppa, ebuf) < 0 || 36117683Spst dlokack(p->fd, "attach", (char *)buf, ebuf) < 0)) 36217683Spst goto bad; 36317683Spst /* 36439291Sfenner ** Bind (defer if using HP-UX 9 or HP-UX 10.20, totally skip if 36539291Sfenner ** using SINIX) 36617683Spst */ 36739291Sfenner#if !defined(HAVE_HPUX9) && !defined(HAVE_HPUX10_20) && !defined(sinix) 36875107Sfenner#ifdef _AIX 36975107Sfenner /* According to IBM's AIX Support Line, the dl_sap value 37075107Sfenner ** should not be less than 0x600 (1536) for standard ethernet 37175107Sfenner */ 37275107Sfenner if (dlbindreq(p->fd, 1537, ebuf) < 0 || 37375107Sfenner#else 37417683Spst if (dlbindreq(p->fd, 0, ebuf) < 0 || 37575107Sfenner#endif 37617683Spst dlbindack(p->fd, (char *)buf, ebuf) < 0) 37717683Spst goto bad; 37817683Spst#endif 37917683Spst 38017683Spst if (promisc) { 38117683Spst /* 38217683Spst ** Enable promiscuous 38317683Spst */ 38417683Spst if (dlpromisconreq(p->fd, DL_PROMISC_PHYS, ebuf) < 0 || 38517683Spst dlokack(p->fd, "promisc_phys", (char *)buf, ebuf) < 0) 38617683Spst goto bad; 38717683Spst 38817683Spst /* 38917683Spst ** Try to enable multicast (you would have thought 39039291Sfenner ** promiscuous would be sufficient). (Skip if using 39139291Sfenner ** HP-UX or SINIX) 39217683Spst */ 39339291Sfenner#if !defined(__hpux) && !defined(sinix) 39417683Spst if (dlpromisconreq(p->fd, DL_PROMISC_MULTI, ebuf) < 0 || 39517683Spst dlokack(p->fd, "promisc_multi", (char *)buf, ebuf) < 0) 39617683Spst fprintf(stderr, 39717683Spst "WARNING: DL_PROMISC_MULTI failed (%s)\n", ebuf); 39817683Spst#endif 39917683Spst } 40017683Spst /* 40139291Sfenner ** Try to enable sap (when not in promiscuous mode when using 40239291Sfenner ** using HP-UX and never under SINIX) 40317683Spst */ 40417683Spst#ifndef sinix 40539291Sfenner if ( 40639291Sfenner#ifdef __hpux 40739291Sfenner !promisc && 40839291Sfenner#endif 40939291Sfenner (dlpromisconreq(p->fd, DL_PROMISC_SAP, ebuf) < 0 || 41039291Sfenner dlokack(p->fd, "promisc_sap", (char *)buf, ebuf) < 0)) { 41117683Spst /* Not fatal if promisc since the DL_PROMISC_PHYS worked */ 41217683Spst if (promisc) 41317683Spst fprintf(stderr, 41417683Spst "WARNING: DL_PROMISC_SAP failed (%s)\n", ebuf); 41517683Spst else 41617683Spst goto bad; 41717683Spst } 41817683Spst#endif 41917683Spst 42017683Spst /* 42139291Sfenner ** HP-UX 9 and HP-UX 10.20 must bind after setting promiscuous 42239291Sfenner ** options) 42317683Spst */ 42439291Sfenner#if defined(HAVE_HPUX9) || defined(HAVE_HPUX10_20) 42517683Spst if (dlbindreq(p->fd, 0, ebuf) < 0 || 42617683Spst dlbindack(p->fd, (char *)buf, ebuf) < 0) 42717683Spst goto bad; 42817683Spst#endif 42917683Spst 43017683Spst /* 43117683Spst ** Determine link type 43217683Spst */ 43317683Spst if (dlinforeq(p->fd, ebuf) < 0 || 43417683Spst dlinfoack(p->fd, (char *)buf, ebuf) < 0) 43517683Spst goto bad; 43617683Spst 43717683Spst infop = &((union DL_primitives *)buf)->info_ack; 43817683Spst switch (infop->dl_mac_type) { 43917683Spst 44017683Spst case DL_CSMACD: 44117683Spst case DL_ETHER: 44217683Spst p->linktype = DLT_EN10MB; 44317683Spst p->offset = 2; 44417683Spst break; 44517683Spst 44617683Spst case DL_FDDI: 44717683Spst p->linktype = DLT_FDDI; 44839291Sfenner p->offset = 3; 44917683Spst break; 45017683Spst 45117683Spst default: 45275107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "unknown mac type %lu", 45375107Sfenner infop->dl_mac_type); 45417683Spst goto bad; 45517683Spst } 45617683Spst 45717683Spst#ifdef DLIOCRAW 45817683Spst /* 45917683Spst ** This is a non standard SunOS hack to get the ethernet header. 46017683Spst */ 46117683Spst if (strioctl(p->fd, DLIOCRAW, 0, NULL) < 0) { 46275107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "DLIOCRAW: %s", 46375107Sfenner pcap_strerror(errno)); 46417683Spst goto bad; 46517683Spst } 46617683Spst#endif 46717683Spst 46817683Spst#ifdef HAVE_SYS_BUFMOD_H 46917683Spst /* 47017683Spst ** Another non standard call to get the data nicely buffered 47117683Spst */ 47217683Spst if (ioctl(p->fd, I_PUSH, "bufmod") != 0) { 47375107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "I_PUSH bufmod: %s", 47475107Sfenner pcap_strerror(errno)); 47517683Spst goto bad; 47617683Spst } 47717683Spst 47817683Spst /* 47917683Spst ** Now that the bufmod is pushed lets configure it. 48017683Spst ** 48117683Spst ** There is a bug in bufmod(7). When dealing with messages of 48217683Spst ** less than snaplen size it strips data from the beginning not 48317683Spst ** the end. 48417683Spst ** 48517683Spst ** This bug is supposed to be fixed in 5.3.2. Also, there is a 48617683Spst ** patch available. Ask for bugid 1149065. 48717683Spst */ 48817683Spst ss = snaplen; 48917683Spst#ifdef HAVE_SOLARIS 49017683Spst release = get_release(&osmajor, &osminor, &osmicro); 49117683Spst if (osmajor == 5 && (osminor <= 2 || (osminor == 3 && osmicro < 2)) && 49217683Spst getenv("BUFMOD_FIXED") == NULL) { 49317683Spst fprintf(stderr, 49417683Spst "WARNING: bufmod is broken in SunOS %s; ignoring snaplen.\n", 49517683Spst release); 49617683Spst ss = 0; 49717683Spst } 49817683Spst#endif 49917683Spst if (ss > 0 && 50017683Spst strioctl(p->fd, SBIOCSSNAP, sizeof(ss), (char *)&ss) != 0) { 50175107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "SBIOCSSNAP: %s", 50275107Sfenner pcap_strerror(errno)); 50317683Spst goto bad; 50417683Spst } 50517683Spst 50617683Spst /* 50717683Spst ** Set up the bufmod flags 50817683Spst */ 50917683Spst if (strioctl(p->fd, SBIOCGFLAGS, sizeof(flag), (char *)&flag) < 0) { 51075107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "SBIOCGFLAGS: %s", 51175107Sfenner pcap_strerror(errno)); 51217683Spst goto bad; 51317683Spst } 51417683Spst flag |= SB_NO_DROPS; 51517683Spst if (strioctl(p->fd, SBIOCSFLAGS, sizeof(flag), (char *)&flag) != 0) { 51675107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "SBIOCSFLAGS: %s", 51775107Sfenner pcap_strerror(errno)); 51817683Spst goto bad; 51917683Spst } 52017683Spst /* 52117683Spst ** Set up the bufmod timeout 52217683Spst */ 52317683Spst if (to_ms != 0) { 52417683Spst struct timeval to; 52517683Spst 52617683Spst to.tv_sec = to_ms / 1000; 52717683Spst to.tv_usec = (to_ms * 1000) % 1000000; 52817683Spst if (strioctl(p->fd, SBIOCSTIME, sizeof(to), (char *)&to) != 0) { 52975107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "SBIOCSTIME: %s", 53075107Sfenner pcap_strerror(errno)); 53117683Spst goto bad; 53217683Spst } 53317683Spst } 53417683Spst#endif 53517683Spst 53617683Spst /* 53717683Spst ** As the last operation flush the read side. 53817683Spst */ 53917683Spst if (ioctl(p->fd, I_FLUSH, FLUSHR) != 0) { 54075107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "FLUSHR: %s", 54175107Sfenner pcap_strerror(errno)); 54217683Spst goto bad; 54317683Spst } 54417683Spst /* Allocate data buffer */ 54517683Spst p->bufsize = MAXDLBUF * sizeof(bpf_u_int32); 54617683Spst p->buffer = (u_char *)malloc(p->bufsize + p->offset); 54717683Spst 54817683Spst return (p); 54917683Spstbad: 55017683Spst free(p); 55117683Spst return (NULL); 55217683Spst} 55317683Spst 55417683Spstint 55517683Spstpcap_setfilter(pcap_t *p, struct bpf_program *fp) 55617683Spst{ 55717683Spst 55875107Sfenner if (install_bpf_program(p, fp) < 0) 55975107Sfenner return (-1); 56017683Spst return (0); 56117683Spst} 56217683Spst 56317683Spststatic int 56417683Spstsend_request(int fd, char *ptr, int len, char *what, char *ebuf) 56517683Spst{ 56617683Spst struct strbuf ctl; 56717683Spst int flags; 56817683Spst 56917683Spst ctl.maxlen = 0; 57017683Spst ctl.len = len; 57117683Spst ctl.buf = ptr; 57217683Spst 57317683Spst flags = 0; 57417683Spst if (putmsg(fd, &ctl, (struct strbuf *) NULL, flags) < 0) { 57575107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 57675107Sfenner "send_request: putmsg \"%s\": %s", 57717683Spst what, pcap_strerror(errno)); 57817683Spst return (-1); 57917683Spst } 58017683Spst return (0); 58117683Spst} 58217683Spst 58317683Spststatic int 58417683Spstrecv_ack(int fd, int size, const char *what, char *bufp, char *ebuf) 58517683Spst{ 58617683Spst union DL_primitives *dlp; 58717683Spst struct strbuf ctl; 58817683Spst int flags; 58917683Spst 59017683Spst ctl.maxlen = MAXDLBUF; 59117683Spst ctl.len = 0; 59217683Spst ctl.buf = bufp; 59317683Spst 59417683Spst flags = 0; 59517683Spst if (getmsg(fd, &ctl, (struct strbuf*)NULL, &flags) < 0) { 59675107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "recv_ack: %s getmsg: %s", 59717683Spst what, pcap_strerror(errno)); 59817683Spst return (-1); 59917683Spst } 60017683Spst 60117683Spst dlp = (union DL_primitives *) ctl.buf; 60217683Spst switch (dlp->dl_primitive) { 60317683Spst 60417683Spst case DL_INFO_ACK: 60517683Spst case DL_BIND_ACK: 60617683Spst case DL_OK_ACK: 60717683Spst#ifdef DL_HP_PPA_ACK 60817683Spst case DL_HP_PPA_ACK: 60917683Spst#endif 61017683Spst 61117683Spst /* These are OK */ 61217683Spst break; 61317683Spst 61417683Spst case DL_ERROR_ACK: 61517683Spst switch (dlp->error_ack.dl_errno) { 61617683Spst 61717683Spst case DL_BADPPA: 61875107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 61975107Sfenner "recv_ack: %s bad ppa (device unit)", what); 62017683Spst break; 62117683Spst 62226175Sfenner 62317683Spst case DL_SYSERR: 62475107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "recv_ack: %s: %s", 62517683Spst what, pcap_strerror(dlp->error_ack.dl_unix_errno)); 62617683Spst break; 62717683Spst 62826175Sfenner case DL_UNSUPPORTED: 62975107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 63026175Sfenner "recv_ack: %s: Service not supplied by provider", 63126175Sfenner what); 63226175Sfenner break; 63326175Sfenner 63417683Spst default: 63575107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 63675107Sfenner "recv_ack: %s error 0x%x", 63717683Spst what, (bpf_u_int32)dlp->error_ack.dl_errno); 63817683Spst break; 63917683Spst } 64017683Spst return (-1); 64117683Spst 64217683Spst default: 64375107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 64475107Sfenner "recv_ack: %s unexpected primitive ack 0x%x ", 64517683Spst what, (bpf_u_int32)dlp->dl_primitive); 64617683Spst return (-1); 64717683Spst } 64817683Spst 64917683Spst if (ctl.len < size) { 65075107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 65175107Sfenner "recv_ack: %s ack too small (%d < %d)", 65217683Spst what, ctl.len, size); 65317683Spst return (-1); 65417683Spst } 65517683Spst return (ctl.len); 65617683Spst} 65717683Spst 65817683Spststatic int 65917683Spstdlattachreq(int fd, bpf_u_int32 ppa, char *ebuf) 66017683Spst{ 66117683Spst dl_attach_req_t req; 66217683Spst 66317683Spst req.dl_primitive = DL_ATTACH_REQ; 66417683Spst req.dl_ppa = ppa; 66517683Spst 66617683Spst return (send_request(fd, (char *)&req, sizeof(req), "attach", ebuf)); 66717683Spst} 66817683Spst 66917683Spststatic int 67017683Spstdlbindreq(int fd, bpf_u_int32 sap, char *ebuf) 67117683Spst{ 67217683Spst 67317683Spst dl_bind_req_t req; 67417683Spst 67517683Spst memset((char *)&req, 0, sizeof(req)); 67617683Spst req.dl_primitive = DL_BIND_REQ; 67717683Spst#ifdef DL_HP_RAWDLS 67817683Spst req.dl_max_conind = 1; /* XXX magic number */ 67917683Spst /* 22 is INSAP as per the HP-UX DLPI Programmer's Guide */ 68017683Spst req.dl_sap = 22; 68117683Spst req.dl_service_mode = DL_HP_RAWDLS; 68217683Spst#else 68317683Spst req.dl_sap = sap; 68426175Sfenner#ifdef DL_CLDLS 68526175Sfenner req.dl_service_mode = DL_CLDLS; 68617683Spst#endif 68726175Sfenner#endif 68817683Spst 68917683Spst return (send_request(fd, (char *)&req, sizeof(req), "bind", ebuf)); 69017683Spst} 69117683Spst 69217683Spststatic int 69317683Spstdlbindack(int fd, char *bufp, char *ebuf) 69417683Spst{ 69517683Spst 69617683Spst return (recv_ack(fd, DL_BIND_ACK_SIZE, "bind", bufp, ebuf)); 69717683Spst} 69817683Spst 69917683Spststatic int 70017683Spstdlpromisconreq(int fd, bpf_u_int32 level, char *ebuf) 70117683Spst{ 70217683Spst dl_promiscon_req_t req; 70317683Spst 70417683Spst req.dl_primitive = DL_PROMISCON_REQ; 70517683Spst req.dl_level = level; 70617683Spst 70717683Spst return (send_request(fd, (char *)&req, sizeof(req), "promiscon", ebuf)); 70817683Spst} 70917683Spst 71017683Spststatic int 71117683Spstdlokack(int fd, const char *what, char *bufp, char *ebuf) 71217683Spst{ 71317683Spst 71417683Spst return (recv_ack(fd, DL_OK_ACK_SIZE, what, bufp, ebuf)); 71517683Spst} 71617683Spst 71717683Spst 71817683Spststatic int 71917683Spstdlinforeq(int fd, char *ebuf) 72017683Spst{ 72117683Spst dl_info_req_t req; 72217683Spst 72317683Spst req.dl_primitive = DL_INFO_REQ; 72417683Spst 72517683Spst return (send_request(fd, (char *)&req, sizeof(req), "info", ebuf)); 72617683Spst} 72717683Spst 72817683Spststatic int 72917683Spstdlinfoack(int fd, char *bufp, char *ebuf) 73017683Spst{ 73117683Spst 73217683Spst return (recv_ack(fd, DL_INFO_ACK_SIZE, "info", bufp, ebuf)); 73317683Spst} 73417683Spst 73517683Spst#ifdef HAVE_SYS_BUFMOD_H 73617683Spststatic int 73717683Spststrioctl(int fd, int cmd, int len, char *dp) 73817683Spst{ 73917683Spst struct strioctl str; 74017683Spst int rc; 74117683Spst 74217683Spst str.ic_cmd = cmd; 74317683Spst str.ic_timout = -1; 74417683Spst str.ic_len = len; 74517683Spst str.ic_dp = dp; 74617683Spst rc = ioctl(fd, I_STR, &str); 74717683Spst 74817683Spst if (rc < 0) 74917683Spst return (rc); 75017683Spst else 75117683Spst return (str.ic_len); 75217683Spst} 75317683Spst#endif 75417683Spst 75517683Spst#if defined(HAVE_SOLARIS) && defined(HAVE_SYS_BUFMOD_H) 75617683Spststatic char * 75717683Spstget_release(bpf_u_int32 *majorp, bpf_u_int32 *minorp, bpf_u_int32 *microp) 75817683Spst{ 75917683Spst char *cp; 76017683Spst static char buf[32]; 76117683Spst 76217683Spst *majorp = 0; 76317683Spst *minorp = 0; 76417683Spst *microp = 0; 76517683Spst if (sysinfo(SI_RELEASE, buf, sizeof(buf)) < 0) 76617683Spst return ("?"); 76717683Spst cp = buf; 76817683Spst if (!isdigit(*cp)) 76917683Spst return (buf); 77017683Spst *majorp = strtol(cp, &cp, 10); 77117683Spst if (*cp++ != '.') 77217683Spst return (buf); 77317683Spst *minorp = strtol(cp, &cp, 10); 77417683Spst if (*cp++ != '.') 77517683Spst return (buf); 77617683Spst *microp = strtol(cp, &cp, 10); 77717683Spst return (buf); 77817683Spst} 77917683Spst#endif 78017683Spst 78117683Spst#ifdef DL_HP_PPA_ACK_OBS 78217683Spst/* 78375107Sfenner * Under HP-UX 10 and HP-UX 11, we can ask for the ppa 78417683Spst */ 78517683Spst 78617683Spst 78775107Sfenner/* 78875107Sfenner * Determine ppa number that specifies ifname. 78975107Sfenner * 79075107Sfenner * If the "dl_hp_ppa_info_t" doesn't have a "dl_module_id_1" member, 79175107Sfenner * the code that's used here is the old code for HP-UX 10.x. 79275107Sfenner * 79375107Sfenner * However, HP-UX 10.20, at least, appears to have such a member 79475107Sfenner * in its "dl_hp_ppa_info_t" structure, so the new code is used. 79575107Sfenner * The new code didn't work on an old 10.20 system on which Rick 79675107Sfenner * Jones of HP tried it, but with later patches installed, it 79775107Sfenner * worked - it appears that the older system had those members but 79875107Sfenner * didn't put anything in them, so, if the search by name fails, we 79975107Sfenner * do the old search. 80075107Sfenner * 80175107Sfenner * Rick suggests that making sure your system is "up on the latest 80275107Sfenner * lancommon/DLPI/driver patches" is probably a good idea; it'd fix 80375107Sfenner * that problem, as well as allowing libpcap to see packets sent 80475107Sfenner * from the system on which the libpcap application is being run. 80575107Sfenner * (On 10.20, in addition to getting the latest patches, you need 80675107Sfenner * to turn the kernel "lanc_outbound_promisc_flag" flag on with ADB; 80775107Sfenner * a posting to "comp.sys.hp.hpux" at 80875107Sfenner * 80975107Sfenner * http://www.deja.com/[ST_rn=ps]/getdoc.xp?AN=558092266 81075107Sfenner * 81175107Sfenner * says that, to see the machine's outgoing traffic, you'd need to 81275107Sfenner * apply the right patches to your system, and also set that variable 81375107Sfenner * with: 81475107Sfenner 81575107Sfennerecho 'lanc_outbound_promisc_flag/W1' | /usr/bin/adb -w /stand/vmunix /dev/kmem 81675107Sfenner 81775107Sfenner * which could be put in, for example, "/sbin/init.d/lan". 81875107Sfenner * 81975107Sfenner * Setting the variable is not necessary on HP-UX 11.x. 82075107Sfenner */ 82117683Spststatic int 82217683Spstget_dlpi_ppa(register int fd, register const char *device, register int unit, 82317683Spst register char *ebuf) 82417683Spst{ 82517683Spst register dl_hp_ppa_ack_t *ap; 82675107Sfenner register dl_hp_ppa_info_t *ipstart, *ip; 82717683Spst register int i; 82875107Sfenner char dname[100]; 82917683Spst register u_long majdev; 83075107Sfenner struct stat statbuf; 83117683Spst dl_hp_ppa_req_t req; 83217683Spst bpf_u_int32 buf[MAXDLBUF]; 83317683Spst 83417683Spst memset((char *)&req, 0, sizeof(req)); 83517683Spst req.dl_primitive = DL_HP_PPA_REQ; 83617683Spst 83717683Spst memset((char *)buf, 0, sizeof(buf)); 83817683Spst if (send_request(fd, (char *)&req, sizeof(req), "hpppa", ebuf) < 0 || 83917683Spst recv_ack(fd, DL_HP_PPA_ACK_SIZE, "hpppa", (char *)buf, ebuf) < 0) 84017683Spst return (-1); 84117683Spst 84217683Spst ap = (dl_hp_ppa_ack_t *)buf; 84375107Sfenner ipstart = (dl_hp_ppa_info_t *)((u_char *)ap + ap->dl_offset); 84475107Sfenner ip = ipstart; 84517683Spst 84675107Sfenner#ifdef HAVE_HP_PPA_INFO_T_DL_MODULE_ID_1 84775107Sfenner /* 84875107Sfenner * The "dl_hp_ppa_info_t" structure has a "dl_module_id_1" 84975107Sfenner * member that should, in theory, contain the part of the 85075107Sfenner * name for the device that comes before the unit number, 85175107Sfenner * and should also have a "dl_module_id_2" member that may 85275107Sfenner * contain an alternate name (e.g., I think Ethernet devices 85375107Sfenner * have both "lan", for "lanN", and "snap", for "snapN", with 85475107Sfenner * the former being for Ethernet packets and the latter being 85575107Sfenner * for 802.3/802.2 packets). 85675107Sfenner * 85775107Sfenner * Search for the device that has the specified name and 85875107Sfenner * instance number. 85975107Sfenner */ 86075107Sfenner for (i = 0; i < ap->dl_count; i++) { 86175107Sfenner if ((strcmp(ip->dl_module_id_1, device) == 0 || 86275107Sfenner strcmp(ip->dl_module_id_2, device) == 0) && 86375107Sfenner ip->dl_instance_num == unit) 86475107Sfenner break; 86517683Spst 86675107Sfenner ip = (dl_hp_ppa_info_t *)((u_char *)ipstart + ip->dl_next_offset); 86775107Sfenner } 86875107Sfenner#else 86975107Sfenner /* 87075107Sfenner * We don't have that member, so the search is impossible; make it 87175107Sfenner * look as if the search failed. 87275107Sfenner */ 87375107Sfenner i = ap->dl_count; 87475107Sfenner#endif 87575107Sfenner 87675107Sfenner if (i == ap->dl_count) { 87775107Sfenner /* 87875107Sfenner * Well, we didn't, or can't, find the device by name. 87975107Sfenner * 88075107Sfenner * HP-UX 10.20, whilst it has "dl_module_id_1" and 88175107Sfenner * "dl_module_id_2" fields in the "dl_hp_ppa_info_t", 88275107Sfenner * doesn't seem to fill them in unless the system is 88375107Sfenner * at a reasonably up-to-date patch level. 88475107Sfenner * 88575107Sfenner * Older HP-UX 10.x systems might not have those fields 88675107Sfenner * at all. 88775107Sfenner * 88875107Sfenner * Therefore, we'll search for the entry with the major 88975107Sfenner * device number of a device with the name "/dev/<dev><unit>", 89075107Sfenner * if such a device exists, as the old code did. 89175107Sfenner */ 89275107Sfenner snprintf(dname, sizeof(dname), "/dev/%s%d", device, unit); 89375107Sfenner if (stat(dname, &statbuf) < 0) { 89475107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "stat: %s: %s", 89575107Sfenner dname, pcap_strerror(errno)); 89675107Sfenner return (-1); 89775107Sfenner } 89875107Sfenner majdev = major(statbuf.st_rdev); 89975107Sfenner 90075107Sfenner ip = ipstart; 90175107Sfenner 90275107Sfenner for (i = 0; i < ap->dl_count; i++) { 90375107Sfenner if (ip->dl_mjr_num == majdev && 90475107Sfenner ip->dl_instance_num == unit) 90575107Sfenner break; 90675107Sfenner 90775107Sfenner ip = (dl_hp_ppa_info_t *)((u_char *)ipstart + ip->dl_next_offset); 90875107Sfenner } 90975107Sfenner } 91017683Spst if (i == ap->dl_count) { 91175107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 91275107Sfenner "can't find /dev/dlpi PPA for %s%d", device, unit); 91317683Spst return (-1); 91417683Spst } 91517683Spst if (ip->dl_hdw_state == HDW_DEAD) { 91675107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 91775107Sfenner "%s%d: hardware state: DOWN\n", device, unit); 91817683Spst return (-1); 91917683Spst } 92017683Spst return ((int)ip->dl_ppa); 92117683Spst} 92217683Spst#endif 92317683Spst 92417683Spst#ifdef HAVE_HPUX9 92517683Spst/* 92617683Spst * Under HP-UX 9, there is no good way to determine the ppa. 92717683Spst * So punt and read it from /dev/kmem. 92817683Spst */ 92917683Spststatic struct nlist nl[] = { 93017683Spst#define NL_IFNET 0 93117683Spst { "ifnet" }, 93217683Spst { "" } 93317683Spst}; 93417683Spst 93517683Spststatic char path_vmunix[] = "/hp-ux"; 93617683Spst 93717683Spst/* Determine ppa number that specifies ifname */ 93817683Spststatic int 93917683Spstget_dlpi_ppa(register int fd, register const char *ifname, register int unit, 94017683Spst register char *ebuf) 94117683Spst{ 94217683Spst register const char *cp; 94317683Spst register int kd; 94417683Spst void *addr; 94517683Spst struct ifnet ifnet; 94675107Sfenner char if_name[sizeof(ifnet.if_name) + 1]; 94717683Spst 94817683Spst cp = strrchr(ifname, '/'); 94917683Spst if (cp != NULL) 95017683Spst ifname = cp + 1; 95117683Spst if (nlist(path_vmunix, &nl) < 0) { 95275107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "nlist %s failed", 95375107Sfenner path_vmunix); 95417683Spst return (-1); 95517683Spst } 95617683Spst if (nl[NL_IFNET].n_value == 0) { 95775107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 95875107Sfenner "could't find %s kernel symbol", 95917683Spst nl[NL_IFNET].n_name); 96017683Spst return (-1); 96117683Spst } 96217683Spst kd = open("/dev/kmem", O_RDONLY); 96317683Spst if (kd < 0) { 96475107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "kmem open: %s", 96575107Sfenner pcap_strerror(errno)); 96617683Spst return (-1); 96717683Spst } 96817683Spst if (dlpi_kread(kd, nl[NL_IFNET].n_value, 96917683Spst &addr, sizeof(addr), ebuf) < 0) { 97017683Spst close(kd); 97117683Spst return (-1); 97217683Spst } 97317683Spst for (; addr != NULL; addr = ifnet.if_next) { 97417683Spst if (dlpi_kread(kd, (off_t)addr, 97517683Spst &ifnet, sizeof(ifnet), ebuf) < 0 || 97617683Spst dlpi_kread(kd, (off_t)ifnet.if_name, 97775107Sfenner if_name, sizeof(ifnet.if_name), ebuf) < 0) { 97817683Spst (void)close(kd); 97917683Spst return (-1); 98017683Spst } 98175107Sfenner if_name[sizeof(ifnet.if_name)] = '\0'; 98275107Sfenner if (strcmp(if_name, ifname) == 0 && ifnet.if_unit == unit) 98317683Spst return (ifnet.if_index); 98417683Spst } 98517683Spst 98675107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "Can't find %s", ifname); 98717683Spst return (-1); 98817683Spst} 98917683Spst 99017683Spststatic int 99117683Spstdlpi_kread(register int fd, register off_t addr, 99217683Spst register void *buf, register u_int len, register char *ebuf) 99317683Spst{ 99417683Spst register int cc; 99517683Spst 99639291Sfenner if (lseek(fd, addr, SEEK_SET) < 0) { 99775107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "lseek: %s", 99875107Sfenner pcap_strerror(errno)); 99917683Spst return (-1); 100017683Spst } 100117683Spst cc = read(fd, buf, len); 100217683Spst if (cc < 0) { 100375107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "read: %s", 100475107Sfenner pcap_strerror(errno)); 100517683Spst return (-1); 100617683Spst } else if (cc != len) { 100775107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "short read (%d != %d)", cc, 100875107Sfenner len); 100917683Spst return (-1); 101017683Spst } 101117683Spst return (cc); 101217683Spst} 101317683Spst#endif 1014