1335640Shselasky/* 2335640Shselasky * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996 3335640Shselasky * The Regents of the University of California. All rights reserved. 4335640Shselasky * 5335640Shselasky * Redistribution and use in source and binary forms, with or without 6335640Shselasky * modification, are permitted provided that: (1) source code distributions 7335640Shselasky * retain the above copyright notice and this paragraph in its entirety, (2) 8335640Shselasky * distributions including binary code include the above copyright notice and 9335640Shselasky * this paragraph in its entirety in the documentation or other materials 10335640Shselasky * provided with the distribution, and (3) all advertising materials mentioning 11335640Shselasky * features or use of this software display the following acknowledgement: 12335640Shselasky * ``This product includes software developed by the University of California, 13335640Shselasky * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 14335640Shselasky * the University nor the names of its contributors may be used to endorse 15335640Shselasky * or promote products derived from this software without specific prior 16335640Shselasky * written permission. 17335640Shselasky * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 18335640Shselasky * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 19335640Shselasky * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 20335640Shselasky * 21335640Shselasky * packet filter subroutines for tcpdump 22335640Shselasky * Extraction/creation by Jeffrey Mogul, DECWRL 23335640Shselasky */ 24335640Shselasky 25335640Shselasky#ifdef HAVE_CONFIG_H 26335640Shselasky#include <config.h> 27335640Shselasky#endif 28335640Shselasky 29335640Shselasky#include <sys/types.h> 30335640Shselasky#include <sys/time.h> 31335640Shselasky#include <sys/timeb.h> 32335640Shselasky#include <sys/socket.h> 33335640Shselasky#include <sys/file.h> 34335640Shselasky#include <sys/ioctl.h> 35335640Shselasky#include <net/pfilt.h> 36335640Shselasky 37335640Shselaskystruct mbuf; 38335640Shselaskystruct rtentry; 39335640Shselasky#include <net/if.h> 40335640Shselasky 41335640Shselasky#include <netinet/in.h> 42335640Shselasky#include <netinet/in_systm.h> 43335640Shselasky#include <netinet/ip.h> 44335640Shselasky#include <netinet/if_ether.h> 45335640Shselasky#include <netinet/ip_var.h> 46335640Shselasky#include <netinet/udp.h> 47335640Shselasky#include <netinet/udp_var.h> 48335640Shselasky#include <netinet/tcp.h> 49335640Shselasky#include <netinet/tcpip.h> 50335640Shselasky 51335640Shselasky#include <ctype.h> 52335640Shselasky#include <errno.h> 53335640Shselasky#include <netdb.h> 54335640Shselasky#include <stdio.h> 55335640Shselasky#include <stdlib.h> 56335640Shselasky#include <string.h> 57335640Shselasky#include <unistd.h> 58335640Shselasky 59335640Shselasky/* 60335640Shselasky * Make "pcap.h" not include "pcap/bpf.h"; we are going to include the 61335640Shselasky * native OS version, as we need various BPF ioctls from it. 62335640Shselasky */ 63335640Shselasky#define PCAP_DONT_INCLUDE_PCAP_BPF_H 64335640Shselasky#include <net/bpf.h> 65335640Shselasky 66335640Shselasky#include "pcap-int.h" 67335640Shselasky 68335640Shselasky#ifdef HAVE_OS_PROTO_H 69335640Shselasky#include "os-proto.h" 70335640Shselasky#endif 71335640Shselasky 72335640Shselasky/* 73335640Shselasky * FDDI packets are padded to make everything line up on a nice boundary. 74335640Shselasky */ 75335640Shselasky#define PCAP_FDDIPAD 3 76335640Shselasky 77335640Shselasky/* 78335640Shselasky * Private data for capturing on Ultrix and DEC OSF/1^WDigital UNIX^W^W 79335640Shselasky * Tru64 UNIX packetfilter devices. 80335640Shselasky */ 81335640Shselaskystruct pcap_pf { 82335640Shselasky int filtering_in_kernel; /* using kernel filter */ 83335640Shselasky u_long TotPkts; /* can't oflow for 79 hrs on ether */ 84335640Shselasky u_long TotAccepted; /* count accepted by filter */ 85335640Shselasky u_long TotDrops; /* count of dropped packets */ 86335640Shselasky long TotMissed; /* missed by i/f during this run */ 87335640Shselasky long OrigMissed; /* missed by i/f before this run */ 88335640Shselasky}; 89335640Shselasky 90335640Shselaskystatic int pcap_setfilter_pf(pcap_t *, struct bpf_program *); 91335640Shselasky 92335640Shselasky/* 93335640Shselasky * BUFSPACE is the size in bytes of the packet read buffer. Most tcpdump 94335640Shselasky * applications aren't going to need more than 200 bytes of packet header 95335640Shselasky * and the read shouldn't return more packets than packetfilter's internal 96335640Shselasky * queue limit (bounded at 256). 97335640Shselasky */ 98335640Shselasky#define BUFSPACE (200 * 256) 99335640Shselasky 100335640Shselaskystatic int 101335640Shselaskypcap_read_pf(pcap_t *pc, int cnt, pcap_handler callback, u_char *user) 102335640Shselasky{ 103335640Shselasky struct pcap_pf *pf = pc->priv; 104335640Shselasky register u_char *p, *bp; 105335640Shselasky register int cc, n, buflen, inc; 106335640Shselasky register struct enstamp *sp; 107335640Shselasky#ifdef LBL_ALIGN 108335640Shselasky struct enstamp stamp; 109335640Shselasky#endif 110335640Shselasky register u_int pad; 111335640Shselasky 112335640Shselasky again: 113335640Shselasky cc = pc->cc; 114335640Shselasky if (cc == 0) { 115335640Shselasky cc = read(pc->fd, (char *)pc->buffer + pc->offset, pc->bufsize); 116335640Shselasky if (cc < 0) { 117335640Shselasky if (errno == EWOULDBLOCK) 118335640Shselasky return (0); 119335640Shselasky if (errno == EINVAL && 120335640Shselasky lseek(pc->fd, 0L, SEEK_CUR) + pc->bufsize < 0) { 121335640Shselasky /* 122335640Shselasky * Due to a kernel bug, after 2^31 bytes, 123335640Shselasky * the kernel file offset overflows and 124335640Shselasky * read fails with EINVAL. The lseek() 125335640Shselasky * to 0 will fix things. 126335640Shselasky */ 127335640Shselasky (void)lseek(pc->fd, 0L, SEEK_SET); 128335640Shselasky goto again; 129335640Shselasky } 130335640Shselasky pcap_fmt_errmsg_for_errno(pc->errbuf, 131335640Shselasky sizeof(pc->errbuf), errno, "pf read"); 132335640Shselasky return (-1); 133335640Shselasky } 134335640Shselasky bp = (u_char *)pc->buffer + pc->offset; 135335640Shselasky } else 136335640Shselasky bp = pc->bp; 137335640Shselasky /* 138335640Shselasky * Loop through each packet. 139335640Shselasky */ 140335640Shselasky n = 0; 141335640Shselasky pad = pc->fddipad; 142335640Shselasky while (cc > 0) { 143335640Shselasky /* 144335640Shselasky * Has "pcap_breakloop()" been called? 145335640Shselasky * If so, return immediately - if we haven't read any 146335640Shselasky * packets, clear the flag and return -2 to indicate 147335640Shselasky * that we were told to break out of the loop, otherwise 148335640Shselasky * leave the flag set, so that the *next* call will break 149335640Shselasky * out of the loop without having read any packets, and 150335640Shselasky * return the number of packets we've processed so far. 151335640Shselasky */ 152335640Shselasky if (pc->break_loop) { 153335640Shselasky if (n == 0) { 154335640Shselasky pc->break_loop = 0; 155335640Shselasky return (-2); 156335640Shselasky } else { 157335640Shselasky pc->cc = cc; 158335640Shselasky pc->bp = bp; 159335640Shselasky return (n); 160335640Shselasky } 161335640Shselasky } 162335640Shselasky if (cc < sizeof(*sp)) { 163335640Shselasky pcap_snprintf(pc->errbuf, sizeof(pc->errbuf), 164335640Shselasky "pf short read (%d)", cc); 165335640Shselasky return (-1); 166335640Shselasky } 167335640Shselasky#ifdef LBL_ALIGN 168335640Shselasky if ((long)bp & 3) { 169335640Shselasky sp = &stamp; 170335640Shselasky memcpy((char *)sp, (char *)bp, sizeof(*sp)); 171335640Shselasky } else 172335640Shselasky#endif 173335640Shselasky sp = (struct enstamp *)bp; 174335640Shselasky if (sp->ens_stamplen != sizeof(*sp)) { 175335640Shselasky pcap_snprintf(pc->errbuf, sizeof(pc->errbuf), 176335640Shselasky "pf short stamplen (%d)", 177335640Shselasky sp->ens_stamplen); 178335640Shselasky return (-1); 179335640Shselasky } 180335640Shselasky 181335640Shselasky p = bp + sp->ens_stamplen; 182335640Shselasky buflen = sp->ens_count; 183335640Shselasky if (buflen > pc->snapshot) 184335640Shselasky buflen = pc->snapshot; 185335640Shselasky 186335640Shselasky /* Calculate inc before possible pad update */ 187335640Shselasky inc = ENALIGN(buflen + sp->ens_stamplen); 188335640Shselasky cc -= inc; 189335640Shselasky bp += inc; 190335640Shselasky pf->TotPkts++; 191335640Shselasky pf->TotDrops += sp->ens_dropped; 192335640Shselasky pf->TotMissed = sp->ens_ifoverflows; 193335640Shselasky if (pf->OrigMissed < 0) 194335640Shselasky pf->OrigMissed = pf->TotMissed; 195335640Shselasky 196335640Shselasky /* 197335640Shselasky * Short-circuit evaluation: if using BPF filter 198335640Shselasky * in kernel, no need to do it now - we already know 199335640Shselasky * the packet passed the filter. 200335640Shselasky * 201335640Shselasky * Note: the filter code was generated assuming 202335640Shselasky * that pc->fddipad was the amount of padding 203335640Shselasky * before the header, as that's what's required 204335640Shselasky * in the kernel, so we run the filter before 205335640Shselasky * skipping that padding. 206335640Shselasky */ 207335640Shselasky if (pf->filtering_in_kernel || 208335640Shselasky bpf_filter(pc->fcode.bf_insns, p, sp->ens_count, buflen)) { 209335640Shselasky struct pcap_pkthdr h; 210335640Shselasky pf->TotAccepted++; 211335640Shselasky h.ts = sp->ens_tstamp; 212335640Shselasky h.len = sp->ens_count - pad; 213335640Shselasky p += pad; 214335640Shselasky buflen -= pad; 215335640Shselasky h.caplen = buflen; 216335640Shselasky (*callback)(user, &h, p); 217335640Shselasky if (++n >= cnt && !PACKET_COUNT_IS_UNLIMITED(cnt)) { 218335640Shselasky pc->cc = cc; 219335640Shselasky pc->bp = bp; 220335640Shselasky return (n); 221335640Shselasky } 222335640Shselasky } 223335640Shselasky } 224335640Shselasky pc->cc = 0; 225335640Shselasky return (n); 226335640Shselasky} 227335640Shselasky 228335640Shselaskystatic int 229335640Shselaskypcap_inject_pf(pcap_t *p, const void *buf, size_t size) 230335640Shselasky{ 231335640Shselasky int ret; 232335640Shselasky 233335640Shselasky ret = write(p->fd, buf, size); 234335640Shselasky if (ret == -1) { 235335640Shselasky pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 236335640Shselasky errno, "send"); 237335640Shselasky return (-1); 238335640Shselasky } 239335640Shselasky return (ret); 240335640Shselasky} 241335640Shselasky 242335640Shselaskystatic int 243335640Shselaskypcap_stats_pf(pcap_t *p, struct pcap_stat *ps) 244335640Shselasky{ 245335640Shselasky struct pcap_pf *pf = p->priv; 246335640Shselasky 247335640Shselasky /* 248335640Shselasky * If packet filtering is being done in the kernel: 249335640Shselasky * 250335640Shselasky * "ps_recv" counts only packets that passed the filter. 251335640Shselasky * This does not include packets dropped because we 252335640Shselasky * ran out of buffer space. (XXX - perhaps it should, 253335640Shselasky * by adding "ps_drop" to "ps_recv", for compatibility 254335640Shselasky * with some other platforms. On the other hand, on 255335640Shselasky * some platforms "ps_recv" counts only packets that 256335640Shselasky * passed the filter, and on others it counts packets 257335640Shselasky * that didn't pass the filter....) 258335640Shselasky * 259335640Shselasky * "ps_drop" counts packets that passed the kernel filter 260335640Shselasky * (if any) but were dropped because the input queue was 261335640Shselasky * full. 262335640Shselasky * 263335640Shselasky * "ps_ifdrop" counts packets dropped by the network 264335640Shselasky * inteface (regardless of whether they would have passed 265335640Shselasky * the input filter, of course). 266335640Shselasky * 267335640Shselasky * If packet filtering is not being done in the kernel: 268335640Shselasky * 269335640Shselasky * "ps_recv" counts only packets that passed the filter. 270335640Shselasky * 271335640Shselasky * "ps_drop" counts packets that were dropped because the 272335640Shselasky * input queue was full, regardless of whether they passed 273335640Shselasky * the userland filter. 274335640Shselasky * 275335640Shselasky * "ps_ifdrop" counts packets dropped by the network 276335640Shselasky * inteface (regardless of whether they would have passed 277335640Shselasky * the input filter, of course). 278335640Shselasky * 279335640Shselasky * These statistics don't include packets not yet read from 280335640Shselasky * the kernel by libpcap, but they may include packets not 281335640Shselasky * yet read from libpcap by the application. 282335640Shselasky */ 283335640Shselasky ps->ps_recv = pf->TotAccepted; 284335640Shselasky ps->ps_drop = pf->TotDrops; 285335640Shselasky ps->ps_ifdrop = pf->TotMissed - pf->OrigMissed; 286335640Shselasky return (0); 287335640Shselasky} 288335640Shselasky 289335640Shselasky/* 290335640Shselasky * We include the OS's <net/bpf.h>, not our "pcap/bpf.h", so we probably 291335640Shselasky * don't get DLT_DOCSIS defined. 292335640Shselasky */ 293335640Shselasky#ifndef DLT_DOCSIS 294335640Shselasky#define DLT_DOCSIS 143 295335640Shselasky#endif 296335640Shselasky 297335640Shselaskystatic int 298335640Shselaskypcap_activate_pf(pcap_t *p) 299335640Shselasky{ 300335640Shselasky struct pcap_pf *pf = p->priv; 301335640Shselasky short enmode; 302335640Shselasky int backlog = -1; /* request the most */ 303335640Shselasky struct enfilter Filter; 304335640Shselasky struct endevp devparams; 305335640Shselasky int err; 306335640Shselasky 307335640Shselasky /* 308335640Shselasky * Initially try a read/write open (to allow the inject 309335640Shselasky * method to work). If that fails due to permission 310335640Shselasky * issues, fall back to read-only. This allows a 311335640Shselasky * non-root user to be granted specific access to pcap 312335640Shselasky * capabilities via file permissions. 313335640Shselasky * 314335640Shselasky * XXX - we should have an API that has a flag that 315335640Shselasky * controls whether to open read-only or read-write, 316335640Shselasky * so that denial of permission to send (or inability 317335640Shselasky * to send, if sending packets isn't supported on 318335640Shselasky * the device in question) can be indicated at open 319335640Shselasky * time. 320335640Shselasky * 321335640Shselasky * XXX - we assume here that "pfopen()" does not, in fact, modify 322335640Shselasky * its argument, even though it takes a "char *" rather than a 323335640Shselasky * "const char *" as its first argument. That appears to be 324335640Shselasky * the case, at least on Digital UNIX 4.0. 325335640Shselasky * 326335640Shselasky * XXX - is there an error that means "no such device"? Is 327335640Shselasky * there one that means "that device doesn't support pf"? 328335640Shselasky */ 329335640Shselasky p->fd = pfopen(p->opt.device, O_RDWR); 330335640Shselasky if (p->fd == -1 && errno == EACCES) 331335640Shselasky p->fd = pfopen(p->opt.device, O_RDONLY); 332335640Shselasky if (p->fd < 0) { 333335640Shselasky if (errno == EACCES) { 334335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 335335640Shselasky "pf open: %s: Permission denied\n" 336335640Shselasky"your system may not be properly configured; see the packetfilter(4) man page", 337335640Shselasky p->opt.device); 338335640Shselasky err = PCAP_ERROR_PERM_DENIED; 339335640Shselasky } else { 340335640Shselasky pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 341335640Shselasky errno, "pf open: %s", p->opt.device); 342335640Shselasky err = PCAP_ERROR; 343335640Shselasky } 344335640Shselasky goto bad; 345335640Shselasky } 346335640Shselasky 347335640Shselasky /* 348335640Shselasky * Turn a negative snapshot value (invalid), a snapshot value of 349335640Shselasky * 0 (unspecified), or a value bigger than the normal maximum 350335640Shselasky * value, into the maximum allowed value. 351335640Shselasky * 352335640Shselasky * If some application really *needs* a bigger snapshot 353335640Shselasky * length, we should just increase MAXIMUM_SNAPLEN. 354335640Shselasky */ 355335640Shselasky if (p->snapshot <= 0 || p->snapshot > MAXIMUM_SNAPLEN) 356335640Shselasky p->snapshot = MAXIMUM_SNAPLEN; 357335640Shselasky 358335640Shselasky pf->OrigMissed = -1; 359335640Shselasky enmode = ENTSTAMP|ENNONEXCL; 360335640Shselasky if (!p->opt.immediate) 361335640Shselasky enmode |= ENBATCH; 362335640Shselasky if (p->opt.promisc) 363335640Shselasky enmode |= ENPROMISC; 364335640Shselasky if (ioctl(p->fd, EIOCMBIS, (caddr_t)&enmode) < 0) { 365335640Shselasky pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 366335640Shselasky errno, "EIOCMBIS"); 367335640Shselasky err = PCAP_ERROR; 368335640Shselasky goto bad; 369335640Shselasky } 370335640Shselasky#ifdef ENCOPYALL 371335640Shselasky /* Try to set COPYALL mode so that we see packets to ourself */ 372335640Shselasky enmode = ENCOPYALL; 373335640Shselasky (void)ioctl(p->fd, EIOCMBIS, (caddr_t)&enmode);/* OK if this fails */ 374335640Shselasky#endif 375335640Shselasky /* set the backlog */ 376335640Shselasky if (ioctl(p->fd, EIOCSETW, (caddr_t)&backlog) < 0) { 377335640Shselasky pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 378335640Shselasky errno, "EIOCSETW"); 379335640Shselasky err = PCAP_ERROR; 380335640Shselasky goto bad; 381335640Shselasky } 382335640Shselasky /* discover interface type */ 383335640Shselasky if (ioctl(p->fd, EIOCDEVP, (caddr_t)&devparams) < 0) { 384335640Shselasky pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 385335640Shselasky errno, "EIOCDEVP"); 386335640Shselasky err = PCAP_ERROR; 387335640Shselasky goto bad; 388335640Shselasky } 389335640Shselasky /* HACK: to compile prior to Ultrix 4.2 */ 390335640Shselasky#ifndef ENDT_FDDI 391335640Shselasky#define ENDT_FDDI 4 392335640Shselasky#endif 393335640Shselasky switch (devparams.end_dev_type) { 394335640Shselasky 395335640Shselasky case ENDT_10MB: 396335640Shselasky p->linktype = DLT_EN10MB; 397335640Shselasky p->offset = 2; 398335640Shselasky /* 399335640Shselasky * This is (presumably) a real Ethernet capture; give it a 400335640Shselasky * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so 401335640Shselasky * that an application can let you choose it, in case you're 402335640Shselasky * capturing DOCSIS traffic that a Cisco Cable Modem 403335640Shselasky * Termination System is putting out onto an Ethernet (it 404335640Shselasky * doesn't put an Ethernet header onto the wire, it puts raw 405335640Shselasky * DOCSIS frames out on the wire inside the low-level 406335640Shselasky * Ethernet framing). 407335640Shselasky */ 408335640Shselasky p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); 409335640Shselasky /* 410335640Shselasky * If that fails, just leave the list empty. 411335640Shselasky */ 412335640Shselasky if (p->dlt_list != NULL) { 413335640Shselasky p->dlt_list[0] = DLT_EN10MB; 414335640Shselasky p->dlt_list[1] = DLT_DOCSIS; 415335640Shselasky p->dlt_count = 2; 416335640Shselasky } 417335640Shselasky break; 418335640Shselasky 419335640Shselasky case ENDT_FDDI: 420335640Shselasky p->linktype = DLT_FDDI; 421335640Shselasky break; 422335640Shselasky 423335640Shselasky#ifdef ENDT_SLIP 424335640Shselasky case ENDT_SLIP: 425335640Shselasky p->linktype = DLT_SLIP; 426335640Shselasky break; 427335640Shselasky#endif 428335640Shselasky 429335640Shselasky#ifdef ENDT_PPP 430335640Shselasky case ENDT_PPP: 431335640Shselasky p->linktype = DLT_PPP; 432335640Shselasky break; 433335640Shselasky#endif 434335640Shselasky 435335640Shselasky#ifdef ENDT_LOOPBACK 436335640Shselasky case ENDT_LOOPBACK: 437335640Shselasky /* 438335640Shselasky * It appears to use Ethernet framing, at least on 439335640Shselasky * Digital UNIX 4.0. 440335640Shselasky */ 441335640Shselasky p->linktype = DLT_EN10MB; 442335640Shselasky p->offset = 2; 443335640Shselasky break; 444335640Shselasky#endif 445335640Shselasky 446335640Shselasky#ifdef ENDT_TRN 447335640Shselasky case ENDT_TRN: 448335640Shselasky p->linktype = DLT_IEEE802; 449335640Shselasky break; 450335640Shselasky#endif 451335640Shselasky 452335640Shselasky default: 453335640Shselasky /* 454335640Shselasky * XXX - what about ENDT_IEEE802? The pfilt.h header 455335640Shselasky * file calls this "IEEE 802 networks (non-Ethernet)", 456335640Shselasky * but that doesn't specify a specific link layer type; 457335640Shselasky * it could be 802.4, or 802.5 (except that 802.5 is 458335640Shselasky * ENDT_TRN), or 802.6, or 802.11, or.... That's why 459335640Shselasky * DLT_IEEE802 was hijacked to mean Token Ring in various 460335640Shselasky * BSDs, and why we went along with that hijacking. 461335640Shselasky * 462335640Shselasky * XXX - what about ENDT_HDLC and ENDT_NULL? 463335640Shselasky * Presumably, as ENDT_OTHER is just "Miscellaneous 464335640Shselasky * framing", there's not much we can do, as that 465335640Shselasky * doesn't specify a particular type of header. 466335640Shselasky */ 467335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 468335640Shselasky "unknown data-link type %u", devparams.end_dev_type); 469335640Shselasky err = PCAP_ERROR; 470335640Shselasky goto bad; 471335640Shselasky } 472335640Shselasky /* set truncation */ 473335640Shselasky if (p->linktype == DLT_FDDI) { 474335640Shselasky p->fddipad = PCAP_FDDIPAD; 475335640Shselasky 476335640Shselasky /* packetfilter includes the padding in the snapshot */ 477335640Shselasky p->snapshot += PCAP_FDDIPAD; 478335640Shselasky } else 479335640Shselasky p->fddipad = 0; 480335640Shselasky if (ioctl(p->fd, EIOCTRUNCATE, (caddr_t)&p->snapshot) < 0) { 481335640Shselasky pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 482335640Shselasky errno, "EIOCTRUNCATE"); 483335640Shselasky err = PCAP_ERROR; 484335640Shselasky goto bad; 485335640Shselasky } 486335640Shselasky /* accept all packets */ 487335640Shselasky memset(&Filter, 0, sizeof(Filter)); 488335640Shselasky Filter.enf_Priority = 37; /* anything > 2 */ 489335640Shselasky Filter.enf_FilterLen = 0; /* means "always true" */ 490335640Shselasky if (ioctl(p->fd, EIOCSETF, (caddr_t)&Filter) < 0) { 491335640Shselasky pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 492335640Shselasky errno, "EIOCSETF"); 493335640Shselasky err = PCAP_ERROR; 494335640Shselasky goto bad; 495335640Shselasky } 496335640Shselasky 497335640Shselasky if (p->opt.timeout != 0) { 498335640Shselasky struct timeval timeout; 499335640Shselasky timeout.tv_sec = p->opt.timeout / 1000; 500335640Shselasky timeout.tv_usec = (p->opt.timeout * 1000) % 1000000; 501335640Shselasky if (ioctl(p->fd, EIOCSRTIMEOUT, (caddr_t)&timeout) < 0) { 502335640Shselasky pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 503335640Shselasky errno, "EIOCSRTIMEOUT"); 504335640Shselasky err = PCAP_ERROR; 505335640Shselasky goto bad; 506335640Shselasky } 507335640Shselasky } 508335640Shselasky 509335640Shselasky p->bufsize = BUFSPACE; 510335640Shselasky p->buffer = malloc(p->bufsize + p->offset); 511335640Shselasky if (p->buffer == NULL) { 512335640Shselasky pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 513335640Shselasky errno, "malloc"); 514335640Shselasky err = PCAP_ERROR; 515335640Shselasky goto bad; 516335640Shselasky } 517335640Shselasky 518335640Shselasky /* 519335640Shselasky * "select()" and "poll()" work on packetfilter devices. 520335640Shselasky */ 521335640Shselasky p->selectable_fd = p->fd; 522335640Shselasky 523335640Shselasky p->read_op = pcap_read_pf; 524335640Shselasky p->inject_op = pcap_inject_pf; 525335640Shselasky p->setfilter_op = pcap_setfilter_pf; 526335640Shselasky p->setdirection_op = NULL; /* Not implemented. */ 527335640Shselasky p->set_datalink_op = NULL; /* can't change data link type */ 528335640Shselasky p->getnonblock_op = pcap_getnonblock_fd; 529335640Shselasky p->setnonblock_op = pcap_setnonblock_fd; 530335640Shselasky p->stats_op = pcap_stats_pf; 531335640Shselasky 532335640Shselasky return (0); 533335640Shselasky bad: 534335640Shselasky pcap_cleanup_live_common(p); 535335640Shselasky return (err); 536335640Shselasky} 537335640Shselasky 538335640Shselaskypcap_t * 539335640Shselaskypcap_create_interface(const char *device _U_, char *ebuf) 540335640Shselasky{ 541335640Shselasky pcap_t *p; 542335640Shselasky 543335640Shselasky p = pcap_create_common(ebuf, sizeof (struct pcap_pf)); 544335640Shselasky if (p == NULL) 545335640Shselasky return (NULL); 546335640Shselasky 547335640Shselasky p->activate_op = pcap_activate_pf; 548335640Shselasky return (p); 549335640Shselasky} 550335640Shselasky 551335640Shselasky/* 552335640Shselasky * XXX - is there an error from pfopen() that means "no such device"? 553335640Shselasky * Is there one that means "that device doesn't support pf"? 554335640Shselasky */ 555335640Shselaskystatic int 556335640Shselaskycan_be_bound(const char *name _U_) 557335640Shselasky{ 558335640Shselasky return (1); 559335640Shselasky} 560335640Shselasky 561335640Shselaskystatic int 562335640Shselaskyget_if_flags(const char *name _U_, bpf_u_int32 *flags _U_, char *errbuf _U_) 563335640Shselasky{ 564335640Shselasky /* 565335640Shselasky * Nothing we can do other than mark loopback devices as "the 566335640Shselasky * connected/disconnected status doesn't apply". 567335640Shselasky * 568335640Shselasky * XXX - is there a way to find out whether an adapter has 569335640Shselasky * something plugged into it? 570335640Shselasky */ 571335640Shselasky if (*flags & PCAP_IF_LOOPBACK) { 572335640Shselasky /* 573335640Shselasky * Loopback devices aren't wireless, and "connected"/ 574335640Shselasky * "disconnected" doesn't apply to them. 575335640Shselasky */ 576335640Shselasky *flags |= PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE; 577335640Shselasky return (0); 578335640Shselasky } 579335640Shselasky return (0); 580335640Shselasky} 581335640Shselasky 582335640Shselaskyint 583335640Shselaskypcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf) 584335640Shselasky{ 585335640Shselasky return (pcap_findalldevs_interfaces(devlistp, errbuf, can_be_bound, 586335640Shselasky get_if_flags)); 587335640Shselasky} 588335640Shselasky 589335640Shselaskystatic int 590335640Shselaskypcap_setfilter_pf(pcap_t *p, struct bpf_program *fp) 591335640Shselasky{ 592335640Shselasky struct pcap_pf *pf = p->priv; 593335640Shselasky struct bpf_version bv; 594335640Shselasky 595335640Shselasky /* 596335640Shselasky * See if BIOCVERSION works. If not, we assume the kernel doesn't 597335640Shselasky * support BPF-style filters (it's not documented in the bpf(7) 598335640Shselasky * or packetfiler(7) man pages, but the code used to fail if 599335640Shselasky * BIOCSETF worked but BIOCVERSION didn't, and I've seen it do 600335640Shselasky * kernel filtering in DU 4.0, so presumably BIOCVERSION works 601335640Shselasky * there, at least). 602335640Shselasky */ 603335640Shselasky if (ioctl(p->fd, BIOCVERSION, (caddr_t)&bv) >= 0) { 604335640Shselasky /* 605335640Shselasky * OK, we have the version of the BPF interpreter; 606335640Shselasky * is it the same major version as us, and the same 607335640Shselasky * or better minor version? 608335640Shselasky */ 609335640Shselasky if (bv.bv_major == BPF_MAJOR_VERSION && 610335640Shselasky bv.bv_minor >= BPF_MINOR_VERSION) { 611335640Shselasky /* 612335640Shselasky * Yes. Try to install the filter. 613335640Shselasky */ 614335640Shselasky if (ioctl(p->fd, BIOCSETF, (caddr_t)fp) < 0) { 615335640Shselasky pcap_fmt_errmsg_for_errno(p->errbuf, 616335640Shselasky sizeof(p->errbuf), errno, "BIOCSETF"); 617335640Shselasky return (-1); 618335640Shselasky } 619335640Shselasky 620335640Shselasky /* 621335640Shselasky * OK, that succeeded. We're doing filtering in 622335640Shselasky * the kernel. (We assume we don't have a 623335640Shselasky * userland filter installed - that'd require 624335640Shselasky * a previous version check to have failed but 625335640Shselasky * this one to succeed.) 626335640Shselasky * 627335640Shselasky * XXX - this message should be supplied to the 628335640Shselasky * application as a warning of some sort, 629335640Shselasky * except that if it's a GUI application, it's 630335640Shselasky * not clear that it should be displayed in 631335640Shselasky * a window to annoy the user. 632335640Shselasky */ 633335640Shselasky fprintf(stderr, "tcpdump: Using kernel BPF filter\n"); 634335640Shselasky pf->filtering_in_kernel = 1; 635335640Shselasky 636335640Shselasky /* 637335640Shselasky * Discard any previously-received packets, 638335640Shselasky * as they might have passed whatever filter 639335640Shselasky * was formerly in effect, but might not pass 640335640Shselasky * this filter (BIOCSETF discards packets buffered 641335640Shselasky * in the kernel, so you can lose packets in any 642335640Shselasky * case). 643335640Shselasky */ 644335640Shselasky p->cc = 0; 645335640Shselasky return (0); 646335640Shselasky } 647335640Shselasky 648335640Shselasky /* 649335640Shselasky * We can't use the kernel's BPF interpreter; don't give 650335640Shselasky * up, just log a message and be inefficient. 651335640Shselasky * 652335640Shselasky * XXX - this should really be supplied to the application 653335640Shselasky * as a warning of some sort. 654335640Shselasky */ 655335640Shselasky fprintf(stderr, 656335640Shselasky "tcpdump: Requires BPF language %d.%d or higher; kernel is %d.%d\n", 657335640Shselasky BPF_MAJOR_VERSION, BPF_MINOR_VERSION, 658335640Shselasky bv.bv_major, bv.bv_minor); 659335640Shselasky } 660335640Shselasky 661335640Shselasky /* 662335640Shselasky * We couldn't do filtering in the kernel; do it in userland. 663335640Shselasky */ 664335640Shselasky if (install_bpf_program(p, fp) < 0) 665335640Shselasky return (-1); 666335640Shselasky 667335640Shselasky /* 668335640Shselasky * XXX - this message should be supplied by the application as 669335640Shselasky * a warning of some sort. 670335640Shselasky */ 671335640Shselasky fprintf(stderr, "tcpdump: Filtering in user process\n"); 672335640Shselasky pf->filtering_in_kernel = 0; 673335640Shselasky return (0); 674335640Shselasky} 675335640Shselasky 676335640Shselasky/* 677335640Shselasky * Libpcap version string. 678335640Shselasky */ 679335640Shselaskyconst char * 680335640Shselaskypcap_lib_version(void) 681335640Shselasky{ 682335640Shselasky return (PCAP_VERSION_STRING); 683335640Shselasky} 684