home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / ip / trace / tcpdump-2.2.1 / pcap-bpf.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-02  |  4.9 KB  |  210 lines

  1. /*
  2.  * Copyright (c) 1990 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that: (1) source code distributions
  7.  * retain the above copyright notice and this paragraph in its entirety, (2)
  8.  * distributions including binary code include the above copyright notice and
  9.  * this paragraph in its entirety in the documentation or other materials
  10.  * provided with the distribution, and (3) all advertising materials mentioning
  11.  * features or use of this software display the following acknowledgement:
  12.  * ``This product includes software developed by the University of California,
  13.  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
  14.  * the University nor the names of its contributors may be used to endorse
  15.  * or promote products derived from this software without specific prior
  16.  * written permission.
  17.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  18.  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  19.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  20.  */
  21. #ifndef lint
  22. static  char rcsid[] =
  23.     "@(#)$Header: pcap-bpf.c,v 1.29 92/06/02 17:57:29 mccanne Exp $ (LBL)";
  24. #endif
  25.  
  26. #include <stdio.h>
  27. #include <netdb.h>
  28. #include <ctype.h>
  29. #include <signal.h>
  30. #include <errno.h>
  31. #include <sys/param.h>            /* optionally get BSD define */
  32. #include <sys/time.h>
  33. #include <sys/timeb.h>
  34. #include <sys/socket.h>
  35. #include <sys/file.h>
  36. #include <sys/ioctl.h>
  37. #include <net/bpf.h>
  38. #include <net/if.h>
  39. #include <string.h>
  40.  
  41. #include "interface.h"
  42.  
  43. extern int errno;
  44.  
  45. static void
  46. bpf_stats(fd)
  47.     int fd;
  48. {
  49.     struct bpf_stat s;
  50.     
  51.     if (ioctl(fd, BIOCGSTATS, &s) < 0)
  52.         return;
  53.  
  54.     (void)fflush(stdout);
  55.     (void)fprintf(stderr, "%d packets received by filter\n", s.bs_recv);
  56.     (void)fprintf(stderr, "%d packets dropped by kernel\n", s.bs_drop);
  57. }
  58.  
  59. void
  60. readloop(cnt, if_fd, fp, printit)
  61.     int cnt;
  62.     int if_fd;
  63.     struct bpf_program *fp;
  64.     void (*printit)();
  65. {
  66.     u_char *buf;
  67.     u_int bufsize;
  68.     int cc;
  69.  
  70.     if (ioctl(if_fd, BIOCGBLEN, (caddr_t)&bufsize) < 0) {
  71.         perror("tcpdump: BIOCGBLEN");
  72.         exit(1);
  73.     }
  74.     buf = (u_char *)malloc(bufsize);
  75.  
  76.     if (ioctl(if_fd, BIOCSETF, (caddr_t)fp) < 0) {
  77.         perror("tcpdump: BIOCSETF");
  78.         exit(1);
  79.     }
  80.     while (1) {
  81.         register u_char *bp, *ep;
  82.  
  83.         if ((cc = read(if_fd, (char *)buf, (int)bufsize)) < 0) {
  84.             /* Don't choke when we get ptraced */
  85.             if (errno == EINTR)
  86.                 continue;
  87. #if defined(sun) && !defined(BSD)
  88.             /*
  89.              * Due to a SunOS bug, after 2^31 bytes, the kernel
  90.              * file offset overflows and read fails with EINVAL.
  91.              * The lseek() to 0 will fix things.
  92.              */
  93.             if (errno == EINVAL &&
  94.                 (long)(tell(if_fd) + bufsize) < 0) {
  95.                 (void)lseek(if_fd, 0, 0);
  96.                 continue;
  97.             }
  98. #endif
  99.             perror("tcpdump: read");
  100.             exit(1);
  101.         }
  102.         /*
  103.          * Loop through each packet.
  104.          */
  105. #define bhp ((struct bpf_hdr *)bp)
  106.         bp = buf;
  107.         ep = bp + cc;
  108.         while (bp < ep) {
  109.             register int caplen, hdrlen;
  110.             if (cnt >= 0 && --cnt < 0)
  111.                 goto out;
  112.             (*printit)(bp + (hdrlen = bhp->bh_hdrlen),
  113.                    &bhp->bh_tstamp, bhp->bh_datalen,
  114.                    caplen = bhp->bh_caplen);
  115.             bp += BPF_WORDALIGN(caplen + hdrlen);
  116.         }
  117. #undef bhp
  118.     }
  119.  out:
  120.     wrapup(if_fd);
  121. }
  122.  
  123. wrapup(fd)
  124.     int fd;
  125. {
  126.     bpf_stats(fd);
  127.     close(fd);
  128. }
  129.  
  130. static inline int
  131. bpf_open()
  132. {
  133.     int fd;
  134.     int n = 0;
  135.     char device[sizeof "/dev/bpf000"];
  136.  
  137.     /*
  138.      * Go through all the minors and find one that isn't in use.
  139.      */
  140.     do {
  141.         (void)sprintf(device, "/dev/bpf%d", n++);
  142.         fd = open(device, O_RDONLY);
  143.     } while (fd < 0 && errno == EBUSY);
  144.  
  145.     if (fd < 0) {
  146.         (void) fprintf(stderr, "tcpdump: ");
  147.         perror(device);
  148.         exit(-1);
  149.     }
  150.     return fd;
  151. }
  152.  
  153. int
  154. initdevice(device, pflag, linktype)
  155.     char *device;
  156.     int pflag;
  157.     int *linktype;
  158. {
  159.     struct timeval timeout;
  160.     int if_fd;
  161.     struct ifreq ifr;
  162.     struct bpf_version bv;
  163.     
  164.     if_fd = bpf_open();
  165.  
  166.     if (ioctl(if_fd, BIOCVERSION, (caddr_t)&bv) < 0)
  167.         warning("kernel bpf interpreter may be out of date");
  168.     else if (bv.bv_major != BPF_MAJOR_VERSION ||
  169.          bv.bv_minor < BPF_MINOR_VERSION)
  170.         error("requires bpf language %d.%d or higher; kernel is %d.%d",
  171.               BPF_MAJOR_VERSION, BPF_MINOR_VERSION,
  172.               bv.bv_major, bv.bv_minor);
  173.  
  174.     (void)strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
  175.     if (ioctl(if_fd, BIOCSETIF, (caddr_t)&ifr) < 0) {
  176.         (void) fprintf(stderr, "tcpdump: BIOCSETIF: ");
  177.         perror(device);
  178.         exit(-1);
  179.     }
  180.     /* Get the data link layer type. */
  181.     if (ioctl(if_fd, BIOCGDLT, (caddr_t)linktype) < 0) {
  182.         perror("tcpdump: BIOCGDLT");
  183.         exit(-1);
  184.     }
  185.     /* set timeout */
  186.     timeout.tv_sec = 1;
  187.     timeout.tv_usec = 0;
  188.     if (ioctl(if_fd, BIOCSRTIMEOUT, (caddr_t)&timeout) < 0) {
  189.         perror("tcpdump: BIOCSRTIMEOUT");
  190.         exit(-1);
  191.     }
  192.     /* set promiscuous mode if requested, but only for broadcast nets */
  193.     if (pflag == 0) {
  194.         switch (*linktype) {
  195.  
  196.         case DLT_SLIP:
  197.         case DLT_PPP:
  198.         case DLT_NULL:
  199.             break;
  200.  
  201.         default:
  202.             if (ioctl(if_fd, BIOCPROMISC, (void *)0) < 0) {
  203.                 perror("tcpdump: BIOCPROMISC");
  204.                 exit(-1);
  205.             }
  206.         }
  207.     }
  208.     return(if_fd);
  209. }
  210.