📄 pcap-dlpi.c
字号:
/* * Copyright (c) 1993, 1994, 1995, 1996, 1997 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that: (1) source code distributions * retain the above copyright notice and this paragraph in its entirety, (2) * distributions including binary code include the above copyright notice and * this paragraph in its entirety in the documentation or other materials * provided with the distribution, and (3) all advertising materials mentioning * features or use of this software display the following acknowledgement: * ``This product includes software developed by the University of California, * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of * the University nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior * written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * This code contributed by Atanu Ghosh (atanu@cs.ucl.ac.uk), * University College London, and subsequently modified by * Guy Harris (guy@alum.mit.edu), Mark Pizzolato * <List-tcpdump-workers@subscriptions.pizzolato.net>, * and Mark C. Brown (mbrown@hp.com). *//* * Packet capture routine for DLPI under SunOS 5, HP-UX 9/10/11, and AIX. * * Notes: * * - The DLIOCRAW ioctl() is specific to SunOS. * * - There is a bug in bufmod(7) such that setting the snapshot * length results in data being left of the front of the packet. * * - It might be desirable to use pfmod(7) to filter packets in the * kernel when possible. * * - An older version of the HP-UX DLPI Programmer's Guide, which * I think was advertised as the 10.20 version, used to be available * at * * http://docs.hp.com/hpux/onlinedocs/B2355-90093/B2355-90093.html * * but is no longer available; it can still be found at * * http://h21007.www2.hp.com/dspp/files/unprotected/Drivers/Docs/Refs/B2355-90093.pdf * * in PDF form. * * - The HP-UX 10.x, 11.0, and 11i v1.6 version of the HP-UX DLPI * Programmer's Guide, which I think was once advertised as the * 11.00 version is available at * * http://docs.hp.com/en/B2355-90139/index.html * * - The HP-UX 11i v2 version of the HP-UX DLPI Programmer's Guide * is available at * * http://docs.hp.com/en/B2355-90871/index.html * * - All of the HP documents describe raw-mode services, which are * what we use if DL_HP_RAWDLS is defined. XXX - we use __hpux * in some places to test for HP-UX, but use DL_HP_RAWDLS in * other places; do we support any versions of HP-UX without * DL_HP_RAWDLS? */#ifndef lintstatic const char rcsid[] _U_ = "@(#) $Header: /tcpdump/master/libpcap/pcap-dlpi.c,v 1.108.2.7 2006/04/04 05:33:02 guy Exp $ (LBL)";#endif#ifdef HAVE_CONFIG_H#include "config.h"#endif#include <sys/types.h>#include <sys/time.h>#ifdef HAVE_SYS_BUFMOD_H#include <sys/bufmod.h>#endif#include <sys/dlpi.h>#ifdef HAVE_SYS_DLPI_EXT_H#include <sys/dlpi_ext.h>#endif#ifdef HAVE_HPUX9#include <sys/socket.h>#endif#ifdef DL_HP_PPA_REQ#include <sys/stat.h>#endif#include <sys/stream.h>#if defined(HAVE_SOLARIS) && defined(HAVE_SYS_BUFMOD_H)#include <sys/systeminfo.h>#endif#ifdef HAVE_HPUX9#include <net/if.h>#endif#include <ctype.h>#ifdef HAVE_HPUX9#include <nlist.h>#endif#include <errno.h>#include <fcntl.h>#include <memory.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <stropts.h>#include <unistd.h>#ifdef HAVE_LIMITS_H#include <limits.h>#else#define INT_MAX 2147483647#endif#include "pcap-int.h"#ifdef HAVE_OS_PROTO_H#include "os-proto.h"#endif#ifndef PCAP_DEV_PREFIX#ifdef _AIX#define PCAP_DEV_PREFIX "/dev/dlpi"#else#define PCAP_DEV_PREFIX "/dev"#endif#endif#define MAXDLBUF 8192#ifdef HAVE_SYS_BUFMOD_H/* * Size of a bufmod chunk to pass upstream; that appears to be the biggest * value to which you can set it, and setting it to that value (which * is bigger than what appears to be the Solaris default of 8192) * reduces the number of packet drops. */#define CHUNKSIZE 65536/* * Size of the buffer to allocate for packet data we read; it must be * large enough to hold a chunk. */#define PKTBUFSIZE CHUNKSIZE#else /* HAVE_SYS_BUFMOD_H *//* * Size of the buffer to allocate for packet data we read; this is * what the value used to be - there's no particular reason why it * should be tied to MAXDLBUF, but we'll leave it as this for now. */#define PKTBUFSIZE (MAXDLBUF * sizeof(bpf_u_int32))#endif/* Forwards */static char *split_dname(char *, int *, char *);static int dl_doattach(int, int, char *);#ifdef DL_HP_RAWDLSstatic int dl_dohpuxbind(int, char *);#endifstatic int dlattachreq(int, bpf_u_int32, char *);static int dlbindreq(int, bpf_u_int32, char *);static int dlbindack(int, char *, char *, int *);static int dlpromisconreq(int, bpf_u_int32, char *);static int dlokack(int, const char *, char *, char *);static int dlinforeq(int, char *);static int dlinfoack(int, char *, char *);#ifdef DL_HP_RAWDLSstatic int dlrawdatareq(int, const u_char *, int);#endifstatic int recv_ack(int, int, const char *, char *, char *, int *);static char *dlstrerror(bpf_u_int32);static char *dlprim(bpf_u_int32);#if defined(HAVE_SOLARIS) && defined(HAVE_SYS_BUFMOD_H)static char *get_release(bpf_u_int32 *, bpf_u_int32 *, bpf_u_int32 *);#endifstatic int send_request(int, char *, int, char *, char *);#ifdef HAVE_SYS_BUFMOD_Hstatic int strioctl(int, int, int, char *);#endif#ifdef HAVE_HPUX9static int dlpi_kread(int, off_t, void *, u_int, char *);#endif#ifdef HAVE_DEV_DLPIstatic int get_dlpi_ppa(int, const char *, int, char *);#endifstatic intpcap_stats_dlpi(pcap_t *p, struct pcap_stat *ps){ /* * "ps_recv" counts packets handed to the filter, not packets * that passed the filter. As filtering is done in userland, * this would not include packets dropped because we ran out * of buffer space; in order to make this more like other * platforms (Linux 2.4 and later, BSDs with BPF), where the * "packets received" count includes packets received but dropped * due to running out of buffer space, and to keep from confusing * applications that, for example, compute packet drop percentages, * we also make it count packets dropped by "bufmod" (otherwise we * might run the risk of the packet drop count being bigger than * the received-packet count). * * "ps_drop" counts packets dropped by "bufmod" because of * flow control requirements or resource exhaustion; it doesn't * count packets dropped by the interface driver, or packets * dropped upstream. As filtering is done in userland, it counts * packets regardless of whether they would've passed the filter. * * These statistics don't include packets not yet read from * the kernel by libpcap, but they may include packets not * yet read from libpcap by the application. */ *ps = p->md.stat; /* * Add in the drop count, as per the above comment. */ ps->ps_recv += ps->ps_drop; return (0);}/* XXX Needed by HP-UX (at least) */static bpf_u_int32 ctlbuf[MAXDLBUF];static struct strbuf ctl = { MAXDLBUF, 0, (char *)ctlbuf};static intpcap_read_dlpi(pcap_t *p, int cnt, pcap_handler callback, u_char *user){ register int cc, n, caplen, origlen; register u_char *bp, *ep, *pk; register struct bpf_insn *fcode;#ifdef HAVE_SYS_BUFMOD_H register struct sb_hdr *sbp;#ifdef LBL_ALIGN struct sb_hdr sbhdr;#endif#endif int flags; struct strbuf data; struct pcap_pkthdr pkthdr; flags = 0; cc = p->cc; if (cc == 0) { data.buf = (char *)p->buffer + p->offset; data.maxlen = p->bufsize; data.len = 0; do { /* * Has "pcap_breakloop()" been called? */ if (p->break_loop) { /* * Yes - clear the flag that indicates * that it has, and return -2 to * indicate that we were told to * break out of the loop. */ p->break_loop = 0; return (-2); } /* * XXX - check for the DLPI primitive, which * would be DL_HP_RAWDATA_IND on HP-UX * if we're in raw mode? */ if (getmsg(p->fd, &ctl, &data, &flags) < 0) { /* Don't choke when we get ptraced */ switch (errno) { case EINTR: cc = 0; continue; case EAGAIN: return (0); } strlcpy(p->errbuf, pcap_strerror(errno), sizeof(p->errbuf)); return (-1); } cc = data.len; } while (cc == 0); bp = p->buffer + p->offset; } else bp = p->bp; /* Loop through packets */ fcode = p->fcode.bf_insns; ep = bp + cc; n = 0;#ifdef HAVE_SYS_BUFMOD_H while (bp < ep) { /* * Has "pcap_breakloop()" been called? * If so, return immediately - if we haven't read any * packets, clear the flag and return -2 to indicate * that we were told to break out of the loop, otherwise * leave the flag set, so that the *next* call will break * out of the loop without having read any packets, and * return the number of packets we've processed so far. */ if (p->break_loop) { if (n == 0) { p->break_loop = 0; return (-2); } else { p->bp = bp; p->cc = ep - bp; return (n); } }#ifdef LBL_ALIGN if ((long)bp & 3) { sbp = &sbhdr; memcpy(sbp, bp, sizeof(*sbp)); } else#endif sbp = (struct sb_hdr *)bp; p->md.stat.ps_drop = sbp->sbh_drops; pk = bp + sizeof(*sbp); bp += sbp->sbh_totlen; origlen = sbp->sbh_origlen; caplen = sbp->sbh_msglen;#else origlen = cc; caplen = min(p->snapshot, cc); pk = bp; bp += caplen;#endif ++p->md.stat.ps_recv; if (bpf_filter(fcode, pk, origlen, caplen)) {#ifdef HAVE_SYS_BUFMOD_H pkthdr.ts.tv_sec = sbp->sbh_timestamp.tv_sec; pkthdr.ts.tv_usec = sbp->sbh_timestamp.tv_usec;#else (void)gettimeofday(&pkthdr.ts, NULL);#endif pkthdr.len = origlen; pkthdr.caplen = caplen; /* Insure caplen does not exceed snapshot */ if (pkthdr.caplen > p->snapshot) pkthdr.caplen = p->snapshot; (*callback)(user, &pkthdr, pk); if (++n >= cnt && cnt >= 0) { p->cc = ep - bp; p->bp = bp; return (n); } }#ifdef HAVE_SYS_BUFMOD_H }#endif p->cc = 0; return (n);}static intpcap_inject_dlpi(pcap_t *p, const void *buf, size_t size){ int ret;#if defined(DLIOCRAW) ret = write(p->fd, buf, size); if (ret == -1) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: %s", pcap_strerror(errno)); return (-1); }#elif defined(DL_HP_RAWDLS) if (p->send_fd < 0) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: Output FD couldn't be opened"); return (-1); } ret = dlrawdatareq(p->send_fd, buf, size); if (ret == -1) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: %s", pcap_strerror(errno)); return (-1); } /* * putmsg() returns either 0 or -1; it doesn't indicate how * many bytes were written (presumably they were all written * or none of them were written). OpenBSD's pcap_inject() * returns the number of bytes written, so, for API compatibility, * we return the number of bytes we were told to write. */ ret = size;#else /* no raw mode */ /* * XXX - this is a pain, because you might have to extract * the address from the packet and use it in a DL_UNITDATA_REQ * request. That would be dependent on the link-layer type. * * I also don't know what SAP you'd have to bind the descriptor * to, or whether you'd need separate "receive" and "send" FDs, * nor do I know whether you'd need different bindings for * D/I/X Ethernet and 802.3, or for {FDDI,Token Ring} plus * 802.2 and {FDDI,Token Ring} plus 802.2 plus SNAP. * * So, for now, we just return a "you can't send" indication, * and leave it up to somebody with a DLPI-based system lacking * both DLIOCRAW and DL_HP_RAWDLS to supply code to implement * packet transmission on that system. If they do, they should * send it to us - but should not send us code that assumes * Ethernet; if the code doesn't work on non-Ethernet interfaces, * it should check "p->linktype" and reject the send request if * it's anything other than DLT_EN10MB. */ strlcpy(p->errbuf, "send: Not supported on this version of this OS", PCAP_ERRBUF_SIZE); ret = -1;#endif /* raw mode */ return (ret);} #ifndef DL_IPATM#define DL_IPATM 0x12 /* ATM Classical IP interface */#endif#ifdef HAVE_SOLARIS/* * For SunATM. */#ifndef A_GET_UNITS#define A_GET_UNITS (('A'<<8)|118)#endif /* A_GET_UNITS */#ifndef A_PROMISCON_REQ#define A_PROMISCON_REQ (('A'<<8)|121)#endif /* A_PROMISCON_REQ */#endif /* HAVE_SOLARIS */static voidpcap_close_dlpi(pcap_t *p){ pcap_close_common(p); if (p->send_fd >= 0) close(p->send_fd);}pcap_t *pcap_open_live(const char *device, int snaplen, int promisc, int to_ms, char *ebuf){ register char *cp; register pcap_t *p; int ppa;#ifdef HAVE_SOLARIS int isatm = 0;#endif register dl_info_ack_t *infop;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -