Index: user/syuu/mq_bpf/contrib/libpcap/pcap/pcap.h =================================================================== --- user/syuu/mq_bpf/contrib/libpcap/pcap/pcap.h (revision 255171) +++ user/syuu/mq_bpf/contrib/libpcap/pcap/pcap.h (revision 255172) @@ -1,465 +1,470 @@ /* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */ /* * 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 the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#) $Header: /tcpdump/master/libpcap/pcap/pcap.h,v 1.15 2008-10-06 15:27:32 gianluca Exp $ (LBL) */ #ifndef lib_pcap_pcap_h #define lib_pcap_pcap_h #if defined(WIN32) #include #elif defined(MSDOS) #include #include /* u_int, u_char etc. */ #else /* UN*X */ #include #include #endif /* WIN32/MSDOS/UN*X */ #include #include #ifdef __cplusplus extern "C" { #endif /* * Version number of the current version of the pcap file format. * * NOTE: this is *NOT* the version number of the libpcap library. * To fetch the version information for the version of libpcap * you're using, use pcap_lib_version(). */ #define PCAP_VERSION_MAJOR 2 #define PCAP_VERSION_MINOR 4 #define PCAP_ERRBUF_SIZE 256 /* * Compatibility for systems that have a bpf.h that * predates the bpf typedefs for 64-bit support. */ #if BPF_RELEASE - 0 < 199406 typedef int bpf_int32; typedef u_int bpf_u_int32; #endif typedef struct pcap pcap_t; typedef struct pcap_dumper pcap_dumper_t; typedef struct pcap_if pcap_if_t; typedef struct pcap_addr pcap_addr_t; /* * The first record in the file contains saved values for some * of the flags used in the printout phases of tcpdump. * Many fields here are 32 bit ints so compilers won't insert unwanted * padding; these files need to be interchangeable across architectures. * * Do not change the layout of this structure, in any way (this includes * changes that only affect the length of fields in this structure). * * Also, do not change the interpretation of any of the members of this * structure, in any way (this includes using values other than * LINKTYPE_ values, as defined in "savefile.c", in the "linktype" * field). * * Instead: * * introduce a new structure for the new format, if the layout * of the structure changed; * * send mail to "tcpdump-workers@lists.tcpdump.org", requesting * a new magic number for your new capture file format, and, when * you get the new magic number, put it in "savefile.c"; * * use that magic number for save files with the changed file * header; * * make the code in "savefile.c" capable of reading files with * the old file header as well as files with the new file header * (using the magic number to determine the header format). * * Then supply the changes by forking the branch at * * https://github.com/mcr/libpcap/issues * * and issuing a pull request, so that future versions of libpcap and * programs that use it (such as tcpdump) will be able to read your new * capture file format. */ struct pcap_file_header { bpf_u_int32 magic; u_short version_major; u_short version_minor; bpf_int32 thiszone; /* gmt to local correction */ bpf_u_int32 sigfigs; /* accuracy of timestamps */ bpf_u_int32 snaplen; /* max length saved portion of each pkt */ bpf_u_int32 linktype; /* data link type (LINKTYPE_*) */ }; /* * Macros for the value returned by pcap_datalink_ext(). * * If LT_FCS_LENGTH_PRESENT(x) is true, the LT_FCS_LENGTH(x) macro * gives the FCS length of packets in the capture. */ #define LT_FCS_LENGTH_PRESENT(x) ((x) & 0x04000000) #define LT_FCS_LENGTH(x) (((x) & 0xF0000000) >> 28) #define LT_FCS_DATALINK_EXT(x) ((((x) & 0xF) << 28) | 0x04000000) typedef enum { PCAP_D_INOUT = 0, PCAP_D_IN, PCAP_D_OUT } pcap_direction_t; /* * Generic per-packet information, as supplied by libpcap. * * The time stamp can and should be a "struct timeval", regardless of * whether your system supports 32-bit tv_sec in "struct timeval", * 64-bit tv_sec in "struct timeval", or both if it supports both 32-bit * and 64-bit applications. The on-disk format of savefiles uses 32-bit * tv_sec (and tv_usec); this structure is irrelevant to that. 32-bit * and 64-bit versions of libpcap, even if they're on the same platform, * should supply the appropriate version of "struct timeval", even if * that's not what the underlying packet capture mechanism supplies. */ struct pcap_pkthdr { struct timeval ts; /* time stamp */ bpf_u_int32 caplen; /* length of portion present */ bpf_u_int32 len; /* length this packet (off wire) */ }; /* * As returned by the pcap_stats() */ struct pcap_stat { u_int ps_recv; /* number of packets received */ u_int ps_drop; /* number of packets dropped */ u_int ps_ifdrop; /* drops by interface -- only supported on some platforms */ #ifdef WIN32 u_int bs_capt; /* number of packets that reach the application */ #endif /* WIN32 */ }; #ifdef MSDOS /* * As returned by the pcap_stats_ex() */ struct pcap_stat_ex { u_long rx_packets; /* total packets received */ u_long tx_packets; /* total packets transmitted */ u_long rx_bytes; /* total bytes received */ u_long tx_bytes; /* total bytes transmitted */ u_long rx_errors; /* bad packets received */ u_long tx_errors; /* packet transmit problems */ u_long rx_dropped; /* no space in Rx buffers */ u_long tx_dropped; /* no space available for Tx */ u_long multicast; /* multicast packets received */ u_long collisions; /* detailed rx_errors: */ u_long rx_length_errors; u_long rx_over_errors; /* receiver ring buff overflow */ u_long rx_crc_errors; /* recv'd pkt with crc error */ u_long rx_frame_errors; /* recv'd frame alignment error */ u_long rx_fifo_errors; /* recv'r fifo overrun */ u_long rx_missed_errors; /* recv'r missed packet */ /* detailed tx_errors */ u_long tx_aborted_errors; u_long tx_carrier_errors; u_long tx_fifo_errors; u_long tx_heartbeat_errors; u_long tx_window_errors; }; #endif /* * Item in a list of interfaces. */ struct pcap_if { struct pcap_if *next; char *name; /* name to hand to "pcap_open_live()" */ char *description; /* textual description of interface, or NULL */ struct pcap_addr *addresses; bpf_u_int32 flags; /* PCAP_IF_ interface flags */ }; #define PCAP_IF_LOOPBACK 0x00000001 /* interface is loopback */ /* * Representation of an interface address. */ struct pcap_addr { struct pcap_addr *next; struct sockaddr *addr; /* address */ struct sockaddr *netmask; /* netmask for that address */ struct sockaddr *broadaddr; /* broadcast address for that address */ struct sockaddr *dstaddr; /* P2P destination address for that address */ }; typedef void (*pcap_handler)(u_char *, const struct pcap_pkthdr *, const u_char *); /* * Error codes for the pcap API. * These will all be negative, so you can check for the success or * failure of a call that returns these codes by checking for a * negative value. */ #define PCAP_ERROR -1 /* generic error code */ #define PCAP_ERROR_BREAK -2 /* loop terminated by pcap_breakloop */ #define PCAP_ERROR_NOT_ACTIVATED -3 /* the capture needs to be activated */ #define PCAP_ERROR_ACTIVATED -4 /* the operation can't be performed on already activated captures */ #define PCAP_ERROR_NO_SUCH_DEVICE -5 /* no such device exists */ #define PCAP_ERROR_RFMON_NOTSUP -6 /* this device doesn't support rfmon (monitor) mode */ #define PCAP_ERROR_NOT_RFMON -7 /* operation supported only in monitor mode */ #define PCAP_ERROR_PERM_DENIED -8 /* no permission to open the device */ #define PCAP_ERROR_IFACE_NOT_UP -9 /* interface isn't up */ #define PCAP_ERROR_CANTSET_TSTAMP_TYPE -10 /* this device doesn't support setting the time stamp type */ #define PCAP_ERROR_PROMISC_PERM_DENIED -11 /* you don't have permission to capture in promiscuous mode */ /* * Warning codes for the pcap API. * These will all be positive and non-zero, so they won't look like * errors. */ #define PCAP_WARNING 1 /* generic warning code */ #define PCAP_WARNING_PROMISC_NOTSUP 2 /* this device doesn't support promiscuous mode */ #define PCAP_WARNING_TSTAMP_TYPE_NOTSUP 3 /* the requested time stamp type is not supported */ /* * Value to pass to pcap_compile() as the netmask if you don't know what * the netmask is. */ #define PCAP_NETMASK_UNKNOWN 0xffffffff char *pcap_lookupdev(char *); int pcap_lookupnet(const char *, bpf_u_int32 *, bpf_u_int32 *, char *); pcap_t *pcap_create(const char *, char *); int pcap_set_snaplen(pcap_t *, int); int pcap_set_promisc(pcap_t *, int); int pcap_can_set_rfmon(pcap_t *); int pcap_set_rfmon(pcap_t *, int); int pcap_set_timeout(pcap_t *, int); int pcap_set_tstamp_type(pcap_t *, int); int pcap_set_buffer_size(pcap_t *, int); int pcap_activate(pcap_t *); int pcap_list_tstamp_types(pcap_t *, int **); void pcap_free_tstamp_types(int *); int pcap_tstamp_type_name_to_val(const char *); const char *pcap_tstamp_type_val_to_name(int); const char *pcap_tstamp_type_val_to_description(int); /* * Time stamp types. * Not all systems and interfaces will necessarily support all of these. * * A system that supports PCAP_TSTAMP_HOST is offering time stamps * provided by the host machine, rather than by the capture device, * but not committing to any characteristics of the time stamp; * it will not offer any of the PCAP_TSTAMP_HOST_ subtypes. * * PCAP_TSTAMP_HOST_LOWPREC is a time stamp, provided by the host machine, * that's low-precision but relatively cheap to fetch; it's normally done * using the system clock, so it's normally synchronized with times you'd * fetch from system calls. * * PCAP_TSTAMP_HOST_HIPREC is a time stamp, provided by the host machine, * that's high-precision; it might be more expensive to fetch. It might * or might not be synchronized with the system clock, and might have * problems with time stamps for packets received on different CPUs, * depending on the platform. * * PCAP_TSTAMP_ADAPTER is a high-precision time stamp supplied by the * capture device; it's synchronized with the system clock. * * PCAP_TSTAMP_ADAPTER_UNSYNCED is a high-precision time stamp supplied by * the capture device; it's not synchronized with the system clock. * * Note that time stamps synchronized with the system clock can go * backwards, as the system clock can go backwards. If a clock is * not in sync with the system clock, that could be because the * system clock isn't keeping accurate time, because the other * clock isn't keeping accurate time, or both. * * Note that host-provided time stamps generally correspond to the * time when the time-stamping code sees the packet; this could * be some unknown amount of time after the first or last bit of * the packet is received by the network adapter, due to batching * of interrupts for packet arrival, queueing delays, etc.. */ #define PCAP_TSTAMP_HOST 0 /* host-provided, unknown characteristics */ #define PCAP_TSTAMP_HOST_LOWPREC 1 /* host-provided, low precision */ #define PCAP_TSTAMP_HOST_HIPREC 2 /* host-provided, high precision */ #define PCAP_TSTAMP_ADAPTER 3 /* device-provided, synced with the system clock */ #define PCAP_TSTAMP_ADAPTER_UNSYNCED 4 /* device-provided, not synced with the system clock */ -int pcap_set_rxq_mask(pcap_t *, uint32_t); -int pcap_set_txq_mask(pcap_t *, uint32_t); -int pcap_set_other_mask(pcap_t *, uint32_t); +int pcap_enable_qmask(pcap_t *); +int pcap_disable_qmask(pcap_t *); +int pcap_set_rxqmask(pcap_t *, u_int); +int pcap_clear_rxqmask(pcap_t *, u_int); +int pcap_set_txqmask(pcap_t *, u_int); +int pcap_clear_txqmask(pcap_t *, u_int); +int pcap_set_noqmask(pcap_t *); +int pcap_clear_noqmask(pcap_t *); pcap_t *pcap_open_live(const char *, int, int, int, char *); pcap_t *pcap_open_dead(int, int); pcap_t *pcap_open_offline(const char *, char *); #if defined(WIN32) pcap_t *pcap_hopen_offline(intptr_t, char *); #if !defined(LIBPCAP_EXPORTS) #define pcap_fopen_offline(f,b) \ pcap_hopen_offline(_get_osfhandle(_fileno(f)), b) #else /*LIBPCAP_EXPORTS*/ static pcap_t *pcap_fopen_offline(FILE *, char *); #endif #else /*WIN32*/ pcap_t *pcap_fopen_offline(FILE *, char *); #endif /*WIN32*/ void pcap_close(pcap_t *); int pcap_loop(pcap_t *, int, pcap_handler, u_char *); int pcap_dispatch(pcap_t *, int, pcap_handler, u_char *); const u_char* pcap_next(pcap_t *, struct pcap_pkthdr *); int pcap_next_ex(pcap_t *, struct pcap_pkthdr **, const u_char **); void pcap_breakloop(pcap_t *); int pcap_stats(pcap_t *, struct pcap_stat *); int pcap_setfilter(pcap_t *, struct bpf_program *); int pcap_setdirection(pcap_t *, pcap_direction_t); int pcap_getnonblock(pcap_t *, char *); int pcap_setnonblock(pcap_t *, int, char *); int pcap_inject(pcap_t *, const void *, size_t); int pcap_sendpacket(pcap_t *, const u_char *, int); const char *pcap_statustostr(int); const char *pcap_strerror(int); char *pcap_geterr(pcap_t *); void pcap_perror(pcap_t *, char *); int pcap_compile(pcap_t *, struct bpf_program *, const char *, int, bpf_u_int32); int pcap_compile_nopcap(int, int, struct bpf_program *, const char *, int, bpf_u_int32); void pcap_freecode(struct bpf_program *); int pcap_offline_filter(const struct bpf_program *, const struct pcap_pkthdr *, const u_char *); int pcap_datalink(pcap_t *); int pcap_datalink_ext(pcap_t *); int pcap_list_datalinks(pcap_t *, int **); int pcap_set_datalink(pcap_t *, int); void pcap_free_datalinks(int *); int pcap_datalink_name_to_val(const char *); const char *pcap_datalink_val_to_name(int); const char *pcap_datalink_val_to_description(int); int pcap_snapshot(pcap_t *); int pcap_is_swapped(pcap_t *); int pcap_major_version(pcap_t *); int pcap_minor_version(pcap_t *); /* XXX */ FILE *pcap_file(pcap_t *); int pcap_fileno(pcap_t *); pcap_dumper_t *pcap_dump_open(pcap_t *, const char *); pcap_dumper_t *pcap_dump_fopen(pcap_t *, FILE *fp); FILE *pcap_dump_file(pcap_dumper_t *); long pcap_dump_ftell(pcap_dumper_t *); int pcap_dump_flush(pcap_dumper_t *); void pcap_dump_close(pcap_dumper_t *); void pcap_dump(u_char *, const struct pcap_pkthdr *, const u_char *); int pcap_findalldevs(pcap_if_t **, char *); void pcap_freealldevs(pcap_if_t *); const char *pcap_lib_version(void); /* * On at least some versions of NetBSD, we don't want to declare * bpf_filter() here, as it's also be declared in , with a * different signature, but, on other BSD-flavored UN*Xes, it's not * declared in , so we *do* want to declare it here, so it's * declared when we build pcap-bpf.c. */ #ifndef __NetBSD__ u_int bpf_filter(struct bpf_insn *, u_char *, u_int, u_int); #endif int bpf_validate(const struct bpf_insn *f, int len); char *bpf_image(struct bpf_insn *, int); void bpf_dump(struct bpf_program *, int); #if defined(WIN32) /* * Win32 definitions */ int pcap_setbuff(pcap_t *p, int dim); int pcap_setmode(pcap_t *p, int mode); int pcap_setmintocopy(pcap_t *p, int size); #ifdef WPCAP /* Include file with the wpcap-specific extensions */ #include #endif /* WPCAP */ #define MODE_CAPT 0 #define MODE_STAT 1 #define MODE_MON 2 #elif defined(MSDOS) /* * MS-DOS definitions */ int pcap_stats_ex (pcap_t *, struct pcap_stat_ex *); void pcap_set_wait (pcap_t *p, void (*yield)(void), int wait); u_long pcap_mac_packets (void); #else /* UN*X */ /* * UN*X definitions */ int pcap_get_selectable_fd(pcap_t *); #endif /* WIN32/MSDOS/UN*X */ #ifdef __cplusplus } #endif #endif /* lib_pcap_pcap_h */ Index: user/syuu/mq_bpf/contrib/libpcap/pcap-bpf.c =================================================================== --- user/syuu/mq_bpf/contrib/libpcap/pcap-bpf.c (revision 255171) +++ user/syuu/mq_bpf/contrib/libpcap/pcap-bpf.c (revision 255172) @@ -1,2752 +1,2745 @@ /* * Copyright (c) 1993, 1994, 1995, 1996, 1998 * 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. * * $FreeBSD$ */ #ifndef lint static const char rcsid[] _U_ = "@(#) $Header: /tcpdump/master/libpcap/pcap-bpf.c,v 1.116 2008-09-16 18:42:29 guy Exp $ (LBL)"; #endif #ifdef HAVE_CONFIG_H #include "config.h" #endif #include /* optionally get BSD define */ #ifdef HAVE_ZEROCOPY_BPF #include #endif #include #include #include /* * defines ioctls, but doesn't include . * * We include as it might be necessary to declare ioctl(); * at least on *BSD and Mac OS X, it also defines various SIOC ioctls - * we could include , but if we're already including * , which includes on those platforms, * there's not much point in doing so. * * If we have , we include it as well, to handle systems * such as Solaris which don't arrange to include if you * include */ #include #ifdef HAVE_SYS_IOCCOM_H #include #endif #include #ifdef HAVE_ZEROCOPY_BPF #include #endif #include #ifdef _AIX /* * Make "pcap.h" not include "pcap/bpf.h"; we are going to include the * native OS version, as we need "struct bpf_config" from it. */ #define PCAP_DONT_INCLUDE_PCAP_BPF_H #include /* * Prevent bpf.h from redefining the DLT_ values to their * IFT_ values, as we're going to return the standard libpcap * values, not IBM's non-standard IFT_ values. */ #undef _AIX #include #define _AIX #include /* for IFT_ values */ #include #include #include #include #ifdef __64BIT__ #define domakedev makedev64 #define getmajor major64 #define bpf_hdr bpf_hdr32 #else /* __64BIT__ */ #define domakedev makedev #define getmajor major #endif /* __64BIT__ */ #define BPF_NAME "bpf" #define BPF_MINORS 4 #define DRIVER_PATH "/usr/lib/drivers" #define BPF_NODE "/dev/bpf" static int bpfloadedflag = 0; static int odmlockid = 0; static int bpf_load(char *errbuf); #else /* _AIX */ #include #endif /* _AIX */ #include #include #include #include #include #include #include #include #ifdef HAVE_NET_IF_MEDIA_H # include #endif #include "pcap-int.h" #ifdef HAVE_OS_PROTO_H #include "os-proto.h" #endif #ifdef BIOCGDLTLIST # if (defined(HAVE_NET_IF_MEDIA_H) && defined(IFM_IEEE80211)) && !defined(__APPLE__) #define HAVE_BSD_IEEE80211 # endif # if defined(__APPLE__) || defined(HAVE_BSD_IEEE80211) static int find_802_11(struct bpf_dltlist *); # ifdef HAVE_BSD_IEEE80211 static int monitor_mode(pcap_t *, int); # endif # if defined(__APPLE__) static void remove_en(pcap_t *); static void remove_802_11(pcap_t *); # endif # endif /* defined(__APPLE__) || defined(HAVE_BSD_IEEE80211) */ #endif /* BIOCGDLTLIST */ #if defined(sun) && defined(LIFNAMSIZ) && defined(lifr_zoneid) #include #endif /* * We include the OS's , not our "pcap/bpf.h", so we probably * don't get DLT_DOCSIS defined. */ #ifndef DLT_DOCSIS #define DLT_DOCSIS 143 #endif /* * On OS X, we don't even get any of the 802.11-plus-radio-header DLT_'s * defined, even though some of them are used by various Airport drivers. */ #ifndef DLT_PRISM_HEADER #define DLT_PRISM_HEADER 119 #endif #ifndef DLT_AIRONET_HEADER #define DLT_AIRONET_HEADER 120 #endif #ifndef DLT_IEEE802_11_RADIO #define DLT_IEEE802_11_RADIO 127 #endif #ifndef DLT_IEEE802_11_RADIO_AVS #define DLT_IEEE802_11_RADIO_AVS 163 #endif static int pcap_can_set_rfmon_bpf(pcap_t *p); static int pcap_activate_bpf(pcap_t *p); static int pcap_setfilter_bpf(pcap_t *p, struct bpf_program *fp); static int pcap_setdirection_bpf(pcap_t *, pcap_direction_t); static int pcap_set_datalink_bpf(pcap_t *p, int dlt); /* * For zerocopy bpf, the setnonblock/getnonblock routines need to modify * p->md.timeout so we don't call select(2) if the pcap handle is in non- * blocking mode. We preserve the timeout supplied by pcap_open functions * to make sure it does not get clobbered if the pcap handle moves between * blocking and non-blocking mode. */ static int pcap_getnonblock_bpf(pcap_t *p, char *errbuf) { #ifdef HAVE_ZEROCOPY_BPF if (p->md.zerocopy) { /* * Use a negative value for the timeout to represent that the * pcap handle is in non-blocking mode. */ return (p->md.timeout < 0); } #endif return (pcap_getnonblock_fd(p, errbuf)); } static int pcap_setnonblock_bpf(pcap_t *p, int nonblock, char *errbuf) { #ifdef HAVE_ZEROCOPY_BPF if (p->md.zerocopy) { /* * Map each value to their corresponding negation to * preserve the timeout value provided with pcap_set_timeout. * (from pcap-linux.c). */ if (nonblock) { if (p->md.timeout >= 0) { /* * Indicate that we're switching to * non-blocking mode. */ p->md.timeout = ~p->md.timeout; } } else { if (p->md.timeout < 0) { p->md.timeout = ~p->md.timeout; } } return (0); } #endif return (pcap_setnonblock_fd(p, nonblock, errbuf)); } #ifdef HAVE_ZEROCOPY_BPF /* * Zero-copy BPF buffer routines to check for and acknowledge BPF data in * shared memory buffers. * * pcap_next_zbuf_shm(): Check for a newly available shared memory buffer, * and set up p->buffer and cc to reflect one if available. Notice that if * there was no prior buffer, we select zbuf1 as this will be the first * buffer filled for a fresh BPF session. */ static int pcap_next_zbuf_shm(pcap_t *p, int *cc) { struct bpf_zbuf_header *bzh; if (p->md.zbuffer == p->md.zbuf2 || p->md.zbuffer == NULL) { bzh = (struct bpf_zbuf_header *)p->md.zbuf1; if (bzh->bzh_user_gen != atomic_load_acq_int(&bzh->bzh_kernel_gen)) { p->md.bzh = bzh; p->md.zbuffer = (u_char *)p->md.zbuf1; p->buffer = p->md.zbuffer + sizeof(*bzh); *cc = bzh->bzh_kernel_len; return (1); } } else if (p->md.zbuffer == p->md.zbuf1) { bzh = (struct bpf_zbuf_header *)p->md.zbuf2; if (bzh->bzh_user_gen != atomic_load_acq_int(&bzh->bzh_kernel_gen)) { p->md.bzh = bzh; p->md.zbuffer = (u_char *)p->md.zbuf2; p->buffer = p->md.zbuffer + sizeof(*bzh); *cc = bzh->bzh_kernel_len; return (1); } } *cc = 0; return (0); } /* * pcap_next_zbuf() -- Similar to pcap_next_zbuf_shm(), except wait using * select() for data or a timeout, and possibly force rotation of the buffer * in the event we time out or are in immediate mode. Invoke the shared * memory check before doing system calls in order to avoid doing avoidable * work. */ static int pcap_next_zbuf(pcap_t *p, int *cc) { struct bpf_zbuf bz; struct timeval tv; struct timespec cur; fd_set r_set; int data, r; int expire, tmout; #define TSTOMILLI(ts) (((ts)->tv_sec * 1000) + ((ts)->tv_nsec / 1000000)) /* * Start out by seeing whether anything is waiting by checking the * next shared memory buffer for data. */ data = pcap_next_zbuf_shm(p, cc); if (data) return (data); /* * If a previous sleep was interrupted due to signal delivery, make * sure that the timeout gets adjusted accordingly. This requires * that we analyze when the timeout should be been expired, and * subtract the current time from that. If after this operation, * our timeout is less then or equal to zero, handle it like a * regular timeout. */ tmout = p->md.timeout; if (tmout) (void) clock_gettime(CLOCK_MONOTONIC, &cur); if (p->md.interrupted && p->md.timeout) { expire = TSTOMILLI(&p->md.firstsel) + p->md.timeout; tmout = expire - TSTOMILLI(&cur); #undef TSTOMILLI if (tmout <= 0) { p->md.interrupted = 0; data = pcap_next_zbuf_shm(p, cc); if (data) return (data); if (ioctl(p->fd, BIOCROTZBUF, &bz) < 0) { (void) snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCROTZBUF: %s", strerror(errno)); return (PCAP_ERROR); } return (pcap_next_zbuf_shm(p, cc)); } } /* * No data in the buffer, so must use select() to wait for data or * the next timeout. Note that we only call select if the handle * is in blocking mode. */ if (p->md.timeout >= 0) { FD_ZERO(&r_set); FD_SET(p->fd, &r_set); if (tmout != 0) { tv.tv_sec = tmout / 1000; tv.tv_usec = (tmout * 1000) % 1000000; } r = select(p->fd + 1, &r_set, NULL, NULL, p->md.timeout != 0 ? &tv : NULL); if (r < 0 && errno == EINTR) { if (!p->md.interrupted && p->md.timeout) { p->md.interrupted = 1; p->md.firstsel = cur; } return (0); } else if (r < 0) { (void) snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "select: %s", strerror(errno)); return (PCAP_ERROR); } } p->md.interrupted = 0; /* * Check again for data, which may exist now that we've either been * woken up as a result of data or timed out. Try the "there's data" * case first since it doesn't require a system call. */ data = pcap_next_zbuf_shm(p, cc); if (data) return (data); /* * Try forcing a buffer rotation to dislodge timed out or immediate * data. */ if (ioctl(p->fd, BIOCROTZBUF, &bz) < 0) { (void) snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCROTZBUF: %s", strerror(errno)); return (PCAP_ERROR); } return (pcap_next_zbuf_shm(p, cc)); } /* * Notify kernel that we are done with the buffer. We don't reset zbuffer so * that we know which buffer to use next time around. */ static int pcap_ack_zbuf(pcap_t *p) { atomic_store_rel_int(&p->md.bzh->bzh_user_gen, p->md.bzh->bzh_kernel_gen); p->md.bzh = NULL; p->buffer = NULL; return (0); } #endif /* HAVE_ZEROCOPY_BPF */ pcap_t * pcap_create_interface(const char *device, char *ebuf) { pcap_t *p; p = pcap_create_common(device, ebuf); if (p == NULL) return (NULL); p->activate_op = pcap_activate_bpf; p->can_set_rfmon_op = pcap_can_set_rfmon_bpf; return (p); } /* * On success, returns a file descriptor for a BPF device. * On failure, returns a PCAP_ERROR_ value, and sets p->errbuf. */ static int bpf_open(pcap_t *p) { int fd; #ifdef HAVE_CLONING_BPF static const char device[] = "/dev/bpf"; #else int n = 0; char device[sizeof "/dev/bpf0000000000"]; #endif #ifdef _AIX /* * Load the bpf driver, if it isn't already loaded, * and create the BPF device entries, if they don't * already exist. */ if (bpf_load(p->errbuf) == PCAP_ERROR) return (PCAP_ERROR); #endif #ifdef HAVE_CLONING_BPF if ((fd = open(device, O_RDWR)) == -1 && (errno != EACCES || (fd = open(device, O_RDONLY)) == -1)) { if (errno == EACCES) fd = PCAP_ERROR_PERM_DENIED; else fd = PCAP_ERROR; snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "(cannot open device) %s: %s", device, pcap_strerror(errno)); } #else /* * Go through all the minors and find one that isn't in use. */ do { (void)snprintf(device, sizeof(device), "/dev/bpf%d", n++); /* * Initially try a read/write open (to allow the inject * method to work). If that fails due to permission * issues, fall back to read-only. This allows a * non-root user to be granted specific access to pcap * capabilities via file permissions. * * XXX - we should have an API that has a flag that * controls whether to open read-only or read-write, * so that denial of permission to send (or inability * to send, if sending packets isn't supported on * the device in question) can be indicated at open * time. */ fd = open(device, O_RDWR); if (fd == -1 && errno == EACCES) fd = open(device, O_RDONLY); } while (fd < 0 && errno == EBUSY); /* * XXX better message for all minors used */ if (fd < 0) { switch (errno) { case ENOENT: fd = PCAP_ERROR; if (n == 1) { /* * /dev/bpf0 doesn't exist, which * means we probably have no BPF * devices. */ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "(there are no BPF devices)"); } else { /* * We got EBUSY on at least one * BPF device, so we have BPF * devices, but all the ones * that exist are busy. */ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "(all BPF devices are busy)"); } break; case EACCES: /* * Got EACCES on the last device we tried, * and EBUSY on all devices before that, * if any. */ fd = PCAP_ERROR_PERM_DENIED; snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "(cannot open BPF device) %s: %s", device, pcap_strerror(errno)); break; default: /* * Some other problem. */ fd = PCAP_ERROR; snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "(cannot open BPF device) %s: %s", device, pcap_strerror(errno)); break; } } #endif return (fd); } #ifdef BIOCGDLTLIST static int get_dlt_list(int fd, int v, struct bpf_dltlist *bdlp, char *ebuf) { memset(bdlp, 0, sizeof(*bdlp)); if (ioctl(fd, BIOCGDLTLIST, (caddr_t)bdlp) == 0) { u_int i; int is_ethernet; bdlp->bfl_list = (u_int *) malloc(sizeof(u_int) * (bdlp->bfl_len + 1)); if (bdlp->bfl_list == NULL) { (void)snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); return (PCAP_ERROR); } if (ioctl(fd, BIOCGDLTLIST, (caddr_t)bdlp) < 0) { (void)snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCGDLTLIST: %s", pcap_strerror(errno)); free(bdlp->bfl_list); return (PCAP_ERROR); } /* * OK, for real Ethernet devices, add DLT_DOCSIS to the * list, so that an application can let you choose it, * in case you're capturing DOCSIS traffic that a Cisco * Cable Modem Termination System is putting out onto * an Ethernet (it doesn't put an Ethernet header onto * the wire, it puts raw DOCSIS frames out on the wire * inside the low-level Ethernet framing). * * A "real Ethernet device" is defined here as a device * that has a link-layer type of DLT_EN10MB and that has * no alternate link-layer types; that's done to exclude * 802.11 interfaces (which might or might not be the * right thing to do, but I suspect it is - Ethernet <-> * 802.11 bridges would probably badly mishandle frames * that don't have Ethernet headers). * * On Solaris with BPF, Ethernet devices also offer * DLT_IPNET, so we, if DLT_IPNET is defined, we don't * treat it as an indication that the device isn't an * Ethernet. */ if (v == DLT_EN10MB) { is_ethernet = 1; for (i = 0; i < bdlp->bfl_len; i++) { if (bdlp->bfl_list[i] != DLT_EN10MB #ifdef DLT_IPNET && bdlp->bfl_list[i] != DLT_IPNET #endif ) { is_ethernet = 0; break; } } if (is_ethernet) { /* * We reserved one more slot at the end of * the list. */ bdlp->bfl_list[bdlp->bfl_len] = DLT_DOCSIS; bdlp->bfl_len++; } } } else { /* * EINVAL just means "we don't support this ioctl on * this device"; don't treat it as an error. */ if (errno != EINVAL) { (void)snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCGDLTLIST: %s", pcap_strerror(errno)); return (PCAP_ERROR); } } return (0); } #endif static int pcap_can_set_rfmon_bpf(pcap_t *p) { #if defined(__APPLE__) struct utsname osinfo; struct ifreq ifr; int fd; #ifdef BIOCGDLTLIST struct bpf_dltlist bdl; #endif /* * The joys of monitor mode on OS X. * * Prior to 10.4, it's not supported at all. * * In 10.4, if adapter enN supports monitor mode, there's a * wltN adapter corresponding to it; you open it, instead of * enN, to get monitor mode. You get whatever link-layer * headers it supplies. * * In 10.5, and, we assume, later releases, if adapter enN * supports monitor mode, it offers, among its selectable * DLT_ values, values that let you get the 802.11 header; * selecting one of those values puts the adapter into monitor * mode (i.e., you can't get 802.11 headers except in monitor * mode, and you can't get Ethernet headers in monitor mode). */ if (uname(&osinfo) == -1) { /* * Can't get the OS version; just say "no". */ return (0); } /* * We assume osinfo.sysname is "Darwin", because * __APPLE__ is defined. We just check the version. */ if (osinfo.release[0] < '8' && osinfo.release[1] == '.') { /* * 10.3 (Darwin 7.x) or earlier. * Monitor mode not supported. */ return (0); } if (osinfo.release[0] == '8' && osinfo.release[1] == '.') { /* * 10.4 (Darwin 8.x). s/en/wlt/, and check * whether the device exists. */ if (strncmp(p->opt.source, "en", 2) != 0) { /* * Not an enN device; no monitor mode. */ return (0); } fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd == -1) { (void)snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "socket: %s", pcap_strerror(errno)); return (PCAP_ERROR); } strlcpy(ifr.ifr_name, "wlt", sizeof(ifr.ifr_name)); strlcat(ifr.ifr_name, p->opt.source + 2, sizeof(ifr.ifr_name)); if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0) { /* * No such device? */ close(fd); return (0); } close(fd); return (1); } #ifdef BIOCGDLTLIST /* * Everything else is 10.5 or later; for those, * we just open the enN device, and check whether * we have any 802.11 devices. * * First, open a BPF device. */ fd = bpf_open(p); if (fd < 0) return (fd); /* fd is the appropriate error code */ /* * Now bind to the device. */ (void)strncpy(ifr.ifr_name, p->opt.source, sizeof(ifr.ifr_name)); if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) { switch (errno) { case ENXIO: /* * There's no such device. */ close(fd); return (PCAP_ERROR_NO_SUCH_DEVICE); case ENETDOWN: /* * Return a "network down" indication, so that * the application can report that rather than * saying we had a mysterious failure and * suggest that they report a problem to the * libpcap developers. */ close(fd); return (PCAP_ERROR_IFACE_NOT_UP); default: snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETIF: %s: %s", p->opt.source, pcap_strerror(errno)); close(fd); return (PCAP_ERROR); } } /* * We know the default link type -- now determine all the DLTs * this interface supports. If this fails with EINVAL, it's * not fatal; we just don't get to use the feature later. * (We don't care about DLT_DOCSIS, so we pass DLT_NULL * as the default DLT for this adapter.) */ if (get_dlt_list(fd, DLT_NULL, &bdl, p->errbuf) == PCAP_ERROR) { close(fd); return (PCAP_ERROR); } if (find_802_11(&bdl) != -1) { /* * We have an 802.11 DLT, so we can set monitor mode. */ free(bdl.bfl_list); close(fd); return (1); } free(bdl.bfl_list); #endif /* BIOCGDLTLIST */ return (0); #elif defined(HAVE_BSD_IEEE80211) int ret; ret = monitor_mode(p, 0); if (ret == PCAP_ERROR_RFMON_NOTSUP) return (0); /* not an error, just a "can't do" */ if (ret == 0) return (1); /* success */ return (ret); #else return (0); #endif } static int pcap_stats_bpf(pcap_t *p, struct pcap_stat *ps) { struct bpf_stat s; /* * "ps_recv" counts packets handed to the filter, not packets * that passed the filter. This includes packets later dropped * because we ran out of buffer space. * * "ps_drop" counts packets dropped inside the BPF device * because we ran out of buffer space. It doesn't count * packets dropped by the interface driver. It counts * only packets that passed the filter. * * Both statistics include packets not yet read from the kernel * by libpcap, and thus not yet seen by the application. */ if (ioctl(p->fd, BIOCGSTATS, (caddr_t)&s) < 0) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCGSTATS: %s", pcap_strerror(errno)); return (PCAP_ERROR); } ps->ps_recv = s.bs_recv; ps->ps_drop = s.bs_drop; ps->ps_ifdrop = 0; return (0); } static int pcap_read_bpf(pcap_t *p, int cnt, pcap_handler callback, u_char *user) { int cc; int n = 0; register u_char *bp, *ep; u_char *datap; #ifdef PCAP_FDDIPAD register int pad; #endif #ifdef HAVE_ZEROCOPY_BPF int i; #endif again: /* * Has "pcap_breakloop()" been called? */ if (p->break_loop) { /* * Yes - clear the flag that indicates that it * has, and return PCAP_ERROR_BREAK to indicate * that we were told to break out of the loop. */ p->break_loop = 0; return (PCAP_ERROR_BREAK); } cc = p->cc; if (p->cc == 0) { /* * When reading without zero-copy from a file descriptor, we * use a single buffer and return a length of data in the * buffer. With zero-copy, we update the p->buffer pointer * to point at whatever underlying buffer contains the next * data and update cc to reflect the data found in the * buffer. */ #ifdef HAVE_ZEROCOPY_BPF if (p->md.zerocopy) { if (p->buffer != NULL) pcap_ack_zbuf(p); i = pcap_next_zbuf(p, &cc); if (i == 0) goto again; if (i < 0) return (PCAP_ERROR); } else #endif { cc = read(p->fd, (char *)p->buffer, p->bufsize); } if (cc < 0) { /* Don't choke when we get ptraced */ switch (errno) { case EINTR: goto again; #ifdef _AIX case EFAULT: /* * Sigh. More AIX wonderfulness. * * For some unknown reason the uiomove() * operation in the bpf kernel extension * used to copy the buffer into user * space sometimes returns EFAULT. I have * no idea why this is the case given that * a kernel debugger shows the user buffer * is correct. This problem appears to * be mostly mitigated by the memset of * the buffer before it is first used. * Very strange.... Shaun Clowes * * In any case this means that we shouldn't * treat EFAULT as a fatal error; as we * don't have an API for returning * a "some packets were dropped since * the last packet you saw" indication, * we just ignore EFAULT and keep reading. */ goto again; #endif case EWOULDBLOCK: return (0); case ENXIO: /* * The device on which we're capturing * went away. * * XXX - we should really return * PCAP_ERROR_IFACE_NOT_UP, but * pcap_dispatch() etc. aren't * defined to retur that. */ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "The interface went down"); return (PCAP_ERROR); #if defined(sun) && !defined(BSD) && !defined(__svr4__) && !defined(__SVR4) /* * Due to a SunOS bug, after 2^31 bytes, the kernel * file offset overflows and read fails with EINVAL. * The lseek() to 0 will fix things. */ case EINVAL: if (lseek(p->fd, 0L, SEEK_CUR) + p->bufsize < 0) { (void)lseek(p->fd, 0L, SEEK_SET); goto again; } /* fall through */ #endif } snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read: %s", pcap_strerror(errno)); return (PCAP_ERROR); } bp = p->buffer; } else bp = p->bp; /* * Loop through each packet. */ #define bhp ((struct bpf_hdr *)bp) ep = bp + cc; #ifdef PCAP_FDDIPAD pad = p->fddipad; #endif while (bp < ep) { register int caplen, hdrlen; /* * Has "pcap_breakloop()" been called? * If so, return immediately - if we haven't read any * packets, clear the flag and return PCAP_ERROR_BREAK * 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) { p->bp = bp; p->cc = ep - bp; /* * ep is set based on the return value of read(), * but read() from a BPF device doesn't necessarily * return a value that's a multiple of the alignment * value for BPF_WORDALIGN(). However, whenever we * increment bp, we round up the increment value by * a value rounded up by BPF_WORDALIGN(), so we * could increment bp past ep after processing the * last packet in the buffer. * * We treat ep < bp as an indication that this * happened, and just set p->cc to 0. */ if (p->cc < 0) p->cc = 0; if (n == 0) { p->break_loop = 0; return (PCAP_ERROR_BREAK); } else return (n); } caplen = bhp->bh_caplen; hdrlen = bhp->bh_hdrlen; datap = bp + hdrlen; /* * Short-circuit evaluation: if using BPF filter * in kernel, no need to do it now - we already know * the packet passed the filter. * #ifdef PCAP_FDDIPAD * Note: the filter code was generated assuming * that p->fddipad was the amount of padding * before the header, as that's what's required * in the kernel, so we run the filter before * skipping that padding. #endif */ if (p->md.use_bpf || bpf_filter(p->fcode.bf_insns, datap, bhp->bh_datalen, caplen)) { struct pcap_pkthdr pkthdr; pkthdr.ts.tv_sec = bhp->bh_tstamp.tv_sec; #ifdef _AIX /* * AIX's BPF returns seconds/nanoseconds time * stamps, not seconds/microseconds time stamps. */ pkthdr.ts.tv_usec = bhp->bh_tstamp.tv_usec/1000; #else pkthdr.ts.tv_usec = bhp->bh_tstamp.tv_usec; #endif #ifdef PCAP_FDDIPAD if (caplen > pad) pkthdr.caplen = caplen - pad; else pkthdr.caplen = 0; if (bhp->bh_datalen > pad) pkthdr.len = bhp->bh_datalen - pad; else pkthdr.len = 0; datap += pad; #else pkthdr.caplen = caplen; pkthdr.len = bhp->bh_datalen; #endif (*callback)(user, &pkthdr, datap); bp += BPF_WORDALIGN(caplen + hdrlen); if (++n >= cnt && cnt > 0) { p->bp = bp; p->cc = ep - bp; /* * See comment above about p->cc < 0. */ if (p->cc < 0) p->cc = 0; return (n); } } else { /* * Skip this packet. */ bp += BPF_WORDALIGN(caplen + hdrlen); } } #undef bhp p->cc = 0; return (n); } static int pcap_inject_bpf(pcap_t *p, const void *buf, size_t size) { int ret; ret = write(p->fd, buf, size); #ifdef __APPLE__ if (ret == -1 && errno == EAFNOSUPPORT) { /* * In Mac OS X, there's a bug wherein setting the * BIOCSHDRCMPLT flag causes writes to fail; see, * for example: * * http://cerberus.sourcefire.com/~jeff/archives/patches/macosx/BIOCSHDRCMPLT-10.3.3.patch * * So, if, on OS X, we get EAFNOSUPPORT from the write, we * assume it's due to that bug, and turn off that flag * and try again. If we succeed, it either means that * somebody applied the fix from that URL, or other patches * for that bug from * * http://cerberus.sourcefire.com/~jeff/archives/patches/macosx/ * * and are running a Darwin kernel with those fixes, or * that Apple fixed the problem in some OS X release. */ u_int spoof_eth_src = 0; if (ioctl(p->fd, BIOCSHDRCMPLT, &spoof_eth_src) == -1) { (void)snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: can't turn off BIOCSHDRCMPLT: %s", pcap_strerror(errno)); return (PCAP_ERROR); } /* * Now try the write again. */ ret = write(p->fd, buf, size); } #endif /* __APPLE__ */ if (ret == -1) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: %s", pcap_strerror(errno)); return (PCAP_ERROR); } return (ret); } #ifdef _AIX static int bpf_odminit(char *errbuf) { char *errstr; if (odm_initialize() == -1) { if (odm_err_msg(odmerrno, &errstr) == -1) errstr = "Unknown error"; snprintf(errbuf, PCAP_ERRBUF_SIZE, "bpf_load: odm_initialize failed: %s", errstr); return (PCAP_ERROR); } if ((odmlockid = odm_lock("/etc/objrepos/config_lock", ODM_WAIT)) == -1) { if (odm_err_msg(odmerrno, &errstr) == -1) errstr = "Unknown error"; snprintf(errbuf, PCAP_ERRBUF_SIZE, "bpf_load: odm_lock of /etc/objrepos/config_lock failed: %s", errstr); (void)odm_terminate(); return (PCAP_ERROR); } return (0); } static int bpf_odmcleanup(char *errbuf) { char *errstr; if (odm_unlock(odmlockid) == -1) { if (errbuf != NULL) { if (odm_err_msg(odmerrno, &errstr) == -1) errstr = "Unknown error"; snprintf(errbuf, PCAP_ERRBUF_SIZE, "bpf_load: odm_unlock failed: %s", errstr); } return (PCAP_ERROR); } if (odm_terminate() == -1) { if (errbuf != NULL) { if (odm_err_msg(odmerrno, &errstr) == -1) errstr = "Unknown error"; snprintf(errbuf, PCAP_ERRBUF_SIZE, "bpf_load: odm_terminate failed: %s", errstr); } return (PCAP_ERROR); } return (0); } static int bpf_load(char *errbuf) { long major; int *minors; int numminors, i, rc; char buf[1024]; struct stat sbuf; struct bpf_config cfg_bpf; struct cfg_load cfg_ld; struct cfg_kmod cfg_km; /* * This is very very close to what happens in the real implementation * but I've fixed some (unlikely) bug situations. */ if (bpfloadedflag) return (0); if (bpf_odminit(errbuf) == PCAP_ERROR) return (PCAP_ERROR); major = genmajor(BPF_NAME); if (major == -1) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "bpf_load: genmajor failed: %s", pcap_strerror(errno)); (void)bpf_odmcleanup(NULL); return (PCAP_ERROR); } minors = getminor(major, &numminors, BPF_NAME); if (!minors) { minors = genminor("bpf", major, 0, BPF_MINORS, 1, 1); if (!minors) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "bpf_load: genminor failed: %s", pcap_strerror(errno)); (void)bpf_odmcleanup(NULL); return (PCAP_ERROR); } } if (bpf_odmcleanup(errbuf) == PCAP_ERROR) return (PCAP_ERROR); rc = stat(BPF_NODE "0", &sbuf); if (rc == -1 && errno != ENOENT) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "bpf_load: can't stat %s: %s", BPF_NODE "0", pcap_strerror(errno)); return (PCAP_ERROR); } if (rc == -1 || getmajor(sbuf.st_rdev) != major) { for (i = 0; i < BPF_MINORS; i++) { sprintf(buf, "%s%d", BPF_NODE, i); unlink(buf); if (mknod(buf, S_IRUSR | S_IFCHR, domakedev(major, i)) == -1) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "bpf_load: can't mknod %s: %s", buf, pcap_strerror(errno)); return (PCAP_ERROR); } } } /* Check if the driver is loaded */ memset(&cfg_ld, 0x0, sizeof(cfg_ld)); cfg_ld.path = buf; sprintf(cfg_ld.path, "%s/%s", DRIVER_PATH, BPF_NAME); if ((sysconfig(SYS_QUERYLOAD, (void *)&cfg_ld, sizeof(cfg_ld)) == -1) || (cfg_ld.kmid == 0)) { /* Driver isn't loaded, load it now */ if (sysconfig(SYS_SINGLELOAD, (void *)&cfg_ld, sizeof(cfg_ld)) == -1) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "bpf_load: could not load driver: %s", strerror(errno)); return (PCAP_ERROR); } } /* Configure the driver */ cfg_km.cmd = CFG_INIT; cfg_km.kmid = cfg_ld.kmid; cfg_km.mdilen = sizeof(cfg_bpf); cfg_km.mdiptr = (void *)&cfg_bpf; for (i = 0; i < BPF_MINORS; i++) { cfg_bpf.devno = domakedev(major, i); if (sysconfig(SYS_CFGKMOD, (void *)&cfg_km, sizeof(cfg_km)) == -1) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "bpf_load: could not configure driver: %s", strerror(errno)); return (PCAP_ERROR); } } bpfloadedflag = 1; return (0); } #endif /* * Turn off rfmon mode if necessary. */ static void pcap_cleanup_bpf(pcap_t *p) { #ifdef HAVE_BSD_IEEE80211 int sock; struct ifmediareq req; struct ifreq ifr; #endif if (p->md.must_do_on_close != 0) { /* * There's something we have to do when closing this * pcap_t. */ #ifdef HAVE_BSD_IEEE80211 if (p->md.must_do_on_close & MUST_CLEAR_RFMON) { /* * We put the interface into rfmon mode; * take it out of rfmon mode. * * XXX - if somebody else wants it in rfmon * mode, this code cannot know that, so it'll take * it out of rfmon mode. */ sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock == -1) { fprintf(stderr, "Can't restore interface flags (socket() failed: %s).\n" "Please adjust manually.\n", strerror(errno)); } else { memset(&req, 0, sizeof(req)); strncpy(req.ifm_name, p->md.device, sizeof(req.ifm_name)); if (ioctl(sock, SIOCGIFMEDIA, &req) < 0) { fprintf(stderr, "Can't restore interface flags (SIOCGIFMEDIA failed: %s).\n" "Please adjust manually.\n", strerror(errno)); } else { if (req.ifm_current & IFM_IEEE80211_MONITOR) { /* * Rfmon mode is currently on; * turn it off. */ memset(&ifr, 0, sizeof(ifr)); (void)strncpy(ifr.ifr_name, p->md.device, sizeof(ifr.ifr_name)); ifr.ifr_media = req.ifm_current & ~IFM_IEEE80211_MONITOR; if (ioctl(sock, SIOCSIFMEDIA, &ifr) == -1) { fprintf(stderr, "Can't restore interface flags (SIOCSIFMEDIA failed: %s).\n" "Please adjust manually.\n", strerror(errno)); } } } close(sock); } } #endif /* HAVE_BSD_IEEE80211 */ /* * Take this pcap out of the list of pcaps for which we * have to take the interface out of some mode. */ pcap_remove_from_pcaps_to_close(p); p->md.must_do_on_close = 0; } #ifdef HAVE_ZEROCOPY_BPF if (p->md.zerocopy) { /* * Delete the mappings. Note that p->buffer gets * initialized to one of the mmapped regions in * this case, so do not try and free it directly; * null it out so that pcap_cleanup_live_common() * doesn't try to free it. */ if (p->md.zbuf1 != MAP_FAILED && p->md.zbuf1 != NULL) (void) munmap(p->md.zbuf1, p->md.zbufsize); if (p->md.zbuf2 != MAP_FAILED && p->md.zbuf2 != NULL) (void) munmap(p->md.zbuf2, p->md.zbufsize); p->buffer = NULL; p->buffer = NULL; } #endif if (p->md.device != NULL) { free(p->md.device); p->md.device = NULL; } pcap_cleanup_live_common(p); } static int check_setif_failure(pcap_t *p, int error) { #ifdef __APPLE__ int fd; struct ifreq ifr; int err; #endif if (error == ENXIO) { /* * No such device exists. */ #ifdef __APPLE__ if (p->opt.rfmon && strncmp(p->opt.source, "wlt", 3) == 0) { /* * Monitor mode was requested, and we're trying * to open a "wltN" device. Assume that this * is 10.4 and that we were asked to open an * "enN" device; if that device exists, return * "monitor mode not supported on the device". */ fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd != -1) { strlcpy(ifr.ifr_name, "en", sizeof(ifr.ifr_name)); strlcat(ifr.ifr_name, p->opt.source + 3, sizeof(ifr.ifr_name)); if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0) { /* * We assume this failed because * the underlying device doesn't * exist. */ err = PCAP_ERROR_NO_SUCH_DEVICE; snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "SIOCGIFFLAGS on %s failed: %s", ifr.ifr_name, pcap_strerror(errno)); } else { /* * The underlying "enN" device * exists, but there's no * corresponding "wltN" device; * that means that the "enN" * device doesn't support * monitor mode, probably because * it's an Ethernet device rather * than a wireless device. */ err = PCAP_ERROR_RFMON_NOTSUP; } close(fd); } else { /* * We can't find out whether there's * an underlying "enN" device, so * just report "no such device". */ err = PCAP_ERROR_NO_SUCH_DEVICE; snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "socket() failed: %s", pcap_strerror(errno)); } return (err); } #endif /* * No such device. */ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETIF failed: %s", pcap_strerror(errno)); return (PCAP_ERROR_NO_SUCH_DEVICE); } else if (errno == ENETDOWN) { /* * Return a "network down" indication, so that * the application can report that rather than * saying we had a mysterious failure and * suggest that they report a problem to the * libpcap developers. */ return (PCAP_ERROR_IFACE_NOT_UP); } else { /* * Some other error; fill in the error string, and * return PCAP_ERROR. */ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETIF: %s: %s", p->opt.source, pcap_strerror(errno)); return (PCAP_ERROR); } } /* * Default capture buffer size. * 32K isn't very much for modern machines with fast networks; we * pick .5M, as that's the maximum on at least some systems with BPF. * * However, on AIX 3.5, the larger buffer sized caused unrecoverable * read failures under stress, so we leave it as 32K; yet another * place where AIX's BPF is broken. */ #ifdef _AIX #define DEFAULT_BUFSIZE 32768 #else #define DEFAULT_BUFSIZE 524288 #endif static int pcap_activate_bpf(pcap_t *p) { int status = 0; int fd; #ifdef LIFNAMSIZ char *zonesep; struct lifreq ifr; char *ifrname = ifr.lifr_name; const size_t ifnamsiz = sizeof(ifr.lifr_name); #else struct ifreq ifr; char *ifrname = ifr.ifr_name; const size_t ifnamsiz = sizeof(ifr.ifr_name); #endif struct bpf_version bv; #ifdef __APPLE__ int sockfd; char *wltdev = NULL; #endif #ifdef BIOCGDLTLIST struct bpf_dltlist bdl; #if defined(__APPLE__) || defined(HAVE_BSD_IEEE80211) int new_dlt; #endif #endif /* BIOCGDLTLIST */ #if defined(BIOCGHDRCMPLT) && defined(BIOCSHDRCMPLT) u_int spoof_eth_src = 1; #endif u_int v; struct bpf_insn total_insn; struct bpf_program total_prog; struct utsname osinfo; #ifdef HAVE_DAG_API if (strstr(device, "dag")) { return dag_open_live(device, snaplen, promisc, to_ms, ebuf); } #endif /* HAVE_DAG_API */ #ifdef BIOCGDLTLIST memset(&bdl, 0, sizeof(bdl)); int have_osinfo = 0; #ifdef HAVE_ZEROCOPY_BPF struct bpf_zbuf bz; u_int bufmode, zbufmax; #endif fd = bpf_open(p); if (fd < 0) { status = fd; goto bad; } p->fd = fd; if (ioctl(fd, BIOCVERSION, (caddr_t)&bv) < 0) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCVERSION: %s", pcap_strerror(errno)); status = PCAP_ERROR; goto bad; } if (bv.bv_major != BPF_MAJOR_VERSION || bv.bv_minor < BPF_MINOR_VERSION) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "kernel bpf filter out of date"); status = PCAP_ERROR; goto bad; } #if defined(LIFNAMSIZ) && defined(ZONENAME_MAX) && defined(lifr_zoneid) /* * Check if the given source network device has a '/' separated * zonename prefix string. The zonename prefixed source device * can be used by libpcap consumers to capture network traffic * in non-global zones from the global zone on Solaris 11 and * above. If the zonename prefix is present then we strip the * prefix and pass the zone ID as part of lifr_zoneid. */ if ((zonesep = strchr(p->opt.source, '/')) != NULL) { char zonename[ZONENAME_MAX]; int znamelen; char *lnamep; znamelen = zonesep - p->opt.source; (void) strlcpy(zonename, p->opt.source, znamelen + 1); lnamep = strdup(zonesep + 1); ifr.lifr_zoneid = getzoneidbyname(zonename); free(p->opt.source); p->opt.source = lnamep; } #endif p->md.device = strdup(p->opt.source); if (p->md.device == NULL) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "strdup: %s", pcap_strerror(errno)); status = PCAP_ERROR; goto bad; } /* * Try finding a good size for the buffer; 32768 may be too * big, so keep cutting it in half until we find a size * that works, or run out of sizes to try. If the default * is larger, don't make it smaller. * * XXX - there should be a user-accessible hook to set the * initial buffer size. * Attempt to find out the version of the OS on which we're running. */ if (uname(&osinfo) == 0) have_osinfo = 1; #ifdef __APPLE__ /* * See comment in pcap_can_set_rfmon_bpf() for an explanation * of why we check the version number. */ if (p->opt.rfmon) { if (have_osinfo) { /* * We assume osinfo.sysname is "Darwin", because * __APPLE__ is defined. We just check the version. */ if (osinfo.release[0] < '8' && osinfo.release[1] == '.') { /* * 10.3 (Darwin 7.x) or earlier. */ status = PCAP_ERROR_RFMON_NOTSUP; goto bad; } if (osinfo.release[0] == '8' && osinfo.release[1] == '.') { /* * 10.4 (Darwin 8.x). s/en/wlt/ */ if (strncmp(p->opt.source, "en", 2) != 0) { /* * Not an enN device; check * whether the device even exists. */ sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (sockfd != -1) { strlcpy(ifrname, p->opt.source, ifnamsiz); if (ioctl(sockfd, SIOCGIFFLAGS, (char *)&ifr) < 0) { /* * We assume this * failed because * the underlying * device doesn't * exist. */ status = PCAP_ERROR_NO_SUCH_DEVICE; snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "SIOCGIFFLAGS failed: %s", pcap_strerror(errno)); } else status = PCAP_ERROR_RFMON_NOTSUP; close(sockfd); } else { /* * We can't find out whether * the device exists, so just * report "no such device". */ status = PCAP_ERROR_NO_SUCH_DEVICE; snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "socket() failed: %s", pcap_strerror(errno)); } goto bad; } wltdev = malloc(strlen(p->opt.source) + 2); if (wltdev == NULL) { (void)snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); status = PCAP_ERROR; goto bad; } strcpy(wltdev, "wlt"); strcat(wltdev, p->opt.source + 2); free(p->opt.source); p->opt.source = wltdev; } /* * Everything else is 10.5 or later; for those, * we just open the enN device, and set the DLT. */ } } #endif /* __APPLE__ */ #ifdef HAVE_ZEROCOPY_BPF /* * If the BPF extension to set buffer mode is present, try setting * the mode to zero-copy. If that fails, use regular buffering. If * it succeeds but other setup fails, return an error to the user. */ bufmode = BPF_BUFMODE_ZBUF; if (ioctl(fd, BIOCSETBUFMODE, (caddr_t)&bufmode) == 0) { /* * We have zerocopy BPF; use it. */ p->md.zerocopy = 1; /* * How to pick a buffer size: first, query the maximum buffer * size supported by zero-copy. This also lets us quickly * determine whether the kernel generally supports zero-copy. * Then, if a buffer size was specified, use that, otherwise * query the default buffer size, which reflects kernel * policy for a desired default. Round to the nearest page * size. */ if (ioctl(fd, BIOCGETZMAX, (caddr_t)&zbufmax) < 0) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCGETZMAX: %s", pcap_strerror(errno)); goto bad; } if (p->opt.buffer_size != 0) { /* * A buffer size was explicitly specified; use it. */ v = p->opt.buffer_size; } else { if ((ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) || v < DEFAULT_BUFSIZE) v = DEFAULT_BUFSIZE; } #ifndef roundup #define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) /* to any y */ #endif p->md.zbufsize = roundup(v, getpagesize()); if (p->md.zbufsize > zbufmax) p->md.zbufsize = zbufmax; p->md.zbuf1 = mmap(NULL, p->md.zbufsize, PROT_READ | PROT_WRITE, MAP_ANON, -1, 0); p->md.zbuf2 = mmap(NULL, p->md.zbufsize, PROT_READ | PROT_WRITE, MAP_ANON, -1, 0); if (p->md.zbuf1 == MAP_FAILED || p->md.zbuf2 == MAP_FAILED) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "mmap: %s", pcap_strerror(errno)); goto bad; } memset(&bz, 0, sizeof(bz)); /* bzero() deprecated, replaced with memset() */ bz.bz_bufa = p->md.zbuf1; bz.bz_bufb = p->md.zbuf2; bz.bz_buflen = p->md.zbufsize; if (ioctl(fd, BIOCSETZBUF, (caddr_t)&bz) < 0) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETZBUF: %s", pcap_strerror(errno)); goto bad; } (void)strncpy(ifrname, p->opt.source, ifnamsiz); if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETIF: %s: %s", p->opt.source, pcap_strerror(errno)); goto bad; } v = p->md.zbufsize - sizeof(struct bpf_zbuf_header); } else #endif { /* * We don't have zerocopy BPF. * Set the buffer size. */ if (p->opt.buffer_size != 0) { /* * A buffer size was explicitly specified; use it. */ if (ioctl(fd, BIOCSBLEN, (caddr_t)&p->opt.buffer_size) < 0) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSBLEN: %s: %s", p->opt.source, pcap_strerror(errno)); status = PCAP_ERROR; goto bad; } /* * Now bind to the device. */ (void)strncpy(ifrname, p->opt.source, ifnamsiz); #ifdef BIOCSETLIF if (ioctl(fd, BIOCSETLIF, (caddr_t)&ifr) < 0) #else if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) #endif { status = check_setif_failure(p, errno); goto bad; } } else { /* * No buffer size was explicitly specified. * * Try finding a good size for the buffer; * DEFAULT_BUFSIZE may be too big, so keep * cutting it in half until we find a size * that works, or run out of sizes to try. * If the default is larger, don't make it smaller. */ if ((ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) || v < DEFAULT_BUFSIZE) v = DEFAULT_BUFSIZE; for ( ; v != 0; v >>= 1) { /* * Ignore the return value - this is because the * call fails on BPF systems that don't have * kernel malloc. And if the call fails, it's * no big deal, we just continue to use the * standard buffer size. */ (void) ioctl(fd, BIOCSBLEN, (caddr_t)&v); (void)strncpy(ifrname, p->opt.source, ifnamsiz); #ifdef BIOCSETLIF if (ioctl(fd, BIOCSETLIF, (caddr_t)&ifr) >= 0) #else if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) >= 0) #endif break; /* that size worked; we're done */ if (errno != ENOBUFS) { status = check_setif_failure(p, errno); goto bad; } } if (v == 0) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSBLEN: %s: No buffer size worked", p->opt.source); status = PCAP_ERROR; goto bad; } } } #endif /* Get the data link layer type. */ if (ioctl(fd, BIOCGDLT, (caddr_t)&v) < 0) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCGDLT: %s", pcap_strerror(errno)); status = PCAP_ERROR; goto bad; } #ifdef _AIX /* * AIX's BPF returns IFF_ types, not DLT_ types, in BIOCGDLT. */ switch (v) { case IFT_ETHER: case IFT_ISO88023: v = DLT_EN10MB; break; case IFT_FDDI: v = DLT_FDDI; break; case IFT_ISO88025: v = DLT_IEEE802; break; case IFT_LOOP: v = DLT_NULL; break; default: /* * We don't know what to map this to yet. */ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "unknown interface type %u", v); status = PCAP_ERROR; goto bad; } #endif #if _BSDI_VERSION - 0 >= 199510 /* The SLIP and PPP link layer header changed in BSD/OS 2.1 */ switch (v) { case DLT_SLIP: v = DLT_SLIP_BSDOS; break; case DLT_PPP: v = DLT_PPP_BSDOS; break; case 11: /*DLT_FR*/ v = DLT_FRELAY; break; case 12: /*DLT_C_HDLC*/ v = DLT_CHDLC; break; } #endif #ifdef BIOCGDLTLIST /* * We know the default link type -- now determine all the DLTs * this interface supports. If this fails with EINVAL, it's * not fatal; we just don't get to use the feature later. */ if (get_dlt_list(fd, v, &bdl, p->errbuf) == -1) { status = PCAP_ERROR; goto bad; } p->dlt_count = bdl.bfl_len; p->dlt_list = bdl.bfl_list; #ifdef __APPLE__ /* * Monitor mode fun, continued. * * For 10.5 and, we're assuming, later releases, as noted above, * 802.1 adapters that support monitor mode offer both DLT_EN10MB, * DLT_IEEE802_11, and possibly some 802.11-plus-radio-information * DLT_ value. Choosing one of the 802.11 DLT_ values will turn * monitor mode on. * * Therefore, if the user asked for monitor mode, we filter out * the DLT_EN10MB value, as you can't get that in monitor mode, * and, if the user didn't ask for monitor mode, we filter out * the 802.11 DLT_ values, because selecting those will turn * monitor mode on. Then, for monitor mode, if an 802.11-plus- * radio DLT_ value is offered, we try to select that, otherwise * we try to select DLT_IEEE802_11. */ if (have_osinfo) { if (isdigit((unsigned)osinfo.release[0]) && (osinfo.release[0] == '9' || isdigit((unsigned)osinfo.release[1]))) { /* * 10.5 (Darwin 9.x), or later. */ new_dlt = find_802_11(&bdl); if (new_dlt != -1) { /* * We have at least one 802.11 DLT_ value, * so this is an 802.11 interface. * new_dlt is the best of the 802.11 * DLT_ values in the list. */ if (p->opt.rfmon) { /* * Our caller wants monitor mode. * Purge DLT_EN10MB from the list * of link-layer types, as selecting * it will keep monitor mode off. */ remove_en(p); /* * If the new mode we want isn't * the default mode, attempt to * select the new mode. */ if (new_dlt != v) { if (ioctl(p->fd, BIOCSDLT, &new_dlt) != -1) { /* * We succeeded; * make this the * new DLT_ value. */ v = new_dlt; } } } else { /* * Our caller doesn't want * monitor mode. Unless this * is being done by pcap_open_live(), * purge the 802.11 link-layer types * from the list, as selecting * one of them will turn monitor * mode on. */ if (!p->oldstyle) remove_802_11(p); } } else { if (p->opt.rfmon) { /* * The caller requested monitor * mode, but we have no 802.11 * link-layer types, so they * can't have it. */ status = PCAP_ERROR_RFMON_NOTSUP; goto bad; } } } } #elif defined(HAVE_BSD_IEEE80211) /* * *BSD with the new 802.11 ioctls. * Do we want monitor mode? */ if (p->opt.rfmon) { /* * Try to put the interface into monitor mode. */ status = monitor_mode(p, 1); if (status != 0) { /* * We failed. */ goto bad; } /* * We're in monitor mode. * Try to find the best 802.11 DLT_ value and, if we * succeed, try to switch to that mode if we're not * already in that mode. */ new_dlt = find_802_11(&bdl); if (new_dlt != -1) { /* * We have at least one 802.11 DLT_ value. * new_dlt is the best of the 802.11 * DLT_ values in the list. * * If the new mode we want isn't the default mode, * attempt to select the new mode. */ if (new_dlt != v) { if (ioctl(p->fd, BIOCSDLT, &new_dlt) != -1) { /* * We succeeded; make this the * new DLT_ value. */ v = new_dlt; } } } } #endif /* various platforms */ #endif /* BIOCGDLTLIST */ /* * If this is an Ethernet device, and we don't have a DLT_ list, * give it a list with DLT_EN10MB and DLT_DOCSIS. (That'd give * 802.11 interfaces DLT_DOCSIS, which isn't the right thing to * do, but there's not much we can do about that without finding * some other way of determining whether it's an Ethernet or 802.11 * device.) */ if (v == DLT_EN10MB && p->dlt_count == 0) { p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); /* * If that fails, just leave the list empty. */ if (p->dlt_list != NULL) { p->dlt_list[0] = DLT_EN10MB; p->dlt_list[1] = DLT_DOCSIS; p->dlt_count = 2; } } #ifdef PCAP_FDDIPAD if (v == DLT_FDDI) p->fddipad = PCAP_FDDIPAD; else p->fddipad = 0; #endif p->linktype = v; #if defined(BIOCGHDRCMPLT) && defined(BIOCSHDRCMPLT) /* * Do a BIOCSHDRCMPLT, if defined, to turn that flag on, so * the link-layer source address isn't forcibly overwritten. * (Should we ignore errors? Should we do this only if * we're open for writing?) * * XXX - I seem to remember some packet-sending bug in some * BSDs - check CVS log for "bpf.c"? */ if (ioctl(fd, BIOCSHDRCMPLT, &spoof_eth_src) == -1) { (void)snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSHDRCMPLT: %s", pcap_strerror(errno)); status = PCAP_ERROR; goto bad; } #endif /* set timeout */ #ifdef HAVE_ZEROCOPY_BPF if (p->md.timeout != 0 && !p->md.zerocopy) { #else if (p->md.timeout) { #endif /* * XXX - is this seconds/nanoseconds in AIX? * (Treating it as such doesn't fix the timeout * problem described below.) * * XXX - Mac OS X 10.6 mishandles BIOCSRTIMEOUT in * 64-bit userland - it takes, as an argument, a * "struct BPF_TIMEVAL", which has 32-bit tv_sec * and tv_usec, rather than a "struct timeval". * * If this platform defines "struct BPF_TIMEVAL", * we check whether the structure size in BIOCSRTIMEOUT * is that of a "struct timeval" and, if not, we use * a "struct BPF_TIMEVAL" rather than a "struct timeval". * (That way, if the bug is fixed in a future release, * we will still do the right thing.) */ struct timeval to; #ifdef HAVE_STRUCT_BPF_TIMEVAL struct BPF_TIMEVAL bpf_to; if (IOCPARM_LEN(BIOCSRTIMEOUT) != sizeof(struct timeval)) { bpf_to.tv_sec = p->md.timeout / 1000; bpf_to.tv_usec = (p->md.timeout * 1000) % 1000000; if (ioctl(p->fd, BIOCSRTIMEOUT, (caddr_t)&bpf_to) < 0) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSRTIMEOUT: %s", pcap_strerror(errno)); status = PCAP_ERROR; goto bad; } } else { #endif to.tv_sec = p->md.timeout / 1000; to.tv_usec = (p->md.timeout * 1000) % 1000000; if (ioctl(p->fd, BIOCSRTIMEOUT, (caddr_t)&to) < 0) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSRTIMEOUT: %s", pcap_strerror(errno)); status = PCAP_ERROR; goto bad; } #ifdef HAVE_STRUCT_BPF_TIMEVAL } #endif } #ifdef _AIX #ifdef BIOCIMMEDIATE /* * Darren Reed notes that * * On AIX (4.2 at least), if BIOCIMMEDIATE is not set, the * timeout appears to be ignored and it waits until the buffer * is filled before returning. The result of not having it * set is almost worse than useless if your BPF filter * is reducing things to only a few packets (i.e. one every * second or so). * * so we turn BIOCIMMEDIATE mode on if this is AIX. * * We don't turn it on for other platforms, as that means we * get woken up for every packet, which may not be what we want; * in the Winter 1993 USENIX paper on BPF, they say: * * Since a process might want to look at every packet on a * network and the time between packets can be only a few * microseconds, it is not possible to do a read system call * per packet and BPF must collect the data from several * packets and return it as a unit when the monitoring * application does a read. * * which I infer is the reason for the timeout - it means we * wait that amount of time, in the hopes that more packets * will arrive and we'll get them all with one read. * * Setting BIOCIMMEDIATE mode on FreeBSD (and probably other * BSDs) causes the timeout to be ignored. * * On the other hand, some platforms (e.g., Linux) don't support * timeouts, they just hand stuff to you as soon as it arrives; * if that doesn't cause a problem on those platforms, it may * be OK to have BIOCIMMEDIATE mode on BSD as well. * * (Note, though, that applications may depend on the read * completing, even if no packets have arrived, when the timeout * expires, e.g. GUI applications that have to check for input * while waiting for packets to arrive; a non-zero timeout * prevents "select()" from working right on FreeBSD and * possibly other BSDs, as the timer doesn't start until a * "read()" is done, so the timer isn't in effect if the * application is blocked on a "select()", and the "select()" * doesn't get woken up for a BPF device until the buffer * fills up.) */ v = 1; if (ioctl(p->fd, BIOCIMMEDIATE, &v) < 0) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCIMMEDIATE: %s", pcap_strerror(errno)); status = PCAP_ERROR; goto bad; } #endif /* BIOCIMMEDIATE */ #endif /* _AIX */ if (p->opt.promisc) { /* set promiscuous mode, just warn if it fails */ if (ioctl(p->fd, BIOCPROMISC, NULL) < 0) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCPROMISC: %s", pcap_strerror(errno)); status = PCAP_WARNING_PROMISC_NOTSUP; } } if (ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCGBLEN: %s", pcap_strerror(errno)); status = PCAP_ERROR; goto bad; } p->bufsize = v; #ifdef HAVE_ZEROCOPY_BPF if (!p->md.zerocopy) { #endif p->buffer = (u_char *)malloc(p->bufsize); if (p->buffer == NULL) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); status = PCAP_ERROR; goto bad; } #ifdef _AIX /* For some strange reason this seems to prevent the EFAULT * problems we have experienced from AIX BPF. */ memset(p->buffer, 0x0, p->bufsize); #endif #ifdef HAVE_ZEROCOPY_BPF } #endif - if (p->rxq_num != (uint32_t)-1 || p->txq_num != (uint32_t)-1 || - p->other_mask != (uint32_t)-1) { - if (ioctl(fd, BIOCENAQMASK, NULL) < 0) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCENAQMASK: %s", + if (p->qmask_enabled) { + if (ioctl(fd, BIOCQMASKENABLE, NULL) < 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCQMASKENABLE: %s", pcap_strerror(errno)); status = PCAP_ERROR; goto bad; } - if (p->rxq_num != (uint32_t)-1) { - if (ioctl(fd, BIOCSTRXQMASK, &p->rxq_num) < 0) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSTRXQMASK: %s", - pcap_strerror(errno)); - status = PCAP_ERROR; - goto bad; - } + if (ioctl(fd, BIOCSRXQMASK, &p->rxqmask) < 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSRXQMASK: %s", + pcap_strerror(errno)); + status = PCAP_ERROR; + goto bad; } - if (p->txq_num != (uint32_t)-1) { - if (ioctl(fd, BIOCSTTXQMASK, &p->txq_num) < 0) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSTTXQMASK: %s", - pcap_strerror(errno)); - status = PCAP_ERROR; - goto bad; - } + if (ioctl(fd, BIOCSTXQMASK, &p->txqmask) < 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSTXQMASK: %s", + pcap_strerror(errno)); + status = PCAP_ERROR; + goto bad; } - if (p->other_mask != (uint32_t)-1) { - if (ioctl(fd, BIOCSTOTHERMASK, &p->other_mask) < 0) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSTOTHERQMASK: %s", - pcap_strerror(errno)); - status = PCAP_ERROR; - goto bad; - } + if (ioctl(fd, BIOCSNOQMASK, &p->noqmask) < 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSNOQMASK: %s", + pcap_strerror(errno)); + status = PCAP_ERROR; + goto bad; } } /* * If there's no filter program installed, there's * no indication to the kernel of what the snapshot * length should be, so no snapshotting is done. * * Therefore, when we open the device, we install * an "accept everything" filter with the specified * snapshot length. */ total_insn.code = (u_short)(BPF_RET | BPF_K); total_insn.jt = 0; total_insn.jf = 0; total_insn.k = p->snapshot; total_prog.bf_len = 1; total_prog.bf_insns = &total_insn; if (ioctl(p->fd, BIOCSETF, (caddr_t)&total_prog) < 0) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETF: %s", pcap_strerror(errno)); status = PCAP_ERROR; goto bad; } /* * On most BPF platforms, either you can do a "select()" or * "poll()" on a BPF file descriptor and it works correctly, * or you can do it and it will return "readable" if the * hold buffer is full but not if the timeout expires *and* * a non-blocking read will, if the hold buffer is empty * but the store buffer isn't empty, rotate the buffers * and return what packets are available. * * In the latter case, the fact that a non-blocking read * will give you the available packets means you can work * around the failure of "select()" and "poll()" to wake up * and return "readable" when the timeout expires by using * the timeout as the "select()" or "poll()" timeout, putting * the BPF descriptor into non-blocking mode, and read from * it regardless of whether "select()" reports it as readable * or not. * * However, in FreeBSD 4.3 and 4.4, "select()" and "poll()" * won't wake up and return "readable" if the timer expires * and non-blocking reads return EWOULDBLOCK if the hold * buffer is empty, even if the store buffer is non-empty. * * This means the workaround in question won't work. * * Therefore, on FreeBSD 4.3 and 4.4, we set "p->selectable_fd" * to -1, which means "sorry, you can't use 'select()' or 'poll()' * here". On all other BPF platforms, we set it to the FD for * the BPF device; in NetBSD, OpenBSD, and Darwin, a non-blocking * read will, if the hold buffer is empty and the store buffer * isn't empty, rotate the buffers and return what packets are * there (and in sufficiently recent versions of OpenBSD * "select()" and "poll()" should work correctly). * * XXX - what about AIX? */ p->selectable_fd = p->fd; /* assume select() works until we know otherwise */ if (have_osinfo) { /* * We can check what OS this is. */ if (strcmp(osinfo.sysname, "FreeBSD") == 0) { if (strncmp(osinfo.release, "4.3-", 4) == 0 || strncmp(osinfo.release, "4.4-", 4) == 0) p->selectable_fd = -1; } } p->read_op = pcap_read_bpf; p->inject_op = pcap_inject_bpf; p->setfilter_op = pcap_setfilter_bpf; p->setdirection_op = pcap_setdirection_bpf; p->set_datalink_op = pcap_set_datalink_bpf; p->getnonblock_op = pcap_getnonblock_bpf; p->setnonblock_op = pcap_setnonblock_bpf; p->stats_op = pcap_stats_bpf; p->cleanup_op = pcap_cleanup_bpf; return (status); bad: pcap_cleanup_bpf(p); return (status); } int pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf) { return (0); } #ifdef HAVE_BSD_IEEE80211 static int monitor_mode(pcap_t *p, int set) { int sock; struct ifmediareq req; int *media_list; int i; int can_do; struct ifreq ifr; sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock == -1) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "can't open socket: %s", pcap_strerror(errno)); return (PCAP_ERROR); } memset(&req, 0, sizeof req); strncpy(req.ifm_name, p->opt.source, sizeof req.ifm_name); /* * Find out how many media types we have. */ if (ioctl(sock, SIOCGIFMEDIA, &req) < 0) { /* * Can't get the media types. */ switch (errno) { case ENXIO: /* * There's no such device. */ close(sock); return (PCAP_ERROR_NO_SUCH_DEVICE); case EINVAL: /* * Interface doesn't support SIOC{G,S}IFMEDIA. */ close(sock); return (PCAP_ERROR_RFMON_NOTSUP); default: snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "SIOCGIFMEDIA 1: %s", pcap_strerror(errno)); close(sock); return (PCAP_ERROR); } } if (req.ifm_count == 0) { /* * No media types. */ close(sock); return (PCAP_ERROR_RFMON_NOTSUP); } /* * Allocate a buffer to hold all the media types, and * get the media types. */ media_list = malloc(req.ifm_count * sizeof(int)); if (media_list == NULL) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); close(sock); return (PCAP_ERROR); } req.ifm_ulist = media_list; if (ioctl(sock, SIOCGIFMEDIA, &req) < 0) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "SIOCGIFMEDIA: %s", pcap_strerror(errno)); free(media_list); close(sock); return (PCAP_ERROR); } /* * Look for an 802.11 "automatic" media type. * We assume that all 802.11 adapters have that media type, * and that it will carry the monitor mode supported flag. */ can_do = 0; for (i = 0; i < req.ifm_count; i++) { if (IFM_TYPE(media_list[i]) == IFM_IEEE80211 && IFM_SUBTYPE(media_list[i]) == IFM_AUTO) { /* OK, does it do monitor mode? */ if (media_list[i] & IFM_IEEE80211_MONITOR) { can_do = 1; break; } } } free(media_list); if (!can_do) { /* * This adapter doesn't support monitor mode. */ close(sock); return (PCAP_ERROR_RFMON_NOTSUP); } if (set) { /* * Don't just check whether we can enable monitor mode, * do so, if it's not already enabled. */ if ((req.ifm_current & IFM_IEEE80211_MONITOR) == 0) { /* * Monitor mode isn't currently on, so turn it on, * and remember that we should turn it off when the * pcap_t is closed. */ /* * If we haven't already done so, arrange to have * "pcap_close_all()" called when we exit. */ if (!pcap_do_addexit(p)) { /* * "atexit()" failed; don't put the interface * in monitor mode, just give up. */ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "atexit failed"); close(sock); return (PCAP_ERROR); } memset(&ifr, 0, sizeof(ifr)); (void)strncpy(ifr.ifr_name, p->opt.source, sizeof(ifr.ifr_name)); ifr.ifr_media = req.ifm_current | IFM_IEEE80211_MONITOR; if (ioctl(sock, SIOCSIFMEDIA, &ifr) == -1) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "SIOCSIFMEDIA: %s", pcap_strerror(errno)); close(sock); return (PCAP_ERROR); } p->md.must_do_on_close |= MUST_CLEAR_RFMON; /* * Add this to the list of pcaps to close when we exit. */ pcap_add_to_pcaps_to_close(p); } } return (0); } #endif /* HAVE_BSD_IEEE80211 */ #if defined(BIOCGDLTLIST) && (defined(__APPLE__) || defined(HAVE_BSD_IEEE80211)) /* * Check whether we have any 802.11 link-layer types; return the best * of the 802.11 link-layer types if we find one, and return -1 * otherwise. * * DLT_IEEE802_11_RADIO, with the radiotap header, is considered the * best 802.11 link-layer type; any of the other 802.11-plus-radio * headers are second-best; 802.11 with no radio information is * the least good. */ static int find_802_11(struct bpf_dltlist *bdlp) { int new_dlt; int i; /* * Scan the list of DLT_ values, looking for 802.11 values, * and, if we find any, choose the best of them. */ new_dlt = -1; for (i = 0; i < bdlp->bfl_len; i++) { switch (bdlp->bfl_list[i]) { case DLT_IEEE802_11: /* * 802.11, but no radio. * * Offer this, and select it as the new mode * unless we've already found an 802.11 * header with radio information. */ if (new_dlt == -1) new_dlt = bdlp->bfl_list[i]; break; case DLT_PRISM_HEADER: case DLT_AIRONET_HEADER: case DLT_IEEE802_11_RADIO_AVS: /* * 802.11 with radio, but not radiotap. * * Offer this, and select it as the new mode * unless we've already found the radiotap DLT_. */ if (new_dlt != DLT_IEEE802_11_RADIO) new_dlt = bdlp->bfl_list[i]; break; case DLT_IEEE802_11_RADIO: /* * 802.11 with radiotap. * * Offer this, and select it as the new mode. */ new_dlt = bdlp->bfl_list[i]; break; default: /* * Not 802.11. */ break; } } return (new_dlt); } #endif /* defined(BIOCGDLTLIST) && (defined(__APPLE__) || defined(HAVE_BSD_IEEE80211)) */ #if defined(__APPLE__) && defined(BIOCGDLTLIST) /* * Remove DLT_EN10MB from the list of DLT_ values, as we're in monitor mode, * and DLT_EN10MB isn't supported in monitor mode. */ static void remove_en(pcap_t *p) { int i, j; /* * Scan the list of DLT_ values and discard DLT_EN10MB. */ j = 0; for (i = 0; i < p->dlt_count; i++) { switch (p->dlt_list[i]) { case DLT_EN10MB: /* * Don't offer this one. */ continue; default: /* * Just copy this mode over. */ break; } /* * Copy this DLT_ value to its new position. */ p->dlt_list[j] = p->dlt_list[i]; j++; } /* * Set the DLT_ count to the number of entries we copied. */ p->dlt_count = j; } /* * Remove 802.11 link-layer types from the list of DLT_ values, as * we're not in monitor mode, and those DLT_ values will switch us * to monitor mode. */ static void remove_802_11(pcap_t *p) { int i, j; /* * Scan the list of DLT_ values and discard 802.11 values. */ j = 0; for (i = 0; i < p->dlt_count; i++) { switch (p->dlt_list[i]) { case DLT_IEEE802_11: case DLT_PRISM_HEADER: case DLT_AIRONET_HEADER: case DLT_IEEE802_11_RADIO: case DLT_IEEE802_11_RADIO_AVS: /* * 802.11. Don't offer this one. */ continue; default: /* * Just copy this mode over. */ break; } /* * Copy this DLT_ value to its new position. */ p->dlt_list[j] = p->dlt_list[i]; j++; } /* * Set the DLT_ count to the number of entries we copied. */ p->dlt_count = j; } #endif /* defined(__APPLE__) && defined(BIOCGDLTLIST) */ static int pcap_setfilter_bpf(pcap_t *p, struct bpf_program *fp) { /* * Free any user-mode filter we might happen to have installed. */ pcap_freecode(&p->fcode); /* * Try to install the kernel filter. */ if (ioctl(p->fd, BIOCSETF, (caddr_t)fp) == 0) { /* * It worked. */ p->md.use_bpf = 1; /* filtering in the kernel */ /* * Discard any previously-received packets, as they might * have passed whatever filter was formerly in effect, but * might not pass this filter (BIOCSETF discards packets * buffered in the kernel, so you can lose packets in any * case). */ p->cc = 0; return (0); } /* * We failed. * * If it failed with EINVAL, that's probably because the program * is invalid or too big. Validate it ourselves; if we like it * (we currently allow backward branches, to support protochain), * run it in userland. (There's no notion of "too big" for * userland.) * * Otherwise, just give up. * XXX - if the copy of the program into the kernel failed, * we will get EINVAL rather than, say, EFAULT on at least * some kernels. */ if (errno != EINVAL) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETF: %s", pcap_strerror(errno)); return (-1); } /* * install_bpf_program() validates the program. * * XXX - what if we already have a filter in the kernel? */ if (install_bpf_program(p, fp) < 0) return (-1); p->md.use_bpf = 0; /* filtering in userland */ return (0); } /* * Set direction flag: Which packets do we accept on a forwarding * single device? IN, OUT or both? */ static int pcap_setdirection_bpf(pcap_t *p, pcap_direction_t d) { #if defined(BIOCSDIRECTION) u_int direction; direction = (d == PCAP_D_IN) ? BPF_D_IN : ((d == PCAP_D_OUT) ? BPF_D_OUT : BPF_D_INOUT); if (ioctl(p->fd, BIOCSDIRECTION, &direction) == -1) { (void) snprintf(p->errbuf, sizeof(p->errbuf), "Cannot set direction to %s: %s", (d == PCAP_D_IN) ? "PCAP_D_IN" : ((d == PCAP_D_OUT) ? "PCAP_D_OUT" : "PCAP_D_INOUT"), strerror(errno)); return (-1); } return (0); #elif defined(BIOCSSEESENT) u_int seesent; /* * We don't support PCAP_D_OUT. */ if (d == PCAP_D_OUT) { snprintf(p->errbuf, sizeof(p->errbuf), "Setting direction to PCAP_D_OUT is not supported on BPF"); return -1; } seesent = (d == PCAP_D_INOUT); if (ioctl(p->fd, BIOCSSEESENT, &seesent) == -1) { (void) snprintf(p->errbuf, sizeof(p->errbuf), "Cannot set direction to %s: %s", (d == PCAP_D_INOUT) ? "PCAP_D_INOUT" : "PCAP_D_IN", strerror(errno)); return (-1); } return (0); #else (void) snprintf(p->errbuf, sizeof(p->errbuf), "This system doesn't support BIOCSSEESENT, so the direction can't be set"); return (-1); #endif } static int pcap_set_datalink_bpf(pcap_t *p, int dlt) { #ifdef BIOCSDLT if (ioctl(p->fd, BIOCSDLT, &dlt) == -1) { (void) snprintf(p->errbuf, sizeof(p->errbuf), "Cannot set DLT %d: %s", dlt, strerror(errno)); return (-1); } #endif return (0); } Index: user/syuu/mq_bpf/contrib/libpcap/pcap-int.h =================================================================== --- user/syuu/mq_bpf/contrib/libpcap/pcap-int.h (revision 255171) +++ user/syuu/mq_bpf/contrib/libpcap/pcap-int.h (revision 255172) @@ -1,516 +1,518 @@ /* * Copyright (c) 1994, 1995, 1996 * 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 the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#) $Header: /tcpdump/master/libpcap/pcap-int.h,v 1.94 2008-09-16 00:20:23 guy Exp $ (LBL) */ #ifndef pcap_int_h #define pcap_int_h #include #ifdef __cplusplus extern "C" { #endif #ifdef HAVE_LIBDLPI #include #endif #ifdef WIN32 #include extern CRITICAL_SECTION g_PcapCompileCriticalSection; #endif /* WIN32 */ #ifdef MSDOS #include #include #endif #ifdef HAVE_SNF_API #include #endif #if (defined(_MSC_VER) && (_MSC_VER <= 1200)) /* we are compiling with Visual Studio 6, that doesn't support the LL suffix*/ /* * Swap byte ordering of unsigned long long timestamp on a big endian * machine. */ #define SWAPLL(ull) ((ull & 0xff00000000000000) >> 56) | \ ((ull & 0x00ff000000000000) >> 40) | \ ((ull & 0x0000ff0000000000) >> 24) | \ ((ull & 0x000000ff00000000) >> 8) | \ ((ull & 0x00000000ff000000) << 8) | \ ((ull & 0x0000000000ff0000) << 24) | \ ((ull & 0x000000000000ff00) << 40) | \ ((ull & 0x00000000000000ff) << 56) #else /* A recent Visual studio compiler or not VC */ /* * Swap byte ordering of unsigned long long timestamp on a big endian * machine. */ #define SWAPLL(ull) ((ull & 0xff00000000000000LL) >> 56) | \ ((ull & 0x00ff000000000000LL) >> 40) | \ ((ull & 0x0000ff0000000000LL) >> 24) | \ ((ull & 0x000000ff00000000LL) >> 8) | \ ((ull & 0x00000000ff000000LL) << 8) | \ ((ull & 0x0000000000ff0000LL) << 24) | \ ((ull & 0x000000000000ff00LL) << 40) | \ ((ull & 0x00000000000000ffLL) << 56) #endif /* _MSC_VER */ /* * Savefile */ typedef enum { NOT_SWAPPED, SWAPPED, MAYBE_SWAPPED } swapped_type_t; /* * Used when reading a savefile. */ struct pcap_sf { FILE *rfile; int (*next_packet_op)(pcap_t *, struct pcap_pkthdr *, u_char **); int swapped; size_t hdrsize; swapped_type_t lengths_swapped; int version_major; int version_minor; bpf_u_int32 ifcount; /* number of interfaces seen in this capture */ u_int tsresol; /* time stamp resolution */ u_int tsscale; /* scaling factor for resolution -> microseconds */ u_int64_t tsoffset; /* time stamp offset */ }; /* * Used when doing a live capture. */ struct pcap_md { struct pcap_stat stat; /*XXX*/ int use_bpf; /* using kernel filter */ u_long TotPkts; /* can't oflow for 79 hrs on ether */ u_long TotAccepted; /* count accepted by filter */ u_long TotDrops; /* count of dropped packets */ long TotMissed; /* missed by i/f during this run */ long OrigMissed; /* missed by i/f before this run */ char *device; /* device name */ int timeout; /* timeout for buffering */ int must_do_on_close; /* stuff we must do when we close */ struct pcap *next; /* list of open pcaps that need stuff cleared on close */ #ifdef linux int sock_packet; /* using Linux 2.0 compatible interface */ int cooked; /* using SOCK_DGRAM rather than SOCK_RAW */ int ifindex; /* interface index of device we're bound to */ int lo_ifindex; /* interface index of the loopback device */ u_int packets_read; /* count of packets read with recvfrom() */ bpf_u_int32 oldmode; /* mode to restore when turning monitor mode off */ char *mondevice; /* mac80211 monitor device we created */ u_char *mmapbuf; /* memory-mapped region pointer */ size_t mmapbuflen; /* size of region */ int vlan_offset; /* offset at which to insert vlan tags; if -1, don't insert */ u_int tp_version; /* version of tpacket_hdr for mmaped ring */ u_int tp_hdrlen; /* hdrlen of tpacket_hdr for mmaped ring */ u_char *oneshot_buffer; /* buffer for copy of packet */ long proc_dropped; /* packets reported dropped by /proc/net/dev */ #endif /* linux */ #ifdef HAVE_DAG_API #ifdef HAVE_DAG_STREAMS_API u_char *dag_mem_bottom; /* DAG card current memory bottom pointer */ u_char *dag_mem_top; /* DAG card current memory top pointer */ #else /* HAVE_DAG_STREAMS_API */ void *dag_mem_base; /* DAG card memory base address */ u_int dag_mem_bottom; /* DAG card current memory bottom offset */ u_int dag_mem_top; /* DAG card current memory top offset */ #endif /* HAVE_DAG_STREAMS_API */ int dag_fcs_bits; /* Number of checksum bits from link layer */ int dag_offset_flags; /* Flags to pass to dag_offset(). */ int dag_stream; /* DAG stream number */ int dag_timeout; /* timeout specified to pcap_open_live. * Same as in linux above, introduce * generally? */ #endif /* HAVE_DAG_API */ #ifdef HAVE_SNF_API snf_handle_t snf_handle; /* opaque device handle */ snf_ring_t snf_ring; /* opaque device ring handle */ int snf_timeout; int snf_boardnum; #endif /*HAVE_SNF_API*/ #ifdef HAVE_ZEROCOPY_BPF /* * Zero-copy read buffer -- for zero-copy BPF. 'buffer' above will * alternative between these two actual mmap'd buffers as required. * As there is a header on the front size of the mmap'd buffer, only * some of the buffer is exposed to libpcap as a whole via bufsize; * zbufsize is the true size. zbuffer tracks the current zbuf * assocated with buffer so that it can be used to decide which the * next buffer to read will be. */ u_char *zbuf1, *zbuf2, *zbuffer; u_int zbufsize; u_int zerocopy; u_int interrupted; struct timespec firstsel; /* * If there's currently a buffer being actively processed, then it is * referenced here; 'buffer' is also pointed at it, but offset by the * size of the header. */ struct bpf_zbuf_header *bzh; #endif /* HAVE_ZEROCOPY_BPF */ }; /* * Stuff to do when we close. */ #define MUST_CLEAR_PROMISC 0x00000001 /* clear promiscuous mode */ #define MUST_CLEAR_RFMON 0x00000002 /* clear rfmon (monitor) mode */ #define MUST_DELETE_MONIF 0x00000004 /* delete monitor-mode interface */ struct pcap_opt { int buffer_size; char *source; int promisc; int rfmon; int tstamp_type; }; /* * Ultrix, DEC OSF/1^H^H^H^H^H^H^H^H^HDigital UNIX^H^H^H^H^H^H^H^H^H^H^H^H * Tru64 UNIX, and some versions of NetBSD pad FDDI packets to make everything * line up on a nice boundary. */ #ifdef __NetBSD__ #include /* needed to declare __NetBSD_Version__ */ #endif #if defined(ultrix) || defined(__osf__) || (defined(__NetBSD__) && __NetBSD_Version__ > 106000000) #define PCAP_FDDIPAD 3 #endif typedef int (*activate_op_t)(pcap_t *); typedef int (*can_set_rfmon_op_t)(pcap_t *); typedef int (*read_op_t)(pcap_t *, int cnt, pcap_handler, u_char *); typedef int (*inject_op_t)(pcap_t *, const void *, size_t); typedef int (*setfilter_op_t)(pcap_t *, struct bpf_program *); typedef int (*setdirection_op_t)(pcap_t *, pcap_direction_t); typedef int (*set_datalink_op_t)(pcap_t *, int); typedef int (*getnonblock_op_t)(pcap_t *, char *); typedef int (*setnonblock_op_t)(pcap_t *, int, char *); typedef int (*stats_op_t)(pcap_t *, struct pcap_stat *); #ifdef WIN32 typedef int (*setbuff_op_t)(pcap_t *, int); typedef int (*setmode_op_t)(pcap_t *, int); typedef int (*setmintocopy_op_t)(pcap_t *, int); #endif typedef void (*cleanup_op_t)(pcap_t *); struct pcap { #ifdef WIN32 ADAPTER *adapter; LPPACKET Packet; int nonblock; #else int fd; int selectable_fd; int send_fd; #endif /* WIN32 */ #ifdef HAVE_LIBDLPI dlpi_handle_t dlpi_hd; #endif int snapshot; int linktype; /* Network linktype */ int linktype_ext; /* Extended information stored in the linktype field of a file */ int tzoff; /* timezone offset */ int offset; /* offset for proper alignment */ int activated; /* true if the capture is really started */ int oldstyle; /* if we're opening with pcap_open_live() */ int break_loop; /* flag set to force break from packet-reading loop */ #ifdef PCAP_FDDIPAD int fddipad; #endif #ifdef MSDOS void (*wait_proc)(void); /* call proc while waiting */ #endif struct pcap_sf sf; struct pcap_md md; struct pcap_opt opt; /* * Read buffer. */ int bufsize; u_char *buffer; u_char *bp; int cc; /* * Place holder for pcap_next(). */ u_char *pkt; /* We're accepting only packets in this direction/these directions. */ pcap_direction_t direction; /* * Methods. */ activate_op_t activate_op; can_set_rfmon_op_t can_set_rfmon_op; read_op_t read_op; inject_op_t inject_op; setfilter_op_t setfilter_op; setdirection_op_t setdirection_op; set_datalink_op_t set_datalink_op; getnonblock_op_t getnonblock_op; setnonblock_op_t setnonblock_op; stats_op_t stats_op; /* * Routine to use as callback for pcap_next()/pcap_next_ex(). */ pcap_handler oneshot_callback; #ifdef WIN32 /* * These are, at least currently, specific to the Win32 NPF * driver. */ setbuff_op_t setbuff_op; setmode_op_t setmode_op; setmintocopy_op_t setmintocopy_op; #endif cleanup_op_t cleanup_op; /* * Placeholder for filter code if bpf not in kernel. */ struct bpf_program fcode; char errbuf[PCAP_ERRBUF_SIZE + 1]; int dlt_count; u_int *dlt_list; int tstamp_type_count; u_int *tstamp_type_list; struct pcap_pkthdr pcap_header; /* This is needed for the pcap_next_ex() to work */ - uint32_t rxq_num, txq_num; - uint32_t other_mask; + int qmask_enabled; + struct bpf_qmask_bits rxqmask; + struct bpf_qmask_bits txqmask; + int noqmask; }; /* * This is a timeval as stored in a savefile. * It has to use the same types everywhere, independent of the actual * `struct timeval'; `struct timeval' has 32-bit tv_sec values on some * platforms and 64-bit tv_sec values on other platforms, and writing * out native `struct timeval' values would mean files could only be * read on systems with the same tv_sec size as the system on which * the file was written. */ struct pcap_timeval { bpf_int32 tv_sec; /* seconds */ bpf_int32 tv_usec; /* microseconds */ }; /* * This is a `pcap_pkthdr' as actually stored in a savefile. * * Do not change the format of this structure, in any way (this includes * changes that only affect the length of fields in this structure), * and do not make the time stamp anything other than seconds and * microseconds (e.g., seconds and nanoseconds). Instead: * * introduce a new structure for the new format; * * send mail to "tcpdump-workers@lists.tcpdump.org", requesting * a new magic number for your new capture file format, and, when * you get the new magic number, put it in "savefile.c"; * * use that magic number for save files with the changed record * header; * * make the code in "savefile.c" capable of reading files with * the old record header as well as files with the new record header * (using the magic number to determine the header format). * * Then supply the changes by forking the branch at * * https://github.com/mcr/libpcap/issues * * and issuing a pull request, so that future versions of libpcap and * programs that use it (such as tcpdump) will be able to read your new * capture file format. */ struct pcap_sf_pkthdr { struct pcap_timeval ts; /* time stamp */ bpf_u_int32 caplen; /* length of portion present */ bpf_u_int32 len; /* length this packet (off wire) */ }; /* * How a `pcap_pkthdr' is actually stored in savefiles written * by some patched versions of libpcap (e.g. the ones in Red * Hat Linux 6.1 and 6.2). * * Do not change the format of this structure, in any way (this includes * changes that only affect the length of fields in this structure). * Instead, introduce a new structure, as per the above. */ struct pcap_sf_patched_pkthdr { struct pcap_timeval ts; /* time stamp */ bpf_u_int32 caplen; /* length of portion present */ bpf_u_int32 len; /* length this packet (off wire) */ int index; unsigned short protocol; unsigned char pkt_type; }; /* * User data structure for the one-shot callback used for pcap_next() * and pcap_next_ex(). */ struct oneshot_userdata { struct pcap_pkthdr *hdr; const u_char **pkt; pcap_t *pd; }; int yylex(void); #ifndef min #define min(a, b) ((a) > (b) ? (b) : (a)) #endif /* XXX should these be in pcap.h? */ int pcap_offline_read(pcap_t *, int, pcap_handler, u_char *); int pcap_read(pcap_t *, int cnt, pcap_handler, u_char *); #ifndef HAVE_STRLCPY #define strlcpy(x, y, z) \ (strncpy((x), (y), (z)), \ ((z) <= 0 ? 0 : ((x)[(z) - 1] = '\0')), \ strlen((y))) #endif #include #if !defined(HAVE_SNPRINTF) #define snprintf pcap_snprintf extern int snprintf (char *, size_t, const char *, ...); #endif #if !defined(HAVE_VSNPRINTF) #define vsnprintf pcap_vsnprintf extern int vsnprintf (char *, size_t, const char *, va_list ap); #endif /* * Routines that most pcap implementations can use for non-blocking mode. */ #if !defined(WIN32) && !defined(MSDOS) int pcap_getnonblock_fd(pcap_t *, char *); int pcap_setnonblock_fd(pcap_t *p, int, char *); #endif /* * Internal interfaces for "pcap_create()". * * "pcap_create_interface()" is the routine to do a pcap_create on * a regular network interface. There are multiple implementations * of this, one for each platform type (Linux, BPF, DLPI, etc.), * with the one used chosen by the configure script. * * "pcap_create_common()" allocates and fills in a pcap_t, for use * by pcap_create routines. */ pcap_t *pcap_create_interface(const char *, char *); pcap_t *pcap_create_common(const char *, char *); int pcap_do_addexit(pcap_t *); void pcap_add_to_pcaps_to_close(pcap_t *); void pcap_remove_from_pcaps_to_close(pcap_t *); void pcap_cleanup_live_common(pcap_t *); int pcap_not_initialized(pcap_t *); int pcap_check_activated(pcap_t *); /* * Internal interfaces for "pcap_findalldevs()". * * "pcap_findalldevs_interfaces()" finds interfaces using the * "standard" mechanisms (SIOCGIFCONF, "getifaddrs()", etc.). * * "pcap_platform_finddevs()" is a platform-dependent routine to * add devices not found by the "standard" mechanisms. * * "pcap_add_if()" adds an interface to the list of interfaces, for * use by various "find interfaces" routines. */ int pcap_findalldevs_interfaces(pcap_if_t **, char *); int pcap_platform_finddevs(pcap_if_t **, char *); int add_addr_to_iflist(pcap_if_t **, const char *, u_int, struct sockaddr *, size_t, struct sockaddr *, size_t, struct sockaddr *, size_t, struct sockaddr *, size_t, char *); int pcap_add_if(pcap_if_t **, const char *, u_int, const char *, char *); struct sockaddr *dup_sockaddr(struct sockaddr *, size_t); int add_or_find_if(pcap_if_t **, pcap_if_t **, const char *, u_int, const char *, char *); #ifdef WIN32 char *pcap_win32strerror(void); #endif int install_bpf_program(pcap_t *, struct bpf_program *); int pcap_strcasecmp(const char *, const char *); #ifdef __cplusplus } #endif #endif Index: user/syuu/mq_bpf/contrib/libpcap/pcap.c =================================================================== --- user/syuu/mq_bpf/contrib/libpcap/pcap.c (revision 255171) +++ user/syuu/mq_bpf/contrib/libpcap/pcap.c (revision 255172) @@ -1,1838 +1,1878 @@ /* * Copyright (c) 1993, 1994, 1995, 1996, 1997, 1998 * 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 the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char rcsid[] _U_ = "@(#) $Header: /tcpdump/master/libpcap/pcap.c,v 1.128 2008-12-23 20:13:29 guy Exp $ (LBL)"; #endif #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef WIN32 #include #else /* WIN32 */ #if HAVE_INTTYPES_H #include #elif HAVE_STDINT_H #include #endif #ifdef HAVE_SYS_BITYPES_H #include #endif #include #include #endif /* WIN32 */ #include #include #include #if !defined(_MSC_VER) && !defined(__BORLANDC__) && !defined(__MINGW32__) #include #endif #include #include #ifdef HAVE_OS_PROTO_H #include "os-proto.h" #endif #ifdef MSDOS #include "pcap-dos.h" #endif #include "pcap-int.h" #ifdef HAVE_DAG_API #include "pcap-dag.h" #endif /* HAVE_DAG_API */ #ifdef HAVE_SEPTEL_API #include "pcap-septel.h" #endif /* HAVE_SEPTEL_API */ #ifdef HAVE_SNF_API #include "pcap-snf.h" #endif /* HAVE_SNF_API */ #ifdef PCAP_SUPPORT_USB #include "pcap-usb-linux.h" #endif #ifdef PCAP_SUPPORT_BT #include "pcap-bt-linux.h" #endif #ifdef PCAP_SUPPORT_CAN #include "pcap-can-linux.h" #endif #ifdef PCAP_SUPPORT_CANUSB #include "pcap-canusb-linux.h" #endif #ifdef PCAP_SUPPORT_NETFILTER #include "pcap-netfilter-linux.h" #endif int pcap_not_initialized(pcap_t *pcap) { /* this means 'not initialized' */ return (PCAP_ERROR_NOT_ACTIVATED); } /* * Returns 1 if rfmon mode can be set on the pcap_t, 0 if it can't, * a PCAP_ERROR value on an error. */ int pcap_can_set_rfmon(pcap_t *p) { return (p->can_set_rfmon_op(p)); } /* * For systems where rfmon mode is never supported. */ static int pcap_cant_set_rfmon(pcap_t *p _U_) { return (0); } /* * Sets *tstamp_typesp to point to an array 1 or more supported time stamp * types; the return value is the number of supported time stamp types. * The list should be freed by a call to pcap_free_tstamp_types() when * you're done with it. * * A return value of 0 means "you don't get a choice of time stamp type", * in which case *tstamp_typesp is set to null. * * PCAP_ERROR is returned on error. */ int pcap_list_tstamp_types(pcap_t *p, int **tstamp_typesp) { if (p->tstamp_type_count == 0) { /* * We don't support multiple time stamp types. */ *tstamp_typesp = NULL; } else { *tstamp_typesp = (int*)calloc(sizeof(**tstamp_typesp), p->tstamp_type_count); if (*tstamp_typesp == NULL) { (void)snprintf(p->errbuf, sizeof(p->errbuf), "malloc: %s", pcap_strerror(errno)); return (PCAP_ERROR); } (void)memcpy(*tstamp_typesp, p->tstamp_type_list, sizeof(**tstamp_typesp) * p->tstamp_type_count); } return (p->tstamp_type_count); } /* * In Windows, you might have a library built with one version of the * C runtime library and an application built with another version of * the C runtime library, which means that the library might use one * version of malloc() and free() and the application might use another * version of malloc() and free(). If so, that means something * allocated by the library cannot be freed by the application, so we * need to have a pcap_free_tstamp_types() routine to free up the list * allocated by pcap_list_tstamp_types(), even though it's just a wrapper * around free(). */ void pcap_free_tstamp_types(int *tstamp_type_list) { free(tstamp_type_list); } /* * Default one-shot callback; overridden for capture types where the * packet data cannot be guaranteed to be available after the callback * returns, so that a copy must be made. */ static void pcap_oneshot(u_char *user, const struct pcap_pkthdr *h, const u_char *pkt) { struct oneshot_userdata *sp = (struct oneshot_userdata *)user; *sp->hdr = *h; *sp->pkt = pkt; } const u_char * pcap_next(pcap_t *p, struct pcap_pkthdr *h) { struct oneshot_userdata s; const u_char *pkt; s.hdr = h; s.pkt = &pkt; s.pd = p; if (pcap_dispatch(p, 1, p->oneshot_callback, (u_char *)&s) <= 0) return (0); return (pkt); } int pcap_next_ex(pcap_t *p, struct pcap_pkthdr **pkt_header, const u_char **pkt_data) { struct oneshot_userdata s; s.hdr = &p->pcap_header; s.pkt = pkt_data; s.pd = p; /* Saves a pointer to the packet headers */ *pkt_header= &p->pcap_header; if (p->sf.rfile != NULL) { int status; /* We are on an offline capture */ status = pcap_offline_read(p, 1, p->oneshot_callback, (u_char *)&s); /* * Return codes for pcap_offline_read() are: * - 0: EOF * - -1: error * - >1: OK * The first one ('0') conflicts with the return code of * 0 from pcap_read() meaning "no packets arrived before * the timeout expired", so we map it to -2 so you can * distinguish between an EOF from a savefile and a * "no packets arrived before the timeout expired, try * again" from a live capture. */ if (status == 0) return (-2); else return (status); } /* * Return codes for pcap_read() are: * - 0: timeout * - -1: error * - -2: loop was broken out of with pcap_breakloop() * - >1: OK * The first one ('0') conflicts with the return code of 0 from * pcap_offline_read() meaning "end of file". */ return (p->read_op(p, 1, p->oneshot_callback, (u_char *)&s)); } #if defined(DAG_ONLY) int pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf) { return (dag_findalldevs(alldevsp, errbuf)); } pcap_t * pcap_create(const char *source, char *errbuf) { return (dag_create(source, errbuf)); } #elif defined(SEPTEL_ONLY) int pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf) { return (septel_findalldevs(alldevsp, errbuf)); } pcap_t * pcap_create(const char *source, char *errbuf) { return (septel_create(source, errbuf)); } #elif defined(SNF_ONLY) int pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf) { return (snf_findalldevs(alldevsp, errbuf)); } pcap_t * pcap_create(const char *source, char *errbuf) { return (snf_create(source, errbuf)); } #else /* regular pcap */ struct capture_source_type { int (*findalldevs_op)(pcap_if_t **, char *); pcap_t *(*create_op)(const char *, char *, int *); } capture_source_types[] = { #ifdef HAVE_DAG_API { dag_findalldevs, dag_create }, #endif #ifdef HAVE_SEPTEL_API { septel_findalldevs, septel_create }, #endif #ifdef HAVE_SNF_API { snf_findalldevs, snf_create }, #endif #ifdef PCAP_SUPPORT_BT { bt_findalldevs, bt_create }, #endif #if PCAP_SUPPORT_CANUSB { canusb_findalldevs, canusb_create }, #endif #ifdef PCAP_SUPPORT_CAN { can_findalldevs, can_create }, #endif #ifdef PCAP_SUPPORT_USB { usb_findalldevs, usb_create }, #endif #ifdef PCAP_SUPPORT_NETFILTER { netfilter_findalldevs, netfilter_create }, #endif { NULL, NULL } }; /* * Get a list of all capture sources that are up and that we can open. * Returns -1 on error, 0 otherwise. * The list, as returned through "alldevsp", may be null if no interfaces * were up and could be opened. */ int pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf) { size_t i; /* * Get the list of regular interfaces first. */ if (pcap_findalldevs_interfaces(alldevsp, errbuf) == -1) return (-1); /* failure */ /* * Add any interfaces that need a platform-specific mechanism * to find. */ if (pcap_platform_finddevs(alldevsp, errbuf) == -1) { /* * We had an error; free the list we've been * constructing. */ if (*alldevsp != NULL) { pcap_freealldevs(*alldevsp); *alldevsp = NULL; } return (-1); } /* * Ask each of the non-local-network-interface capture * source types what interfaces they have. */ for (i = 0; capture_source_types[i].findalldevs_op != NULL; i++) { if (capture_source_types[i].findalldevs_op(alldevsp, errbuf) == -1) { /* * We had an error; free the list we've been * constructing. */ if (*alldevsp != NULL) { pcap_freealldevs(*alldevsp); *alldevsp = NULL; } return (-1); } } return (0); } pcap_t * pcap_create(const char *source, char *errbuf) { size_t i; int is_theirs; pcap_t *p; /* * A null source name is equivalent to the "any" device - * which might not be supported on this platform, but * this means that you'll get a "not supported" error * rather than, say, a crash when we try to dereference * the null pointer. */ if (source == NULL) source = "any"; /* * Try each of the non-local-network-interface capture * source types until we find one that works for this * device or run out of types. */ for (i = 0; capture_source_types[i].create_op != NULL; i++) { is_theirs = 0; p = capture_source_types[i].create_op(source, errbuf, &is_theirs); if (is_theirs) { /* * The device name refers to a device of the * type in question; either it succeeded, * in which case p refers to a pcap_t to * later activate for the device, or it * failed, in which case p is null and we * should return that to report the failure * to create. */ return (p); } } /* * OK, try it as a regular network interface. */ return (pcap_create_interface(source, errbuf)); } #endif static void initialize_ops(pcap_t *p) { /* * Set operation pointers for operations that only work on * an activated pcap_t to point to a routine that returns * a "this isn't activated" error. */ p->read_op = (read_op_t)pcap_not_initialized; p->inject_op = (inject_op_t)pcap_not_initialized; p->setfilter_op = (setfilter_op_t)pcap_not_initialized; p->setdirection_op = (setdirection_op_t)pcap_not_initialized; p->set_datalink_op = (set_datalink_op_t)pcap_not_initialized; p->getnonblock_op = (getnonblock_op_t)pcap_not_initialized; p->setnonblock_op = (setnonblock_op_t)pcap_not_initialized; p->stats_op = (stats_op_t)pcap_not_initialized; #ifdef WIN32 p->setbuff_op = (setbuff_op_t)pcap_not_initialized; p->setmode_op = (setmode_op_t)pcap_not_initialized; p->setmintocopy_op = (setmintocopy_op_t)pcap_not_initialized; #endif /* * Default cleanup operation - implementations can override * this, but should call pcap_cleanup_live_common() after * doing their own additional cleanup. */ p->cleanup_op = pcap_cleanup_live_common; /* * In most cases, the standard one-short callback can * be used for pcap_next()/pcap_next_ex(). */ p->oneshot_callback = pcap_oneshot; } pcap_t * pcap_create_common(const char *source, char *ebuf) { pcap_t *p; p = malloc(sizeof(*p)); if (p == NULL) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); return (NULL); } memset(p, 0, sizeof(*p)); #ifndef WIN32 p->fd = -1; /* not opened yet */ p->selectable_fd = -1; p->send_fd = -1; #endif p->opt.source = strdup(source); if (p->opt.source == NULL) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); free(p); return (NULL); } /* * Default to "can't set rfmon mode"; if it's supported by * a platform, the create routine that called us can set * the op to its routine to check whether a particular * device supports it. */ p->can_set_rfmon_op = pcap_cant_set_rfmon; initialize_ops(p); /* put in some defaults*/ pcap_set_timeout(p, 0); pcap_set_snaplen(p, 65535); /* max packet size */ p->opt.promisc = 0; p->opt.buffer_size = 0; p->opt.tstamp_type = -1; /* default to not setting time stamp type */ - p->rxq_num = (uint32_t)-1; - p->txq_num = (uint32_t)-1; - p->other_mask = (uint32_t)-1; + p->qmask_enabled = 0; return (p); } int pcap_check_activated(pcap_t *p) { if (p->activated) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "can't perform " " operation on activated capture"); return (-1); } return (0); } int pcap_set_snaplen(pcap_t *p, int snaplen) { if (pcap_check_activated(p)) return (PCAP_ERROR_ACTIVATED); p->snapshot = snaplen; return (0); } int pcap_set_promisc(pcap_t *p, int promisc) { if (pcap_check_activated(p)) return (PCAP_ERROR_ACTIVATED); p->opt.promisc = promisc; return (0); } int pcap_set_rfmon(pcap_t *p, int rfmon) { if (pcap_check_activated(p)) return (PCAP_ERROR_ACTIVATED); p->opt.rfmon = rfmon; return (0); } int pcap_set_timeout(pcap_t *p, int timeout_ms) { if (pcap_check_activated(p)) return (PCAP_ERROR_ACTIVATED); p->md.timeout = timeout_ms; return (0); } int pcap_set_tstamp_type(pcap_t *p, int tstamp_type) { int i; if (pcap_check_activated(p)) return (PCAP_ERROR_ACTIVATED); /* * If p->tstamp_type_count is 0, we don't support setting * the time stamp type at all. */ if (p->tstamp_type_count == 0) return (PCAP_ERROR_CANTSET_TSTAMP_TYPE); /* * Check whether we claim to support this type of time stamp. */ for (i = 0; i < p->tstamp_type_count; i++) { if (p->tstamp_type_list[i] == tstamp_type) { /* * Yes. */ p->opt.tstamp_type = tstamp_type; return (0); } } /* * No. We support setting the time stamp type, but not to this * particular value. */ return (PCAP_WARNING_TSTAMP_TYPE_NOTSUP); } int pcap_set_buffer_size(pcap_t *p, int buffer_size) { if (pcap_check_activated(p)) return (PCAP_ERROR_ACTIVATED); p->opt.buffer_size = buffer_size; return (0); } int pcap_activate(pcap_t *p) { int status; /* * Catch attempts to re-activate an already-activated * pcap_t; this should, for example, catch code that * calls pcap_open_live() followed by pcap_activate(), * as some code that showed up in a Stack Exchange * question did. */ if (pcap_check_activated(p)) return (PCAP_ERROR_ACTIVATED); status = p->activate_op(p); if (status >= 0) p->activated = 1; else { if (p->errbuf[0] == '\0') { /* * No error message supplied by the activate routine; * for the benefit of programs that don't specially * handle errors other than PCAP_ERROR, return the * error message corresponding to the status. */ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s", pcap_statustostr(status)); } /* * Undo any operation pointer setting, etc. done by * the activate operation. */ initialize_ops(p); } return (status); } int -pcap_set_rxq_mask(pcap_t *p, uint32_t num) +pcap_enable_qmask(pcap_t *p) { + p->qmask_enabled = 1; + BPFQ_ZERO(&p->rxqmask); + BPFQ_ZERO(&p->txqmask); + p->noqmask = 0; +} + +int +pcap_disable_qmask(pcap_t *p) +{ + p->qmask_enabled = 0; +} + +int +pcap_set_rxqmask(pcap_t *p, u_int queueid) +{ if (pcap_check_activated(p)) return PCAP_ERROR_ACTIVATED; - p->rxq_num = num; + BPFQ_SET(queueid, &p->rxqmask); return 0; } int -pcap_set_txq_mask(pcap_t *p, uint32_t num) +pcap_clear_rxqmask(pcap_t *p, u_int queueid) { if (pcap_check_activated(p)) return PCAP_ERROR_ACTIVATED; - p->txq_num = num; + BPFQ_CLR(queueid, &p->rxqmask); return 0; } int -pcap_set_other_mask(pcap_t *p, uint32_t mask) +pcap_set_txqmask(pcap_t *p, u_int queueid) { if (pcap_check_activated(p)) return PCAP_ERROR_ACTIVATED; - p->other_mask = mask; + BPFQ_SET(queueid, &p->txqmask); + return 0; +} + +int +pcap_clear_txqmask(pcap_t *p, u_int queueid) +{ + if (pcap_check_activated(p)) + return PCAP_ERROR_ACTIVATED; + BPFQ_CLR(queueid, &p->txqmask); + return 0; +} + +int +pcap_set_noqmask(pcap_t *p) +{ + if (pcap_check_activated(p)) + return PCAP_ERROR_ACTIVATED; + p->noqmask = 1; + return 0; +} + +int +pcap_clear_noqmask(pcap_t *p) +{ + if (pcap_check_activated(p)) + return PCAP_ERROR_ACTIVATED; + p->noqmask = 0; return 0; } pcap_t * pcap_open_live(const char *source, int snaplen, int promisc, int to_ms, char *errbuf) { pcap_t *p; int status; p = pcap_create(source, errbuf); if (p == NULL) return (NULL); status = pcap_set_snaplen(p, snaplen); if (status < 0) goto fail; status = pcap_set_promisc(p, promisc); if (status < 0) goto fail; status = pcap_set_timeout(p, to_ms); if (status < 0) goto fail; /* * Mark this as opened with pcap_open_live(), so that, for * example, we show the full list of DLT_ values, rather * than just the ones that are compatible with capturing * when not in monitor mode. That allows existing applications * to work the way they used to work, but allows new applications * that know about the new open API to, for example, find out the * DLT_ values that they can select without changing whether * the adapter is in monitor mode or not. */ p->oldstyle = 1; status = pcap_activate(p); if (status < 0) goto fail; return (p); fail: if (status == PCAP_ERROR) snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", source, p->errbuf); else if (status == PCAP_ERROR_NO_SUCH_DEVICE || status == PCAP_ERROR_PERM_DENIED || status == PCAP_ERROR_PROMISC_PERM_DENIED) snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s (%s)", source, pcap_statustostr(status), p->errbuf); else snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", source, pcap_statustostr(status)); pcap_close(p); return (NULL); } int pcap_dispatch(pcap_t *p, int cnt, pcap_handler callback, u_char *user) { return (p->read_op(p, cnt, callback, user)); } /* * XXX - is this necessary? */ int pcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) { return (p->read_op(p, cnt, callback, user)); } int pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user) { register int n; for (;;) { if (p->sf.rfile != NULL) { /* * 0 means EOF, so don't loop if we get 0. */ n = pcap_offline_read(p, cnt, callback, user); } else { /* * XXX keep reading until we get something * (or an error occurs) */ do { n = p->read_op(p, cnt, callback, user); } while (n == 0); } if (n <= 0) return (n); if (cnt > 0) { cnt -= n; if (cnt <= 0) return (0); } } } /* * Force the loop in "pcap_read()" or "pcap_read_offline()" to terminate. */ void pcap_breakloop(pcap_t *p) { p->break_loop = 1; } int pcap_datalink(pcap_t *p) { return (p->linktype); } int pcap_datalink_ext(pcap_t *p) { return (p->linktype_ext); } int pcap_list_datalinks(pcap_t *p, int **dlt_buffer) { if (p->dlt_count == 0) { /* * We couldn't fetch the list of DLTs, which means * this platform doesn't support changing the * DLT for an interface. Return a list of DLTs * containing only the DLT this device supports. */ *dlt_buffer = (int*)malloc(sizeof(**dlt_buffer)); if (*dlt_buffer == NULL) { (void)snprintf(p->errbuf, sizeof(p->errbuf), "malloc: %s", pcap_strerror(errno)); return (-1); } **dlt_buffer = p->linktype; return (1); } else { *dlt_buffer = (int*)calloc(sizeof(**dlt_buffer), p->dlt_count); if (*dlt_buffer == NULL) { (void)snprintf(p->errbuf, sizeof(p->errbuf), "malloc: %s", pcap_strerror(errno)); return (-1); } (void)memcpy(*dlt_buffer, p->dlt_list, sizeof(**dlt_buffer) * p->dlt_count); return (p->dlt_count); } } /* * In Windows, you might have a library built with one version of the * C runtime library and an application built with another version of * the C runtime library, which means that the library might use one * version of malloc() and free() and the application might use another * version of malloc() and free(). If so, that means something * allocated by the library cannot be freed by the application, so we * need to have a pcap_free_datalinks() routine to free up the list * allocated by pcap_list_datalinks(), even though it's just a wrapper * around free(). */ void pcap_free_datalinks(int *dlt_list) { free(dlt_list); } int pcap_set_datalink(pcap_t *p, int dlt) { int i; const char *dlt_name; if (p->dlt_count == 0 || p->set_datalink_op == NULL) { /* * We couldn't fetch the list of DLTs, or we don't * have a "set datalink" operation, which means * this platform doesn't support changing the * DLT for an interface. Check whether the new * DLT is the one this interface supports. */ if (p->linktype != dlt) goto unsupported; /* * It is, so there's nothing we need to do here. */ return (0); } for (i = 0; i < p->dlt_count; i++) if (p->dlt_list[i] == dlt) break; if (i >= p->dlt_count) goto unsupported; if (p->dlt_count == 2 && p->dlt_list[0] == DLT_EN10MB && dlt == DLT_DOCSIS) { /* * This is presumably an Ethernet device, as the first * link-layer type it offers is DLT_EN10MB, and the only * other type it offers is DLT_DOCSIS. That means that * we can't tell the driver to supply DOCSIS link-layer * headers - we're just pretending that's what we're * getting, as, presumably, we're capturing on a dedicated * link to a Cisco Cable Modem Termination System, and * it's putting raw DOCSIS frames on the wire inside low-level * Ethernet framing. */ p->linktype = dlt; return (0); } if (p->set_datalink_op(p, dlt) == -1) return (-1); p->linktype = dlt; return (0); unsupported: dlt_name = pcap_datalink_val_to_name(dlt); if (dlt_name != NULL) { (void) snprintf(p->errbuf, sizeof(p->errbuf), "%s is not one of the DLTs supported by this device", dlt_name); } else { (void) snprintf(p->errbuf, sizeof(p->errbuf), "DLT %d is not one of the DLTs supported by this device", dlt); } return (-1); } /* * This array is designed for mapping upper and lower case letter * together for a case independent comparison. The mappings are * based upon ascii character sequences. */ static const u_char charmap[] = { (u_char)'\000', (u_char)'\001', (u_char)'\002', (u_char)'\003', (u_char)'\004', (u_char)'\005', (u_char)'\006', (u_char)'\007', (u_char)'\010', (u_char)'\011', (u_char)'\012', (u_char)'\013', (u_char)'\014', (u_char)'\015', (u_char)'\016', (u_char)'\017', (u_char)'\020', (u_char)'\021', (u_char)'\022', (u_char)'\023', (u_char)'\024', (u_char)'\025', (u_char)'\026', (u_char)'\027', (u_char)'\030', (u_char)'\031', (u_char)'\032', (u_char)'\033', (u_char)'\034', (u_char)'\035', (u_char)'\036', (u_char)'\037', (u_char)'\040', (u_char)'\041', (u_char)'\042', (u_char)'\043', (u_char)'\044', (u_char)'\045', (u_char)'\046', (u_char)'\047', (u_char)'\050', (u_char)'\051', (u_char)'\052', (u_char)'\053', (u_char)'\054', (u_char)'\055', (u_char)'\056', (u_char)'\057', (u_char)'\060', (u_char)'\061', (u_char)'\062', (u_char)'\063', (u_char)'\064', (u_char)'\065', (u_char)'\066', (u_char)'\067', (u_char)'\070', (u_char)'\071', (u_char)'\072', (u_char)'\073', (u_char)'\074', (u_char)'\075', (u_char)'\076', (u_char)'\077', (u_char)'\100', (u_char)'\141', (u_char)'\142', (u_char)'\143', (u_char)'\144', (u_char)'\145', (u_char)'\146', (u_char)'\147', (u_char)'\150', (u_char)'\151', (u_char)'\152', (u_char)'\153', (u_char)'\154', (u_char)'\155', (u_char)'\156', (u_char)'\157', (u_char)'\160', (u_char)'\161', (u_char)'\162', (u_char)'\163', (u_char)'\164', (u_char)'\165', (u_char)'\166', (u_char)'\167', (u_char)'\170', (u_char)'\171', (u_char)'\172', (u_char)'\133', (u_char)'\134', (u_char)'\135', (u_char)'\136', (u_char)'\137', (u_char)'\140', (u_char)'\141', (u_char)'\142', (u_char)'\143', (u_char)'\144', (u_char)'\145', (u_char)'\146', (u_char)'\147', (u_char)'\150', (u_char)'\151', (u_char)'\152', (u_char)'\153', (u_char)'\154', (u_char)'\155', (u_char)'\156', (u_char)'\157', (u_char)'\160', (u_char)'\161', (u_char)'\162', (u_char)'\163', (u_char)'\164', (u_char)'\165', (u_char)'\166', (u_char)'\167', (u_char)'\170', (u_char)'\171', (u_char)'\172', (u_char)'\173', (u_char)'\174', (u_char)'\175', (u_char)'\176', (u_char)'\177', (u_char)'\200', (u_char)'\201', (u_char)'\202', (u_char)'\203', (u_char)'\204', (u_char)'\205', (u_char)'\206', (u_char)'\207', (u_char)'\210', (u_char)'\211', (u_char)'\212', (u_char)'\213', (u_char)'\214', (u_char)'\215', (u_char)'\216', (u_char)'\217', (u_char)'\220', (u_char)'\221', (u_char)'\222', (u_char)'\223', (u_char)'\224', (u_char)'\225', (u_char)'\226', (u_char)'\227', (u_char)'\230', (u_char)'\231', (u_char)'\232', (u_char)'\233', (u_char)'\234', (u_char)'\235', (u_char)'\236', (u_char)'\237', (u_char)'\240', (u_char)'\241', (u_char)'\242', (u_char)'\243', (u_char)'\244', (u_char)'\245', (u_char)'\246', (u_char)'\247', (u_char)'\250', (u_char)'\251', (u_char)'\252', (u_char)'\253', (u_char)'\254', (u_char)'\255', (u_char)'\256', (u_char)'\257', (u_char)'\260', (u_char)'\261', (u_char)'\262', (u_char)'\263', (u_char)'\264', (u_char)'\265', (u_char)'\266', (u_char)'\267', (u_char)'\270', (u_char)'\271', (u_char)'\272', (u_char)'\273', (u_char)'\274', (u_char)'\275', (u_char)'\276', (u_char)'\277', (u_char)'\300', (u_char)'\341', (u_char)'\342', (u_char)'\343', (u_char)'\344', (u_char)'\345', (u_char)'\346', (u_char)'\347', (u_char)'\350', (u_char)'\351', (u_char)'\352', (u_char)'\353', (u_char)'\354', (u_char)'\355', (u_char)'\356', (u_char)'\357', (u_char)'\360', (u_char)'\361', (u_char)'\362', (u_char)'\363', (u_char)'\364', (u_char)'\365', (u_char)'\366', (u_char)'\367', (u_char)'\370', (u_char)'\371', (u_char)'\372', (u_char)'\333', (u_char)'\334', (u_char)'\335', (u_char)'\336', (u_char)'\337', (u_char)'\340', (u_char)'\341', (u_char)'\342', (u_char)'\343', (u_char)'\344', (u_char)'\345', (u_char)'\346', (u_char)'\347', (u_char)'\350', (u_char)'\351', (u_char)'\352', (u_char)'\353', (u_char)'\354', (u_char)'\355', (u_char)'\356', (u_char)'\357', (u_char)'\360', (u_char)'\361', (u_char)'\362', (u_char)'\363', (u_char)'\364', (u_char)'\365', (u_char)'\366', (u_char)'\367', (u_char)'\370', (u_char)'\371', (u_char)'\372', (u_char)'\373', (u_char)'\374', (u_char)'\375', (u_char)'\376', (u_char)'\377', }; int pcap_strcasecmp(const char *s1, const char *s2) { register const u_char *cm = charmap, *us1 = (const u_char *)s1, *us2 = (const u_char *)s2; while (cm[*us1] == cm[*us2++]) if (*us1++ == '\0') return(0); return (cm[*us1] - cm[*--us2]); } struct dlt_choice { const char *name; const char *description; int dlt; }; #define DLT_CHOICE(code, description) { #code, description, code } #define DLT_CHOICE_SENTINEL { NULL, NULL, 0 } static struct dlt_choice dlt_choices[] = { DLT_CHOICE(DLT_NULL, "BSD loopback"), DLT_CHOICE(DLT_EN10MB, "Ethernet"), DLT_CHOICE(DLT_IEEE802, "Token ring"), DLT_CHOICE(DLT_ARCNET, "BSD ARCNET"), DLT_CHOICE(DLT_SLIP, "SLIP"), DLT_CHOICE(DLT_PPP, "PPP"), DLT_CHOICE(DLT_FDDI, "FDDI"), DLT_CHOICE(DLT_ATM_RFC1483, "RFC 1483 LLC-encapsulated ATM"), DLT_CHOICE(DLT_RAW, "Raw IP"), DLT_CHOICE(DLT_SLIP_BSDOS, "BSD/OS SLIP"), DLT_CHOICE(DLT_PPP_BSDOS, "BSD/OS PPP"), DLT_CHOICE(DLT_ATM_CLIP, "Linux Classical IP-over-ATM"), DLT_CHOICE(DLT_PPP_SERIAL, "PPP over serial"), DLT_CHOICE(DLT_PPP_ETHER, "PPPoE"), DLT_CHOICE(DLT_SYMANTEC_FIREWALL, "Symantec Firewall"), DLT_CHOICE(DLT_C_HDLC, "Cisco HDLC"), DLT_CHOICE(DLT_IEEE802_11, "802.11"), DLT_CHOICE(DLT_FRELAY, "Frame Relay"), DLT_CHOICE(DLT_LOOP, "OpenBSD loopback"), DLT_CHOICE(DLT_ENC, "OpenBSD encapsulated IP"), DLT_CHOICE(DLT_LINUX_SLL, "Linux cooked"), DLT_CHOICE(DLT_LTALK, "Localtalk"), DLT_CHOICE(DLT_PFLOG, "OpenBSD pflog file"), DLT_CHOICE(DLT_PFSYNC, "Packet filter state syncing"), DLT_CHOICE(DLT_PRISM_HEADER, "802.11 plus Prism header"), DLT_CHOICE(DLT_IP_OVER_FC, "RFC 2625 IP-over-Fibre Channel"), DLT_CHOICE(DLT_SUNATM, "Sun raw ATM"), DLT_CHOICE(DLT_IEEE802_11_RADIO, "802.11 plus radiotap header"), DLT_CHOICE(DLT_ARCNET_LINUX, "Linux ARCNET"), DLT_CHOICE(DLT_JUNIPER_MLPPP, "Juniper Multi-Link PPP"), DLT_CHOICE(DLT_JUNIPER_MLFR, "Juniper Multi-Link Frame Relay"), DLT_CHOICE(DLT_JUNIPER_ES, "Juniper Encryption Services PIC"), DLT_CHOICE(DLT_JUNIPER_GGSN, "Juniper GGSN PIC"), DLT_CHOICE(DLT_JUNIPER_MFR, "Juniper FRF.16 Frame Relay"), DLT_CHOICE(DLT_JUNIPER_ATM2, "Juniper ATM2 PIC"), DLT_CHOICE(DLT_JUNIPER_SERVICES, "Juniper Advanced Services PIC"), DLT_CHOICE(DLT_JUNIPER_ATM1, "Juniper ATM1 PIC"), DLT_CHOICE(DLT_APPLE_IP_OVER_IEEE1394, "Apple IP-over-IEEE 1394"), DLT_CHOICE(DLT_MTP2_WITH_PHDR, "SS7 MTP2 with Pseudo-header"), DLT_CHOICE(DLT_MTP2, "SS7 MTP2"), DLT_CHOICE(DLT_MTP3, "SS7 MTP3"), DLT_CHOICE(DLT_SCCP, "SS7 SCCP"), DLT_CHOICE(DLT_DOCSIS, "DOCSIS"), DLT_CHOICE(DLT_LINUX_IRDA, "Linux IrDA"), DLT_CHOICE(DLT_IEEE802_11_RADIO_AVS, "802.11 plus AVS radio information header"), DLT_CHOICE(DLT_JUNIPER_MONITOR, "Juniper Passive Monitor PIC"), DLT_CHOICE(DLT_PPP_PPPD, "PPP for pppd, with direction flag"), DLT_CHOICE(DLT_JUNIPER_PPPOE, "Juniper PPPoE"), DLT_CHOICE(DLT_JUNIPER_PPPOE_ATM, "Juniper PPPoE/ATM"), DLT_CHOICE(DLT_GPRS_LLC, "GPRS LLC"), DLT_CHOICE(DLT_GPF_T, "GPF-T"), DLT_CHOICE(DLT_GPF_F, "GPF-F"), DLT_CHOICE(DLT_JUNIPER_PIC_PEER, "Juniper PIC Peer"), DLT_CHOICE(DLT_ERF_ETH, "Ethernet with Endace ERF header"), DLT_CHOICE(DLT_ERF_POS, "Packet-over-SONET with Endace ERF header"), DLT_CHOICE(DLT_LINUX_LAPD, "Linux vISDN LAPD"), DLT_CHOICE(DLT_JUNIPER_ETHER, "Juniper Ethernet"), DLT_CHOICE(DLT_JUNIPER_PPP, "Juniper PPP"), DLT_CHOICE(DLT_JUNIPER_FRELAY, "Juniper Frame Relay"), DLT_CHOICE(DLT_JUNIPER_CHDLC, "Juniper C-HDLC"), DLT_CHOICE(DLT_MFR, "FRF.16 Frame Relay"), DLT_CHOICE(DLT_JUNIPER_VP, "Juniper Voice PIC"), DLT_CHOICE(DLT_A429, "Arinc 429"), DLT_CHOICE(DLT_A653_ICM, "Arinc 653 Interpartition Communication"), DLT_CHOICE(DLT_USB, "USB"), DLT_CHOICE(DLT_BLUETOOTH_HCI_H4, "Bluetooth HCI UART transport layer"), DLT_CHOICE(DLT_IEEE802_16_MAC_CPS, "IEEE 802.16 MAC Common Part Sublayer"), DLT_CHOICE(DLT_USB_LINUX, "USB with Linux header"), DLT_CHOICE(DLT_CAN20B, "Controller Area Network (CAN) v. 2.0B"), DLT_CHOICE(DLT_IEEE802_15_4_LINUX, "IEEE 802.15.4 with Linux padding"), DLT_CHOICE(DLT_PPI, "Per-Packet Information"), DLT_CHOICE(DLT_IEEE802_16_MAC_CPS_RADIO, "IEEE 802.16 MAC Common Part Sublayer plus radiotap header"), DLT_CHOICE(DLT_JUNIPER_ISM, "Juniper Integrated Service Module"), DLT_CHOICE(DLT_IEEE802_15_4, "IEEE 802.15.4 with FCS"), DLT_CHOICE(DLT_SITA, "SITA pseudo-header"), DLT_CHOICE(DLT_ERF, "Endace ERF header"), DLT_CHOICE(DLT_RAIF1, "Ethernet with u10 Networks pseudo-header"), DLT_CHOICE(DLT_IPMB, "IPMB"), DLT_CHOICE(DLT_JUNIPER_ST, "Juniper Secure Tunnel"), DLT_CHOICE(DLT_BLUETOOTH_HCI_H4_WITH_PHDR, "Bluetooth HCI UART transport layer plus pseudo-header"), DLT_CHOICE(DLT_AX25_KISS, "AX.25 with KISS header"), DLT_CHOICE(DLT_IEEE802_15_4_NONASK_PHY, "IEEE 802.15.4 with non-ASK PHY data"), DLT_CHOICE(DLT_MPLS, "MPLS with label as link-layer header"), DLT_CHOICE(DLT_USB_LINUX_MMAPPED, "USB with padded Linux header"), DLT_CHOICE(DLT_DECT, "DECT"), DLT_CHOICE(DLT_AOS, "AOS Space Data Link protocol"), DLT_CHOICE(DLT_WIHART, "Wireless HART"), DLT_CHOICE(DLT_FC_2, "Fibre Channel FC-2"), DLT_CHOICE(DLT_FC_2_WITH_FRAME_DELIMS, "Fibre Channel FC-2 with frame delimiters"), DLT_CHOICE(DLT_IPNET, "Solaris ipnet"), DLT_CHOICE(DLT_CAN_SOCKETCAN, "CAN-bus with SocketCAN headers"), DLT_CHOICE(DLT_IPV4, "Raw IPv4"), DLT_CHOICE(DLT_IPV6, "Raw IPv6"), DLT_CHOICE(DLT_IEEE802_15_4_NOFCS, "IEEE 802.15.4 without FCS"), DLT_CHOICE(DLT_JUNIPER_VS, "Juniper Virtual Server"), DLT_CHOICE(DLT_JUNIPER_SRX_E2E, "Juniper SRX E2E"), DLT_CHOICE(DLT_JUNIPER_FIBRECHANNEL, "Juniper Fibre Channel"), DLT_CHOICE(DLT_DVB_CI, "DVB-CI"), DLT_CHOICE(DLT_JUNIPER_ATM_CEMIC, "Juniper ATM CEMIC"), DLT_CHOICE(DLT_NFLOG, "Linux netfilter log messages"), DLT_CHOICE(DLT_NETANALYZER, "Ethernet with Hilscher netANALYZER pseudo-header"), DLT_CHOICE(DLT_NETANALYZER_TRANSPARENT, "Ethernet with Hilscher netANALYZER pseudo-header and with preamble and SFD"), DLT_CHOICE(DLT_IPOIB, "RFC 4391 IP-over-Infiniband"), DLT_CHOICE_SENTINEL }; int pcap_datalink_name_to_val(const char *name) { int i; for (i = 0; dlt_choices[i].name != NULL; i++) { if (pcap_strcasecmp(dlt_choices[i].name + sizeof("DLT_") - 1, name) == 0) return (dlt_choices[i].dlt); } return (-1); } const char * pcap_datalink_val_to_name(int dlt) { int i; for (i = 0; dlt_choices[i].name != NULL; i++) { if (dlt_choices[i].dlt == dlt) return (dlt_choices[i].name + sizeof("DLT_") - 1); } return (NULL); } const char * pcap_datalink_val_to_description(int dlt) { int i; for (i = 0; dlt_choices[i].name != NULL; i++) { if (dlt_choices[i].dlt == dlt) return (dlt_choices[i].description); } return (NULL); } struct tstamp_type_choice { const char *name; const char *description; int type; }; static struct tstamp_type_choice tstamp_type_choices[] = { { "host", "Host", PCAP_TSTAMP_HOST }, { "host_lowprec", "Host, low precision", PCAP_TSTAMP_HOST_LOWPREC }, { "host_hiprec", "Host, high precision", PCAP_TSTAMP_HOST_HIPREC }, { "adapter", "Adapter", PCAP_TSTAMP_ADAPTER }, { "adapter_unsynced", "Adapter, not synced with system time", PCAP_TSTAMP_ADAPTER_UNSYNCED }, { NULL, NULL, 0 } }; int pcap_tstamp_type_name_to_val(const char *name) { int i; for (i = 0; tstamp_type_choices[i].name != NULL; i++) { if (pcap_strcasecmp(tstamp_type_choices[i].name, name) == 0) return (tstamp_type_choices[i].type); } return (PCAP_ERROR); } const char * pcap_tstamp_type_val_to_name(int tstamp_type) { int i; for (i = 0; tstamp_type_choices[i].name != NULL; i++) { if (tstamp_type_choices[i].type == tstamp_type) return (tstamp_type_choices[i].name); } return (NULL); } const char * pcap_tstamp_type_val_to_description(int tstamp_type) { int i; for (i = 0; tstamp_type_choices[i].name != NULL; i++) { if (tstamp_type_choices[i].type == tstamp_type) return (tstamp_type_choices[i].description); } return (NULL); } int pcap_snapshot(pcap_t *p) { return (p->snapshot); } int pcap_is_swapped(pcap_t *p) { return (p->sf.swapped); } int pcap_major_version(pcap_t *p) { return (p->sf.version_major); } int pcap_minor_version(pcap_t *p) { return (p->sf.version_minor); } FILE * pcap_file(pcap_t *p) { return (p->sf.rfile); } int pcap_fileno(pcap_t *p) { #ifndef WIN32 return (p->fd); #else if (p->adapter != NULL) return ((int)(DWORD)p->adapter->hFile); else return (-1); #endif } #if !defined(WIN32) && !defined(MSDOS) int pcap_get_selectable_fd(pcap_t *p) { return (p->selectable_fd); } #endif void pcap_perror(pcap_t *p, char *prefix) { fprintf(stderr, "%s: %s\n", prefix, p->errbuf); } char * pcap_geterr(pcap_t *p) { return (p->errbuf); } int pcap_getnonblock(pcap_t *p, char *errbuf) { int ret; ret = p->getnonblock_op(p, errbuf); if (ret == -1) { /* * In case somebody depended on the bug wherein * the error message was put into p->errbuf * by pcap_getnonblock_fd(). */ strlcpy(p->errbuf, errbuf, PCAP_ERRBUF_SIZE); } return (ret); } /* * Get the current non-blocking mode setting, under the assumption that * it's just the standard POSIX non-blocking flag. * * We don't look at "p->nonblock", in case somebody tweaked the FD * directly. */ #if !defined(WIN32) && !defined(MSDOS) int pcap_getnonblock_fd(pcap_t *p, char *errbuf) { int fdflags; fdflags = fcntl(p->fd, F_GETFL, 0); if (fdflags == -1) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "F_GETFL: %s", pcap_strerror(errno)); return (-1); } if (fdflags & O_NONBLOCK) return (1); else return (0); } #endif int pcap_setnonblock(pcap_t *p, int nonblock, char *errbuf) { int ret; ret = p->setnonblock_op(p, nonblock, errbuf); if (ret == -1) { /* * In case somebody depended on the bug wherein * the error message was put into p->errbuf * by pcap_setnonblock_fd(). */ strlcpy(p->errbuf, errbuf, PCAP_ERRBUF_SIZE); } return (ret); } #if !defined(WIN32) && !defined(MSDOS) /* * Set non-blocking mode, under the assumption that it's just the * standard POSIX non-blocking flag. (This can be called by the * per-platform non-blocking-mode routine if that routine also * needs to do some additional work.) */ int pcap_setnonblock_fd(pcap_t *p, int nonblock, char *errbuf) { int fdflags; fdflags = fcntl(p->fd, F_GETFL, 0); if (fdflags == -1) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "F_GETFL: %s", pcap_strerror(errno)); return (-1); } if (nonblock) fdflags |= O_NONBLOCK; else fdflags &= ~O_NONBLOCK; if (fcntl(p->fd, F_SETFL, fdflags) == -1) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "F_SETFL: %s", pcap_strerror(errno)); return (-1); } return (0); } #endif #ifdef WIN32 /* * Generate a string for the last Win32-specific error (i.e. an error generated when * calling a Win32 API). * For errors occurred during standard C calls, we still use pcap_strerror() */ char * pcap_win32strerror(void) { DWORD error; static char errbuf[PCAP_ERRBUF_SIZE+1]; int errlen; char *p; error = GetLastError(); FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, errbuf, PCAP_ERRBUF_SIZE, NULL); /* * "FormatMessage()" "helpfully" sticks CR/LF at the end of the * message. Get rid of it. */ errlen = strlen(errbuf); if (errlen >= 2) { errbuf[errlen - 1] = '\0'; errbuf[errlen - 2] = '\0'; } p = strchr(errbuf, '\0'); snprintf (p, sizeof(errbuf)-(p-errbuf), " (%lu)", error); return (errbuf); } #endif /* * Generate error strings for PCAP_ERROR_ and PCAP_WARNING_ values. */ const char * pcap_statustostr(int errnum) { static char ebuf[15+10+1]; switch (errnum) { case PCAP_WARNING: return("Generic warning"); case PCAP_WARNING_TSTAMP_TYPE_NOTSUP: return ("That type of time stamp is not supported by that device"); case PCAP_WARNING_PROMISC_NOTSUP: return ("That device doesn't support promiscuous mode"); case PCAP_ERROR: return("Generic error"); case PCAP_ERROR_BREAK: return("Loop terminated by pcap_breakloop"); case PCAP_ERROR_NOT_ACTIVATED: return("The pcap_t has not been activated"); case PCAP_ERROR_ACTIVATED: return ("The setting can't be changed after the pcap_t is activated"); case PCAP_ERROR_NO_SUCH_DEVICE: return ("No such device exists"); case PCAP_ERROR_RFMON_NOTSUP: return ("That device doesn't support monitor mode"); case PCAP_ERROR_NOT_RFMON: return ("That operation is supported only in monitor mode"); case PCAP_ERROR_PERM_DENIED: return ("You don't have permission to capture on that device"); case PCAP_ERROR_IFACE_NOT_UP: return ("That device is not up"); case PCAP_ERROR_CANTSET_TSTAMP_TYPE: return ("That device doesn't support setting the time stamp type"); case PCAP_ERROR_PROMISC_PERM_DENIED: return ("You don't have permission to capture in promiscuous mode on that device"); } (void)snprintf(ebuf, sizeof ebuf, "Unknown error: %d", errnum); return(ebuf); } /* * Not all systems have strerror(). */ const char * pcap_strerror(int errnum) { #ifdef HAVE_STRERROR return (strerror(errnum)); #else extern int sys_nerr; extern const char *const sys_errlist[]; static char ebuf[15+10+1]; if ((unsigned int)errnum < sys_nerr) return ((char *)sys_errlist[errnum]); (void)snprintf(ebuf, sizeof ebuf, "Unknown error: %d", errnum); return(ebuf); #endif } int pcap_setfilter(pcap_t *p, struct bpf_program *fp) { return (p->setfilter_op(p, fp)); } /* * Set direction flag, which controls whether we accept only incoming * packets, only outgoing packets, or both. * Note that, depending on the platform, some or all direction arguments * might not be supported. */ int pcap_setdirection(pcap_t *p, pcap_direction_t d) { if (p->setdirection_op == NULL) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Setting direction is not implemented on this platform"); return (-1); } else return (p->setdirection_op(p, d)); } int pcap_stats(pcap_t *p, struct pcap_stat *ps) { return (p->stats_op(p, ps)); } static int pcap_stats_dead(pcap_t *p, struct pcap_stat *ps _U_) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Statistics aren't available from a pcap_open_dead pcap_t"); return (-1); } #ifdef WIN32 int pcap_setbuff(pcap_t *p, int dim) { return (p->setbuff_op(p, dim)); } static int pcap_setbuff_dead(pcap_t *p, int dim) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "The kernel buffer size cannot be set on a pcap_open_dead pcap_t"); return (-1); } int pcap_setmode(pcap_t *p, int mode) { return (p->setmode_op(p, mode)); } static int pcap_setmode_dead(pcap_t *p, int mode) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "impossible to set mode on a pcap_open_dead pcap_t"); return (-1); } int pcap_setmintocopy(pcap_t *p, int size) { return (p->setmintocopy_op(p, size)); } static int pcap_setmintocopy_dead(pcap_t *p, int size) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "The mintocopy parameter cannot be set on a pcap_open_dead pcap_t"); return (-1); } #endif /* * On some platforms, we need to clean up promiscuous or monitor mode * when we close a device - and we want that to happen even if the * application just exits without explicitl closing devices. * On those platforms, we need to register a "close all the pcaps" * routine to be called when we exit, and need to maintain a list of * pcaps that need to be closed to clean up modes. * * XXX - not thread-safe. */ /* * List of pcaps on which we've done something that needs to be * cleaned up. * If there are any such pcaps, we arrange to call "pcap_close_all()" * when we exit, and have it close all of them. */ static struct pcap *pcaps_to_close; /* * TRUE if we've already called "atexit()" to cause "pcap_close_all()" to * be called on exit. */ static int did_atexit; static void pcap_close_all(void) { struct pcap *handle; while ((handle = pcaps_to_close) != NULL) pcap_close(handle); } int pcap_do_addexit(pcap_t *p) { /* * If we haven't already done so, arrange to have * "pcap_close_all()" called when we exit. */ if (!did_atexit) { if (atexit(pcap_close_all) == -1) { /* * "atexit()" failed; let our caller know. */ strncpy(p->errbuf, "atexit failed", PCAP_ERRBUF_SIZE); return (0); } did_atexit = 1; } return (1); } void pcap_add_to_pcaps_to_close(pcap_t *p) { p->md.next = pcaps_to_close; pcaps_to_close = p; } void pcap_remove_from_pcaps_to_close(pcap_t *p) { pcap_t *pc, *prevpc; for (pc = pcaps_to_close, prevpc = NULL; pc != NULL; prevpc = pc, pc = pc->md.next) { if (pc == p) { /* * Found it. Remove it from the list. */ if (prevpc == NULL) { /* * It was at the head of the list. */ pcaps_to_close = pc->md.next; } else { /* * It was in the middle of the list. */ prevpc->md.next = pc->md.next; } break; } } } void pcap_cleanup_live_common(pcap_t *p) { if (p->buffer != NULL) { free(p->buffer); p->buffer = NULL; } if (p->dlt_list != NULL) { free(p->dlt_list); p->dlt_list = NULL; p->dlt_count = 0; } if (p->tstamp_type_list != NULL) { free(p->tstamp_type_list); p->tstamp_type_list = NULL; p->tstamp_type_count = 0; } pcap_freecode(&p->fcode); #if !defined(WIN32) && !defined(MSDOS) if (p->fd >= 0) { close(p->fd); p->fd = -1; } p->selectable_fd = -1; p->send_fd = -1; #endif } static void pcap_cleanup_dead(pcap_t *p _U_) { /* Nothing to do. */ } pcap_t * pcap_open_dead(int linktype, int snaplen) { pcap_t *p; p = malloc(sizeof(*p)); if (p == NULL) return NULL; memset (p, 0, sizeof(*p)); p->snapshot = snaplen; p->linktype = linktype; p->stats_op = pcap_stats_dead; #ifdef WIN32 p->setbuff_op = pcap_setbuff_dead; p->setmode_op = pcap_setmode_dead; p->setmintocopy_op = pcap_setmintocopy_dead; #endif p->cleanup_op = pcap_cleanup_dead; p->activated = 1; return (p); } /* * API compatible with WinPcap's "send a packet" routine - returns -1 * on error, 0 otherwise. * * XXX - what if we get a short write? */ int pcap_sendpacket(pcap_t *p, const u_char *buf, int size) { if (p->inject_op(p, buf, size) == -1) return (-1); return (0); } /* * API compatible with OpenBSD's "send a packet" routine - returns -1 on * error, number of bytes written otherwise. */ int pcap_inject(pcap_t *p, const void *buf, size_t size) { return (p->inject_op(p, buf, size)); } void pcap_close(pcap_t *p) { if (p->opt.source != NULL) free(p->opt.source); p->cleanup_op(p); free(p); } /* * Given a BPF program, a pcap_pkthdr structure for a packet, and the raw * data for the packet, check whether the packet passes the filter. * Returns the return value of the filter program, which will be zero if * the packet doesn't pass and non-zero if the packet does pass. */ int pcap_offline_filter(const struct bpf_program *fp, const struct pcap_pkthdr *h, const u_char *pkt) { const struct bpf_insn *fcode = fp->bf_insns; if (fcode != NULL) return (bpf_filter(fcode, pkt, h->len, h->caplen)); else return (0); } /* * We make the version string static, and return a pointer to it, rather * than exporting the version string directly. On at least some UNIXes, * if you import data from a shared library into an program, the data is * bound into the program binary, so if the string in the version of the * library with which the program was linked isn't the same as the * string in the version of the library with which the program is being * run, various undesirable things may happen (warnings, the string * being the one from the version of the library with which the program * was linked, or even weirder things, such as the string being the one * from the library but being truncated). */ #ifdef HAVE_VERSION_H #include "version.h" #else static const char pcap_version_string[] = "libpcap version 1.x.y"; #endif #ifdef WIN32 /* * XXX - it'd be nice if we could somehow generate the WinPcap and libpcap * version numbers when building WinPcap. (It'd be nice to do so for * the packet.dll version number as well.) */ static const char wpcap_version_string[] = "4.0"; static const char pcap_version_string_fmt[] = "WinPcap version %s, based on %s"; static const char pcap_version_string_packet_dll_fmt[] = "WinPcap version %s (packet.dll version %s), based on %s"; static char *full_pcap_version_string; const char * pcap_lib_version(void) { char *packet_version_string; size_t full_pcap_version_string_len; if (full_pcap_version_string == NULL) { /* * Generate the version string. */ packet_version_string = PacketGetVersion(); if (strcmp(wpcap_version_string, packet_version_string) == 0) { /* * WinPcap version string and packet.dll version * string are the same; just report the WinPcap * version. */ full_pcap_version_string_len = (sizeof pcap_version_string_fmt - 4) + strlen(wpcap_version_string) + strlen(pcap_version_string); full_pcap_version_string = malloc(full_pcap_version_string_len); sprintf(full_pcap_version_string, pcap_version_string_fmt, wpcap_version_string, pcap_version_string); } else { /* * WinPcap version string and packet.dll version * string are different; that shouldn't be the * case (the two libraries should come from the * same version of WinPcap), so we report both * versions. */ full_pcap_version_string_len = (sizeof pcap_version_string_packet_dll_fmt - 6) + strlen(wpcap_version_string) + strlen(packet_version_string) + strlen(pcap_version_string); full_pcap_version_string = malloc(full_pcap_version_string_len); sprintf(full_pcap_version_string, pcap_version_string_packet_dll_fmt, wpcap_version_string, packet_version_string, pcap_version_string); } } return (full_pcap_version_string); } #elif defined(MSDOS) static char *full_pcap_version_string; const char * pcap_lib_version (void) { char *packet_version_string; size_t full_pcap_version_string_len; static char dospfx[] = "DOS-"; if (full_pcap_version_string == NULL) { /* * Generate the version string. */ full_pcap_version_string_len = sizeof dospfx + strlen(pcap_version_string); full_pcap_version_string = malloc(full_pcap_version_string_len); strcpy(full_pcap_version_string, dospfx); strcat(full_pcap_version_string, pcap_version_string); } return (full_pcap_version_string); } #else /* UN*X */ const char * pcap_lib_version(void) { return (pcap_version_string); } #endif Index: user/syuu/mq_bpf/contrib/tcpdump/tcpdump.c =================================================================== --- user/syuu/mq_bpf/contrib/tcpdump/tcpdump.c (revision 255171) +++ user/syuu/mq_bpf/contrib/tcpdump/tcpdump.c (revision 255172) @@ -1,2153 +1,2161 @@ /* * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000 * 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. * * Support for splitting captures into multiple files with a maximum * file size: * * Copyright (c) 2001 * Seth Webster */ #ifndef lint static const char copyright[] _U_ = "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\ The Regents of the University of California. All rights reserved.\n"; static const char rcsid[] _U_ = "@(#) $Header: /tcpdump/master/tcpdump/tcpdump.c,v 1.283 2008-09-25 21:45:50 guy Exp $ (LBL)"; #endif /* $FreeBSD$ */ /* * tcpdump - monitor tcp/ip traffic on an ethernet. * * First written in 1987 by Van Jacobson, Lawrence Berkeley Laboratory. * Mercilessly hacked and occasionally improved since then via the * combined efforts of Van, Steve McCanne and Craig Leres of LBL. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #ifdef WIN32 #include "getopt.h" #include "w32_fzs.h" extern int strcasecmp (const char *__s1, const char *__s2); extern int SIZE_BUF; #define off_t long #define uint UINT #endif /* WIN32 */ #ifdef HAVE_SMI_H #include #endif #include #include #include #include #include #include #ifndef WIN32 #include #include #include #include #include #endif /* WIN32 */ /* capabilities convinience library */ #ifdef HAVE_CAP_NG_H #include #endif /* HAVE_CAP_NG_H */ #include "netdissect.h" #include "interface.h" #include "addrtoname.h" #include "machdep.h" #include "setsignal.h" #include "gmt2local.h" #include "pcap-missing.h" #ifndef PATH_MAX #define PATH_MAX 1024 #endif #ifdef SIGINFO #define SIGNAL_REQ_INFO SIGINFO #elif SIGUSR1 #define SIGNAL_REQ_INFO SIGUSR1 #endif netdissect_options Gndo; netdissect_options *gndo = &Gndo; static int dflag; /* print filter code */ static int Lflag; /* list available data link types and exit */ #ifdef HAVE_PCAP_SET_TSTAMP_TYPE static int Jflag; /* list available time stamp types */ #endif static char *zflag = NULL; /* compress each savefile using a specified command (like gzip or bzip2) */ static int infodelay; static int infoprint; char *program_name; int32_t thiszone; /* seconds offset from gmt to local time */ /* Forwards */ static RETSIGTYPE cleanup(int); static RETSIGTYPE child_cleanup(int); static void usage(void) __attribute__((noreturn)); static void show_dlts_and_exit(const char *device, pcap_t *pd) __attribute__((noreturn)); static void print_packet(u_char *, const struct pcap_pkthdr *, const u_char *); static void ndo_default_print(netdissect_options *, const u_char *, u_int); static void dump_packet_and_trunc(u_char *, const struct pcap_pkthdr *, const u_char *); static void dump_packet(u_char *, const struct pcap_pkthdr *, const u_char *); static void droproot(const char *, const char *); static void ndo_error(netdissect_options *ndo, const char *fmt, ...) __attribute__ ((noreturn, format (printf, 2, 3))); static void ndo_warning(netdissect_options *ndo, const char *fmt, ...); #ifdef SIGNAL_REQ_INFO RETSIGTYPE requestinfo(int); #endif #if defined(USE_WIN32_MM_TIMER) #include static UINT timer_id; static void CALLBACK verbose_stats_dump(UINT, UINT, DWORD_PTR, DWORD_PTR, DWORD_PTR); #elif defined(HAVE_ALARM) static void verbose_stats_dump(int sig); #endif static void info(int); static u_int packets_captured; struct printer { if_printer f; int type; }; struct ndo_printer { if_ndo_printer f; int type; }; static struct printer printers[] = { { arcnet_if_print, DLT_ARCNET }, #ifdef DLT_ARCNET_LINUX { arcnet_linux_if_print, DLT_ARCNET_LINUX }, #endif { token_if_print, DLT_IEEE802 }, #ifdef DLT_LANE8023 { lane_if_print, DLT_LANE8023 }, #endif #ifdef DLT_CIP { cip_if_print, DLT_CIP }, #endif #ifdef DLT_ATM_CLIP { cip_if_print, DLT_ATM_CLIP }, #endif { sl_if_print, DLT_SLIP }, #ifdef DLT_SLIP_BSDOS { sl_bsdos_if_print, DLT_SLIP_BSDOS }, #endif { ppp_if_print, DLT_PPP }, #ifdef DLT_PPP_WITHDIRECTION { ppp_if_print, DLT_PPP_WITHDIRECTION }, #endif #ifdef DLT_PPP_BSDOS { ppp_bsdos_if_print, DLT_PPP_BSDOS }, #endif { fddi_if_print, DLT_FDDI }, { null_if_print, DLT_NULL }, #ifdef DLT_LOOP { null_if_print, DLT_LOOP }, #endif { raw_if_print, DLT_RAW }, { atm_if_print, DLT_ATM_RFC1483 }, #ifdef DLT_C_HDLC { chdlc_if_print, DLT_C_HDLC }, #endif #ifdef DLT_HDLC { chdlc_if_print, DLT_HDLC }, #endif #ifdef DLT_PPP_SERIAL { ppp_hdlc_if_print, DLT_PPP_SERIAL }, #endif #ifdef DLT_PPP_ETHER { pppoe_if_print, DLT_PPP_ETHER }, #endif #ifdef DLT_LINUX_SLL { sll_if_print, DLT_LINUX_SLL }, #endif #ifdef DLT_IEEE802_11 { ieee802_11_if_print, DLT_IEEE802_11}, #endif #ifdef DLT_LTALK { ltalk_if_print, DLT_LTALK }, #endif #if defined(DLT_PFLOG) && defined(HAVE_NET_PFVAR_H) { pflog_if_print, DLT_PFLOG }, #endif #ifdef DLT_FR { fr_if_print, DLT_FR }, #endif #ifdef DLT_FRELAY { fr_if_print, DLT_FRELAY }, #endif #ifdef DLT_SUNATM { sunatm_if_print, DLT_SUNATM }, #endif #ifdef DLT_IP_OVER_FC { ipfc_if_print, DLT_IP_OVER_FC }, #endif #ifdef DLT_PRISM_HEADER { prism_if_print, DLT_PRISM_HEADER }, #endif #ifdef DLT_IEEE802_11_RADIO { ieee802_11_radio_if_print, DLT_IEEE802_11_RADIO }, #endif #ifdef DLT_ENC { enc_if_print, DLT_ENC }, #endif #ifdef DLT_SYMANTEC_FIREWALL { symantec_if_print, DLT_SYMANTEC_FIREWALL }, #endif #ifdef DLT_APPLE_IP_OVER_IEEE1394 { ap1394_if_print, DLT_APPLE_IP_OVER_IEEE1394 }, #endif #ifdef DLT_IEEE802_11_RADIO_AVS { ieee802_11_radio_avs_if_print, DLT_IEEE802_11_RADIO_AVS }, #endif #ifdef DLT_JUNIPER_ATM1 { juniper_atm1_print, DLT_JUNIPER_ATM1 }, #endif #ifdef DLT_JUNIPER_ATM2 { juniper_atm2_print, DLT_JUNIPER_ATM2 }, #endif #ifdef DLT_JUNIPER_MFR { juniper_mfr_print, DLT_JUNIPER_MFR }, #endif #ifdef DLT_JUNIPER_MLFR { juniper_mlfr_print, DLT_JUNIPER_MLFR }, #endif #ifdef DLT_JUNIPER_MLPPP { juniper_mlppp_print, DLT_JUNIPER_MLPPP }, #endif #ifdef DLT_JUNIPER_PPPOE { juniper_pppoe_print, DLT_JUNIPER_PPPOE }, #endif #ifdef DLT_JUNIPER_PPPOE_ATM { juniper_pppoe_atm_print, DLT_JUNIPER_PPPOE_ATM }, #endif #ifdef DLT_JUNIPER_GGSN { juniper_ggsn_print, DLT_JUNIPER_GGSN }, #endif #ifdef DLT_JUNIPER_ES { juniper_es_print, DLT_JUNIPER_ES }, #endif #ifdef DLT_JUNIPER_MONITOR { juniper_monitor_print, DLT_JUNIPER_MONITOR }, #endif #ifdef DLT_JUNIPER_SERVICES { juniper_services_print, DLT_JUNIPER_SERVICES }, #endif #ifdef DLT_JUNIPER_ETHER { juniper_ether_print, DLT_JUNIPER_ETHER }, #endif #ifdef DLT_JUNIPER_PPP { juniper_ppp_print, DLT_JUNIPER_PPP }, #endif #ifdef DLT_JUNIPER_FRELAY { juniper_frelay_print, DLT_JUNIPER_FRELAY }, #endif #ifdef DLT_JUNIPER_CHDLC { juniper_chdlc_print, DLT_JUNIPER_CHDLC }, #endif #ifdef DLT_MFR { mfr_if_print, DLT_MFR }, #endif #if defined(DLT_BLUETOOTH_HCI_H4_WITH_PHDR) && defined(HAVE_PCAP_BLUETOOTH_H) { bt_if_print, DLT_BLUETOOTH_HCI_H4_WITH_PHDR}, #endif #ifdef HAVE_PCAP_USB_H #ifdef DLT_USB_LINUX { usb_linux_48_byte_print, DLT_USB_LINUX}, #endif /* DLT_USB_LINUX */ #ifdef DLT_USB_LINUX_MMAPPED { usb_linux_64_byte_print, DLT_USB_LINUX_MMAPPED}, #endif /* DLT_USB_LINUX_MMAPPED */ #endif /* HAVE_PCAP_USB_H */ #ifdef DLT_IPV4 { raw_if_print, DLT_IPV4 }, #endif #ifdef DLT_IPV6 { raw_if_print, DLT_IPV6 }, #endif { NULL, 0 }, }; static struct ndo_printer ndo_printers[] = { { ether_if_print, DLT_EN10MB }, #ifdef DLT_IPNET { ipnet_if_print, DLT_IPNET }, #endif #ifdef DLT_IEEE802_15_4 { ieee802_15_4_if_print, DLT_IEEE802_15_4 }, #endif #ifdef DLT_IEEE802_15_4_NOFCS { ieee802_15_4_if_print, DLT_IEEE802_15_4_NOFCS }, #endif #ifdef DLT_PPI { ppi_if_print, DLT_PPI }, #endif #ifdef DLT_NETANALYZER { netanalyzer_if_print, DLT_NETANALYZER }, #endif #ifdef DLT_NETANALYZER_TRANSPARENT { netanalyzer_transparent_if_print, DLT_NETANALYZER_TRANSPARENT }, #endif { NULL, 0 }, }; if_printer lookup_printer(int type) { struct printer *p; for (p = printers; p->f; ++p) if (type == p->type) return p->f; return NULL; /* NOTREACHED */ } if_ndo_printer lookup_ndo_printer(int type) { struct ndo_printer *p; for (p = ndo_printers; p->f; ++p) if (type == p->type) return p->f; return NULL; /* NOTREACHED */ } static pcap_t *pd; static int supports_monitor_mode; extern int optind; extern int opterr; extern char *optarg; struct print_info { netdissect_options *ndo; union { if_printer printer; if_ndo_printer ndo_printer; } p; int ndo_type; }; struct dump_info { char *WFileName; char *CurrentFileName; pcap_t *pd; pcap_dumper_t *p; }; #ifdef HAVE_PCAP_SET_TSTAMP_TYPE static void show_tstamp_types_and_exit(const char *device, pcap_t *pd) { int n_tstamp_types; int *tstamp_types = 0; const char *tstamp_type_name; int i; n_tstamp_types = pcap_list_tstamp_types(pd, &tstamp_types); if (n_tstamp_types < 0) error("%s", pcap_geterr(pd)); if (n_tstamp_types == 0) { fprintf(stderr, "Time stamp type cannot be set for %s\n", device); exit(0); } fprintf(stderr, "Time stamp types for %s (use option -j to set):\n", device); for (i = 0; i < n_tstamp_types; i++) { tstamp_type_name = pcap_tstamp_type_val_to_name(tstamp_types[i]); if (tstamp_type_name != NULL) { (void) fprintf(stderr, " %s (%s)\n", tstamp_type_name, pcap_tstamp_type_val_to_description(tstamp_types[i])); } else { (void) fprintf(stderr, " %d\n", tstamp_types[i]); } } pcap_free_tstamp_types(tstamp_types); exit(0); } #endif static void show_dlts_and_exit(const char *device, pcap_t *pd) { int n_dlts; int *dlts = 0; const char *dlt_name; n_dlts = pcap_list_datalinks(pd, &dlts); if (n_dlts < 0) error("%s", pcap_geterr(pd)); else if (n_dlts == 0 || !dlts) error("No data link types."); /* * If the interface is known to support monitor mode, indicate * whether these are the data link types available when not in * monitor mode, if -I wasn't specified, or when in monitor mode, * when -I was specified (the link-layer types available in * monitor mode might be different from the ones available when * not in monitor mode). */ if (supports_monitor_mode) (void) fprintf(stderr, "Data link types for %s %s (use option -y to set):\n", device, Iflag ? "when in monitor mode" : "when not in monitor mode"); else (void) fprintf(stderr, "Data link types for %s (use option -y to set):\n", device); while (--n_dlts >= 0) { dlt_name = pcap_datalink_val_to_name(dlts[n_dlts]); if (dlt_name != NULL) { (void) fprintf(stderr, " %s (%s)", dlt_name, pcap_datalink_val_to_description(dlts[n_dlts])); /* * OK, does tcpdump handle that type? */ if (lookup_printer(dlts[n_dlts]) == NULL && lookup_ndo_printer(dlts[n_dlts]) == NULL) (void) fprintf(stderr, " (printing not supported)"); fprintf(stderr, "\n"); } else { (void) fprintf(stderr, " DLT %d (printing not supported)\n", dlts[n_dlts]); } } #ifdef HAVE_PCAP_FREE_DATALINKS pcap_free_datalinks(dlts); #endif exit(0); } /* * Set up flags that might or might not be supported depending on the * version of libpcap we're using. */ #if defined(HAVE_PCAP_CREATE) || defined(WIN32) #define B_FLAG "B:" #define B_FLAG_USAGE " [ -B size ]" #else /* defined(HAVE_PCAP_CREATE) || defined(WIN32) */ #define B_FLAG #define B_FLAG_USAGE #endif /* defined(HAVE_PCAP_CREATE) || defined(WIN32) */ #ifdef HAVE_PCAP_CREATE #define I_FLAG "I" #else /* HAVE_PCAP_CREATE */ #define I_FLAG #endif /* HAVE_PCAP_CREATE */ #ifdef HAVE_PCAP_SET_TSTAMP_TYPE #define j_FLAG "j:" #define j_FLAG_USAGE " [ -j tstamptype ]" #define J_FLAG "J" #else /* PCAP_ERROR_TSTAMP_TYPE_NOTSUP */ #define j_FLAG #define j_FLAG_USAGE #define J_FLAG #endif /* PCAP_ERROR_TSTAMP_TYPE_NOTSUP */ #ifdef HAVE_PCAP_FINDALLDEVS #ifndef HAVE_PCAP_IF_T #undef HAVE_PCAP_FINDALLDEVS #endif #endif #ifdef HAVE_PCAP_FINDALLDEVS #define D_FLAG "D" #else #define D_FLAG #endif #ifdef HAVE_PCAP_DUMP_FLUSH #define U_FLAG "U" #else #define U_FLAG #endif #ifndef WIN32 /* Drop root privileges and chroot if necessary */ static void droproot(const char *username, const char *chroot_dir) { struct passwd *pw = NULL; if (chroot_dir && !username) { fprintf(stderr, "tcpdump: Chroot without dropping root is insecure\n"); exit(1); } pw = getpwnam(username); if (pw) { if (chroot_dir) { if (chroot(chroot_dir) != 0 || chdir ("/") != 0) { fprintf(stderr, "tcpdump: Couldn't chroot/chdir to '%.64s': %s\n", chroot_dir, pcap_strerror(errno)); exit(1); } } #ifdef HAVE_CAP_NG_H int ret = capng_change_id(pw->pw_uid, pw->pw_gid, CAPNG_NO_FLAG); if (ret < 0) { printf("error : ret %d\n", ret); } /* We don't need CAP_SETUID and CAP_SETGID */ capng_update(CAPNG_DROP, CAPNG_EFFECTIVE, CAP_SETUID); capng_update(CAPNG_DROP, CAPNG_EFFECTIVE, CAP_SETUID); capng_update(CAPNG_DROP, CAPNG_PERMITTED, CAP_SETUID); capng_update(CAPNG_DROP, CAPNG_PERMITTED, CAP_SETUID); capng_apply(CAPNG_SELECT_BOTH); #else if (initgroups(pw->pw_name, pw->pw_gid) != 0 || setgid(pw->pw_gid) != 0 || setuid(pw->pw_uid) != 0) { fprintf(stderr, "tcpdump: Couldn't change to '%.32s' uid=%lu gid=%lu: %s\n", username, (unsigned long)pw->pw_uid, (unsigned long)pw->pw_gid, pcap_strerror(errno)); exit(1); } #endif /* HAVE_CAP_NG_H */ } else { fprintf(stderr, "tcpdump: Couldn't find user '%.32s'\n", username); exit(1); } } #endif /* WIN32 */ static int getWflagChars(int x) { int c = 0; x -= 1; while (x > 0) { c += 1; x /= 10; } return c; } static void MakeFilename(char *buffer, char *orig_name, int cnt, int max_chars) { char *filename = malloc(PATH_MAX + 1); if (filename == NULL) error("Makefilename: malloc"); /* Process with strftime if Gflag is set. */ if (Gflag != 0) { struct tm *local_tm; /* Convert Gflag_time to a usable format */ if ((local_tm = localtime(&Gflag_time)) == NULL) { error("MakeTimedFilename: localtime"); } /* There's no good way to detect an error in strftime since a return * value of 0 isn't necessarily failure. */ strftime(filename, PATH_MAX, orig_name, local_tm); } else { strncpy(filename, orig_name, PATH_MAX); } if (cnt == 0 && max_chars == 0) strncpy(buffer, filename, PATH_MAX + 1); else if (snprintf(buffer, PATH_MAX + 1, "%s%0*d", filename, max_chars, cnt) > PATH_MAX) /* Report an error if the filename is too large */ error("too many output files or filename is too long (> %d)", PATH_MAX); free(filename); } static int tcpdump_printf(netdissect_options *ndo _U_, const char *fmt, ...) { va_list args; int ret; va_start(args, fmt); ret=vfprintf(stdout, fmt, args); va_end(args); return ret; } static struct print_info get_print_info(int type) { struct print_info printinfo; printinfo.ndo_type = 1; printinfo.ndo = gndo; printinfo.p.ndo_printer = lookup_ndo_printer(type); if (printinfo.p.ndo_printer == NULL) { printinfo.p.printer = lookup_printer(type); printinfo.ndo_type = 0; if (printinfo.p.printer == NULL) { gndo->ndo_dltname = pcap_datalink_val_to_name(type); if (gndo->ndo_dltname != NULL) error("packet printing is not supported for link type %s: use -w", gndo->ndo_dltname); else error("packet printing is not supported for link type %d: use -w", type); } } return (printinfo); } static char * get_next_file(FILE *VFile, char *ptr) { char *ret; ret = fgets(ptr, PATH_MAX, VFile); if (!ret) return NULL; if (ptr[strlen(ptr) - 1] == '\n') ptr[strlen(ptr) - 1] = '\0'; return ret; } int main(int argc, char **argv) { register int cnt, op, i; bpf_u_int32 localnet, netmask; register char *cp, *infile, *cmdbuf, *device, *RFileName, *VFileName, *WFileName; pcap_handler callback; int type; int dlt; int new_dlt; const char *dlt_name; struct bpf_program fcode; #ifndef WIN32 RETSIGTYPE (*oldhandler)(int); #endif struct print_info printinfo; struct dump_info dumpinfo; u_char *pcap_userdata; char ebuf[PCAP_ERRBUF_SIZE]; char VFileLine[PATH_MAX + 1]; char *username = NULL; char *chroot_dir = NULL; char *ret = NULL; char *end; #ifdef HAVE_PCAP_FINDALLDEVS pcap_if_t *devpointer; int devnum; #endif int status; FILE *VFile; - uint32_t rxq = (uint32_t)-1, txq = (uint32_t)-1, other = (uint32_t)-1; + int qmask = 0; + u_int rxq = (u_int)-1, txq = (u_int)-1; + int noq = -1; + #ifdef WIN32 if(wsockinit() != 0) return 1; #endif /* WIN32 */ jflag=-1; /* not set */ gndo->ndo_Oflag=1; gndo->ndo_Rflag=1; gndo->ndo_dlt=-1; gndo->ndo_default_print=ndo_default_print; gndo->ndo_printf=tcpdump_printf; gndo->ndo_error=ndo_error; gndo->ndo_warning=ndo_warning; gndo->ndo_snaplen = DEFAULT_SNAPLEN; cnt = -1; device = NULL; infile = NULL; RFileName = NULL; VFileName = NULL; VFile = NULL; WFileName = NULL; dlt = -1; if ((cp = strrchr(argv[0], '/')) != NULL) program_name = cp + 1; else program_name = argv[0]; if (abort_on_misalignment(ebuf, sizeof(ebuf)) < 0) error("%s", ebuf); #ifdef LIBSMI smiInit("tcpdump"); #endif while ( (op = getopt(argc, argv, "aAb" B_FLAG "c:C:d" D_FLAG "eE:fF:G:hHi:" I_FLAG j_FLAG J_FLAG "KlLm:M:nNOpqr:Rs:StT:u" U_FLAG "V:vw:W:xXy:Yz:Z:Q:g:k")) != -1) switch (op) { case 'a': /* compatibility for old -a */ break; case 'A': ++Aflag; break; case 'b': ++bflag; break; #if defined(HAVE_PCAP_CREATE) || defined(WIN32) case 'B': Bflag = atoi(optarg)*1024; if (Bflag <= 0) error("invalid packet buffer size %s", optarg); break; #endif /* defined(HAVE_PCAP_CREATE) || defined(WIN32) */ case 'c': cnt = atoi(optarg); if (cnt <= 0) error("invalid packet count %s", optarg); break; case 'C': Cflag = atoi(optarg) * 1000000; if (Cflag < 0) error("invalid file size %s", optarg); break; case 'd': ++dflag; break; #ifdef HAVE_PCAP_FINDALLDEVS case 'D': if (pcap_findalldevs(&devpointer, ebuf) < 0) error("%s", ebuf); else { for (i = 0; devpointer != 0; i++) { printf("%d.%s", i+1, devpointer->name); if (devpointer->description != NULL) printf(" (%s)", devpointer->description); printf("\n"); devpointer = devpointer->next; } } return 0; #endif /* HAVE_PCAP_FINDALLDEVS */ case 'L': Lflag++; break; case 'e': ++eflag; break; case 'E': #ifndef HAVE_LIBCRYPTO warning("crypto code not compiled in"); #endif gndo->ndo_espsecret = optarg; break; case 'f': ++fflag; break; case 'F': infile = optarg; break; case 'g': + qmask = 1; txq = atoi(optarg); break; case 'G': Gflag = atoi(optarg); if (Gflag < 0) error("invalid number of seconds %s", optarg); /* We will create one file initially. */ Gflag_count = 0; /* Grab the current time for rotation use. */ if ((Gflag_time = time(NULL)) == (time_t)-1) { error("main: can't get current time: %s", pcap_strerror(errno)); } break; case 'h': usage(); break; case 'H': ++Hflag; break; case 'i': if (optarg[0] == '0' && optarg[1] == 0) error("Invalid adapter index"); #ifdef HAVE_PCAP_FINDALLDEVS /* * If the argument is a number, treat it as * an index into the list of adapters, as * printed by "tcpdump -D". * * This should be OK on UNIX systems, as interfaces * shouldn't have names that begin with digits. * It can be useful on Windows, where more than * one interface can have the same name. */ devnum = strtol(optarg, &end, 10); if (optarg != end && *end == '\0') { if (devnum < 0) error("Invalid adapter index"); if (pcap_findalldevs(&devpointer, ebuf) < 0) error("%s", ebuf); else { /* * Look for the devnum-th entry * in the list of devices * (1-based). */ for (i = 0; i < devnum-1 && devpointer != NULL; i++, devpointer = devpointer->next) ; if (devpointer == NULL) error("Invalid adapter index"); } device = devpointer->name; break; } #endif /* HAVE_PCAP_FINDALLDEVS */ device = optarg; break; #ifdef HAVE_PCAP_CREATE case 'I': ++Iflag; break; #endif /* HAVE_PCAP_CREATE */ #ifdef HAVE_PCAP_SET_TSTAMP_TYPE case 'j': jflag = pcap_tstamp_type_name_to_val(optarg); if (jflag < 0) error("invalid time stamp type %s", optarg); break; case 'J': Jflag++; break; #endif case 'l': #ifdef WIN32 /* * _IOLBF is the same as _IOFBF in Microsoft's C * libraries; the only alternative they offer * is _IONBF. * * XXX - this should really be checking for MSVC++, * not WIN32, if, for example, MinGW has its own * C library that is more UNIX-compatible. */ setvbuf(stdout, NULL, _IONBF, 0); #else /* WIN32 */ #ifdef HAVE_SETLINEBUF setlinebuf(stdout); #else setvbuf(stdout, NULL, _IOLBF, 0); #endif #endif /* WIN32 */ break; case 'k': - other = atoi(optarg); - if (other != 0 || other != 1) + qmask = 1; + noq = atoi(optarg); + if (noq != 0 || noq != 1) usage(); break; case 'K': ++Kflag; break; case 'm': #ifdef LIBSMI if (smiLoadModule(optarg) == 0) { error("could not load MIB module %s", optarg); } sflag = 1; #else (void)fprintf(stderr, "%s: ignoring option `-m %s' ", program_name, optarg); (void)fprintf(stderr, "(no libsmi support)\n"); #endif break; case 'M': /* TCP-MD5 shared secret */ #ifndef HAVE_LIBCRYPTO warning("crypto code not compiled in"); #endif sigsecret = optarg; break; case 'n': ++nflag; break; case 'N': ++Nflag; break; case 'O': Oflag = 0; break; case 'p': ++pflag; break; case 'q': ++qflag; ++suppress_default_print; break; case 'Q': + qmask = 1; rxq = atoi(optarg); break; case 'r': RFileName = optarg; break; case 'R': Rflag = 0; break; case 's': snaplen = strtol(optarg, &end, 0); if (optarg == end || *end != '\0' || snaplen < 0 || snaplen > MAXIMUM_SNAPLEN) error("invalid snaplen %s", optarg); else if (snaplen == 0) snaplen = MAXIMUM_SNAPLEN; break; case 'S': ++Sflag; break; case 't': ++tflag; break; case 'T': if (strcasecmp(optarg, "vat") == 0) packettype = PT_VAT; else if (strcasecmp(optarg, "wb") == 0) packettype = PT_WB; else if (strcasecmp(optarg, "rpc") == 0) packettype = PT_RPC; else if (strcasecmp(optarg, "rtp") == 0) packettype = PT_RTP; else if (strcasecmp(optarg, "rtcp") == 0) packettype = PT_RTCP; else if (strcasecmp(optarg, "snmp") == 0) packettype = PT_SNMP; else if (strcasecmp(optarg, "cnfp") == 0) packettype = PT_CNFP; else if (strcasecmp(optarg, "tftp") == 0) packettype = PT_TFTP; else if (strcasecmp(optarg, "aodv") == 0) packettype = PT_AODV; else if (strcasecmp(optarg, "carp") == 0) packettype = PT_CARP; else if (strcasecmp(optarg, "radius") == 0) packettype = PT_RADIUS; else if (strcasecmp(optarg, "zmtp1") == 0) packettype = PT_ZMTP1; else if (strcasecmp(optarg, "vxlan") == 0) packettype = PT_VXLAN; else error("unknown packet type `%s'", optarg); break; case 'u': ++uflag; break; #ifdef HAVE_PCAP_DUMP_FLUSH case 'U': ++Uflag; break; #endif case 'v': ++vflag; break; case 'V': VFileName = optarg; break; case 'w': WFileName = optarg; break; case 'W': Wflag = atoi(optarg); if (Wflag < 0) error("invalid number of output files %s", optarg); WflagChars = getWflagChars(Wflag); break; case 'x': ++xflag; ++suppress_default_print; break; case 'X': ++Xflag; ++suppress_default_print; break; case 'y': gndo->ndo_dltname = optarg; gndo->ndo_dlt = pcap_datalink_name_to_val(gndo->ndo_dltname); if (gndo->ndo_dlt < 0) error("invalid data link type %s", gndo->ndo_dltname); break; #if defined(HAVE_PCAP_DEBUG) || defined(HAVE_YYDEBUG) case 'Y': { /* Undocumented flag */ #ifdef HAVE_PCAP_DEBUG extern int pcap_debug; pcap_debug = 1; #else extern int yydebug; yydebug = 1; #endif } break; #endif case 'z': if (optarg) { zflag = strdup(optarg); } else { usage(); /* NOTREACHED */ } break; case 'Z': if (optarg) { username = strdup(optarg); } else { usage(); /* NOTREACHED */ } break; default: usage(); /* NOTREACHED */ } switch (tflag) { case 0: /* Default */ case 4: /* Default + Date*/ thiszone = gmt2local(0); break; case 1: /* No time stamp */ case 2: /* Unix timeval style */ case 3: /* Microseconds since previous packet */ case 5: /* Microseconds since first packet */ break; default: /* Not supported */ error("only -t, -tt, -ttt, -tttt and -ttttt are supported"); break; } if (fflag != 0 && (VFileName != NULL || RFileName != NULL)) error("-f can not be used with -V or -r"); if (VFileName != NULL && RFileName != NULL) error("-V and -r are mutually exclusive."); #ifdef WITH_CHROOT /* if run as root, prepare for chrooting */ if (getuid() == 0 || geteuid() == 0) { /* future extensibility for cmd-line arguments */ if (!chroot_dir) chroot_dir = WITH_CHROOT; } #endif #ifdef WITH_USER /* if run as root, prepare for dropping root privileges */ if (getuid() == 0 || geteuid() == 0) { /* Run with '-Z root' to restore old behaviour */ if (!username) username = WITH_USER; } #endif if (RFileName != NULL || VFileName != NULL) { /* * If RFileName is non-null, it's the pathname of a * savefile to read. If VFileName is non-null, it's * the pathname of a file containing a list of pathnames * (one per line) of savefiles to read. * * In either case, we're reading a savefile, not doing * a live capture. */ #ifndef WIN32 /* * We don't need network access, so relinquish any set-UID * or set-GID privileges we have (if any). * * We do *not* want set-UID privileges when opening a * trace file, as that might let the user read other * people's trace files (especially if we're set-UID * root). */ if (setgid(getgid()) != 0 || setuid(getuid()) != 0 ) fprintf(stderr, "Warning: setgid/setuid failed !\n"); #endif /* WIN32 */ if (VFileName != NULL) { if (VFileName[0] == '-' && VFileName[1] == '\0') VFile = stdin; else VFile = fopen(VFileName, "r"); if (VFile == NULL) error("Unable to open file: %s\n", strerror(errno)); ret = get_next_file(VFile, VFileLine); if (!ret) error("Nothing in %s\n", VFileName); RFileName = VFileLine; } pd = pcap_open_offline(RFileName, ebuf); if (pd == NULL) error("%s", ebuf); dlt = pcap_datalink(pd); dlt_name = pcap_datalink_val_to_name(dlt); if (dlt_name == NULL) { fprintf(stderr, "reading from file %s, link-type %u\n", RFileName, dlt); } else { fprintf(stderr, "reading from file %s, link-type %s (%s)\n", RFileName, dlt_name, pcap_datalink_val_to_description(dlt)); } localnet = 0; netmask = 0; } else { /* * We're doing a live capture. */ if (device == NULL) { device = pcap_lookupdev(ebuf); if (device == NULL) error("%s", ebuf); } #ifdef WIN32 /* * Print a message to the standard error on Windows. * XXX - why do it here, with a different message? */ if(strlen(device) == 1) //we assume that an ASCII string is always longer than 1 char { //a Unicode string has a \0 as second byte (so strlen() is 1) fprintf(stderr, "%s: listening on %ws\n", program_name, device); } else { fprintf(stderr, "%s: listening on %s\n", program_name, device); } fflush(stderr); #endif /* WIN32 */ #ifdef HAVE_PCAP_CREATE pd = pcap_create(device, ebuf); if (pd == NULL) error("%s", ebuf); #ifdef HAVE_PCAP_SET_TSTAMP_TYPE if (Jflag) show_tstamp_types_and_exit(device, pd); #endif /* * Is this an interface that supports monitor mode? */ if (pcap_can_set_rfmon(pd) == 1) supports_monitor_mode = 1; else supports_monitor_mode = 0; status = pcap_set_snaplen(pd, snaplen); if (status != 0) error("%s: Can't set snapshot length: %s", device, pcap_statustostr(status)); status = pcap_set_promisc(pd, !pflag); if (status != 0) error("%s: Can't set promiscuous mode: %s", device, pcap_statustostr(status)); if (Iflag) { status = pcap_set_rfmon(pd, 1); if (status != 0) error("%s: Can't set monitor mode: %s", device, pcap_statustostr(status)); } status = pcap_set_timeout(pd, 1000); if (status != 0) error("%s: pcap_set_timeout failed: %s", device, pcap_statustostr(status)); if (Bflag != 0) { status = pcap_set_buffer_size(pd, Bflag); if (status != 0) error("%s: Can't set buffer size: %s", device, pcap_statustostr(status)); } #ifdef HAVE_PCAP_SET_TSTAMP_TYPE if (jflag != -1) { status = pcap_set_tstamp_type(pd, jflag); if (status < 0) error("%s: Can't set time stamp type: %s", device, pcap_statustostr(status)); } #endif - if (rxq != (uint32_t)-1) - pcap_set_rxq_mask(pd, rxq); - if (txq != (uint32_t)-1) - pcap_set_txq_mask(pd, txq); - if (other != (uint32_t)-1) - pcap_set_other_mask(pd, other); + if (qmask) + pcap_enable_qmask(pd); + if (rxq != (u_int)-1) + pcap_set_rxqmask(pd, rxq); + if (txq != (u_int)-1) + pcap_set_txqmask(pd, txq); + if (noq != -1) + noq ? pcap_set_noqmask(pd) : pcap_clear_noqmask(pd); status = pcap_activate(pd); if (status < 0) { /* * pcap_activate() failed. */ cp = pcap_geterr(pd); if (status == PCAP_ERROR) error("%s", cp); else if ((status == PCAP_ERROR_NO_SUCH_DEVICE || status == PCAP_ERROR_PERM_DENIED) && *cp != '\0') error("%s: %s\n(%s)", device, pcap_statustostr(status), cp); else error("%s: %s", device, pcap_statustostr(status)); } else if (status > 0) { /* * pcap_activate() succeeded, but it's warning us * of a problem it had. */ cp = pcap_geterr(pd); if (status == PCAP_WARNING) warning("%s", cp); else if (status == PCAP_WARNING_PROMISC_NOTSUP && *cp != '\0') warning("%s: %s\n(%s)", device, pcap_statustostr(status), cp); else warning("%s: %s", device, pcap_statustostr(status)); } #else *ebuf = '\0'; pd = pcap_open_live(device, snaplen, !pflag, 1000, ebuf); if (pd == NULL) error("%s", ebuf); else if (*ebuf) warning("%s", ebuf); #endif /* HAVE_PCAP_CREATE */ /* * Let user own process after socket has been opened. */ #ifndef WIN32 if (setgid(getgid()) != 0 || setuid(getuid()) != 0) fprintf(stderr, "Warning: setgid/setuid failed !\n"); #endif /* WIN32 */ #if !defined(HAVE_PCAP_CREATE) && defined(WIN32) if(Bflag != 0) if(pcap_setbuff(pd, Bflag)==-1){ error("%s", pcap_geterr(pd)); } #endif /* !defined(HAVE_PCAP_CREATE) && defined(WIN32) */ if (Lflag) show_dlts_and_exit(device, pd); if (gndo->ndo_dlt >= 0) { #ifdef HAVE_PCAP_SET_DATALINK if (pcap_set_datalink(pd, gndo->ndo_dlt) < 0) error("%s", pcap_geterr(pd)); #else /* * We don't actually support changing the * data link type, so we only let them * set it to what it already is. */ if (gndo->ndo_dlt != pcap_datalink(pd)) { error("%s is not one of the DLTs supported by this device\n", gndo->ndo_dltname); } #endif (void)fprintf(stderr, "%s: data link type %s\n", program_name, gndo->ndo_dltname); (void)fflush(stderr); } i = pcap_snapshot(pd); if (snaplen < i) { warning("snaplen raised from %d to %d", snaplen, i); snaplen = i; } if (pcap_lookupnet(device, &localnet, &netmask, ebuf) < 0) { localnet = 0; netmask = 0; warning("%s", ebuf); } } if (infile) cmdbuf = read_infile(infile); else cmdbuf = copy_argv(&argv[optind]); if (pcap_compile(pd, &fcode, cmdbuf, Oflag, netmask) < 0) error("%s", pcap_geterr(pd)); if (dflag) { bpf_dump(&fcode, dflag); pcap_close(pd); free(cmdbuf); exit(0); } init_addrtoname(localnet, netmask); init_checksum(); #ifndef WIN32 (void)setsignal(SIGPIPE, cleanup); (void)setsignal(SIGTERM, cleanup); (void)setsignal(SIGINT, cleanup); #endif /* WIN32 */ #if defined(HAVE_FORK) || defined(HAVE_VFORK) (void)setsignal(SIGCHLD, child_cleanup); #endif /* Cooperate with nohup(1) */ #ifndef WIN32 if ((oldhandler = setsignal(SIGHUP, cleanup)) != SIG_DFL) (void)setsignal(SIGHUP, oldhandler); #endif /* WIN32 */ #ifndef WIN32 /* * If a user name was specified with "-Z", attempt to switch to * that user's UID. This would probably be used with sudo, * to allow tcpdump to be run in a special restricted * account (if you just want to allow users to open capture * devices, and can't just give users that permission, * you'd make tcpdump set-UID or set-GID). * * Tcpdump doesn't necessarily write only to one savefile; * the general only way to allow a -Z instance to write to * savefiles as the user under whose UID it's run, rather * than as the user specified with -Z, would thus be to switch * to the original user ID before opening a capture file and * then switch back to the -Z user ID after opening the savefile. * Switching to the -Z user ID only after opening the first * savefile doesn't handle the general case. */ #ifdef HAVE_CAP_NG_H /* We are running as root and we will be writing to savefile */ if ((getuid() == 0 || geteuid() == 0) && WFileName) { if (username) { /* Drop all capabilities from effective set */ capng_clear(CAPNG_EFFECTIVE); /* Add capabilities we will need*/ capng_update(CAPNG_ADD, CAPNG_PERMITTED, CAP_SETUID); capng_update(CAPNG_ADD, CAPNG_PERMITTED, CAP_SETGID); capng_update(CAPNG_ADD, CAPNG_PERMITTED, CAP_DAC_OVERRIDE); capng_update(CAPNG_ADD, CAPNG_EFFECTIVE, CAP_SETUID); capng_update(CAPNG_ADD, CAPNG_EFFECTIVE, CAP_SETGID); capng_update(CAPNG_ADD, CAPNG_EFFECTIVE, CAP_DAC_OVERRIDE); capng_apply(CAPNG_SELECT_BOTH); } } #endif /* HAVE_CAP_NG_H */ if (getuid() == 0 || geteuid() == 0) { if (username || chroot_dir) droproot(username, chroot_dir); } #endif /* WIN32 */ if (pcap_setfilter(pd, &fcode) < 0) error("%s", pcap_geterr(pd)); if (WFileName) { pcap_dumper_t *p; /* Do not exceed the default PATH_MAX for files. */ dumpinfo.CurrentFileName = (char *)malloc(PATH_MAX + 1); if (dumpinfo.CurrentFileName == NULL) error("malloc of dumpinfo.CurrentFileName"); /* We do not need numbering for dumpfiles if Cflag isn't set. */ if (Cflag != 0) MakeFilename(dumpinfo.CurrentFileName, WFileName, 0, WflagChars); else MakeFilename(dumpinfo.CurrentFileName, WFileName, 0, 0); p = pcap_dump_open(pd, dumpinfo.CurrentFileName); #ifdef HAVE_CAP_NG_H /* Give up capabilities, clear Effective set */ capng_clear(CAPNG_EFFECTIVE); #endif if (p == NULL) error("%s", pcap_geterr(pd)); if (Cflag != 0 || Gflag != 0) { callback = dump_packet_and_trunc; dumpinfo.WFileName = WFileName; dumpinfo.pd = pd; dumpinfo.p = p; pcap_userdata = (u_char *)&dumpinfo; } else { callback = dump_packet; pcap_userdata = (u_char *)p; } #ifdef HAVE_PCAP_DUMP_FLUSH if (Uflag) pcap_dump_flush(p); #endif } else { type = pcap_datalink(pd); printinfo = get_print_info(type); callback = print_packet; pcap_userdata = (u_char *)&printinfo; } #ifdef SIGNAL_REQ_INFO /* * We can't get statistics when reading from a file rather * than capturing from a device. */ if (RFileName == NULL) (void)setsignal(SIGNAL_REQ_INFO, requestinfo); #endif if (vflag > 0 && WFileName) { /* * When capturing to a file, "-v" means tcpdump should, * every 10 secodns, "v"erbosely report the number of * packets captured. */ #ifdef USE_WIN32_MM_TIMER /* call verbose_stats_dump() each 1000 +/-100msec */ timer_id = timeSetEvent(1000, 100, verbose_stats_dump, 0, TIME_PERIODIC); setvbuf(stderr, NULL, _IONBF, 0); #elif defined(HAVE_ALARM) (void)setsignal(SIGALRM, verbose_stats_dump); alarm(1); #endif } #ifndef WIN32 if (RFileName == NULL) { /* * Live capture (if -V was specified, we set RFileName * to a file from the -V file). Print a message to * the standard error on UN*X. */ if (!vflag && !WFileName) { (void)fprintf(stderr, "%s: verbose output suppressed, use -v or -vv for full protocol decode\n", program_name); } else (void)fprintf(stderr, "%s: ", program_name); dlt = pcap_datalink(pd); dlt_name = pcap_datalink_val_to_name(dlt); if (dlt_name == NULL) { (void)fprintf(stderr, "listening on %s, link-type %u, capture size %u bytes\n", device, dlt, snaplen); } else { (void)fprintf(stderr, "listening on %s, link-type %s (%s), capture size %u bytes\n", device, dlt_name, pcap_datalink_val_to_description(dlt), snaplen); } (void)fflush(stderr); } #endif /* WIN32 */ do { status = pcap_loop(pd, cnt, callback, pcap_userdata); if (WFileName == NULL) { /* * We're printing packets. Flush the printed output, * so it doesn't get intermingled with error output. */ if (status == -2) { /* * We got interrupted, so perhaps we didn't * manage to finish a line we were printing. * Print an extra newline, just in case. */ putchar('\n'); } (void)fflush(stdout); } if (status == -1) { /* * Error. Report it. */ (void)fprintf(stderr, "%s: pcap_loop: %s\n", program_name, pcap_geterr(pd)); } if (RFileName == NULL) { /* * We're doing a live capture. Report the capture * statistics. */ info(1); } pcap_close(pd); if (VFileName != NULL) { ret = get_next_file(VFile, VFileLine); if (ret) { RFileName = VFileLine; pd = pcap_open_offline(RFileName, ebuf); if (pd == NULL) error("%s", ebuf); new_dlt = pcap_datalink(pd); if (WFileName && new_dlt != dlt) error("%s: new dlt does not match original", RFileName); printinfo = get_print_info(new_dlt); dlt_name = pcap_datalink_val_to_name(new_dlt); if (dlt_name == NULL) { fprintf(stderr, "reading from file %s, link-type %u\n", RFileName, new_dlt); } else { fprintf(stderr, "reading from file %s, link-type %s (%s)\n", RFileName, dlt_name, pcap_datalink_val_to_description(new_dlt)); } if (pcap_compile(pd, &fcode, cmdbuf, Oflag, netmask) < 0) error("%s", pcap_geterr(pd)); if (pcap_setfilter(pd, &fcode) < 0) error("%s", pcap_geterr(pd)); } } } while (ret != NULL); free(cmdbuf); exit(status == -1 ? 1 : 0); } /* make a clean exit on interrupts */ static RETSIGTYPE cleanup(int signo _U_) { #ifdef USE_WIN32_MM_TIMER if (timer_id) timeKillEvent(timer_id); timer_id = 0; #elif defined(HAVE_ALARM) alarm(0); #endif #ifdef HAVE_PCAP_BREAKLOOP /* * We have "pcap_breakloop()"; use it, so that we do as little * as possible in the signal handler (it's probably not safe * to do anything with standard I/O streams in a signal handler - * the ANSI C standard doesn't say it is). */ pcap_breakloop(pd); #else /* * We don't have "pcap_breakloop()"; this isn't safe, but * it's the best we can do. Print the summary if we're * not reading from a savefile - i.e., if we're doing a * live capture - and exit. */ if (pd != NULL && pcap_file(pd) == NULL) { /* * We got interrupted, so perhaps we didn't * manage to finish a line we were printing. * Print an extra newline, just in case. */ putchar('\n'); (void)fflush(stdout); info(1); } exit(0); #endif } /* On windows, we do not use a fork, so we do not care less about waiting a child processes to die */ #if defined(HAVE_FORK) || defined(HAVE_VFORK) static RETSIGTYPE child_cleanup(int signo _U_) { wait(NULL); } #endif /* HAVE_FORK && HAVE_VFORK */ static void info(register int verbose) { struct pcap_stat stat; /* * Older versions of libpcap didn't set ps_ifdrop on some * platforms; initialize it to 0 to handle that. */ stat.ps_ifdrop = 0; if (pcap_stats(pd, &stat) < 0) { (void)fprintf(stderr, "pcap_stats: %s\n", pcap_geterr(pd)); infoprint = 0; return; } if (!verbose) fprintf(stderr, "%s: ", program_name); (void)fprintf(stderr, "%u packet%s captured", packets_captured, PLURAL_SUFFIX(packets_captured)); if (!verbose) fputs(", ", stderr); else putc('\n', stderr); (void)fprintf(stderr, "%u packet%s received by filter", stat.ps_recv, PLURAL_SUFFIX(stat.ps_recv)); if (!verbose) fputs(", ", stderr); else putc('\n', stderr); (void)fprintf(stderr, "%u packet%s dropped by kernel", stat.ps_drop, PLURAL_SUFFIX(stat.ps_drop)); if (stat.ps_ifdrop != 0) { if (!verbose) fputs(", ", stderr); else putc('\n', stderr); (void)fprintf(stderr, "%u packet%s dropped by interface\n", stat.ps_ifdrop, PLURAL_SUFFIX(stat.ps_ifdrop)); } else putc('\n', stderr); infoprint = 0; } #if defined(HAVE_FORK) || defined(HAVE_VFORK) static void compress_savefile(const char *filename) { # ifdef HAVE_FORK if (fork()) # else if (vfork()) # endif return; /* * Set to lowest priority so that this doesn't disturb the capture */ #ifdef NZERO setpriority(PRIO_PROCESS, 0, NZERO - 1); #else setpriority(PRIO_PROCESS, 0, 19); #endif if (execlp(zflag, zflag, filename, (char *)NULL) == -1) fprintf(stderr, "compress_savefile:execlp(%s, %s): %s\n", zflag, filename, strerror(errno)); # ifdef HAVE_FORK exit(1); # else _exit(1); # endif } #else /* HAVE_FORK && HAVE_VFORK */ static void compress_savefile(const char *filename) { fprintf(stderr, "compress_savefile failed. Functionality not implemented under your system\n"); } #endif /* HAVE_FORK && HAVE_VFORK */ static void dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) { struct dump_info *dump_info; ++packets_captured; ++infodelay; dump_info = (struct dump_info *)user; /* * XXX - this won't force the file to rotate on the specified time * boundary, but it will rotate on the first packet received after the * specified Gflag number of seconds. Note: if a Gflag time boundary * and a Cflag size boundary coincide, the time rotation will occur * first thereby cancelling the Cflag boundary (since the file should * be 0). */ if (Gflag != 0) { /* Check if it is time to rotate */ time_t t; /* Get the current time */ if ((t = time(NULL)) == (time_t)-1) { error("dump_and_trunc_packet: can't get current_time: %s", pcap_strerror(errno)); } /* If the time is greater than the specified window, rotate */ if (t - Gflag_time >= Gflag) { /* Update the Gflag_time */ Gflag_time = t; /* Update Gflag_count */ Gflag_count++; /* * Close the current file and open a new one. */ pcap_dump_close(dump_info->p); /* * Compress the file we just closed, if the user asked for it */ if (zflag != NULL) compress_savefile(dump_info->CurrentFileName); /* * Check to see if we've exceeded the Wflag (when * not using Cflag). */ if (Cflag == 0 && Wflag > 0 && Gflag_count >= Wflag) { (void)fprintf(stderr, "Maximum file limit reached: %d\n", Wflag); exit(0); /* NOTREACHED */ } if (dump_info->CurrentFileName != NULL) free(dump_info->CurrentFileName); /* Allocate space for max filename + \0. */ dump_info->CurrentFileName = (char *)malloc(PATH_MAX + 1); if (dump_info->CurrentFileName == NULL) error("dump_packet_and_trunc: malloc"); /* * This is always the first file in the Cflag * rotation: e.g. 0 * We also don't need numbering if Cflag is not set. */ if (Cflag != 0) MakeFilename(dump_info->CurrentFileName, dump_info->WFileName, 0, WflagChars); else MakeFilename(dump_info->CurrentFileName, dump_info->WFileName, 0, 0); #ifdef HAVE_CAP_NG_H capng_update(CAPNG_ADD, CAPNG_EFFECTIVE, CAP_DAC_OVERRIDE); capng_apply(CAPNG_EFFECTIVE); #endif /* HAVE_CAP_NG_H */ dump_info->p = pcap_dump_open(dump_info->pd, dump_info->CurrentFileName); #ifdef HAVE_CAP_NG_H capng_update(CAPNG_DROP, CAPNG_EFFECTIVE, CAP_DAC_OVERRIDE); capng_apply(CAPNG_EFFECTIVE); #endif /* HAVE_CAP_NG_H */ if (dump_info->p == NULL) error("%s", pcap_geterr(pd)); } } /* * XXX - this won't prevent capture files from getting * larger than Cflag - the last packet written to the * file could put it over Cflag. */ if (Cflag != 0 && pcap_dump_ftell(dump_info->p) > Cflag) { /* * Close the current file and open a new one. */ pcap_dump_close(dump_info->p); /* * Compress the file we just closed, if the user asked for it */ if (zflag != NULL) compress_savefile(dump_info->CurrentFileName); Cflag_count++; if (Wflag > 0) { if (Cflag_count >= Wflag) Cflag_count = 0; } if (dump_info->CurrentFileName != NULL) free(dump_info->CurrentFileName); dump_info->CurrentFileName = (char *)malloc(PATH_MAX + 1); if (dump_info->CurrentFileName == NULL) error("dump_packet_and_trunc: malloc"); MakeFilename(dump_info->CurrentFileName, dump_info->WFileName, Cflag_count, WflagChars); dump_info->p = pcap_dump_open(dump_info->pd, dump_info->CurrentFileName); if (dump_info->p == NULL) error("%s", pcap_geterr(pd)); } pcap_dump((u_char *)dump_info->p, h, sp); #ifdef HAVE_PCAP_DUMP_FLUSH if (Uflag) pcap_dump_flush(dump_info->p); #endif --infodelay; if (infoprint) info(0); } static void dump_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) { ++packets_captured; ++infodelay; pcap_dump(user, h, sp); #ifdef HAVE_PCAP_DUMP_FLUSH if (Uflag) pcap_dump_flush((pcap_dumper_t *)user); #endif --infodelay; if (infoprint) info(0); } static void print_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) { struct print_info *print_info; u_int hdrlen; ++packets_captured; ++infodelay; ts_print(&h->ts); print_info = (struct print_info *)user; /* * Some printers want to check that they're not walking off the * end of the packet. * Rather than pass it all the way down, we set this global. */ snapend = sp + h->caplen; if(print_info->ndo_type) { hdrlen = (*print_info->p.ndo_printer)(print_info->ndo, h, sp); } else { hdrlen = (*print_info->p.printer)(h, sp); } if (Xflag) { /* * Print the raw packet data in hex and ASCII. */ if (Xflag > 1) { /* * Include the link-layer header. */ hex_and_ascii_print("\n\t", sp, h->caplen); } else { /* * Don't include the link-layer header - and if * we have nothing past the link-layer header, * print nothing. */ if (h->caplen > hdrlen) hex_and_ascii_print("\n\t", sp + hdrlen, h->caplen - hdrlen); } } else if (xflag) { /* * Print the raw packet data in hex. */ if (xflag > 1) { /* * Include the link-layer header. */ hex_print("\n\t", sp, h->caplen); } else { /* * Don't include the link-layer header - and if * we have nothing past the link-layer header, * print nothing. */ if (h->caplen > hdrlen) hex_print("\n\t", sp + hdrlen, h->caplen - hdrlen); } } else if (Aflag) { /* * Print the raw packet data in ASCII. */ if (Aflag > 1) { /* * Include the link-layer header. */ ascii_print(sp, h->caplen); } else { /* * Don't include the link-layer header - and if * we have nothing past the link-layer header, * print nothing. */ if (h->caplen > hdrlen) ascii_print(sp + hdrlen, h->caplen - hdrlen); } } putchar('\n'); --infodelay; if (infoprint) info(0); } #ifdef WIN32 /* * XXX - there should really be libpcap calls to get the version * number as a string (the string would be generated from #defines * at run time, so that it's not generated from string constants * in the library, as, on many UNIX systems, those constants would * be statically linked into the application executable image, and * would thus reflect the version of libpcap on the system on * which the application was *linked*, not the system on which it's * *running*. * * That routine should be documented, unlike the "version[]" * string, so that UNIX vendors providing their own libpcaps * don't omit it (as a couple of vendors have...). * * Packet.dll should perhaps also export a routine to return the * version number of the Packet.dll code, to supply the * "Wpcap_version" information on Windows. */ char WDversion[]="current-cvs.tcpdump.org"; #if !defined(HAVE_GENERATED_VERSION) char version[]="current-cvs.tcpdump.org"; #endif char pcap_version[]="current-cvs.tcpdump.org"; char Wpcap_version[]="3.1"; #endif /* * By default, print the specified data out in hex and ASCII. */ static void ndo_default_print(netdissect_options *ndo _U_, const u_char *bp, u_int length) { hex_and_ascii_print("\n\t", bp, length); /* pass on lf and identation string */ } void default_print(const u_char *bp, u_int length) { ndo_default_print(gndo, bp, length); } #ifdef SIGNAL_REQ_INFO RETSIGTYPE requestinfo(int signo _U_) { if (infodelay) ++infoprint; else info(0); } #endif /* * Called once each second in verbose mode while dumping to file */ #ifdef USE_WIN32_MM_TIMER void CALLBACK verbose_stats_dump (UINT timer_id _U_, UINT msg _U_, DWORD_PTR arg _U_, DWORD_PTR dw1 _U_, DWORD_PTR dw2 _U_) { struct pcap_stat stat; if (infodelay == 0 && pcap_stats(pd, &stat) >= 0) fprintf(stderr, "Got %u\r", packets_captured); } #elif defined(HAVE_ALARM) static void verbose_stats_dump(int sig _U_) { struct pcap_stat stat; if (infodelay == 0 && pcap_stats(pd, &stat) >= 0) fprintf(stderr, "Got %u\r", packets_captured); alarm(1); } #endif static void usage(void) { extern char version[]; #ifndef HAVE_PCAP_LIB_VERSION #if defined(WIN32) || defined(HAVE_PCAP_VERSION) extern char pcap_version[]; #else /* defined(WIN32) || defined(HAVE_PCAP_VERSION) */ static char pcap_version[] = "unknown"; #endif /* defined(WIN32) || defined(HAVE_PCAP_VERSION) */ #endif /* HAVE_PCAP_LIB_VERSION */ #ifdef HAVE_PCAP_LIB_VERSION #ifdef WIN32 (void)fprintf(stderr, "%s version %s, based on tcpdump version %s\n", program_name, WDversion, version); #else /* WIN32 */ (void)fprintf(stderr, "%s version %s\n", program_name, version); #endif /* WIN32 */ (void)fprintf(stderr, "%s\n",pcap_lib_version()); #else /* HAVE_PCAP_LIB_VERSION */ #ifdef WIN32 (void)fprintf(stderr, "%s version %s, based on tcpdump version %s\n", program_name, WDversion, version); (void)fprintf(stderr, "WinPcap version %s, based on libpcap version %s\n",Wpcap_version, pcap_version); #else /* WIN32 */ (void)fprintf(stderr, "%s version %s\n", program_name, version); (void)fprintf(stderr, "libpcap version %s\n", pcap_version); #endif /* WIN32 */ #endif /* HAVE_PCAP_LIB_VERSION */ (void)fprintf(stderr, "Usage: %s [-aAbd" D_FLAG "efghH" I_FLAG J_FLAG "kKlLnNOpqQRStu" U_FLAG "vxX]" B_FLAG_USAGE " [ -c count ]\n", program_name); (void)fprintf(stderr, "\t\t[ -C file_size ] [ -E algo:secret ] [ -F file ] [ -G seconds ]\n"); (void)fprintf(stderr, "\t\t[ -i interface ]" j_FLAG_USAGE " [ -M secret ]\n"); (void)fprintf(stderr, "\t\t[ -r file ] [ -s snaplen ] [ -T type ] [ -V file ] [ -w file ]\n"); (void)fprintf(stderr, "\t\t[ -W filecount ] [ -y datalinktype ] [ -z command ]\n"); (void)fprintf(stderr, "\t\t[ -Z user ] [ expression ]\n"); exit(1); } /* VARARGS */ static void ndo_error(netdissect_options *ndo _U_, const char *fmt, ...) { va_list ap; (void)fprintf(stderr, "%s: ", program_name); va_start(ap, fmt); (void)vfprintf(stderr, fmt, ap); va_end(ap); if (*fmt) { fmt += strlen(fmt); if (fmt[-1] != '\n') (void)fputc('\n', stderr); } exit(1); /* NOTREACHED */ } /* VARARGS */ static void ndo_warning(netdissect_options *ndo _U_, const char *fmt, ...) { va_list ap; (void)fprintf(stderr, "%s: WARNING: ", program_name); va_start(ap, fmt); (void)vfprintf(stderr, fmt, ap); va_end(ap); if (*fmt) { fmt += strlen(fmt); if (fmt[-1] != '\n') (void)fputc('\n', stderr); } } Index: user/syuu/mq_bpf/sbin/ifconfig/af_inet.c =================================================================== --- user/syuu/mq_bpf/sbin/ifconfig/af_inet.c (revision 255171) +++ user/syuu/mq_bpf/sbin/ifconfig/af_inet.c (revision 255172) @@ -1,212 +1,214 @@ /* * Copyright (c) 1983, 1993 * 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 the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ #include #include #include #include #include #include #include #include #include #include #include #include #include /* for struct ifaddr */ #include #include #include #include "ifconfig.h" static struct in_aliasreq in_addreq; static struct ifreq in_ridreq; static void in_status(int s __unused, const struct ifaddrs *ifa) { struct sockaddr_in *sin, null_sin; memset(&null_sin, 0, sizeof(null_sin)); sin = (struct sockaddr_in *)ifa->ifa_addr; if (sin == NULL) return; printf("\tinet %s ", inet_ntoa(sin->sin_addr)); if (ifa->ifa_flags & IFF_POINTOPOINT) { sin = (struct sockaddr_in *)ifa->ifa_dstaddr; if (sin == NULL) sin = &null_sin; printf("--> %s ", inet_ntoa(sin->sin_addr)); } sin = (struct sockaddr_in *)ifa->ifa_netmask; if (sin == NULL) sin = &null_sin; printf("netmask 0x%lx ", (unsigned long)ntohl(sin->sin_addr.s_addr)); if (ifa->ifa_flags & IFF_BROADCAST) { sin = (struct sockaddr_in *)ifa->ifa_broadaddr; if (sin != NULL && sin->sin_addr.s_addr != 0) printf("broadcast %s ", inet_ntoa(sin->sin_addr)); } print_vhid(ifa, " "); putchar('\n'); } #define SIN(x) ((struct sockaddr_in *) &(x)) static struct sockaddr_in *sintab[] = { SIN(in_ridreq.ifr_addr), SIN(in_addreq.ifra_addr), SIN(in_addreq.ifra_mask), SIN(in_addreq.ifra_broadaddr) }; static void in_getaddr(const char *s, int which) { +#ifndef MIN #define MIN(a,b) ((a)<(b)?(a):(b)) +#endif struct sockaddr_in *sin = sintab[which]; struct hostent *hp; struct netent *np; sin->sin_len = sizeof(*sin); sin->sin_family = AF_INET; if (which == ADDR) { char *p = NULL; if((p = strrchr(s, '/')) != NULL) { const char *errstr; /* address is `name/masklen' */ int masklen; struct sockaddr_in *min = sintab[MASK]; *p = '\0'; if (!isdigit(*(p + 1))) errstr = "invalid"; else masklen = (int)strtonum(p + 1, 0, 32, &errstr); if (errstr != NULL) { *p = '/'; errx(1, "%s: bad value (width %s)", s, errstr); } min->sin_family = AF_INET; min->sin_len = sizeof(*min); min->sin_addr.s_addr = htonl(~((1LL << (32 - masklen)) - 1) & 0xffffffff); } } if (inet_aton(s, &sin->sin_addr)) return; if ((hp = gethostbyname(s)) != 0) bcopy(hp->h_addr, (char *)&sin->sin_addr, MIN((size_t)hp->h_length, sizeof(sin->sin_addr))); else if ((np = getnetbyname(s)) != 0) sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY); else errx(1, "%s: bad value", s); #undef MIN } static void in_status_tunnel(int s) { char src[NI_MAXHOST]; char dst[NI_MAXHOST]; struct ifreq ifr; const struct sockaddr *sa = (const struct sockaddr *) &ifr.ifr_addr; memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, name, IFNAMSIZ); if (ioctl(s, SIOCGIFPSRCADDR, (caddr_t)&ifr) < 0) return; if (sa->sa_family != AF_INET) return; if (getnameinfo(sa, sa->sa_len, src, sizeof(src), 0, 0, NI_NUMERICHOST) != 0) src[0] = '\0'; if (ioctl(s, SIOCGIFPDSTADDR, (caddr_t)&ifr) < 0) return; if (sa->sa_family != AF_INET) return; if (getnameinfo(sa, sa->sa_len, dst, sizeof(dst), 0, 0, NI_NUMERICHOST) != 0) dst[0] = '\0'; printf("\ttunnel inet %s --> %s\n", src, dst); } static void in_set_tunnel(int s, struct addrinfo *srcres, struct addrinfo *dstres) { struct in_aliasreq addreq; memset(&addreq, 0, sizeof(addreq)); strncpy(addreq.ifra_name, name, IFNAMSIZ); memcpy(&addreq.ifra_addr, srcres->ai_addr, srcres->ai_addr->sa_len); memcpy(&addreq.ifra_dstaddr, dstres->ai_addr, dstres->ai_addr->sa_len); if (ioctl(s, SIOCSIFPHYADDR, &addreq) < 0) warn("SIOCSIFPHYADDR"); } static struct afswtch af_inet = { .af_name = "inet", .af_af = AF_INET, .af_status = in_status, .af_getaddr = in_getaddr, .af_status_tunnel = in_status_tunnel, .af_settunnel = in_set_tunnel, .af_difaddr = SIOCDIFADDR, .af_aifaddr = SIOCAIFADDR, .af_ridreq = &in_ridreq, .af_addreq = &in_addreq, }; static __constructor void inet_ctor(void) { #ifndef RESCUE if (!feature_present("inet")) return; #endif af_register(&af_inet); } Index: user/syuu/mq_bpf/sys/net/bpf.c =================================================================== --- user/syuu/mq_bpf/sys/net/bpf.c (revision 255171) +++ user/syuu/mq_bpf/sys/net/bpf.c (revision 255172) @@ -1,3144 +1,3144 @@ /*- * Copyright (c) 1990, 1991, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from the Stanford/CMU enet packet filter, * (net/enet.c) distributed as part of 4.3BSD, and code contributed * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence * Berkeley Laboratory. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)bpf.c 8.4 (Berkeley) 1/9/95 */ #include __FBSDID("$FreeBSD$"); #include "opt_bpf.h" #include "opt_compat.h" #include "opt_netgraph.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define BPF_INTERNAL #include #include #ifdef BPF_JITTER #include #endif #include #include #include #include #include #include #include #include #include MALLOC_DEFINE(M_BPF, "BPF", "BPF data"); #if defined(DEV_BPF) || defined(NETGRAPH_BPF) #define PRINET 26 /* interruptible */ #define SIZEOF_BPF_HDR(type) \ (offsetof(type, bh_hdrlen) + sizeof(((type *)0)->bh_hdrlen)) #ifdef COMPAT_FREEBSD32 #include #include #define BPF_ALIGNMENT32 sizeof(int32_t) #define BPF_WORDALIGN32(x) (((x)+(BPF_ALIGNMENT32-1))&~(BPF_ALIGNMENT32-1)) #ifndef BURN_BRIDGES /* * 32-bit version of structure prepended to each packet. We use this header * instead of the standard one for 32-bit streams. We mark the a stream as * 32-bit the first time we see a 32-bit compat ioctl request. */ struct bpf_hdr32 { struct timeval32 bh_tstamp; /* time stamp */ uint32_t bh_caplen; /* length of captured portion */ uint32_t bh_datalen; /* original length of packet */ uint16_t bh_hdrlen; /* length of bpf header (this struct plus alignment padding) */ }; #endif struct bpf_program32 { u_int bf_len; uint32_t bf_insns; }; struct bpf_dltlist32 { u_int bfl_len; u_int bfl_list; }; #define BIOCSETF32 _IOW('B', 103, struct bpf_program32) #define BIOCSRTIMEOUT32 _IOW('B', 109, struct timeval32) #define BIOCGRTIMEOUT32 _IOR('B', 110, struct timeval32) #define BIOCGDLTLIST32 _IOWR('B', 121, struct bpf_dltlist32) #define BIOCSETWF32 _IOW('B', 123, struct bpf_program32) #define BIOCSETFNR32 _IOW('B', 130, struct bpf_program32) #endif /* * bpf_iflist is a list of BPF interface structures, each corresponding to a * specific DLT. The same network interface might have several BPF interface * structures registered by different layers in the stack (i.e., 802.11 * frames, ethernet frames, etc). */ static LIST_HEAD(, bpf_if) bpf_iflist, bpf_freelist; static struct mtx bpf_mtx; /* bpf global lock */ static int bpf_bpfd_cnt; static void bpf_attachd(struct bpf_d *, struct bpf_if *); static void bpf_detachd(struct bpf_d *); static void bpf_detachd_locked(struct bpf_d *); static void bpf_freed(struct bpf_d *); static int bpf_movein(struct uio *, int, struct ifnet *, struct mbuf **, struct sockaddr *, int *, struct bpf_insn *); static int bpf_setif(struct bpf_d *, struct ifreq *); static void bpf_timed_out(void *); static __inline void bpf_wakeup(struct bpf_d *); static void catchpacket(struct bpf_d *, u_char *, u_int, u_int, void (*)(struct bpf_d *, caddr_t, u_int, void *, u_int), struct bintime *); static void reset_d(struct bpf_d *); static int bpf_setf(struct bpf_d *, struct bpf_program *, u_long cmd); static int bpf_getdltlist(struct bpf_d *, struct bpf_dltlist *); static int bpf_setdlt(struct bpf_d *, u_int); static void filt_bpfdetach(struct knote *); static int filt_bpfread(struct knote *, long); static void bpf_drvinit(void *); static int bpf_stats_sysctl(SYSCTL_HANDLER_ARGS); SYSCTL_NODE(_net, OID_AUTO, bpf, CTLFLAG_RW, 0, "bpf sysctl"); int bpf_maxinsns = BPF_MAXINSNS; SYSCTL_INT(_net_bpf, OID_AUTO, maxinsns, CTLFLAG_RW, &bpf_maxinsns, 0, "Maximum bpf program instructions"); static int bpf_zerocopy_enable = 0; SYSCTL_INT(_net_bpf, OID_AUTO, zerocopy_enable, CTLFLAG_RW, &bpf_zerocopy_enable, 0, "Enable new zero-copy BPF buffer sessions"); static SYSCTL_NODE(_net_bpf, OID_AUTO, stats, CTLFLAG_MPSAFE | CTLFLAG_RW, bpf_stats_sysctl, "bpf statistics portal"); static VNET_DEFINE(int, bpf_optimize_writers) = 0; #define V_bpf_optimize_writers VNET(bpf_optimize_writers) SYSCTL_VNET_INT(_net_bpf, OID_AUTO, optimize_writers, CTLFLAG_RW, &VNET_NAME(bpf_optimize_writers), 0, "Do not send packets until BPF program is set"); static d_open_t bpfopen; static d_read_t bpfread; static d_write_t bpfwrite; static d_ioctl_t bpfioctl; static d_poll_t bpfpoll; static d_kqfilter_t bpfkqfilter; static struct cdevsw bpf_cdevsw = { .d_version = D_VERSION, .d_open = bpfopen, .d_read = bpfread, .d_write = bpfwrite, .d_ioctl = bpfioctl, .d_poll = bpfpoll, .d_name = "bpf", .d_kqfilter = bpfkqfilter, }; static struct filterops bpfread_filtops = { .f_isfd = 1, .f_detach = filt_bpfdetach, .f_event = filt_bpfread, }; eventhandler_tag bpf_ifdetach_cookie = NULL; /* * LOCKING MODEL USED BY BPF: * Locks: * 1) global lock (BPF_LOCK). Mutex, used to protect interface addition/removal, * some global counters and every bpf_if reference. * 2) Interface lock. Rwlock, used to protect list of BPF descriptors and their filters. * 3) Descriptor lock. Mutex, used to protect BPF buffers and various structure fields * used by bpf_mtap code. * * Lock order: * * Global lock, interface lock, descriptor lock * * We have to acquire interface lock before descriptor main lock due to BPF_MTAP[2] * working model. In many places (like bpf_detachd) we start with BPF descriptor * (and we need to at least rlock it to get reliable interface pointer). This * gives us potential LOR. As a result, we use global lock to protect from bpf_if * change in every such place. * * Changing d->bd_bif is protected by 1) global lock, 2) interface lock and * 3) descriptor main wlock. * Reading bd_bif can be protected by any of these locks, typically global lock. * * Changing read/write BPF filter is protected by the same three locks, * the same applies for reading. * * Sleeping in global lock is not allowed due to bpfdetach() using it. */ /* * Wrapper functions for various buffering methods. If the set of buffer * modes expands, we will probably want to introduce a switch data structure * similar to protosw, et. */ static void bpf_append_bytes(struct bpf_d *d, caddr_t buf, u_int offset, void *src, u_int len) { BPFD_LOCK_ASSERT(d); switch (d->bd_bufmode) { case BPF_BUFMODE_BUFFER: return (bpf_buffer_append_bytes(d, buf, offset, src, len)); case BPF_BUFMODE_ZBUF: d->bd_zcopy++; return (bpf_zerocopy_append_bytes(d, buf, offset, src, len)); default: panic("bpf_buf_append_bytes"); } } static void bpf_append_mbuf(struct bpf_d *d, caddr_t buf, u_int offset, void *src, u_int len) { BPFD_LOCK_ASSERT(d); switch (d->bd_bufmode) { case BPF_BUFMODE_BUFFER: return (bpf_buffer_append_mbuf(d, buf, offset, src, len)); case BPF_BUFMODE_ZBUF: d->bd_zcopy++; return (bpf_zerocopy_append_mbuf(d, buf, offset, src, len)); default: panic("bpf_buf_append_mbuf"); } } /* * This function gets called when the free buffer is re-assigned. */ static void bpf_buf_reclaimed(struct bpf_d *d) { BPFD_LOCK_ASSERT(d); switch (d->bd_bufmode) { case BPF_BUFMODE_BUFFER: return; case BPF_BUFMODE_ZBUF: bpf_zerocopy_buf_reclaimed(d); return; default: panic("bpf_buf_reclaimed"); } } /* * If the buffer mechanism has a way to decide that a held buffer can be made * free, then it is exposed via the bpf_canfreebuf() interface. (1) is * returned if the buffer can be discarded, (0) is returned if it cannot. */ static int bpf_canfreebuf(struct bpf_d *d) { BPFD_LOCK_ASSERT(d); switch (d->bd_bufmode) { case BPF_BUFMODE_ZBUF: return (bpf_zerocopy_canfreebuf(d)); } return (0); } /* * Allow the buffer model to indicate that the current store buffer is * immutable, regardless of the appearance of space. Return (1) if the * buffer is writable, and (0) if not. */ static int bpf_canwritebuf(struct bpf_d *d) { BPFD_LOCK_ASSERT(d); switch (d->bd_bufmode) { case BPF_BUFMODE_ZBUF: return (bpf_zerocopy_canwritebuf(d)); } return (1); } /* * Notify buffer model that an attempt to write to the store buffer has * resulted in a dropped packet, in which case the buffer may be considered * full. */ static void bpf_buffull(struct bpf_d *d) { BPFD_LOCK_ASSERT(d); switch (d->bd_bufmode) { case BPF_BUFMODE_ZBUF: bpf_zerocopy_buffull(d); break; } } /* * Notify the buffer model that a buffer has moved into the hold position. */ void bpf_bufheld(struct bpf_d *d) { BPFD_LOCK_ASSERT(d); switch (d->bd_bufmode) { case BPF_BUFMODE_ZBUF: bpf_zerocopy_bufheld(d); break; } } static void bpf_free(struct bpf_d *d) { switch (d->bd_bufmode) { case BPF_BUFMODE_BUFFER: return (bpf_buffer_free(d)); case BPF_BUFMODE_ZBUF: return (bpf_zerocopy_free(d)); default: panic("bpf_buf_free"); } } static int bpf_uiomove(struct bpf_d *d, caddr_t buf, u_int len, struct uio *uio) { if (d->bd_bufmode != BPF_BUFMODE_BUFFER) return (EOPNOTSUPP); return (bpf_buffer_uiomove(d, buf, len, uio)); } static int bpf_ioctl_sblen(struct bpf_d *d, u_int *i) { if (d->bd_bufmode != BPF_BUFMODE_BUFFER) return (EOPNOTSUPP); return (bpf_buffer_ioctl_sblen(d, i)); } static int bpf_ioctl_getzmax(struct thread *td, struct bpf_d *d, size_t *i) { if (d->bd_bufmode != BPF_BUFMODE_ZBUF) return (EOPNOTSUPP); return (bpf_zerocopy_ioctl_getzmax(td, d, i)); } static int bpf_ioctl_rotzbuf(struct thread *td, struct bpf_d *d, struct bpf_zbuf *bz) { if (d->bd_bufmode != BPF_BUFMODE_ZBUF) return (EOPNOTSUPP); return (bpf_zerocopy_ioctl_rotzbuf(td, d, bz)); } static int bpf_ioctl_setzbuf(struct thread *td, struct bpf_d *d, struct bpf_zbuf *bz) { if (d->bd_bufmode != BPF_BUFMODE_ZBUF) return (EOPNOTSUPP); return (bpf_zerocopy_ioctl_setzbuf(td, d, bz)); } /* * General BPF functions. */ static int bpf_movein(struct uio *uio, int linktype, struct ifnet *ifp, struct mbuf **mp, struct sockaddr *sockp, int *hdrlen, struct bpf_insn *wfilter) { const struct ieee80211_bpf_params *p; struct ether_header *eh; struct mbuf *m; int error; int len; int hlen; int slen; /* * Build a sockaddr based on the data link layer type. * We do this at this level because the ethernet header * is copied directly into the data field of the sockaddr. * In the case of SLIP, there is no header and the packet * is forwarded as is. * Also, we are careful to leave room at the front of the mbuf * for the link level header. */ switch (linktype) { case DLT_SLIP: sockp->sa_family = AF_INET; hlen = 0; break; case DLT_EN10MB: sockp->sa_family = AF_UNSPEC; /* XXX Would MAXLINKHDR be better? */ hlen = ETHER_HDR_LEN; break; case DLT_FDDI: sockp->sa_family = AF_IMPLINK; hlen = 0; break; case DLT_RAW: sockp->sa_family = AF_UNSPEC; hlen = 0; break; case DLT_NULL: /* * null interface types require a 4 byte pseudo header which * corresponds to the address family of the packet. */ sockp->sa_family = AF_UNSPEC; hlen = 4; break; case DLT_ATM_RFC1483: /* * en atm driver requires 4-byte atm pseudo header. * though it isn't standard, vpi:vci needs to be * specified anyway. */ sockp->sa_family = AF_UNSPEC; hlen = 12; /* XXX 4(ATM_PH) + 3(LLC) + 5(SNAP) */ break; case DLT_PPP: sockp->sa_family = AF_UNSPEC; hlen = 4; /* This should match PPP_HDRLEN */ break; case DLT_IEEE802_11: /* IEEE 802.11 wireless */ sockp->sa_family = AF_IEEE80211; hlen = 0; break; case DLT_IEEE802_11_RADIO: /* IEEE 802.11 wireless w/ phy params */ sockp->sa_family = AF_IEEE80211; sockp->sa_len = 12; /* XXX != 0 */ hlen = sizeof(struct ieee80211_bpf_params); break; default: return (EIO); } len = uio->uio_resid; if (len < hlen || len - hlen > ifp->if_mtu) return (EMSGSIZE); m = m_get2(len, M_WAITOK, MT_DATA, M_PKTHDR); if (m == NULL) return (EIO); m->m_pkthdr.len = m->m_len = len; *mp = m; error = uiomove(mtod(m, u_char *), len, uio); if (error) goto bad; slen = bpf_filter(wfilter, mtod(m, u_char *), len, len); if (slen == 0) { error = EPERM; goto bad; } /* Check for multicast destination */ switch (linktype) { case DLT_EN10MB: eh = mtod(m, struct ether_header *); if (ETHER_IS_MULTICAST(eh->ether_dhost)) { if (bcmp(ifp->if_broadcastaddr, eh->ether_dhost, ETHER_ADDR_LEN) == 0) m->m_flags |= M_BCAST; else m->m_flags |= M_MCAST; } break; } /* * Make room for link header, and copy it to sockaddr */ if (hlen != 0) { if (sockp->sa_family == AF_IEEE80211) { /* * Collect true length from the parameter header * NB: sockp is known to be zero'd so if we do a * short copy unspecified parameters will be * zero. * NB: packet may not be aligned after stripping * bpf params * XXX check ibp_vers */ p = mtod(m, const struct ieee80211_bpf_params *); hlen = p->ibp_len; if (hlen > sizeof(sockp->sa_data)) { error = EINVAL; goto bad; } } bcopy(m->m_data, sockp->sa_data, hlen); } *hdrlen = hlen; return (0); bad: m_freem(m); return (error); } /* * Attach file to the bpf interface, i.e. make d listen on bp. */ static void bpf_attachd(struct bpf_d *d, struct bpf_if *bp) { int op_w; BPF_LOCK_ASSERT(); /* * Save sysctl value to protect from sysctl change * between reads */ op_w = V_bpf_optimize_writers; if (d->bd_bif != NULL) bpf_detachd_locked(d); /* * Point d at bp, and add d to the interface's list. * Since there are many applicaiotns using BPF for * sending raw packets only (dhcpd, cdpd are good examples) * we can delay adding d to the list of active listeners until * some filter is configured. */ BPFIF_WLOCK(bp); BPFD_LOCK(d); d->bd_bif = bp; if (op_w != 0) { /* Add to writers-only list */ LIST_INSERT_HEAD(&bp->bif_wlist, d, bd_next); /* * We decrement bd_writer on every filter set operation. * First BIOCSETF is done by pcap_open_live() to set up * snap length. After that appliation usually sets its own filter */ d->bd_writer = 2; } else LIST_INSERT_HEAD(&bp->bif_dlist, d, bd_next); BPFD_UNLOCK(d); BPFIF_WUNLOCK(bp); bpf_bpfd_cnt++; CTR3(KTR_NET, "%s: bpf_attach called by pid %d, adding to %s list", __func__, d->bd_pid, d->bd_writer ? "writer" : "active"); if (op_w == 0) EVENTHANDLER_INVOKE(bpf_track, bp->bif_ifp, bp->bif_dlt, 1); } /* * Add d to the list of active bp filters. * Reuqires bpf_attachd() to be called before */ static void bpf_upgraded(struct bpf_d *d) { struct bpf_if *bp; BPF_LOCK_ASSERT(); bp = d->bd_bif; /* * Filter can be set several times without specifying interface. * Mark d as reader and exit. */ if (bp == NULL) { BPFD_LOCK(d); d->bd_writer = 0; BPFD_UNLOCK(d); return; } BPFIF_WLOCK(bp); BPFD_LOCK(d); /* Remove from writers-only list */ LIST_REMOVE(d, bd_next); LIST_INSERT_HEAD(&bp->bif_dlist, d, bd_next); /* Mark d as reader */ d->bd_writer = 0; BPFD_UNLOCK(d); BPFIF_WUNLOCK(bp); CTR2(KTR_NET, "%s: upgrade required by pid %d", __func__, d->bd_pid); EVENTHANDLER_INVOKE(bpf_track, bp->bif_ifp, bp->bif_dlt, 1); } /* * Detach a file from its interface. */ static void bpf_detachd(struct bpf_d *d) { BPF_LOCK(); bpf_detachd_locked(d); BPF_UNLOCK(); } static void bpf_detachd_locked(struct bpf_d *d) { int error; struct bpf_if *bp; struct ifnet *ifp; CTR2(KTR_NET, "%s: detach required by pid %d", __func__, d->bd_pid); BPF_LOCK_ASSERT(); /* Check if descriptor is attached */ if ((bp = d->bd_bif) == NULL) return; BPFIF_WLOCK(bp); BPFD_LOCK(d); /* Save bd_writer value */ error = d->bd_writer; /* * Remove d from the interface's descriptor list. */ LIST_REMOVE(d, bd_next); ifp = bp->bif_ifp; d->bd_bif = NULL; BPFD_UNLOCK(d); BPFIF_WUNLOCK(bp); bpf_bpfd_cnt--; /* Call event handler iff d is attached */ if (error == 0) EVENTHANDLER_INVOKE(bpf_track, ifp, bp->bif_dlt, 0); /* * Check if this descriptor had requested promiscuous mode. * If so, turn it off. */ if (d->bd_promisc) { d->bd_promisc = 0; CURVNET_SET(ifp->if_vnet); error = ifpromisc(ifp, 0); CURVNET_RESTORE(); if (error != 0 && error != ENXIO) { /* * ENXIO can happen if a pccard is unplugged * Something is really wrong if we were able to put * the driver into promiscuous mode, but can't * take it out. */ if_printf(bp->bif_ifp, "bpf_detach: ifpromisc failed (%d)\n", error); } } } /* * Close the descriptor by detaching it from its interface, * deallocating its buffers, and marking it free. */ static void bpf_dtor(void *data) { struct bpf_d *d = data; BPFD_LOCK(d); if (d->bd_state == BPF_WAITING) callout_stop(&d->bd_callout); d->bd_state = BPF_IDLE; BPFD_UNLOCK(d); funsetown(&d->bd_sigio); bpf_detachd(d); #ifdef MAC mac_bpfdesc_destroy(d); #endif /* MAC */ seldrain(&d->bd_sel); knlist_destroy(&d->bd_sel.si_note); callout_drain(&d->bd_callout); bpf_freed(d); free(d, M_BPF); } /* * Open ethernet device. Returns ENXIO for illegal minor device number, * EBUSY if file is open by another process. */ /* ARGSUSED */ static int bpfopen(struct cdev *dev, int flags, int fmt, struct thread *td) { struct bpf_d *d; int error, size; d = malloc(sizeof(*d), M_BPF, M_WAITOK | M_ZERO); error = devfs_set_cdevpriv(d, bpf_dtor); if (error != 0) { free(d, M_BPF); return (error); } /* * For historical reasons, perform a one-time initialization call to * the buffer routines, even though we're not yet committed to a * particular buffer method. */ bpf_buffer_init(d); d->bd_hbuf_in_use = 0; d->bd_bufmode = BPF_BUFMODE_BUFFER; d->bd_sig = SIGIO; d->bd_direction = BPF_D_INOUT; BPF_PID_REFRESH(d, td); #ifdef MAC mac_bpfdesc_init(d); mac_bpfdesc_create(td->td_ucred, d); #endif mtx_init(&d->bd_lock, devtoname(dev), "bpf cdev lock", MTX_DEF); callout_init_mtx(&d->bd_callout, &d->bd_lock, 0); knlist_init_mtx(&d->bd_sel.si_note, &d->bd_lock); /* Allocate default buffers */ size = d->bd_bufsize; bpf_buffer_ioctl_sblen(d, &size); d->bd_qmask.qm_enabled = FALSE; BPFQ_LOCK_INIT(&d->bd_qmask); return (0); } /* * bpfread - read next chunk of packets from buffers */ static int bpfread(struct cdev *dev, struct uio *uio, int ioflag) { struct bpf_d *d; int error; int non_block; int timed_out; error = devfs_get_cdevpriv((void **)&d); if (error != 0) return (error); /* * Restrict application to use a buffer the same size as * as kernel buffers. */ if (uio->uio_resid != d->bd_bufsize) return (EINVAL); non_block = ((ioflag & O_NONBLOCK) != 0); BPFD_LOCK(d); BPF_PID_REFRESH_CUR(d); if (d->bd_bufmode != BPF_BUFMODE_BUFFER) { BPFD_UNLOCK(d); return (EOPNOTSUPP); } if (d->bd_state == BPF_WAITING) callout_stop(&d->bd_callout); timed_out = (d->bd_state == BPF_TIMED_OUT); d->bd_state = BPF_IDLE; while (d->bd_hbuf_in_use) { error = mtx_sleep(&d->bd_hbuf_in_use, &d->bd_lock, PRINET|PCATCH, "bd_hbuf", 0); if (error != 0) { BPFD_UNLOCK(d); return (error); } } /* * If the hold buffer is empty, then do a timed sleep, which * ends when the timeout expires or when enough packets * have arrived to fill the store buffer. */ while (d->bd_hbuf == NULL) { if (d->bd_slen != 0) { /* * A packet(s) either arrived since the previous * read or arrived while we were asleep. */ if (d->bd_immediate || non_block || timed_out) { /* * Rotate the buffers and return what's here * if we are in immediate mode, non-blocking * flag is set, or this descriptor timed out. */ ROTATE_BUFFERS(d); break; } } /* * No data is available, check to see if the bpf device * is still pointed at a real interface. If not, return * ENXIO so that the userland process knows to rebind * it before using it again. */ if (d->bd_bif == NULL) { BPFD_UNLOCK(d); return (ENXIO); } if (non_block) { BPFD_UNLOCK(d); return (EWOULDBLOCK); } error = msleep(d, &d->bd_lock, PRINET|PCATCH, "bpf", d->bd_rtout); if (error == EINTR || error == ERESTART) { BPFD_UNLOCK(d); return (error); } if (error == EWOULDBLOCK) { /* * On a timeout, return what's in the buffer, * which may be nothing. If there is something * in the store buffer, we can rotate the buffers. */ if (d->bd_hbuf) /* * We filled up the buffer in between * getting the timeout and arriving * here, so we don't need to rotate. */ break; if (d->bd_slen == 0) { BPFD_UNLOCK(d); return (0); } ROTATE_BUFFERS(d); break; } } /* * At this point, we know we have something in the hold slot. */ d->bd_hbuf_in_use = 1; BPFD_UNLOCK(d); /* * Move data from hold buffer into user space. * We know the entire buffer is transferred since * we checked above that the read buffer is bpf_bufsize bytes. * * We do not have to worry about simultaneous reads because * we waited for sole access to the hold buffer above. */ error = bpf_uiomove(d, d->bd_hbuf, d->bd_hlen, uio); BPFD_LOCK(d); KASSERT(d->bd_hbuf != NULL, ("bpfread: lost bd_hbuf")); d->bd_fbuf = d->bd_hbuf; d->bd_hbuf = NULL; d->bd_hlen = 0; bpf_buf_reclaimed(d); d->bd_hbuf_in_use = 0; wakeup(&d->bd_hbuf_in_use); BPFD_UNLOCK(d); return (error); } /* * If there are processes sleeping on this descriptor, wake them up. */ static __inline void bpf_wakeup(struct bpf_d *d) { BPFD_LOCK_ASSERT(d); if (d->bd_state == BPF_WAITING) { callout_stop(&d->bd_callout); d->bd_state = BPF_IDLE; } wakeup(d); if (d->bd_async && d->bd_sig && d->bd_sigio) pgsigio(&d->bd_sigio, d->bd_sig, 0); selwakeuppri(&d->bd_sel, PRINET); KNOTE_LOCKED(&d->bd_sel.si_note, 0); } static void bpf_timed_out(void *arg) { struct bpf_d *d = (struct bpf_d *)arg; BPFD_LOCK_ASSERT(d); if (callout_pending(&d->bd_callout) || !callout_active(&d->bd_callout)) return; if (d->bd_state == BPF_WAITING) { d->bd_state = BPF_TIMED_OUT; if (d->bd_slen != 0) bpf_wakeup(d); } } static int bpf_ready(struct bpf_d *d) { BPFD_LOCK_ASSERT(d); if (!bpf_canfreebuf(d) && d->bd_hlen != 0) return (1); if ((d->bd_immediate || d->bd_state == BPF_TIMED_OUT) && d->bd_slen != 0) return (1); return (0); } static int bpfwrite(struct cdev *dev, struct uio *uio, int ioflag) { struct bpf_d *d; struct ifnet *ifp; struct mbuf *m, *mc; struct sockaddr dst; int error, hlen; error = devfs_get_cdevpriv((void **)&d); if (error != 0) return (error); BPF_PID_REFRESH_CUR(d); d->bd_wcount++; /* XXX: locking required */ if (d->bd_bif == NULL) { d->bd_wdcount++; return (ENXIO); } ifp = d->bd_bif->bif_ifp; if ((ifp->if_flags & IFF_UP) == 0) { d->bd_wdcount++; return (ENETDOWN); } if (uio->uio_resid == 0) { d->bd_wdcount++; return (0); } bzero(&dst, sizeof(dst)); m = NULL; hlen = 0; /* XXX: bpf_movein() can sleep */ error = bpf_movein(uio, (int)d->bd_bif->bif_dlt, ifp, &m, &dst, &hlen, d->bd_wfilter); if (error) { d->bd_wdcount++; return (error); } d->bd_wfcount++; if (d->bd_hdrcmplt) dst.sa_family = pseudo_AF_HDRCMPLT; if (d->bd_feedback) { mc = m_dup(m, M_NOWAIT); if (mc != NULL) mc->m_pkthdr.rcvif = ifp; /* Set M_PROMISC for outgoing packets to be discarded. */ if (d->bd_direction == BPF_D_INOUT) m->m_flags |= M_PROMISC; } else mc = NULL; m->m_pkthdr.len -= hlen; m->m_len -= hlen; m->m_data += hlen; /* XXX */ CURVNET_SET(ifp->if_vnet); #ifdef MAC BPFD_LOCK(d); mac_bpfdesc_create_mbuf(d, m); if (mc != NULL) mac_bpfdesc_create_mbuf(d, mc); BPFD_UNLOCK(d); #endif error = (*ifp->if_output)(ifp, m, &dst, NULL); if (error) d->bd_wdcount++; if (mc != NULL) { if (error == 0) (*ifp->if_input)(ifp, mc); else m_freem(mc); } CURVNET_RESTORE(); return (error); } /* * Reset a descriptor by flushing its packet buffer and clearing the receive * and drop counts. This is doable for kernel-only buffers, but with * zero-copy buffers, we can't write to (or rotate) buffers that are * currently owned by userspace. It would be nice if we could encapsulate * this logic in the buffer code rather than here. */ static void reset_d(struct bpf_d *d) { BPFD_LOCK_ASSERT(d); while (d->bd_hbuf_in_use) mtx_sleep(&d->bd_hbuf_in_use, &d->bd_lock, PRINET, "bd_hbuf", 0); if ((d->bd_hbuf != NULL) && (d->bd_bufmode != BPF_BUFMODE_ZBUF || bpf_canfreebuf(d))) { /* Free the hold buffer. */ d->bd_fbuf = d->bd_hbuf; d->bd_hbuf = NULL; d->bd_hlen = 0; bpf_buf_reclaimed(d); } if (bpf_canwritebuf(d)) d->bd_slen = 0; d->bd_rcount = 0; d->bd_dcount = 0; d->bd_fcount = 0; d->bd_wcount = 0; d->bd_wfcount = 0; d->bd_wdcount = 0; d->bd_zcopy = 0; } /* * FIONREAD Check for read packet available. * SIOCGIFADDR Get interface address - convenient hook to driver. * BIOCGBLEN Get buffer len [for read()]. * BIOCSETF Set read filter. * BIOCSETFNR Set read filter without resetting descriptor. * BIOCSETWF Set write filter. * BIOCFLUSH Flush read packet buffer. * BIOCPROMISC Put interface into promiscuous mode. * BIOCGDLT Get link layer type. * BIOCGETIF Get interface name. * BIOCSETIF Set interface. * BIOCSRTIMEOUT Set read timeout. * BIOCGRTIMEOUT Get read timeout. * BIOCGSTATS Get packet stats. * BIOCIMMEDIATE Set immediate mode. * BIOCVERSION Get filter language version. * BIOCGHDRCMPLT Get "header already complete" flag * BIOCSHDRCMPLT Set "header already complete" flag * BIOCGDIRECTION Get packet direction flag * BIOCSDIRECTION Set packet direction flag * BIOCGTSTAMP Get time stamp format and resolution. * BIOCSTSTAMP Set time stamp format and resolution. * BIOCLOCK Set "locked" flag * BIOCFEEDBACK Set packet feedback mode. * BIOCSETZBUF Set current zero-copy buffer locations. * BIOCGETZMAX Get maximum zero-copy buffer size. * BIOCROTZBUF Force rotation of zero-copy buffer * BIOCSETBUFMODE Set buffer mode. * BIOCGETBUFMODE Get current buffer mode. */ /* ARGSUSED */ static int bpfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td) { struct bpf_d *d; int error; error = devfs_get_cdevpriv((void **)&d); if (error != 0) return (error); /* * Refresh PID associated with this descriptor. */ BPFD_LOCK(d); BPF_PID_REFRESH(d, td); if (d->bd_state == BPF_WAITING) callout_stop(&d->bd_callout); d->bd_state = BPF_IDLE; BPFD_UNLOCK(d); if (d->bd_locked == 1) { switch (cmd) { case BIOCGBLEN: case BIOCFLUSH: case BIOCGDLT: case BIOCGDLTLIST: #ifdef COMPAT_FREEBSD32 case BIOCGDLTLIST32: #endif case BIOCGETIF: case BIOCGRTIMEOUT: #if defined(COMPAT_FREEBSD32) && !defined(__mips__) case BIOCGRTIMEOUT32: #endif case BIOCGSTATS: case BIOCVERSION: case BIOCGRSIG: case BIOCGHDRCMPLT: case BIOCSTSTAMP: case BIOCFEEDBACK: case FIONREAD: case BIOCLOCK: case BIOCSRTIMEOUT: #if defined(COMPAT_FREEBSD32) && !defined(__mips__) case BIOCSRTIMEOUT32: #endif case BIOCIMMEDIATE: case TIOCGPGRP: case BIOCROTZBUF: break; default: return (EPERM); } } #ifdef COMPAT_FREEBSD32 /* * If we see a 32-bit compat ioctl, mark the stream as 32-bit so * that it will get 32-bit packet headers. */ switch (cmd) { case BIOCSETF32: case BIOCSETFNR32: case BIOCSETWF32: case BIOCGDLTLIST32: case BIOCGRTIMEOUT32: case BIOCSRTIMEOUT32: BPFD_LOCK(d); d->bd_compat32 = 1; BPFD_UNLOCK(d); } #endif CURVNET_SET(TD_TO_VNET(td)); switch (cmd) { default: error = EINVAL; break; /* * Check for read packet available. */ case FIONREAD: { int n; BPFD_LOCK(d); n = d->bd_slen; while (d->bd_hbuf_in_use) mtx_sleep(&d->bd_hbuf_in_use, &d->bd_lock, PRINET, "bd_hbuf", 0); if (d->bd_hbuf) n += d->bd_hlen; BPFD_UNLOCK(d); *(int *)addr = n; break; } case SIOCGIFADDR: { struct ifnet *ifp; if (d->bd_bif == NULL) error = EINVAL; else { ifp = d->bd_bif->bif_ifp; error = (*ifp->if_ioctl)(ifp, cmd, addr); } break; } /* * Get buffer len [for read()]. */ case BIOCGBLEN: BPFD_LOCK(d); *(u_int *)addr = d->bd_bufsize; BPFD_UNLOCK(d); break; /* * Set buffer length. */ case BIOCSBLEN: error = bpf_ioctl_sblen(d, (u_int *)addr); break; /* * Set link layer read filter. */ case BIOCSETF: case BIOCSETFNR: case BIOCSETWF: #ifdef COMPAT_FREEBSD32 case BIOCSETF32: case BIOCSETFNR32: case BIOCSETWF32: #endif error = bpf_setf(d, (struct bpf_program *)addr, cmd); break; /* * Flush read packet buffer. */ case BIOCFLUSH: BPFD_LOCK(d); reset_d(d); BPFD_UNLOCK(d); break; /* * Put interface into promiscuous mode. */ case BIOCPROMISC: if (d->bd_bif == NULL) { /* * No interface attached yet. */ error = EINVAL; break; } if (d->bd_promisc == 0) { error = ifpromisc(d->bd_bif->bif_ifp, 1); if (error == 0) d->bd_promisc = 1; } break; /* * Get current data link type. */ case BIOCGDLT: BPF_LOCK(); if (d->bd_bif == NULL) error = EINVAL; else *(u_int *)addr = d->bd_bif->bif_dlt; BPF_UNLOCK(); break; /* * Get a list of supported data link types. */ #ifdef COMPAT_FREEBSD32 case BIOCGDLTLIST32: { struct bpf_dltlist32 *list32; struct bpf_dltlist dltlist; list32 = (struct bpf_dltlist32 *)addr; dltlist.bfl_len = list32->bfl_len; dltlist.bfl_list = PTRIN(list32->bfl_list); BPF_LOCK(); if (d->bd_bif == NULL) error = EINVAL; else { error = bpf_getdltlist(d, &dltlist); if (error == 0) list32->bfl_len = dltlist.bfl_len; } BPF_UNLOCK(); break; } #endif case BIOCGDLTLIST: BPF_LOCK(); if (d->bd_bif == NULL) error = EINVAL; else error = bpf_getdltlist(d, (struct bpf_dltlist *)addr); BPF_UNLOCK(); break; /* * Set data link type. */ case BIOCSDLT: BPF_LOCK(); if (d->bd_bif == NULL) error = EINVAL; else error = bpf_setdlt(d, *(u_int *)addr); BPF_UNLOCK(); break; /* * Get interface name. */ case BIOCGETIF: BPF_LOCK(); if (d->bd_bif == NULL) error = EINVAL; else { struct ifnet *const ifp = d->bd_bif->bif_ifp; struct ifreq *const ifr = (struct ifreq *)addr; strlcpy(ifr->ifr_name, ifp->if_xname, sizeof(ifr->ifr_name)); } BPF_UNLOCK(); break; /* * Set interface. */ case BIOCSETIF: BPF_LOCK(); error = bpf_setif(d, (struct ifreq *)addr); BPF_UNLOCK(); break; /* * Set read timeout. */ case BIOCSRTIMEOUT: #if defined(COMPAT_FREEBSD32) && !defined(__mips__) case BIOCSRTIMEOUT32: #endif { struct timeval *tv = (struct timeval *)addr; #if defined(COMPAT_FREEBSD32) && !defined(__mips__) struct timeval32 *tv32; struct timeval tv64; if (cmd == BIOCSRTIMEOUT32) { tv32 = (struct timeval32 *)addr; tv = &tv64; tv->tv_sec = tv32->tv_sec; tv->tv_usec = tv32->tv_usec; } else #endif tv = (struct timeval *)addr; /* * Subtract 1 tick from tvtohz() since this isn't * a one-shot timer. */ if ((error = itimerfix(tv)) == 0) d->bd_rtout = tvtohz(tv) - 1; break; } /* * Get read timeout. */ case BIOCGRTIMEOUT: #if defined(COMPAT_FREEBSD32) && !defined(__mips__) case BIOCGRTIMEOUT32: #endif { struct timeval *tv; #if defined(COMPAT_FREEBSD32) && !defined(__mips__) struct timeval32 *tv32; struct timeval tv64; if (cmd == BIOCGRTIMEOUT32) tv = &tv64; else #endif tv = (struct timeval *)addr; tv->tv_sec = d->bd_rtout / hz; tv->tv_usec = (d->bd_rtout % hz) * tick; #if defined(COMPAT_FREEBSD32) && !defined(__mips__) if (cmd == BIOCGRTIMEOUT32) { tv32 = (struct timeval32 *)addr; tv32->tv_sec = tv->tv_sec; tv32->tv_usec = tv->tv_usec; } #endif break; } /* * Get packet stats. */ case BIOCGSTATS: { struct bpf_stat *bs = (struct bpf_stat *)addr; /* XXXCSJP overflow */ bs->bs_recv = d->bd_rcount; bs->bs_drop = d->bd_dcount; break; } /* * Set immediate mode. */ case BIOCIMMEDIATE: BPFD_LOCK(d); d->bd_immediate = *(u_int *)addr; BPFD_UNLOCK(d); break; case BIOCVERSION: { struct bpf_version *bv = (struct bpf_version *)addr; bv->bv_major = BPF_MAJOR_VERSION; bv->bv_minor = BPF_MINOR_VERSION; break; } /* * Get "header already complete" flag */ case BIOCGHDRCMPLT: BPFD_LOCK(d); *(u_int *)addr = d->bd_hdrcmplt; BPFD_UNLOCK(d); break; /* * Set "header already complete" flag */ case BIOCSHDRCMPLT: BPFD_LOCK(d); d->bd_hdrcmplt = *(u_int *)addr ? 1 : 0; BPFD_UNLOCK(d); break; /* * Get packet direction flag */ case BIOCGDIRECTION: BPFD_LOCK(d); *(u_int *)addr = d->bd_direction; BPFD_UNLOCK(d); break; /* * Set packet direction flag */ case BIOCSDIRECTION: { u_int direction; direction = *(u_int *)addr; switch (direction) { case BPF_D_IN: case BPF_D_INOUT: case BPF_D_OUT: BPFD_LOCK(d); d->bd_direction = direction; BPFD_UNLOCK(d); break; default: error = EINVAL; } } break; /* * Get packet timestamp format and resolution. */ case BIOCGTSTAMP: BPFD_LOCK(d); *(u_int *)addr = d->bd_tstamp; BPFD_UNLOCK(d); break; /* * Set packet timestamp format and resolution. */ case BIOCSTSTAMP: { u_int func; func = *(u_int *)addr; if (BPF_T_VALID(func)) d->bd_tstamp = func; else error = EINVAL; } break; case BIOCFEEDBACK: BPFD_LOCK(d); d->bd_feedback = *(u_int *)addr; BPFD_UNLOCK(d); break; case BIOCLOCK: BPFD_LOCK(d); d->bd_locked = 1; BPFD_UNLOCK(d); break; case FIONBIO: /* Non-blocking I/O */ break; case FIOASYNC: /* Send signal on receive packets */ BPFD_LOCK(d); d->bd_async = *(int *)addr; BPFD_UNLOCK(d); break; case FIOSETOWN: /* * XXX: Add some sort of locking here? * fsetown() can sleep. */ error = fsetown(*(int *)addr, &d->bd_sigio); break; case FIOGETOWN: BPFD_LOCK(d); *(int *)addr = fgetown(&d->bd_sigio); BPFD_UNLOCK(d); break; /* This is deprecated, FIOSETOWN should be used instead. */ case TIOCSPGRP: error = fsetown(-(*(int *)addr), &d->bd_sigio); break; /* This is deprecated, FIOGETOWN should be used instead. */ case TIOCGPGRP: *(int *)addr = -fgetown(&d->bd_sigio); break; case BIOCSRSIG: /* Set receive signal */ { u_int sig; sig = *(u_int *)addr; if (sig >= NSIG) error = EINVAL; else { BPFD_LOCK(d); d->bd_sig = sig; BPFD_UNLOCK(d); } break; } case BIOCGRSIG: BPFD_LOCK(d); *(u_int *)addr = d->bd_sig; BPFD_UNLOCK(d); break; case BIOCGETBUFMODE: BPFD_LOCK(d); *(u_int *)addr = d->bd_bufmode; BPFD_UNLOCK(d); break; case BIOCSETBUFMODE: /* * Allow the buffering mode to be changed as long as we * haven't yet committed to a particular mode. Our * definition of commitment, for now, is whether or not a * buffer has been allocated or an interface attached, since * that's the point where things get tricky. */ switch (*(u_int *)addr) { case BPF_BUFMODE_BUFFER: break; case BPF_BUFMODE_ZBUF: if (bpf_zerocopy_enable) break; /* FALLSTHROUGH */ default: CURVNET_RESTORE(); return (EINVAL); } BPFD_LOCK(d); if (d->bd_sbuf != NULL || d->bd_hbuf != NULL || d->bd_fbuf != NULL || d->bd_bif != NULL) { BPFD_UNLOCK(d); CURVNET_RESTORE(); return (EBUSY); } d->bd_bufmode = *(u_int *)addr; BPFD_UNLOCK(d); break; case BIOCGETZMAX: error = bpf_ioctl_getzmax(td, d, (size_t *)addr); break; case BIOCSETZBUF: error = bpf_ioctl_setzbuf(td, d, (struct bpf_zbuf *)addr); break; case BIOCROTZBUF: error = bpf_ioctl_rotzbuf(td, d, (struct bpf_zbuf *)addr); break; case BIOCQMASKENABLE: { struct ifnet *ifp; if (d->bd_bif == NULL) { /* * No interface attached yet. */ error = EINVAL; break; } BPFQ_WLOCK(&d->bd_qmask); if (d->bd_qmask.qm_enabled) { BPFQ_WUNLOCK(&d->bd_qmask); error = EINVAL; break; } ifp = d->bd_bif->bif_ifp; if (!(ifp->if_capabilities & IFCAP_MULTIQUEUE)) { BPFQ_WUNLOCK(&d->bd_qmask); error = EINVAL; break; } BPFQ_ZERO(&d->bd_qmask.qm_rxqmask); BPFQ_ZERO(&d->bd_qmask.qm_txqmask); d->bd_qmask.qm_noqmask = FALSE; d->bd_qmask.qm_enabled = TRUE; BPFQ_WUNLOCK(&d->bd_qmask); break; } case BIOCQMASKDISABLE: { if (d->bd_bif == NULL) { /* * No interface attached yet. */ error = EINVAL; break; } BPFQ_WLOCK(&d->bd_qmask); if (!d->bd_qmask.qm_enabled) { BPFQ_WUNLOCK(&d->bd_qmask); error = EINVAL; break; } d->bd_qmask.qm_enabled = FALSE; BPFQ_WUNLOCK(&d->bd_qmask); break; } case BIOCGRXQMASK: { - bpf_qmask_bits_t *qmask = (bpf_qmask_bits_t *)addr; + struct bpf_qmask_bits *qmask = (struct bpf_qmask_bits *)addr; if (d->bd_bif == NULL) { /* * No interface attached yet. */ error = EINVAL; break; } BPFQ_WLOCK(&d->bd_qmask); if (!d->bd_qmask.qm_enabled) { BPFQ_WUNLOCK(&d->bd_qmask); error = EINVAL; break; } BPFQ_COPY(&d->bd_qmask.qm_rxqmask, qmask); BPFQ_WUNLOCK(&d->bd_qmask); break; } case BIOCSRXQMASK: { - bpf_qmask_bits_t *qmask = (bpf_qmask_bits_t *)addr; + struct bpf_qmask_bits *qmask = (struct bpf_qmask_bits *)addr; if (d->bd_bif == NULL) { /* * No interface attached yet. */ error = EINVAL; break; } BPFQ_WLOCK(&d->bd_qmask); if (!d->bd_qmask.qm_enabled) { BPFQ_WUNLOCK(&d->bd_qmask); error = EINVAL; break; } BPFQ_COPY(qmask, &d->bd_qmask.qm_rxqmask); BPFQ_WUNLOCK(&d->bd_qmask); break; } case BIOCGTXQMASK: { - bpf_qmask_bits_t *qmask = (bpf_qmask_bits_t *)addr; + struct bpf_qmask_bits *qmask = (struct bpf_qmask_bits *)addr; if (d->bd_bif == NULL) { /* * No interface attached yet. */ error = EINVAL; break; } BPFQ_WLOCK(&d->bd_qmask); if (!d->bd_qmask.qm_enabled) { BPFQ_WUNLOCK(&d->bd_qmask); error = EINVAL; break; } BPFQ_COPY(&d->bd_qmask.qm_txqmask, qmask); BPFQ_WUNLOCK(&d->bd_qmask); break; } case BIOCSTXQMASK: { - bpf_qmask_bits_t *qmask = (bpf_qmask_bits_t *)addr; + struct bpf_qmask_bits *qmask = (struct bpf_qmask_bits *)addr; if (d->bd_bif == NULL) { /* * No interface attached yet. */ error = EINVAL; break; } BPFQ_WLOCK(&d->bd_qmask); if (!d->bd_qmask.qm_enabled) { BPFQ_WUNLOCK(&d->bd_qmask); error = EINVAL; break; } BPFQ_COPY(qmask, &d->bd_qmask.qm_txqmask); BPFQ_WUNLOCK(&d->bd_qmask); break; } case BIOCGNOQMASK: { boolean_t *noqmask = (boolean_t *)addr; if (d->bd_bif == NULL) { /* * No interface attached yet. */ error = EINVAL; break; } BPFQ_WLOCK(&d->bd_qmask); if (!d->bd_qmask.qm_enabled) { BPFQ_WUNLOCK(&d->bd_qmask); error = EINVAL; break; } *noqmask = d->bd_qmask.qm_noqmask; BPFQ_WUNLOCK(&d->bd_qmask); break; } case BIOCSNOQMASK: { boolean_t *noqmask = (boolean_t *)addr; if (d->bd_bif == NULL) { /* * No interface attached yet. */ error = EINVAL; break; } BPFQ_WLOCK(&d->bd_qmask); if (!d->bd_qmask.qm_enabled) { BPFQ_WUNLOCK(&d->bd_qmask); error = EINVAL; break; } d->bd_qmask.qm_noqmask = *noqmask; BPFQ_WUNLOCK(&d->bd_qmask); break; } } CURVNET_RESTORE(); return (error); } /* * Set d's packet filter program to fp. If this file already has a filter, * free it and replace it. Returns EINVAL for bogus requests. * * Note we need global lock here to serialize bpf_setf() and bpf_setif() calls * since reading d->bd_bif can't be protected by d or interface lock due to * lock order. * * Additionally, we have to acquire interface write lock due to bpf_mtap() uses * interface read lock to read all filers. * */ static int bpf_setf(struct bpf_d *d, struct bpf_program *fp, u_long cmd) { #ifdef COMPAT_FREEBSD32 struct bpf_program fp_swab; struct bpf_program32 *fp32; #endif struct bpf_insn *fcode, *old; #ifdef BPF_JITTER bpf_jit_filter *jfunc, *ofunc; #endif size_t size; u_int flen; int need_upgrade; #ifdef COMPAT_FREEBSD32 switch (cmd) { case BIOCSETF32: case BIOCSETWF32: case BIOCSETFNR32: fp32 = (struct bpf_program32 *)fp; fp_swab.bf_len = fp32->bf_len; fp_swab.bf_insns = (struct bpf_insn *)(uintptr_t)fp32->bf_insns; fp = &fp_swab; switch (cmd) { case BIOCSETF32: cmd = BIOCSETF; break; case BIOCSETWF32: cmd = BIOCSETWF; break; } break; } #endif fcode = NULL; #ifdef BPF_JITTER jfunc = ofunc = NULL; #endif need_upgrade = 0; /* * Check new filter validness before acquiring any locks. * Allocate memory for new filter, if needed. */ flen = fp->bf_len; if (flen > bpf_maxinsns || (fp->bf_insns == NULL && flen != 0)) return (EINVAL); size = flen * sizeof(*fp->bf_insns); if (size > 0) { /* We're setting up new filter. Copy and check actual data. */ fcode = malloc(size, M_BPF, M_WAITOK); if (copyin(fp->bf_insns, fcode, size) != 0 || !bpf_validate(fcode, flen)) { free(fcode, M_BPF); return (EINVAL); } #ifdef BPF_JITTER /* Filter is copied inside fcode and is perfectly valid. */ jfunc = bpf_jitter(fcode, flen); #endif } BPF_LOCK(); /* * Set up new filter. * Protect filter change by interface lock. * Additionally, we are protected by global lock here. */ if (d->bd_bif != NULL) BPFIF_WLOCK(d->bd_bif); BPFD_LOCK(d); if (cmd == BIOCSETWF) { old = d->bd_wfilter; d->bd_wfilter = fcode; } else { old = d->bd_rfilter; d->bd_rfilter = fcode; #ifdef BPF_JITTER ofunc = d->bd_bfilter; d->bd_bfilter = jfunc; #endif if (cmd == BIOCSETF) reset_d(d); if (fcode != NULL) { /* * Do not require upgrade by first BIOCSETF * (used to set snaplen) by pcap_open_live(). */ if (d->bd_writer != 0 && --d->bd_writer == 0) need_upgrade = 1; CTR4(KTR_NET, "%s: filter function set by pid %d, " "bd_writer counter %d, need_upgrade %d", __func__, d->bd_pid, d->bd_writer, need_upgrade); } } BPFD_UNLOCK(d); if (d->bd_bif != NULL) BPFIF_WUNLOCK(d->bd_bif); if (old != NULL) free(old, M_BPF); #ifdef BPF_JITTER if (ofunc != NULL) bpf_destroy_jit_filter(ofunc); #endif /* Move d to active readers list. */ if (need_upgrade) bpf_upgraded(d); BPF_UNLOCK(); return (0); } /* * Detach a file from its current interface (if attached at all) and attach * to the interface indicated by the name stored in ifr. * Return an errno or 0. */ static int bpf_setif(struct bpf_d *d, struct ifreq *ifr) { struct bpf_if *bp; struct ifnet *theywant; BPF_LOCK_ASSERT(); theywant = ifunit(ifr->ifr_name); if (theywant == NULL || theywant->if_bpf == NULL) return (ENXIO); bp = theywant->if_bpf; /* Check if interface is not being detached from BPF */ BPFIF_RLOCK(bp); if (bp->flags & BPFIF_FLAG_DYING) { BPFIF_RUNLOCK(bp); return (ENXIO); } BPFIF_RUNLOCK(bp); /* * Behavior here depends on the buffering model. If we're using * kernel memory buffers, then we can allocate them here. If we're * using zero-copy, then the user process must have registered * buffers by the time we get here. If not, return an error. */ switch (d->bd_bufmode) { case BPF_BUFMODE_BUFFER: case BPF_BUFMODE_ZBUF: if (d->bd_sbuf == NULL) return (EINVAL); break; default: panic("bpf_setif: bufmode %d", d->bd_bufmode); } if (bp != d->bd_bif) bpf_attachd(d, bp); BPFD_LOCK(d); reset_d(d); BPFD_UNLOCK(d); return (0); } /* * Support for select() and poll() system calls * * Return true iff the specific operation will not block indefinitely. * Otherwise, return false but make a note that a selwakeup() must be done. */ static int bpfpoll(struct cdev *dev, int events, struct thread *td) { struct bpf_d *d; int revents; if (devfs_get_cdevpriv((void **)&d) != 0 || d->bd_bif == NULL) return (events & (POLLHUP|POLLIN|POLLRDNORM|POLLOUT|POLLWRNORM)); /* * Refresh PID associated with this descriptor. */ revents = events & (POLLOUT | POLLWRNORM); BPFD_LOCK(d); BPF_PID_REFRESH(d, td); if (events & (POLLIN | POLLRDNORM)) { if (bpf_ready(d)) revents |= events & (POLLIN | POLLRDNORM); else { selrecord(td, &d->bd_sel); /* Start the read timeout if necessary. */ if (d->bd_rtout > 0 && d->bd_state == BPF_IDLE) { callout_reset(&d->bd_callout, d->bd_rtout, bpf_timed_out, d); d->bd_state = BPF_WAITING; } } } BPFD_UNLOCK(d); return (revents); } /* * Support for kevent() system call. Register EVFILT_READ filters and * reject all others. */ int bpfkqfilter(struct cdev *dev, struct knote *kn) { struct bpf_d *d; if (devfs_get_cdevpriv((void **)&d) != 0 || kn->kn_filter != EVFILT_READ) return (1); /* * Refresh PID associated with this descriptor. */ BPFD_LOCK(d); BPF_PID_REFRESH_CUR(d); kn->kn_fop = &bpfread_filtops; kn->kn_hook = d; knlist_add(&d->bd_sel.si_note, kn, 1); BPFD_UNLOCK(d); return (0); } static void filt_bpfdetach(struct knote *kn) { struct bpf_d *d = (struct bpf_d *)kn->kn_hook; knlist_remove(&d->bd_sel.si_note, kn, 0); } static int filt_bpfread(struct knote *kn, long hint) { struct bpf_d *d = (struct bpf_d *)kn->kn_hook; int ready; BPFD_LOCK_ASSERT(d); ready = bpf_ready(d); if (ready) { kn->kn_data = d->bd_slen; while (d->bd_hbuf_in_use) mtx_sleep(&d->bd_hbuf_in_use, &d->bd_lock, PRINET, "bd_hbuf", 0); if (d->bd_hbuf) kn->kn_data += d->bd_hlen; } else if (d->bd_rtout > 0 && d->bd_state == BPF_IDLE) { callout_reset(&d->bd_callout, d->bd_rtout, bpf_timed_out, d); d->bd_state = BPF_WAITING; } return (ready); } #define BPF_TSTAMP_NONE 0 #define BPF_TSTAMP_FAST 1 #define BPF_TSTAMP_NORMAL 2 #define BPF_TSTAMP_EXTERN 3 static int bpf_ts_quality(int tstype) { if (tstype == BPF_T_NONE) return (BPF_TSTAMP_NONE); if ((tstype & BPF_T_FAST) != 0) return (BPF_TSTAMP_FAST); return (BPF_TSTAMP_NORMAL); } static int bpf_gettime(struct bintime *bt, int tstype, struct mbuf *m) { struct m_tag *tag; int quality; quality = bpf_ts_quality(tstype); if (quality == BPF_TSTAMP_NONE) return (quality); if (m != NULL) { tag = m_tag_locate(m, MTAG_BPF, MTAG_BPF_TIMESTAMP, NULL); if (tag != NULL) { *bt = *(struct bintime *)(tag + 1); return (BPF_TSTAMP_EXTERN); } } if (quality == BPF_TSTAMP_NORMAL) binuptime(bt); else getbinuptime(bt); return (quality); } /* * Incoming linkage from device drivers. Process the packet pkt, of length * pktlen, which is stored in a contiguous buffer. The packet is parsed * by each process' filter, and if accepted, stashed into the corresponding * buffer. */ void bpf_tap(struct bpf_if *bp, u_char *pkt, u_int pktlen) { struct bintime bt; struct bpf_d *d; #ifdef BPF_JITTER bpf_jit_filter *bf; #endif u_int slen; int gottime; gottime = BPF_TSTAMP_NONE; BPFIF_RLOCK(bp); LIST_FOREACH(d, &bp->bif_dlist, bd_next) { BPFQ_RLOCK(&d->bd_qmask); if (d->bd_qmask.qm_enabled) { if (!d->bd_qmask.qm_noqmask) { BPFQ_RUNLOCK(&d->bd_qmask); continue; } } BPFQ_RUNLOCK(&d->bd_qmask); /* * We are not using any locks for d here because: * 1) any filter change is protected by interface * write lock * 2) destroying/detaching d is protected by interface * write lock, too */ /* XXX: Do not protect counter for the sake of performance. */ ++d->bd_rcount; /* * NB: We dont call BPF_CHECK_DIRECTION() here since there is no * way for the caller to indiciate to us whether this packet * is inbound or outbound. In the bpf_mtap() routines, we use * the interface pointers on the mbuf to figure it out. */ #ifdef BPF_JITTER bf = bpf_jitter_enable != 0 ? d->bd_bfilter : NULL; if (bf != NULL) slen = (*(bf->func))(pkt, pktlen, pktlen); else #endif slen = bpf_filter(d->bd_rfilter, pkt, pktlen, pktlen); if (slen != 0) { /* * Filter matches. Let's to acquire write lock. */ BPFD_LOCK(d); d->bd_fcount++; if (gottime < bpf_ts_quality(d->bd_tstamp)) gottime = bpf_gettime(&bt, d->bd_tstamp, NULL); #ifdef MAC if (mac_bpfdesc_check_receive(d, bp->bif_ifp) == 0) #endif catchpacket(d, pkt, pktlen, slen, bpf_append_bytes, &bt); BPFD_UNLOCK(d); } } BPFIF_RUNLOCK(bp); } #define BPF_CHECK_DIRECTION(d, r, i) \ (((d)->bd_direction == BPF_D_IN && (r) != (i)) || \ ((d)->bd_direction == BPF_D_OUT && (r) == (i))) /* * Incoming linkage from device drivers, when packet is in an mbuf chain. * Locking model is explained in bpf_tap(). */ void bpf_mtap(struct bpf_if *bp, struct mbuf *m) { struct bintime bt; struct bpf_d *d; #ifdef BPF_JITTER bpf_jit_filter *bf; #endif u_int pktlen, slen; int gottime; /* Skip outgoing duplicate packets. */ if ((m->m_flags & M_PROMISC) != 0 && m->m_pkthdr.rcvif == NULL) { m->m_flags &= ~M_PROMISC; return; } pktlen = m_length(m, NULL); gottime = BPF_TSTAMP_NONE; BPFIF_RLOCK(bp); LIST_FOREACH(d, &bp->bif_dlist, bd_next) { BPFQ_RLOCK(&d->bd_qmask); if (d->bd_qmask.qm_enabled) { M_ASSERTPKTHDR(m); if (m->m_flags & M_QUEUEID) { switch (m->m_pkthdr.queuetype) { case QUEUETYPE_RX: if (!BPFQ_ISSET(m->m_pkthdr.queueid, &d->bd_qmask.qm_rxqmask)) { BPFQ_RUNLOCK(&d->bd_qmask); continue; } break; case QUEUETYPE_TX: if (!BPFQ_ISSET(m->m_pkthdr.queueid, &d->bd_qmask.qm_rxqmask)) { BPFQ_RUNLOCK(&d->bd_qmask); continue; } break; default: if (!d->bd_qmask.qm_noqmask) { BPFQ_RUNLOCK(&d->bd_qmask); continue; } } }else{ if (!d->bd_qmask.qm_noqmask) { BPFQ_RUNLOCK(&d->bd_qmask); continue; } } } BPFQ_RUNLOCK(&d->bd_qmask); if (BPF_CHECK_DIRECTION(d, m->m_pkthdr.rcvif, bp->bif_ifp)) continue; ++d->bd_rcount; #ifdef BPF_JITTER bf = bpf_jitter_enable != 0 ? d->bd_bfilter : NULL; /* XXX We cannot handle multiple mbufs. */ if (bf != NULL && m->m_next == NULL) slen = (*(bf->func))(mtod(m, u_char *), pktlen, pktlen); else #endif slen = bpf_filter(d->bd_rfilter, (u_char *)m, pktlen, 0); if (slen != 0) { BPFD_LOCK(d); d->bd_fcount++; if (gottime < bpf_ts_quality(d->bd_tstamp)) gottime = bpf_gettime(&bt, d->bd_tstamp, m); #ifdef MAC if (mac_bpfdesc_check_receive(d, bp->bif_ifp) == 0) #endif catchpacket(d, (u_char *)m, pktlen, slen, bpf_append_mbuf, &bt); BPFD_UNLOCK(d); } } BPFIF_RUNLOCK(bp); } /* * Incoming linkage from device drivers, when packet is in * an mbuf chain and to be prepended by a contiguous header. */ void bpf_mtap2(struct bpf_if *bp, void *data, u_int dlen, struct mbuf *m) { struct bintime bt; struct mbuf mb; struct bpf_d *d; u_int pktlen, slen; int gottime; /* Skip outgoing duplicate packets. */ if ((m->m_flags & M_PROMISC) != 0 && m->m_pkthdr.rcvif == NULL) { m->m_flags &= ~M_PROMISC; return; } pktlen = m_length(m, NULL); /* * Craft on-stack mbuf suitable for passing to bpf_filter. * Note that we cut corners here; we only setup what's * absolutely needed--this mbuf should never go anywhere else. */ mb.m_next = m; mb.m_data = data; mb.m_len = dlen; pktlen += dlen; gottime = BPF_TSTAMP_NONE; BPFIF_RLOCK(bp); LIST_FOREACH(d, &bp->bif_dlist, bd_next) { BPFQ_RLOCK(&d->bd_qmask); if (d->bd_qmask.qm_enabled) { M_ASSERTPKTHDR(m); if (m->m_flags & M_QUEUEID) { switch (m->m_pkthdr.queuetype) { case QUEUETYPE_RX: if (!BPFQ_ISSET(m->m_pkthdr.queueid, &d->bd_qmask.qm_rxqmask)) { BPFQ_RUNLOCK(&d->bd_qmask); continue; } break; case QUEUETYPE_TX: if (!BPFQ_ISSET(m->m_pkthdr.queueid, &d->bd_qmask.qm_rxqmask)) { BPFQ_RUNLOCK(&d->bd_qmask); continue; } break; default: if (!d->bd_qmask.qm_noqmask) { BPFQ_RUNLOCK(&d->bd_qmask); continue; } } }else{ if (!d->bd_qmask.qm_noqmask) { BPFQ_RUNLOCK(&d->bd_qmask); continue; } } } BPFQ_RUNLOCK(&d->bd_qmask); if (BPF_CHECK_DIRECTION(d, m->m_pkthdr.rcvif, bp->bif_ifp)) continue; ++d->bd_rcount; slen = bpf_filter(d->bd_rfilter, (u_char *)&mb, pktlen, 0); if (slen != 0) { BPFD_LOCK(d); d->bd_fcount++; if (gottime < bpf_ts_quality(d->bd_tstamp)) gottime = bpf_gettime(&bt, d->bd_tstamp, m); #ifdef MAC if (mac_bpfdesc_check_receive(d, bp->bif_ifp) == 0) #endif catchpacket(d, (u_char *)&mb, pktlen, slen, bpf_append_mbuf, &bt); BPFD_UNLOCK(d); } } BPFIF_RUNLOCK(bp); } #undef BPF_CHECK_DIRECTION #undef BPF_TSTAMP_NONE #undef BPF_TSTAMP_FAST #undef BPF_TSTAMP_NORMAL #undef BPF_TSTAMP_EXTERN static int bpf_hdrlen(struct bpf_d *d) { int hdrlen; hdrlen = d->bd_bif->bif_hdrlen; #ifndef BURN_BRIDGES if (d->bd_tstamp == BPF_T_NONE || BPF_T_FORMAT(d->bd_tstamp) == BPF_T_MICROTIME) #ifdef COMPAT_FREEBSD32 if (d->bd_compat32) hdrlen += SIZEOF_BPF_HDR(struct bpf_hdr32); else #endif hdrlen += SIZEOF_BPF_HDR(struct bpf_hdr); else #endif hdrlen += SIZEOF_BPF_HDR(struct bpf_xhdr); #ifdef COMPAT_FREEBSD32 if (d->bd_compat32) hdrlen = BPF_WORDALIGN32(hdrlen); else #endif hdrlen = BPF_WORDALIGN(hdrlen); return (hdrlen - d->bd_bif->bif_hdrlen); } static void bpf_bintime2ts(struct bintime *bt, struct bpf_ts *ts, int tstype) { struct bintime bt2; struct timeval tsm; struct timespec tsn; if ((tstype & BPF_T_MONOTONIC) == 0) { bt2 = *bt; bintime_add(&bt2, &boottimebin); bt = &bt2; } switch (BPF_T_FORMAT(tstype)) { case BPF_T_MICROTIME: bintime2timeval(bt, &tsm); ts->bt_sec = tsm.tv_sec; ts->bt_frac = tsm.tv_usec; break; case BPF_T_NANOTIME: bintime2timespec(bt, &tsn); ts->bt_sec = tsn.tv_sec; ts->bt_frac = tsn.tv_nsec; break; case BPF_T_BINTIME: ts->bt_sec = bt->sec; ts->bt_frac = bt->frac; break; } } /* * Move the packet data from interface memory (pkt) into the * store buffer. "cpfn" is the routine called to do the actual data * transfer. bcopy is passed in to copy contiguous chunks, while * bpf_append_mbuf is passed in to copy mbuf chains. In the latter case, * pkt is really an mbuf. */ static void catchpacket(struct bpf_d *d, u_char *pkt, u_int pktlen, u_int snaplen, void (*cpfn)(struct bpf_d *, caddr_t, u_int, void *, u_int), struct bintime *bt) { struct bpf_xhdr hdr; #ifndef BURN_BRIDGES struct bpf_hdr hdr_old; #ifdef COMPAT_FREEBSD32 struct bpf_hdr32 hdr32_old; #endif #endif int caplen, curlen, hdrlen, totlen; int do_wakeup = 0; int do_timestamp; int tstype; BPFD_LOCK_ASSERT(d); /* * Detect whether user space has released a buffer back to us, and if * so, move it from being a hold buffer to a free buffer. This may * not be the best place to do it (for example, we might only want to * run this check if we need the space), but for now it's a reliable * spot to do it. */ if (d->bd_fbuf == NULL && bpf_canfreebuf(d)) { while (d->bd_hbuf_in_use) mtx_sleep(&d->bd_hbuf_in_use, &d->bd_lock, PRINET, "bd_hbuf", 0); d->bd_fbuf = d->bd_hbuf; d->bd_hbuf = NULL; d->bd_hlen = 0; bpf_buf_reclaimed(d); } /* * Figure out how many bytes to move. If the packet is * greater or equal to the snapshot length, transfer that * much. Otherwise, transfer the whole packet (unless * we hit the buffer size limit). */ hdrlen = bpf_hdrlen(d); totlen = hdrlen + min(snaplen, pktlen); if (totlen > d->bd_bufsize) totlen = d->bd_bufsize; /* * Round up the end of the previous packet to the next longword. * * Drop the packet if there's no room and no hope of room * If the packet would overflow the storage buffer or the storage * buffer is considered immutable by the buffer model, try to rotate * the buffer and wakeup pending processes. */ #ifdef COMPAT_FREEBSD32 if (d->bd_compat32) curlen = BPF_WORDALIGN32(d->bd_slen); else #endif curlen = BPF_WORDALIGN(d->bd_slen); if (curlen + totlen > d->bd_bufsize || !bpf_canwritebuf(d)) { if (d->bd_fbuf == NULL) { /* * There's no room in the store buffer, and no * prospect of room, so drop the packet. Notify the * buffer model. */ bpf_buffull(d); ++d->bd_dcount; return; } while (d->bd_hbuf_in_use) mtx_sleep(&d->bd_hbuf_in_use, &d->bd_lock, PRINET, "bd_hbuf", 0); ROTATE_BUFFERS(d); do_wakeup = 1; curlen = 0; } else if (d->bd_immediate || d->bd_state == BPF_TIMED_OUT) /* * Immediate mode is set, or the read timeout has already * expired during a select call. A packet arrived, so the * reader should be woken up. */ do_wakeup = 1; caplen = totlen - hdrlen; tstype = d->bd_tstamp; do_timestamp = tstype != BPF_T_NONE; #ifndef BURN_BRIDGES if (tstype == BPF_T_NONE || BPF_T_FORMAT(tstype) == BPF_T_MICROTIME) { struct bpf_ts ts; if (do_timestamp) bpf_bintime2ts(bt, &ts, tstype); #ifdef COMPAT_FREEBSD32 if (d->bd_compat32) { bzero(&hdr32_old, sizeof(hdr32_old)); if (do_timestamp) { hdr32_old.bh_tstamp.tv_sec = ts.bt_sec; hdr32_old.bh_tstamp.tv_usec = ts.bt_frac; } hdr32_old.bh_datalen = pktlen; hdr32_old.bh_hdrlen = hdrlen; hdr32_old.bh_caplen = caplen; bpf_append_bytes(d, d->bd_sbuf, curlen, &hdr32_old, sizeof(hdr32_old)); goto copy; } #endif bzero(&hdr_old, sizeof(hdr_old)); if (do_timestamp) { hdr_old.bh_tstamp.tv_sec = ts.bt_sec; hdr_old.bh_tstamp.tv_usec = ts.bt_frac; } hdr_old.bh_datalen = pktlen; hdr_old.bh_hdrlen = hdrlen; hdr_old.bh_caplen = caplen; bpf_append_bytes(d, d->bd_sbuf, curlen, &hdr_old, sizeof(hdr_old)); goto copy; } #endif /* * Append the bpf header. Note we append the actual header size, but * move forward the length of the header plus padding. */ bzero(&hdr, sizeof(hdr)); if (do_timestamp) bpf_bintime2ts(bt, &hdr.bh_tstamp, tstype); hdr.bh_datalen = pktlen; hdr.bh_hdrlen = hdrlen; hdr.bh_caplen = caplen; bpf_append_bytes(d, d->bd_sbuf, curlen, &hdr, sizeof(hdr)); /* * Copy the packet data into the store buffer and update its length. */ #ifndef BURN_BRIDGES copy: #endif (*cpfn)(d, d->bd_sbuf, curlen + hdrlen, pkt, caplen); d->bd_slen = curlen + totlen; if (do_wakeup) bpf_wakeup(d); } /* * Free buffers currently in use by a descriptor. * Called on close. */ static void bpf_freed(struct bpf_d *d) { /* * We don't need to lock out interrupts since this descriptor has * been detached from its interface and it yet hasn't been marked * free. */ bpf_free(d); if (d->bd_rfilter != NULL) { free((caddr_t)d->bd_rfilter, M_BPF); #ifdef BPF_JITTER if (d->bd_bfilter != NULL) bpf_destroy_jit_filter(d->bd_bfilter); #endif } if (d->bd_wfilter != NULL) free((caddr_t)d->bd_wfilter, M_BPF); mtx_destroy(&d->bd_lock); } /* * Attach an interface to bpf. dlt is the link layer type; hdrlen is the * fixed size of the link header (variable length headers not yet supported). */ void bpfattach(struct ifnet *ifp, u_int dlt, u_int hdrlen) { bpfattach2(ifp, dlt, hdrlen, &ifp->if_bpf); } /* * Attach an interface to bpf. ifp is a pointer to the structure * defining the interface to be attached, dlt is the link layer type, * and hdrlen is the fixed size of the link header (variable length * headers are not yet supporrted). */ void bpfattach2(struct ifnet *ifp, u_int dlt, u_int hdrlen, struct bpf_if **driverp) { struct bpf_if *bp; bp = malloc(sizeof(*bp), M_BPF, M_NOWAIT | M_ZERO); if (bp == NULL) panic("bpfattach"); LIST_INIT(&bp->bif_dlist); LIST_INIT(&bp->bif_wlist); bp->bif_ifp = ifp; bp->bif_dlt = dlt; rw_init(&bp->bif_lock, "bpf interface lock"); KASSERT(*driverp == NULL, ("bpfattach2: driverp already initialized")); *driverp = bp; BPF_LOCK(); LIST_INSERT_HEAD(&bpf_iflist, bp, bif_next); BPF_UNLOCK(); bp->bif_hdrlen = hdrlen; if (bootverbose) if_printf(ifp, "bpf attached\n"); } /* * Detach bpf from an interface. This involves detaching each descriptor * associated with the interface. Notify each descriptor as it's detached * so that any sleepers wake up and get ENXIO. */ void bpfdetach(struct ifnet *ifp) { struct bpf_if *bp, *bp_temp; struct bpf_d *d; int ndetached; ndetached = 0; BPF_LOCK(); /* Find all bpf_if struct's which reference ifp and detach them. */ LIST_FOREACH_SAFE(bp, &bpf_iflist, bif_next, bp_temp) { if (ifp != bp->bif_ifp) continue; LIST_REMOVE(bp, bif_next); /* Add to to-be-freed list */ LIST_INSERT_HEAD(&bpf_freelist, bp, bif_next); ndetached++; /* * Delay freeing bp till interface is detached * and all routes through this interface are removed. * Mark bp as detached to restrict new consumers. */ BPFIF_WLOCK(bp); bp->flags |= BPFIF_FLAG_DYING; BPFIF_WUNLOCK(bp); CTR4(KTR_NET, "%s: sheduling free for encap %d (%p) for if %p", __func__, bp->bif_dlt, bp, ifp); /* Free common descriptors */ while ((d = LIST_FIRST(&bp->bif_dlist)) != NULL) { bpf_detachd_locked(d); BPFD_LOCK(d); bpf_wakeup(d); BPFD_UNLOCK(d); } /* Free writer-only descriptors */ while ((d = LIST_FIRST(&bp->bif_wlist)) != NULL) { bpf_detachd_locked(d); BPFD_LOCK(d); bpf_wakeup(d); BPFD_UNLOCK(d); } } BPF_UNLOCK(); #ifdef INVARIANTS if (ndetached == 0) printf("bpfdetach: %s was not attached\n", ifp->if_xname); #endif } /* * Interface departure handler. * Note departure event does not guarantee interface is going down. * Interface renaming is currently done via departure/arrival event set. * * Departure handled is called after all routes pointing to * given interface are removed and interface is in down state * restricting any packets to be sent/received. We assume it is now safe * to free data allocated by BPF. */ static void bpf_ifdetach(void *arg __unused, struct ifnet *ifp) { struct bpf_if *bp, *bp_temp; int nmatched = 0; BPF_LOCK(); /* * Find matching entries in free list. * Nothing should be found if bpfdetach() was not called. */ LIST_FOREACH_SAFE(bp, &bpf_freelist, bif_next, bp_temp) { if (ifp != bp->bif_ifp) continue; CTR3(KTR_NET, "%s: freeing BPF instance %p for interface %p", __func__, bp, ifp); LIST_REMOVE(bp, bif_next); rw_destroy(&bp->bif_lock); free(bp, M_BPF); nmatched++; } BPF_UNLOCK(); /* * Note that we cannot zero other pointers to * custom DLTs possibly used by given interface. */ if (nmatched != 0) ifp->if_bpf = NULL; } /* * Get a list of available data link type of the interface. */ static int bpf_getdltlist(struct bpf_d *d, struct bpf_dltlist *bfl) { int n, error; struct ifnet *ifp; struct bpf_if *bp; BPF_LOCK_ASSERT(); ifp = d->bd_bif->bif_ifp; n = 0; error = 0; LIST_FOREACH(bp, &bpf_iflist, bif_next) { if (bp->bif_ifp != ifp) continue; if (bfl->bfl_list != NULL) { if (n >= bfl->bfl_len) return (ENOMEM); error = copyout(&bp->bif_dlt, bfl->bfl_list + n, sizeof(u_int)); } n++; } bfl->bfl_len = n; return (error); } /* * Set the data link type of a BPF instance. */ static int bpf_setdlt(struct bpf_d *d, u_int dlt) { int error, opromisc; struct ifnet *ifp; struct bpf_if *bp; BPF_LOCK_ASSERT(); if (d->bd_bif->bif_dlt == dlt) return (0); ifp = d->bd_bif->bif_ifp; LIST_FOREACH(bp, &bpf_iflist, bif_next) { if (bp->bif_ifp == ifp && bp->bif_dlt == dlt) break; } if (bp != NULL) { opromisc = d->bd_promisc; bpf_attachd(d, bp); BPFD_LOCK(d); reset_d(d); BPFD_UNLOCK(d); if (opromisc) { error = ifpromisc(bp->bif_ifp, 1); if (error) if_printf(bp->bif_ifp, "bpf_setdlt: ifpromisc failed (%d)\n", error); else d->bd_promisc = 1; } } return (bp == NULL ? EINVAL : 0); } static void bpf_drvinit(void *unused) { struct cdev *dev; mtx_init(&bpf_mtx, "bpf global lock", NULL, MTX_DEF); LIST_INIT(&bpf_iflist); LIST_INIT(&bpf_freelist); dev = make_dev(&bpf_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "bpf"); /* For compatibility */ make_dev_alias(dev, "bpf0"); /* Register interface departure handler */ bpf_ifdetach_cookie = EVENTHANDLER_REGISTER( ifnet_departure_event, bpf_ifdetach, NULL, EVENTHANDLER_PRI_ANY); } /* * Zero out the various packet counters associated with all of the bpf * descriptors. At some point, we will probably want to get a bit more * granular and allow the user to specify descriptors to be zeroed. */ static void bpf_zero_counters(void) { struct bpf_if *bp; struct bpf_d *bd; BPF_LOCK(); LIST_FOREACH(bp, &bpf_iflist, bif_next) { BPFIF_RLOCK(bp); LIST_FOREACH(bd, &bp->bif_dlist, bd_next) { BPFD_LOCK(bd); bd->bd_rcount = 0; bd->bd_dcount = 0; bd->bd_fcount = 0; bd->bd_wcount = 0; bd->bd_wfcount = 0; bd->bd_zcopy = 0; BPFD_UNLOCK(bd); } BPFIF_RUNLOCK(bp); } BPF_UNLOCK(); } /* * Fill filter statistics */ static void bpfstats_fill_xbpf(struct xbpf_d *d, struct bpf_d *bd) { bzero(d, sizeof(*d)); BPFD_LOCK_ASSERT(bd); d->bd_structsize = sizeof(*d); /* XXX: reading should be protected by global lock */ d->bd_immediate = bd->bd_immediate; d->bd_promisc = bd->bd_promisc; d->bd_hdrcmplt = bd->bd_hdrcmplt; d->bd_direction = bd->bd_direction; d->bd_feedback = bd->bd_feedback; d->bd_async = bd->bd_async; d->bd_rcount = bd->bd_rcount; d->bd_dcount = bd->bd_dcount; d->bd_fcount = bd->bd_fcount; d->bd_sig = bd->bd_sig; d->bd_slen = bd->bd_slen; d->bd_hlen = bd->bd_hlen; d->bd_bufsize = bd->bd_bufsize; d->bd_pid = bd->bd_pid; strlcpy(d->bd_ifname, bd->bd_bif->bif_ifp->if_xname, IFNAMSIZ); d->bd_locked = bd->bd_locked; d->bd_wcount = bd->bd_wcount; d->bd_wdcount = bd->bd_wdcount; d->bd_wfcount = bd->bd_wfcount; d->bd_zcopy = bd->bd_zcopy; d->bd_bufmode = bd->bd_bufmode; } /* * Handle `netstat -B' stats request */ static int bpf_stats_sysctl(SYSCTL_HANDLER_ARGS) { struct xbpf_d *xbdbuf, *xbd, zerostats; int index, error; struct bpf_if *bp; struct bpf_d *bd; /* * XXX This is not technically correct. It is possible for non * privileged users to open bpf devices. It would make sense * if the users who opened the devices were able to retrieve * the statistics for them, too. */ error = priv_check(req->td, PRIV_NET_BPF); if (error) return (error); /* * Check to see if the user is requesting that the counters be * zeroed out. Explicitly check that the supplied data is zeroed, * as we aren't allowing the user to set the counters currently. */ if (req->newptr != NULL) { if (req->newlen != sizeof(zerostats)) return (EINVAL); bzero(&zerostats, sizeof(zerostats)); xbd = req->newptr; if (bcmp(xbd, &zerostats, sizeof(*xbd)) != 0) return (EINVAL); bpf_zero_counters(); return (0); } if (req->oldptr == NULL) return (SYSCTL_OUT(req, 0, bpf_bpfd_cnt * sizeof(*xbd))); if (bpf_bpfd_cnt == 0) return (SYSCTL_OUT(req, 0, 0)); xbdbuf = malloc(req->oldlen, M_BPF, M_WAITOK); BPF_LOCK(); if (req->oldlen < (bpf_bpfd_cnt * sizeof(*xbd))) { BPF_UNLOCK(); free(xbdbuf, M_BPF); return (ENOMEM); } index = 0; LIST_FOREACH(bp, &bpf_iflist, bif_next) { BPFIF_RLOCK(bp); /* Send writers-only first */ LIST_FOREACH(bd, &bp->bif_wlist, bd_next) { xbd = &xbdbuf[index++]; BPFD_LOCK(bd); bpfstats_fill_xbpf(xbd, bd); BPFD_UNLOCK(bd); } LIST_FOREACH(bd, &bp->bif_dlist, bd_next) { xbd = &xbdbuf[index++]; BPFD_LOCK(bd); bpfstats_fill_xbpf(xbd, bd); BPFD_UNLOCK(bd); } BPFIF_RUNLOCK(bp); } BPF_UNLOCK(); error = SYSCTL_OUT(req, xbdbuf, index * sizeof(*xbd)); free(xbdbuf, M_BPF); return (error); } SYSINIT(bpfdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE,bpf_drvinit,NULL); #else /* !DEV_BPF && !NETGRAPH_BPF */ /* * NOP stubs to allow bpf-using drivers to load and function. * * A 'better' implementation would allow the core bpf functionality * to be loaded at runtime. */ static struct bpf_if bp_null; void bpf_tap(struct bpf_if *bp, u_char *pkt, u_int pktlen) { } void bpf_mtap(struct bpf_if *bp, struct mbuf *m) { } void bpf_mtap2(struct bpf_if *bp, void *d, u_int l, struct mbuf *m) { } void bpfattach(struct ifnet *ifp, u_int dlt, u_int hdrlen) { bpfattach2(ifp, dlt, hdrlen, &ifp->if_bpf); } void bpfattach2(struct ifnet *ifp, u_int dlt, u_int hdrlen, struct bpf_if **driverp) { *driverp = &bp_null; } void bpfdetach(struct ifnet *ifp) { } u_int bpf_filter(const struct bpf_insn *pc, u_char *p, u_int wirelen, u_int buflen) { return -1; /* "no filter" behaviour */ } int bpf_validate(const struct bpf_insn *f, int len) { return 0; /* false */ } #endif /* !DEV_BPF && !NETGRAPH_BPF */ Index: user/syuu/mq_bpf/sys/net/bpf.h =================================================================== --- user/syuu/mq_bpf/sys/net/bpf.h (revision 255171) +++ user/syuu/mq_bpf/sys/net/bpf.h (revision 255172) @@ -1,1321 +1,1351 @@ /*- * Copyright (c) 1990, 1991, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from the Stanford/CMU enet packet filter, * (net/enet.c) distributed as part of 4.3BSD, and code contributed * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence * Berkeley Laboratory. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)bpf.h 8.1 (Berkeley) 6/10/93 * @(#)bpf.h 1.34 (LBL) 6/16/96 * * $FreeBSD$ */ #ifndef _NET_BPF_H_ #define _NET_BPF_H_ /* BSD style release date */ #define BPF_RELEASE 199606 typedef int32_t bpf_int32; typedef u_int32_t bpf_u_int32; typedef int64_t bpf_int64; typedef u_int64_t bpf_u_int64; /* * Alignment macros. BPF_WORDALIGN rounds up to the next * even multiple of BPF_ALIGNMENT. */ #define BPF_ALIGNMENT sizeof(long) #define BPF_WORDALIGN(x) (((x)+(BPF_ALIGNMENT-1))&~(BPF_ALIGNMENT-1)) #define BPF_MAXINSNS 512 #define BPF_MAXBUFSIZE 0x80000 #define BPF_MINBUFSIZE 32 /* * Structure for BIOCSETF. */ struct bpf_program { u_int bf_len; struct bpf_insn *bf_insns; }; /* * Struct returned by BIOCGSTATS. */ struct bpf_stat { u_int bs_recv; /* number of packets received */ u_int bs_drop; /* number of packets dropped */ }; /* * Struct return by BIOCVERSION. This represents the version number of * the filter language described by the instruction encodings below. * bpf understands a program iff kernel_major == filter_major && * kernel_minor >= filter_minor, that is, if the value returned by the * running kernel has the same major number and a minor number equal * equal to or less than the filter being downloaded. Otherwise, the * results are undefined, meaning an error may be returned or packets * may be accepted haphazardly. * It has nothing to do with the source code version. */ struct bpf_version { u_short bv_major; u_short bv_minor; }; /* Current version number of filter architecture. */ #define BPF_MAJOR_VERSION 1 #define BPF_MINOR_VERSION 1 /* * Historically, BPF has supported a single buffering model, first using mbuf * clusters in kernel, and later using malloc(9) buffers in kernel. We now * support multiple buffering modes, which may be queried and set using * BIOCGETBUFMODE and BIOCSETBUFMODE. So as to avoid handling the complexity * of changing modes while sniffing packets, the mode becomes fixed once an * interface has been attached to the BPF descriptor. */ #define BPF_BUFMODE_BUFFER 1 /* Kernel buffers with read(). */ #define BPF_BUFMODE_ZBUF 2 /* Zero-copy buffers. */ /*- * Struct used by BIOCSETZBUF, BIOCROTZBUF: describes up to two zero-copy * buffer as used by BPF. */ struct bpf_zbuf { void *bz_bufa; /* Location of 'a' zero-copy buffer. */ void *bz_bufb; /* Location of 'b' zero-copy buffer. */ size_t bz_buflen; /* Size of zero-copy buffers. */ }; +#ifndef _KERNEL +#include +#include +#include + +#define BPFQ_BITS 256 +BITSET_DEFINE(bpf_qmask_bits, BPFQ_BITS); + +#define BPFQ_CLR(n, p) BIT_CLR(BPFQ_BITS, n, p) +#define BPFQ_COPY(f, t) BIT_COPY(BPFQ_BITS, f, t) +#define BPFQ_ISSET(n, p) BIT_ISSET(BPFQ_BITS, n, p) +#define BPFQ_SET(n, p) BIT_SET(BPFQ_BITS, n, p) +#define BPFQ_ZERO(p) BIT_ZERO(BPFQ_BITS, p) +#define BPFQ_FILL(p) BIT_FILL(BPFQ_BITS, p) +#define BPFQ_SETOF(n, p) BIT_SETOF(BPFQ_BITS, n, p) +#define BPFQ_EMPTY(p) BIT_EMPTY(BPFQ_BITS, p) +#define BPFQ_ISFULLSET(p) BIT_ISFULLSET(BPFQ_BITS, p) +#define BPFQ_SUBSET(p, c) BIT_SUBSET(BPFQ_BITS, p, c) +#define BPFQ_OVERLAP(p, c) BIT_OVERLAP(BPFQ_BITS, p, c) +#define BPFQ_CMP(p, c) BIT_CMP(BPFQ_BITS, p, c) +#define BPFQ_OR(d, s) BIT_OR(BPFQ_BITS, d, s) +#define BPFQ_AND(d, s) BIT_AND(BPFQ_BITS, d, s) +#define BPFQ_NAND(d, s) BIT_NAND(BPFQ_BITS, d, s) +#define BPFQ_CLR_ATOMIC(n, p) BIT_CLR_ATOMIC(BPFQ_BITS, n, p) +#define BPFQ_SET_ATOMIC(n, p) BIT_SET_ATOMIC(BPFQ_BITS, n, p) +#define BPFQ_OR_ATOMIC(d, s) BIT_OR_ATOMIC(BPFQ_BITS, d, s) +#define BPFQ_COPY_STORE_REL(f, t) BIT_COPY_STORE_REL(BPFQ_BITS, f, t) +#define BPFQ_FFS(p) BIT_FFS(BPFQ_BITS, p) +#endif + #define BIOCGBLEN _IOR('B', 102, u_int) #define BIOCSBLEN _IOWR('B', 102, u_int) #define BIOCSETF _IOW('B', 103, struct bpf_program) #define BIOCFLUSH _IO('B', 104) #define BIOCPROMISC _IO('B', 105) #define BIOCGDLT _IOR('B', 106, u_int) #define BIOCGETIF _IOR('B', 107, struct ifreq) #define BIOCSETIF _IOW('B', 108, struct ifreq) #define BIOCSRTIMEOUT _IOW('B', 109, struct timeval) #define BIOCGRTIMEOUT _IOR('B', 110, struct timeval) #define BIOCGSTATS _IOR('B', 111, struct bpf_stat) #define BIOCIMMEDIATE _IOW('B', 112, u_int) #define BIOCVERSION _IOR('B', 113, struct bpf_version) #define BIOCGRSIG _IOR('B', 114, u_int) #define BIOCSRSIG _IOW('B', 115, u_int) #define BIOCGHDRCMPLT _IOR('B', 116, u_int) #define BIOCSHDRCMPLT _IOW('B', 117, u_int) #define BIOCGDIRECTION _IOR('B', 118, u_int) #define BIOCSDIRECTION _IOW('B', 119, u_int) #define BIOCSDLT _IOW('B', 120, u_int) #define BIOCGDLTLIST _IOWR('B', 121, struct bpf_dltlist) #define BIOCLOCK _IO('B', 122) #define BIOCSETWF _IOW('B', 123, struct bpf_program) #define BIOCFEEDBACK _IOW('B', 124, u_int) #define BIOCGETBUFMODE _IOR('B', 125, u_int) #define BIOCSETBUFMODE _IOW('B', 126, u_int) #define BIOCGETZMAX _IOR('B', 127, size_t) #define BIOCROTZBUF _IOR('B', 128, struct bpf_zbuf) #define BIOCSETZBUF _IOW('B', 129, struct bpf_zbuf) #define BIOCSETFNR _IOW('B', 130, struct bpf_program) #define BIOCGTSTAMP _IOR('B', 131, u_int) #define BIOCSTSTAMP _IOW('B', 132, u_int) #define BIOCQMASKENABLE _IO('B', 133) #define BIOCQMASKDISABLE _IO('B', 134) -#define BIOCGRXQMASK _IOR('B', 135, bpf_qmask_bits_t) -#define BIOCSRXQMASK _IOW('B', 135, bpf_qmask_bits_t) -#define BIOCGTXQMASK _IOR('B', 136, bpf_qmask_bits_t) -#define BIOCSTXQMASK _IOW('B', 137, bpf_qmask_bits_t) -#define BIOCGNOQMASK _IOR('B', 138, boolean_t) -#define BIOCSNOQMASK _IOW('B', 139, boolean_t) +#define BIOCGRXQMASK _IOR('B', 135, struct bpf_qmask_bits) +#define BIOCSRXQMASK _IOW('B', 135, struct bpf_qmask_bits) +#define BIOCGTXQMASK _IOR('B', 136, struct bpf_qmask_bits) +#define BIOCSTXQMASK _IOW('B', 137, struct bpf_qmask_bits) +#define BIOCGNOQMASK _IOR('B', 138, int) +#define BIOCSNOQMASK _IOW('B', 139, int) /* Obsolete */ #define BIOCGSEESENT BIOCGDIRECTION #define BIOCSSEESENT BIOCSDIRECTION /* Packet directions */ enum bpf_direction { BPF_D_IN, /* See incoming packets */ BPF_D_INOUT, /* See incoming and outgoing packets */ BPF_D_OUT /* See outgoing packets */ }; /* Time stamping functions */ #define BPF_T_MICROTIME 0x0000 #define BPF_T_NANOTIME 0x0001 #define BPF_T_BINTIME 0x0002 #define BPF_T_NONE 0x0003 #define BPF_T_FORMAT_MASK 0x0003 #define BPF_T_NORMAL 0x0000 #define BPF_T_FAST 0x0100 #define BPF_T_MONOTONIC 0x0200 #define BPF_T_MONOTONIC_FAST (BPF_T_FAST | BPF_T_MONOTONIC) #define BPF_T_FLAG_MASK 0x0300 #define BPF_T_FORMAT(t) ((t) & BPF_T_FORMAT_MASK) #define BPF_T_FLAG(t) ((t) & BPF_T_FLAG_MASK) #define BPF_T_VALID(t) \ ((t) == BPF_T_NONE || (BPF_T_FORMAT(t) != BPF_T_NONE && \ ((t) & ~(BPF_T_FORMAT_MASK | BPF_T_FLAG_MASK)) == 0)) #define BPF_T_MICROTIME_FAST (BPF_T_MICROTIME | BPF_T_FAST) #define BPF_T_NANOTIME_FAST (BPF_T_NANOTIME | BPF_T_FAST) #define BPF_T_BINTIME_FAST (BPF_T_BINTIME | BPF_T_FAST) #define BPF_T_MICROTIME_MONOTONIC (BPF_T_MICROTIME | BPF_T_MONOTONIC) #define BPF_T_NANOTIME_MONOTONIC (BPF_T_NANOTIME | BPF_T_MONOTONIC) #define BPF_T_BINTIME_MONOTONIC (BPF_T_BINTIME | BPF_T_MONOTONIC) #define BPF_T_MICROTIME_MONOTONIC_FAST (BPF_T_MICROTIME | BPF_T_MONOTONIC_FAST) #define BPF_T_NANOTIME_MONOTONIC_FAST (BPF_T_NANOTIME | BPF_T_MONOTONIC_FAST) #define BPF_T_BINTIME_MONOTONIC_FAST (BPF_T_BINTIME | BPF_T_MONOTONIC_FAST) /* * Structure prepended to each packet. */ struct bpf_ts { bpf_int64 bt_sec; /* seconds */ bpf_u_int64 bt_frac; /* fraction */ }; struct bpf_xhdr { struct bpf_ts bh_tstamp; /* time stamp */ bpf_u_int32 bh_caplen; /* length of captured portion */ bpf_u_int32 bh_datalen; /* original length of packet */ u_short bh_hdrlen; /* length of bpf header (this struct plus alignment padding) */ }; /* Obsolete */ struct bpf_hdr { struct timeval bh_tstamp; /* time stamp */ bpf_u_int32 bh_caplen; /* length of captured portion */ bpf_u_int32 bh_datalen; /* original length of packet */ u_short bh_hdrlen; /* length of bpf header (this struct plus alignment padding) */ }; #ifdef _KERNEL #define MTAG_BPF 0x627066 #define MTAG_BPF_TIMESTAMP 0 #endif /* * When using zero-copy BPF buffers, a shared memory header is present * allowing the kernel BPF implementation and user process to synchronize * without using system calls. This structure defines that header. When * accessing these fields, appropriate atomic operation and memory barriers * are required in order not to see stale or out-of-order data; see bpf(4) * for reference code to access these fields from userspace. * * The layout of this structure is critical, and must not be changed; if must * fit in a single page on all architectures. */ struct bpf_zbuf_header { volatile u_int bzh_kernel_gen; /* Kernel generation number. */ volatile u_int bzh_kernel_len; /* Length of data in the buffer. */ volatile u_int bzh_user_gen; /* User generation number. */ u_int _bzh_pad[5]; }; /* * Data-link level type codes. */ #define DLT_NULL 0 /* BSD loopback encapsulation */ #define DLT_EN10MB 1 /* Ethernet (10Mb) */ #define DLT_EN3MB 2 /* Experimental Ethernet (3Mb) */ #define DLT_AX25 3 /* Amateur Radio AX.25 */ #define DLT_PRONET 4 /* Proteon ProNET Token Ring */ #define DLT_CHAOS 5 /* Chaos */ #define DLT_IEEE802 6 /* IEEE 802 Networks */ #define DLT_ARCNET 7 /* ARCNET */ #define DLT_SLIP 8 /* Serial Line IP */ #define DLT_PPP 9 /* Point-to-point Protocol */ #define DLT_FDDI 10 /* FDDI */ #define DLT_ATM_RFC1483 11 /* LLC/SNAP encapsulated atm */ #define DLT_RAW 12 /* raw IP */ /* * These are values from BSD/OS's "bpf.h". * These are not the same as the values from the traditional libpcap * "bpf.h"; however, these values shouldn't be generated by any * OS other than BSD/OS, so the correct values to use here are the * BSD/OS values. * * Platforms that have already assigned these values to other * DLT_ codes, however, should give these codes the values * from that platform, so that programs that use these codes will * continue to compile - even though they won't correctly read * files of these types. */ #define DLT_SLIP_BSDOS 15 /* BSD/OS Serial Line IP */ #define DLT_PPP_BSDOS 16 /* BSD/OS Point-to-point Protocol */ #define DLT_ATM_CLIP 19 /* Linux Classical-IP over ATM */ /* * These values are defined by NetBSD; other platforms should refrain from * using them for other purposes, so that NetBSD savefiles with link * types of 50 or 51 can be read as this type on all platforms. */ #define DLT_PPP_SERIAL 50 /* PPP over serial with HDLC encapsulation */ #define DLT_PPP_ETHER 51 /* PPP over Ethernet */ /* * Reserved for the Symantec Enterprise Firewall. */ #define DLT_SYMANTEC_FIREWALL 99 /* * Values between 100 and 103 are used in capture file headers as * link-layer header type LINKTYPE_ values corresponding to DLT_ types * that differ between platforms; don't use those values for new DLT_ * new types. */ /* * Values starting with 104 are used for newly-assigned link-layer * header type values; for those link-layer header types, the DLT_ * value returned by pcap_datalink() and passed to pcap_open_dead(), * and the LINKTYPE_ value that appears in capture files, are the * same. * * DLT_MATCHING_MIN is the lowest such value; DLT_MATCHING_MAX is * the highest such value. */ #define DLT_MATCHING_MIN 104 /* * This value was defined by libpcap 0.5; platforms that have defined * it with a different value should define it here with that value - * a link type of 104 in a save file will be mapped to DLT_C_HDLC, * whatever value that happens to be, so programs will correctly * handle files with that link type regardless of the value of * DLT_C_HDLC. * * The name DLT_C_HDLC was used by BSD/OS; we use that name for source * compatibility with programs written for BSD/OS. * * libpcap 0.5 defined it as DLT_CHDLC; we define DLT_CHDLC as well, * for source compatibility with programs written for libpcap 0.5. */ #define DLT_C_HDLC 104 /* Cisco HDLC */ #define DLT_CHDLC DLT_C_HDLC #define DLT_IEEE802_11 105 /* IEEE 802.11 wireless */ /* * Values between 106 and 107 are used in capture file headers as * link-layer types corresponding to DLT_ types that might differ * between platforms; don't use those values for new DLT_ new types. */ /* * Frame Relay; BSD/OS has a DLT_FR with a value of 11, but that collides * with other values. * DLT_FR and DLT_FRELAY packets start with the Q.922 Frame Relay header * (DLCI, etc.). */ #define DLT_FRELAY 107 /* * OpenBSD DLT_LOOP, for loopback devices; it's like DLT_NULL, except * that the AF_ type in the link-layer header is in network byte order. * * OpenBSD defines it as 12, but that collides with DLT_RAW, so we * define it as 108 here. If OpenBSD picks up this file, it should * define DLT_LOOP as 12 in its version, as per the comment above - * and should not use 108 as a DLT_ value. */ #define DLT_LOOP 108 /* * Values between 109 and 112 are used in capture file headers as * link-layer types corresponding to DLT_ types that might differ * between platforms; don't use those values for new DLT_ new types. */ /* * Encapsulated packets for IPsec; DLT_ENC is 13 in OpenBSD, but that's * DLT_SLIP_BSDOS in NetBSD, so we don't use 13 for it in OSes other * than OpenBSD. */ #define DLT_ENC 109 /* * This is for Linux cooked sockets. */ #define DLT_LINUX_SLL 113 /* * Apple LocalTalk hardware. */ #define DLT_LTALK 114 /* * Acorn Econet. */ #define DLT_ECONET 115 /* * Reserved for use with OpenBSD ipfilter. */ #define DLT_IPFILTER 116 /* * Reserved for use in capture-file headers as a link-layer type * corresponding to OpenBSD DLT_PFLOG; DLT_PFLOG is 17 in OpenBSD, * but that's DLT_LANE8023 in SuSE 6.3, so we can't use 17 for it * in capture-file headers. */ #define DLT_PFLOG 117 /* * Registered for Cisco-internal use. */ #define DLT_CISCO_IOS 118 /* * Reserved for 802.11 cards using the Prism II chips, with a link-layer * header including Prism monitor mode information plus an 802.11 * header. */ #define DLT_PRISM_HEADER 119 /* * Reserved for Aironet 802.11 cards, with an Aironet link-layer header * (see Doug Ambrisko's FreeBSD patches). */ #define DLT_AIRONET_HEADER 120 /* * Reserved for use by OpenBSD's pfsync device. */ #define DLT_PFSYNC 121 /* * Reserved for Siemens HiPath HDLC. XXX */ #define DLT_HHDLC 121 /* * Reserved for RFC 2625 IP-over-Fibre Channel. */ #define DLT_IP_OVER_FC 122 /* * Reserved for Full Frontal ATM on Solaris. */ #define DLT_SUNATM 123 /* * Reserved as per request from Kent Dahlgren * for private use. */ #define DLT_RIO 124 /* RapidIO */ #define DLT_PCI_EXP 125 /* PCI Express */ #define DLT_AURORA 126 /* Xilinx Aurora link layer */ /* * BSD header for 802.11 plus a number of bits of link-layer information * including radio information. */ #ifndef DLT_IEEE802_11_RADIO #define DLT_IEEE802_11_RADIO 127 #endif /* * Reserved for TZSP encapsulation. */ #define DLT_TZSP 128 /* Tazmen Sniffer Protocol */ /* * Reserved for Linux ARCNET. */ #define DLT_ARCNET_LINUX 129 /* * Juniper-private data link types. */ #define DLT_JUNIPER_MLPPP 130 #define DLT_JUNIPER_MLFR 131 #define DLT_JUNIPER_ES 132 #define DLT_JUNIPER_GGSN 133 #define DLT_JUNIPER_MFR 134 #define DLT_JUNIPER_ATM2 135 #define DLT_JUNIPER_SERVICES 136 #define DLT_JUNIPER_ATM1 137 /* * Apple IP-over-IEEE 1394, as per a request from Dieter Siegmund * . The header that's presented is an Ethernet-like * header: * * #define FIREWIRE_EUI64_LEN 8 * struct firewire_header { * u_char firewire_dhost[FIREWIRE_EUI64_LEN]; * u_char firewire_shost[FIREWIRE_EUI64_LEN]; * u_short firewire_type; * }; * * with "firewire_type" being an Ethernet type value, rather than, * for example, raw GASP frames being handed up. */ #define DLT_APPLE_IP_OVER_IEEE1394 138 /* * Various SS7 encapsulations, as per a request from Jeff Morriss * and subsequent discussions. */ #define DLT_MTP2_WITH_PHDR 139 /* pseudo-header with various info, followed by MTP2 */ #define DLT_MTP2 140 /* MTP2, without pseudo-header */ #define DLT_MTP3 141 /* MTP3, without pseudo-header or MTP2 */ #define DLT_SCCP 142 /* SCCP, without pseudo-header or MTP2 or MTP3 */ /* * Reserved for DOCSIS. */ #define DLT_DOCSIS 143 /* * Reserved for Linux IrDA. */ #define DLT_LINUX_IRDA 144 /* * Reserved for IBM SP switch and IBM Next Federation switch. */ #define DLT_IBM_SP 145 #define DLT_IBM_SN 146 /* * Reserved for private use. If you have some link-layer header type * that you want to use within your organization, with the capture files * using that link-layer header type not ever be sent outside your * organization, you can use these values. * * No libpcap release will use these for any purpose, nor will any * tcpdump release use them, either. * * Do *NOT* use these in capture files that you expect anybody not using * your private versions of capture-file-reading tools to read; in * particular, do *NOT* use them in products, otherwise you may find that * people won't be able to use tcpdump, or snort, or Ethereal, or... to * read capture files from your firewall/intrusion detection/traffic * monitoring/etc. appliance, or whatever product uses that DLT_ value, * and you may also find that the developers of those applications will * not accept patches to let them read those files. * * Also, do not use them if somebody might send you a capture using them * for *their* private type and tools using them for *your* private type * would have to read them. * * Instead, ask "tcpdump-workers@tcpdump.org" for a new DLT_ value, * as per the comment above, and use the type you're given. */ #define DLT_USER0 147 #define DLT_USER1 148 #define DLT_USER2 149 #define DLT_USER3 150 #define DLT_USER4 151 #define DLT_USER5 152 #define DLT_USER6 153 #define DLT_USER7 154 #define DLT_USER8 155 #define DLT_USER9 156 #define DLT_USER10 157 #define DLT_USER11 158 #define DLT_USER12 159 #define DLT_USER13 160 #define DLT_USER14 161 #define DLT_USER15 162 /* * For future use with 802.11 captures - defined by AbsoluteValue * Systems to store a number of bits of link-layer information * including radio information: * * http://www.shaftnet.org/~pizza/software/capturefrm.txt * * but it might be used by some non-AVS drivers now or in the * future. */ #define DLT_IEEE802_11_RADIO_AVS 163 /* 802.11 plus AVS radio header */ /* * Juniper-private data link type, as per request from * Hannes Gredler . The DLT_s are used * for passing on chassis-internal metainformation such as * QOS profiles, etc.. */ #define DLT_JUNIPER_MONITOR 164 /* * Reserved for BACnet MS/TP. */ #define DLT_BACNET_MS_TP 165 /* * Another PPP variant as per request from Karsten Keil . * * This is used in some OSes to allow a kernel socket filter to distinguish * between incoming and outgoing packets, on a socket intended to * supply pppd with outgoing packets so it can do dial-on-demand and * hangup-on-lack-of-demand; incoming packets are filtered out so they * don't cause pppd to hold the connection up (you don't want random * input packets such as port scans, packets from old lost connections, * etc. to force the connection to stay up). * * The first byte of the PPP header (0xff03) is modified to accomodate * the direction - 0x00 = IN, 0x01 = OUT. */ #define DLT_PPP_PPPD 166 /* * Names for backwards compatibility with older versions of some PPP * software; new software should use DLT_PPP_PPPD. */ #define DLT_PPP_WITH_DIRECTION DLT_PPP_PPPD #define DLT_LINUX_PPP_WITHDIRECTION DLT_PPP_PPPD /* * Juniper-private data link type, as per request from * Hannes Gredler . The DLT_s are used * for passing on chassis-internal metainformation such as * QOS profiles, cookies, etc.. */ #define DLT_JUNIPER_PPPOE 167 #define DLT_JUNIPER_PPPOE_ATM 168 #define DLT_GPRS_LLC 169 /* GPRS LLC */ #define DLT_GPF_T 170 /* GPF-T (ITU-T G.7041/Y.1303) */ #define DLT_GPF_F 171 /* GPF-F (ITU-T G.7041/Y.1303) */ /* * Requested by Oolan Zimmer for use in Gcom's T1/E1 line * monitoring equipment. */ #define DLT_GCOM_T1E1 172 #define DLT_GCOM_SERIAL 173 /* * Juniper-private data link type, as per request from * Hannes Gredler . The DLT_ is used * for internal communication to Physical Interface Cards (PIC) */ #define DLT_JUNIPER_PIC_PEER 174 /* * Link types requested by Gregor Maier of Endace * Measurement Systems. They add an ERF header (see * http://www.endace.com/support/EndaceRecordFormat.pdf) in front of * the link-layer header. */ #define DLT_ERF_ETH 175 /* Ethernet */ #define DLT_ERF_POS 176 /* Packet-over-SONET */ /* * Requested by Daniele Orlandi for raw LAPD * for vISDN (http://www.orlandi.com/visdn/). Its link-layer header * includes additional information before the LAPD header, so it's * not necessarily a generic LAPD header. */ #define DLT_LINUX_LAPD 177 /* * Juniper-private data link type, as per request from * Hannes Gredler . * The DLT_ are used for prepending meta-information * like interface index, interface name * before standard Ethernet, PPP, Frelay & C-HDLC Frames */ #define DLT_JUNIPER_ETHER 178 #define DLT_JUNIPER_PPP 179 #define DLT_JUNIPER_FRELAY 180 #define DLT_JUNIPER_CHDLC 181 /* * Multi Link Frame Relay (FRF.16) */ #define DLT_MFR 182 /* * Juniper-private data link type, as per request from * Hannes Gredler . * The DLT_ is used for internal communication with a * voice Adapter Card (PIC) */ #define DLT_JUNIPER_VP 183 /* * Arinc 429 frames. * DLT_ requested by Gianluca Varenni . * Every frame contains a 32bit A429 label. * More documentation on Arinc 429 can be found at * http://www.condoreng.com/support/downloads/tutorials/ARINCTutorial.pdf */ #define DLT_A429 184 /* * Arinc 653 Interpartition Communication messages. * DLT_ requested by Gianluca Varenni . * Please refer to the A653-1 standard for more information. */ #define DLT_A653_ICM 185 /* * USB packets, beginning with a USB setup header; requested by * Paolo Abeni . */ #define DLT_USB 186 /* * Bluetooth HCI UART transport layer (part H:4); requested by * Paolo Abeni. */ #define DLT_BLUETOOTH_HCI_H4 187 /* * IEEE 802.16 MAC Common Part Sublayer; requested by Maria Cruz * . */ #define DLT_IEEE802_16_MAC_CPS 188 /* * USB packets, beginning with a Linux USB header; requested by * Paolo Abeni . */ #define DLT_USB_LINUX 189 /* * Controller Area Network (CAN) v. 2.0B packets. * DLT_ requested by Gianluca Varenni . * Used to dump CAN packets coming from a CAN Vector board. * More documentation on the CAN v2.0B frames can be found at * http://www.can-cia.org/downloads/?269 */ #define DLT_CAN20B 190 /* * IEEE 802.15.4, with address fields padded, as is done by Linux * drivers; requested by Juergen Schimmer. */ #define DLT_IEEE802_15_4_LINUX 191 /* * Per Packet Information encapsulated packets. * DLT_ requested by Gianluca Varenni . */ #define DLT_PPI 192 /* * Header for 802.16 MAC Common Part Sublayer plus a radiotap radio header; * requested by Charles Clancy. */ #define DLT_IEEE802_16_MAC_CPS_RADIO 193 /* * Juniper-private data link type, as per request from * Hannes Gredler . * The DLT_ is used for internal communication with a * integrated service module (ISM). */ #define DLT_JUNIPER_ISM 194 /* * IEEE 802.15.4, exactly as it appears in the spec (no padding, no * nothing); requested by Mikko Saarnivala . */ #define DLT_IEEE802_15_4 195 /* * Various link-layer types, with a pseudo-header, for SITA * (http://www.sita.aero/); requested by Fulko Hew (fulko.hew@gmail.com). */ #define DLT_SITA 196 /* * Various link-layer types, with a pseudo-header, for Endace DAG cards; * encapsulates Endace ERF records. Requested by Stephen Donnelly * . */ #define DLT_ERF 197 /* * Special header prepended to Ethernet packets when capturing from a * u10 Networks board. Requested by Phil Mulholland * . */ #define DLT_RAIF1 198 /* * IPMB packet for IPMI, beginning with the I2C slave address, followed * by the netFn and LUN, etc.. Requested by Chanthy Toeung * . */ #define DLT_IPMB 199 /* * Juniper-private data link type, as per request from * Hannes Gredler . * The DLT_ is used for capturing data on a secure tunnel interface. */ #define DLT_JUNIPER_ST 200 /* * Bluetooth HCI UART transport layer (part H:4), with pseudo-header * that includes direction information; requested by Paolo Abeni. */ #define DLT_BLUETOOTH_HCI_H4_WITH_PHDR 201 /* * AX.25 packet with a 1-byte KISS header; see * * http://www.ax25.net/kiss.htm * * as per Richard Stearn . */ #define DLT_AX25_KISS 202 /* * LAPD packets from an ISDN channel, starting with the address field, * with no pseudo-header. * Requested by Varuna De Silva . */ #define DLT_LAPD 203 /* * Variants of various link-layer headers, with a one-byte direction * pseudo-header prepended - zero means "received by this host", * non-zero (any non-zero value) means "sent by this host" - as per * Will Barker . */ #define DLT_PPP_WITH_DIR 204 /* PPP - don't confuse with DLT_PPP_WITH_DIRECTION */ #define DLT_C_HDLC_WITH_DIR 205 /* Cisco HDLC */ #define DLT_FRELAY_WITH_DIR 206 /* Frame Relay */ #define DLT_LAPB_WITH_DIR 207 /* LAPB */ /* * 208 is reserved for an as-yet-unspecified proprietary link-layer * type, as requested by Will Barker. */ /* * IPMB with a Linux-specific pseudo-header; as requested by Alexey Neyman * . */ #define DLT_IPMB_LINUX 209 /* * FlexRay automotive bus - http://www.flexray.com/ - as requested * by Hannes Kaelber . */ #define DLT_FLEXRAY 210 /* * Media Oriented Systems Transport (MOST) bus for multimedia * transport - http://www.mostcooperation.com/ - as requested * by Hannes Kaelber . */ #define DLT_MOST 211 /* * Local Interconnect Network (LIN) bus for vehicle networks - * http://www.lin-subbus.org/ - as requested by Hannes Kaelber * . */ #define DLT_LIN 212 /* * X2E-private data link type used for serial line capture, * as requested by Hannes Kaelber . */ #define DLT_X2E_SERIAL 213 /* * X2E-private data link type used for the Xoraya data logger * family, as requested by Hannes Kaelber . */ #define DLT_X2E_XORAYA 214 /* * IEEE 802.15.4, exactly as it appears in the spec (no padding, no * nothing), but with the PHY-level data for non-ASK PHYs (4 octets * of 0 as preamble, one octet of SFD, one octet of frame length+ * reserved bit, and then the MAC-layer data, starting with the * frame control field). * * Requested by Max Filippov . */ #define DLT_IEEE802_15_4_NONASK_PHY 215 /* * David Gibson requested this for * captures from the Linux kernel /dev/input/eventN devices. This * is used to communicate keystrokes and mouse movements from the * Linux kernel to display systems, such as Xorg. */ #define DLT_LINUX_EVDEV 216 /* * GSM Um and Abis interfaces, preceded by a "gsmtap" header. * * Requested by Harald Welte . */ #define DLT_GSMTAP_UM 217 #define DLT_GSMTAP_ABIS 218 /* * MPLS, with an MPLS label as the link-layer header. * Requested by Michele Marchetto on behalf * of OpenBSD. */ #define DLT_MPLS 219 /* * USB packets, beginning with a Linux USB header, with the USB header * padded to 64 bytes; required for memory-mapped access. */ #define DLT_USB_LINUX_MMAPPED 220 /* * DECT packets, with a pseudo-header; requested by * Matthias Wenzel . */ #define DLT_DECT 221 /* * From: "Lidwa, Eric (GSFC-582.0)[SGT INC]" * Date: Mon, 11 May 2009 11:18:30 -0500 * * DLT_AOS. We need it for AOS Space Data Link Protocol. * I have already written dissectors for but need an OK from * legal before I can submit a patch. * */ #define DLT_AOS 222 /* * Wireless HART (Highway Addressable Remote Transducer) * From the HART Communication Foundation * IES/PAS 62591 * * Requested by Sam Roberts . */ #define DLT_WIHART 223 /* * Fibre Channel FC-2 frames, beginning with a Frame_Header. * Requested by Kahou Lei . */ #define DLT_FC_2 224 /* * Fibre Channel FC-2 frames, beginning with an encoding of the * SOF, and ending with an encoding of the EOF. * * The encodings represent the frame delimiters as 4-byte sequences * representing the corresponding ordered sets, with K28.5 * represented as 0xBC, and the D symbols as the corresponding * byte values; for example, SOFi2, which is K28.5 - D21.5 - D1.2 - D21.2, * is represented as 0xBC 0xB5 0x55 0x55. * * Requested by Kahou Lei . */ #define DLT_FC_2_WITH_FRAME_DELIMS 225 /* * Solaris ipnet pseudo-header; requested by Darren Reed . * * The pseudo-header starts with a one-byte version number; for version 2, * the pseudo-header is: * * struct dl_ipnetinfo { * u_int8_t dli_version; * u_int8_t dli_family; * u_int16_t dli_htype; * u_int32_t dli_pktlen; * u_int32_t dli_ifindex; * u_int32_t dli_grifindex; * u_int32_t dli_zsrc; * u_int32_t dli_zdst; * }; * * dli_version is 2 for the current version of the pseudo-header. * * dli_family is a Solaris address family value, so it's 2 for IPv4 * and 26 for IPv6. * * dli_htype is a "hook type" - 0 for incoming packets, 1 for outgoing * packets, and 2 for packets arriving from another zone on the same * machine. * * dli_pktlen is the length of the packet data following the pseudo-header * (so the captured length minus dli_pktlen is the length of the * pseudo-header, assuming the entire pseudo-header was captured). * * dli_ifindex is the interface index of the interface on which the * packet arrived. * * dli_grifindex is the group interface index number (for IPMP interfaces). * * dli_zsrc is the zone identifier for the source of the packet. * * dli_zdst is the zone identifier for the destination of the packet. * * A zone number of 0 is the global zone; a zone number of 0xffffffff * means that the packet arrived from another host on the network, not * from another zone on the same machine. * * An IPv4 or IPv6 datagram follows the pseudo-header; dli_family indicates * which of those it is. */ #define DLT_IPNET 226 /* * CAN (Controller Area Network) frames, with a pseudo-header as supplied * by Linux SocketCAN. See Documentation/networking/can.txt in the Linux * source. * * Requested by Felix Obenhuber . */ #define DLT_CAN_SOCKETCAN 227 /* * Raw IPv4/IPv6; different from DLT_RAW in that the DLT_ value specifies * whether it's v4 or v6. Requested by Darren Reed . */ #define DLT_IPV4 228 #define DLT_IPV6 229 /* * IEEE 802.15.4, exactly as it appears in the spec (no padding, no * nothing), and with no FCS at the end of the frame; requested by * Jon Smirl . */ #define DLT_IEEE802_15_4_NOFCS 230 /* * Raw D-Bus: * * http://www.freedesktop.org/wiki/Software/dbus * * messages: * * http://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-messages * * starting with the endianness flag, followed by the message type, etc., * but without the authentication handshake before the message sequence: * * http://dbus.freedesktop.org/doc/dbus-specification.html#auth-protocol * * Requested by Martin Vidner . */ #define DLT_DBUS 231 /* * Juniper-private data link type, as per request from * Hannes Gredler . */ #define DLT_JUNIPER_VS 232 #define DLT_JUNIPER_SRX_E2E 233 #define DLT_JUNIPER_FIBRECHANNEL 234 /* * DVB-CI (DVB Common Interface for communication between a PC Card * module and a DVB receiver). See * * http://www.kaiser.cx/pcap-dvbci.html * * for the specification. * * Requested by Martin Kaiser . */ #define DLT_DVB_CI 235 /* * Variant of 3GPP TS 27.010 multiplexing protocol (similar to, but * *not* the same as, 27.010). Requested by Hans-Christoph Schemmel * . */ #define DLT_MUX27010 236 /* * STANAG 5066 D_PDUs. Requested by M. Baris Demiray * . */ #define DLT_STANAG_5066_D_PDU 237 /* * Juniper-private data link type, as per request from * Hannes Gredler . */ #define DLT_JUNIPER_ATM_CEMIC 238 /* * NetFilter LOG messages * (payload of netlink NFNL_SUBSYS_ULOG/NFULNL_MSG_PACKET packets) * * Requested by Jakub Zawadzki */ #define DLT_NFLOG 239 /* * Hilscher Gesellschaft fuer Systemautomation mbH link-layer type * for Ethernet packets with a 4-byte pseudo-header and always * with the payload including the FCS, as supplied by their * netANALYZER hardware and software. * * Requested by Holger P. Frommer */ #define DLT_NETANALYZER 240 /* * Hilscher Gesellschaft fuer Systemautomation mbH link-layer type * for Ethernet packets with a 4-byte pseudo-header and FCS and * with the Ethernet header preceded by 7 bytes of preamble and * 1 byte of SFD, as supplied by their netANALYZER hardware and * software. * * Requested by Holger P. Frommer */ #define DLT_NETANALYZER_TRANSPARENT 241 /* * IP-over-Infiniband, as specified by RFC 4391. * * Requested by Petr Sumbera . */ #define DLT_IPOIB 242 /* * MPEG-2 transport stream (ISO 13818-1/ITU-T H.222.0). * * Requested by Guy Martin . */ #define DLT_MPEG_2_TS 243 /* * ng4T GmbH's UMTS Iub/Iur-over-ATM and Iub/Iur-over-IP format as * used by their ng40 protocol tester. * * Requested by Jens Grimmer . */ #define DLT_NG40 244 /* * Pseudo-header giving adapter number and flags, followed by an NFC * (Near-Field Communications) Logical Link Control Protocol (LLCP) PDU, * as specified by NFC Forum Logical Link Control Protocol Technical * Specification LLCP 1.1. * * Requested by Mike Wakerly . */ #define DLT_NFC_LLCP 245 /* * 245 is used as LINKTYPE_PFSYNC; do not use it for any other purpose. * * DLT_PFSYNC has different values on different platforms, and all of * them collide with something used elsewhere. On platforms that * don't already define it, define it as 245. */ #if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__DragonFly__) && !defined(__APPLE__) #define DLT_PFSYNC 246 #endif #define DLT_MATCHING_MAX 246 /* highest value in the "matching" range */ /* * DLT and savefile link type values are split into a class and * a member of that class. A class value of 0 indicates a regular * DLT_/LINKTYPE_ value. */ #define DLT_CLASS(x) ((x) & 0x03ff0000) /* * The instruction encodings. */ /* instruction classes */ #define BPF_CLASS(code) ((code) & 0x07) #define BPF_LD 0x00 #define BPF_LDX 0x01 #define BPF_ST 0x02 #define BPF_STX 0x03 #define BPF_ALU 0x04 #define BPF_JMP 0x05 #define BPF_RET 0x06 #define BPF_MISC 0x07 /* ld/ldx fields */ #define BPF_SIZE(code) ((code) & 0x18) #define BPF_W 0x00 #define BPF_H 0x08 #define BPF_B 0x10 #define BPF_MODE(code) ((code) & 0xe0) #define BPF_IMM 0x00 #define BPF_ABS 0x20 #define BPF_IND 0x40 #define BPF_MEM 0x60 #define BPF_LEN 0x80 #define BPF_MSH 0xa0 /* alu/jmp fields */ #define BPF_OP(code) ((code) & 0xf0) #define BPF_ADD 0x00 #define BPF_SUB 0x10 #define BPF_MUL 0x20 #define BPF_DIV 0x30 #define BPF_OR 0x40 #define BPF_AND 0x50 #define BPF_LSH 0x60 #define BPF_RSH 0x70 #define BPF_NEG 0x80 #define BPF_JA 0x00 #define BPF_JEQ 0x10 #define BPF_JGT 0x20 #define BPF_JGE 0x30 #define BPF_JSET 0x40 #define BPF_SRC(code) ((code) & 0x08) #define BPF_K 0x00 #define BPF_X 0x08 /* ret - BPF_K and BPF_X also apply */ #define BPF_RVAL(code) ((code) & 0x18) #define BPF_A 0x10 /* misc */ #define BPF_MISCOP(code) ((code) & 0xf8) #define BPF_TAX 0x00 #define BPF_TXA 0x80 /* * The instruction data structure. */ struct bpf_insn { u_short code; u_char jt; u_char jf; bpf_u_int32 k; }; /* * Macros for insn array initializers. */ #define BPF_STMT(code, k) { (u_short)(code), 0, 0, k } #define BPF_JUMP(code, k, jt, jf) { (u_short)(code), jt, jf, k } /* * Structure to retrieve available DLTs for the interface. */ struct bpf_dltlist { u_int bfl_len; /* number of bfd_list array */ u_int *bfl_list; /* array of DLTs */ }; #ifdef _KERNEL #ifdef MALLOC_DECLARE MALLOC_DECLARE(M_BPF); #endif #ifdef SYSCTL_DECL SYSCTL_DECL(_net_bpf); #endif /* * Rotate the packet buffers in descriptor d. Move the store buffer into the * hold slot, and the free buffer ino the store slot. Zero the length of the * new store buffer. Descriptor lock should be held. Hold buffer must * not be marked "in use". */ #define ROTATE_BUFFERS(d) do { \ (d)->bd_hbuf = (d)->bd_sbuf; \ (d)->bd_hlen = (d)->bd_slen; \ (d)->bd_sbuf = (d)->bd_fbuf; \ (d)->bd_slen = 0; \ (d)->bd_fbuf = NULL; \ bpf_bufheld(d); \ } while (0) /* * Descriptor associated with each attached hardware interface. * FIXME: this structure is exposed to external callers to speed up * bpf_peers_present() call. However we cover all fields not needed by * this function via BPF_INTERNAL define */ struct bpf_if { LIST_ENTRY(bpf_if) bif_next; /* list of all interfaces */ LIST_HEAD(, bpf_d) bif_dlist; /* descriptor list */ #ifdef BPF_INTERNAL u_int bif_dlt; /* link layer type */ u_int bif_hdrlen; /* length of link header */ struct ifnet *bif_ifp; /* corresponding interface */ struct rwlock bif_lock; /* interface lock */ LIST_HEAD(, bpf_d) bif_wlist; /* writer-only list */ int flags; /* Interface flags */ #endif }; void bpf_bufheld(struct bpf_d *d); int bpf_validate(const struct bpf_insn *, int); void bpf_tap(struct bpf_if *, u_char *, u_int); void bpf_mtap(struct bpf_if *, struct mbuf *); void bpf_mtap2(struct bpf_if *, void *, u_int, struct mbuf *); void bpfattach(struct ifnet *, u_int, u_int); void bpfattach2(struct ifnet *, u_int, u_int, struct bpf_if **); void bpfdetach(struct ifnet *); void bpfilterattach(int); u_int bpf_filter(const struct bpf_insn *, u_char *, u_int, u_int); static __inline int bpf_peers_present(struct bpf_if *bpf) { if (!LIST_EMPTY(&bpf->bif_dlist)) return (1); return (0); } #define BPF_TAP(_ifp,_pkt,_pktlen) do { \ if (bpf_peers_present((_ifp)->if_bpf)) \ bpf_tap((_ifp)->if_bpf, (_pkt), (_pktlen)); \ } while (0) #define BPF_MTAP(_ifp,_m) do { \ if (bpf_peers_present((_ifp)->if_bpf)) { \ M_ASSERTVALID(_m); \ bpf_mtap((_ifp)->if_bpf, (_m)); \ } \ } while (0) #define BPF_MTAP2(_ifp,_data,_dlen,_m) do { \ if (bpf_peers_present((_ifp)->if_bpf)) { \ M_ASSERTVALID(_m); \ bpf_mtap2((_ifp)->if_bpf,(_data),(_dlen),(_m)); \ } \ } while (0) #endif /* * Number of scratch memory words (for BPF_LD|BPF_MEM and BPF_ST). */ #define BPF_MEMWORDS 16 #endif /* _NET_BPF_H_ */ Index: user/syuu/mq_bpf/sys/net/bpfdesc.h =================================================================== --- user/syuu/mq_bpf/sys/net/bpfdesc.h (revision 255171) +++ user/syuu/mq_bpf/sys/net/bpfdesc.h (revision 255172) @@ -1,184 +1,204 @@ /*- * Copyright (c) 1990, 1991, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from the Stanford/CMU enet packet filter, * (net/enet.c) distributed as part of 4.3BSD, and code contributed * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence * Berkeley Laboratory. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)bpfdesc.h 8.1 (Berkeley) 6/10/93 * * $FreeBSD$ */ #ifndef _NET_BPFDESC_H_ #define _NET_BPFDESC_H_ #include #include #include #include -#include +#include +#include #include -typedef cpuset_t bpf_qmask_bits_t; +#define BPFQ_BITS 256 +BITSET_DEFINE(bpf_qmask_bits, BPFQ_BITS); struct bpf_qmask { - boolean_t qm_enabled; - bpf_qmask_bits_t qm_rxqmask; - bpf_qmask_bits_t qm_txqmask; - boolean_t qm_noqmask; + int qm_enabled; + struct bpf_qmask_bits qm_rxqmask; + struct bpf_qmask_bits qm_txqmask; + int qm_noqmask; struct rwlock qm_lock; }; #define BPFQ_LOCK_INIT(qm) rw_init(&(qm)->qm_lock, "qmask lock") #define BPFQ_LOCK_DESTROY(qm) rw_destroy(&(qm)->qm_lock) #define BPFQ_RLOCK(qm) rw_rlock(&(qm)->qm_lock) #define BPFQ_RUNLOCK(qm) rw_runlock(&(qm)->qm_lock) #define BPFQ_WLOCK(qm) rw_wlock(&(qm)->qm_lock) #define BPFQ_WUNLOCK(qm) rw_wunlock(&(qm)->qm_lock) -#define BPFQ_ZERO CPU_ZERO -#define BPFQ_COPY CPU_COPY -#define BPFQ_ISSET CPU_ISSET + +#define BPFQ_CLR(n, p) BIT_CLR(BPFQ_BITS, n, p) +#define BPFQ_COPY(f, t) BIT_COPY(BPFQ_BITS, f, t) +#define BPFQ_ISSET(n, p) BIT_ISSET(BPFQ_BITS, n, p) +#define BPFQ_SET(n, p) BIT_SET(BPFQ_BITS, n, p) +#define BPFQ_ZERO(p) BIT_ZERO(BPFQ_BITS, p) +#define BPFQ_FILL(p) BIT_FILL(BPFQ_BITS, p) +#define BPFQ_SETOF(n, p) BIT_SETOF(BPFQ_BITS, n, p) +#define BPFQ_EMPTY(p) BIT_EMPTY(BPFQ_BITS, p) +#define BPFQ_ISFULLSET(p) BIT_ISFULLSET(BPFQ_BITS, p) +#define BPFQ_SUBSET(p, c) BIT_SUBSET(BPFQ_BITS, p, c) +#define BPFQ_OVERLAP(p, c) BIT_OVERLAP(BPFQ_BITS, p, c) +#define BPFQ_CMP(p, c) BIT_CMP(BPFQ_BITS, p, c) +#define BPFQ_OR(d, s) BIT_OR(BPFQ_BITS, d, s) +#define BPFQ_AND(d, s) BIT_AND(BPFQ_BITS, d, s) +#define BPFQ_NAND(d, s) BIT_NAND(BPFQ_BITS, d, s) +#define BPFQ_CLR_ATOMIC(n, p) BIT_CLR_ATOMIC(BPFQ_BITS, n, p) +#define BPFQ_SET_ATOMIC(n, p) BIT_SET_ATOMIC(BPFQ_BITS, n, p) +#define BPFQ_OR_ATOMIC(d, s) BIT_OR_ATOMIC(BPFQ_BITS, d, s) +#define BPFQ_COPY_STORE_REL(f, t) BIT_COPY_STORE_REL(BPFQ_BITS, f, t) +#define BPFQ_FFS(p) BIT_FFS(BPFQ_BITS, p) /* * Descriptor associated with each open bpf file. */ struct zbuf; struct bpf_d { LIST_ENTRY(bpf_d) bd_next; /* Linked list of descriptors */ /* * Buffer slots: two memory buffers store the incoming packets. * The model has three slots. Sbuf is always occupied. * sbuf (store) - Receive interrupt puts packets here. * hbuf (hold) - When sbuf is full, put buffer here and * wakeup read (replace sbuf with fbuf). * fbuf (free) - When read is done, put buffer here. * On receiving, if sbuf is full and fbuf is 0, packet is dropped. */ caddr_t bd_sbuf; /* store slot */ caddr_t bd_hbuf; /* hold slot */ caddr_t bd_fbuf; /* free slot */ int bd_hbuf_in_use; /* don't rotate buffers */ int bd_slen; /* current length of store buffer */ int bd_hlen; /* current length of hold buffer */ int bd_bufsize; /* absolute length of buffers */ struct bpf_if * bd_bif; /* interface descriptor */ u_long bd_rtout; /* Read timeout in 'ticks' */ struct bpf_insn *bd_rfilter; /* read filter code */ struct bpf_insn *bd_wfilter; /* write filter code */ void *bd_bfilter; /* binary filter code */ u_int64_t bd_rcount; /* number of packets received */ u_int64_t bd_dcount; /* number of packets dropped */ u_char bd_promisc; /* true if listening promiscuously */ u_char bd_state; /* idle, waiting, or timed out */ u_char bd_immediate; /* true to return on packet arrival */ u_char bd_writer; /* non-zero if d is writer-only */ int bd_hdrcmplt; /* false to fill in src lladdr automatically */ int bd_direction; /* select packet direction */ int bd_tstamp; /* select time stamping function */ int bd_feedback; /* true to feed back sent packets */ int bd_async; /* non-zero if packet reception should generate signal */ int bd_sig; /* signal to send upon packet reception */ struct sigio * bd_sigio; /* information for async I/O */ struct selinfo bd_sel; /* bsd select info */ struct mtx bd_lock; /* per-descriptor lock */ struct callout bd_callout; /* for BPF timeouts with select */ struct label *bd_label; /* MAC label for descriptor */ u_int64_t bd_fcount; /* number of packets which matched filter */ pid_t bd_pid; /* PID which created descriptor */ int bd_locked; /* true if descriptor is locked */ u_int bd_bufmode; /* Current buffer mode. */ u_int64_t bd_wcount; /* number of packets written */ u_int64_t bd_wfcount; /* number of packets that matched write filter */ u_int64_t bd_wdcount; /* number of packets dropped during a write */ u_int64_t bd_zcopy; /* number of zero copy operations */ u_char bd_compat32; /* 32-bit stream on LP64 system */ struct bpf_qmask bd_qmask; }; /* Values for bd_state */ #define BPF_IDLE 0 /* no select in progress */ #define BPF_WAITING 1 /* waiting for read timeout in select */ #define BPF_TIMED_OUT 2 /* read timeout has expired in select */ #define BPFD_LOCK(bd) mtx_lock(&(bd)->bd_lock) #define BPFD_UNLOCK(bd) mtx_unlock(&(bd)->bd_lock) #define BPFD_LOCK_ASSERT(bd) mtx_assert(&(bd)->bd_lock, MA_OWNED) #define BPF_PID_REFRESH(bd, td) (bd)->bd_pid = (td)->td_proc->p_pid #define BPF_PID_REFRESH_CUR(bd) (bd)->bd_pid = curthread->td_proc->p_pid #define BPF_LOCK() mtx_lock(&bpf_mtx) #define BPF_UNLOCK() mtx_unlock(&bpf_mtx) #define BPF_LOCK_ASSERT() mtx_assert(&bpf_mtx, MA_OWNED) /* * External representation of the bpf descriptor */ struct xbpf_d { u_int bd_structsize; /* Size of this structure. */ u_char bd_promisc; u_char bd_immediate; u_char __bd_pad[6]; int bd_hdrcmplt; int bd_direction; int bd_feedback; int bd_async; u_int64_t bd_rcount; u_int64_t bd_dcount; u_int64_t bd_fcount; int bd_sig; int bd_slen; int bd_hlen; int bd_bufsize; pid_t bd_pid; char bd_ifname[IFNAMSIZ]; int bd_locked; u_int64_t bd_wcount; u_int64_t bd_wfcount; u_int64_t bd_wdcount; u_int64_t bd_zcopy; int bd_bufmode; /* * Allocate 4 64 bit unsigned integers for future expansion so we do * not have to worry about breaking the ABI. */ u_int64_t bd_spare[4]; }; #define BPFIF_RLOCK(bif) rw_rlock(&(bif)->bif_lock) #define BPFIF_RUNLOCK(bif) rw_runlock(&(bif)->bif_lock) #define BPFIF_WLOCK(bif) rw_wlock(&(bif)->bif_lock) #define BPFIF_WUNLOCK(bif) rw_wunlock(&(bif)->bif_lock) #define BPFIF_FLAG_DYING 1 /* Reject new bpf consumers */ #endif