pcap-enet.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. /*
  2. * Stanford Enetfilter subroutines for tcpdump
  3. *
  4. * Based on the MERIT NNstat etherifrt.c and the Ultrix pcap-pf.c
  5. * subroutines.
  6. *
  7. * Rayan Zachariassen, CA*Net
  8. */
  9. #ifdef HAVE_CONFIG_H
  10. #include <config.h>
  11. #endif
  12. #include <sys/types.h>
  13. #include <sys/time.h>
  14. #include <sys/file.h>
  15. #include <sys/ioctl.h>
  16. #include <sys/socket.h>
  17. #include <net/if.h>
  18. #include <pcap/bpf.h>
  19. #include <net/enet.h>
  20. #include <netinet/in.h>
  21. #include <netinet/if_ether.h>
  22. #include <stdio.h>
  23. #include <errno.h>
  24. #include "interface.h"
  25. struct packet_header {
  26. #ifdef IBMRTPC
  27. struct LengthWords length;
  28. struct tap_header tap;
  29. #endif /* IBMRTPC */
  30. u_char packet[8]
  31. };
  32. extern int errno;
  33. #define BUFSPACE (4*1024)
  34. /* Forwards */
  35. static void efReadError(int, char *);
  36. void
  37. readloop(int cnt, int if_fd, struct bpf_program *fp, printfunc printit)
  38. {
  39. #ifdef IBMRTPC
  40. register struct packet_header *ph;
  41. register u_char *bp;
  42. register int inc;
  43. #else /* !IBMRTPC */
  44. static struct timeval tv = { 0 };
  45. #endif /* IBMRTPC */
  46. register int cc, caplen;
  47. register struct bpf_insn *fcode = fp->bf_insns;
  48. union {
  49. struct packet_header hdr;
  50. u_char p[BUFSPACE];
  51. u_short s;
  52. } buf;
  53. while (1) {
  54. if ((cc = read(if_fd, (char *)buf.p, sizeof(buf))) < 0)
  55. efReadError(if_fd, "reader");
  56. #ifdef IBMRTPC
  57. /*
  58. * Loop through each packet.
  59. */
  60. bp = buf.p;
  61. while (cc > 0) {
  62. ph = (struct packet_header *)bp;
  63. caplen = ph->tap.th_wirelen > snaplen ? snaplen : ph->tap
  64. .th_wirelen ;
  65. if (bpf_filter(fcode, (char *)ph->packet,
  66. ph->tap.th_wirelen, caplen)) {
  67. if (cnt >= 0 && --cnt < 0)
  68. goto out;
  69. (*printit)((char *)ph->packet,
  70. (struct timeval *)ph->tap.th_timestamp,
  71. ph->tap.th_wirelen, caplen);
  72. }
  73. inc = ph->length.PacketOffset;
  74. cc -= inc;
  75. bp += inc;
  76. }
  77. #else /* !IBMRTPC */
  78. caplen = cc > snaplen ? snaplen : cc ;
  79. if (bpf_filter(fcode, buf.hdr.packet, cc, caplen)) {
  80. if (cnt >= 0 && --cnt < 0)
  81. goto out;
  82. (*printit)(buf.hdr.packet, &tv, cc, caplen);
  83. }
  84. #endif /* IBMRTPC */
  85. }
  86. out:
  87. wrapup(if_fd);
  88. }
  89. /* Call ONLY if read() has returned an error on packet filter */
  90. static void
  91. efReadError(int fid, char *msg)
  92. {
  93. if (errno == EINVAL) { /* read MAXINT bytes already! */
  94. if (lseek(fid, 0, 0) < 0) {
  95. perror("tcpdump: efReadError/lseek");
  96. exit(-1);
  97. }
  98. else
  99. return;
  100. }
  101. else {
  102. (void) fprintf(stderr, "tcpdump: ");
  103. perror(msg);
  104. exit(-1);
  105. }
  106. }
  107. void
  108. wrapup(int fd)
  109. {
  110. #ifdef IBMRTPC
  111. struct enstats es;
  112. if (ioctl(fd, EIOSTATS, &es) == -1) {
  113. perror("tcpdump: enet ioctl EIOSTATS error");
  114. exit(-1);
  115. }
  116. fprintf(stderr, "%d packets queued", es.enStat_Rcnt);
  117. if (es.enStat_Rdrops > 0)
  118. fprintf(stderr, ", %d dropped", es.enStat_Rdrops);
  119. if (es.enStat_Reads > 0)
  120. fprintf(stderr, ", %d tcpdump %s", es.enStat_Reads,
  121. es.enStat_Reads > 1 ? "reads" : "read");
  122. if (es.enStat_MaxRead > 1)
  123. fprintf(stderr, ", %d packets in largest read",
  124. es.enStat_MaxRead);
  125. putc('\n', stderr);
  126. #endif /* IBMRTPC */
  127. close(fd);
  128. }
  129. int
  130. initdevice(char *device, int pflag, int *linktype)
  131. {
  132. struct eniocb ctl;
  133. struct enfilter filter;
  134. u_int maxwaiting;
  135. int if_fd;
  136. #ifdef IBMRTPC
  137. GETENETDEVICE(0, O_RDONLY, &if_fd);
  138. #else /* !IBMRTPC */
  139. if_fd = open("/dev/enet", O_RDONLY, 0);
  140. #endif /* IBMRTPC */
  141. if (if_fd == -1) {
  142. perror("tcpdump: enet open error");
  143. error(
  144. "your system may not be properly configured; see \"man enet(4)\"");
  145. exit(-1);
  146. }
  147. /* Get operating parameters. */
  148. if (ioctl(if_fd, EIOCGETP, (char *)&ctl) == -1) {
  149. perror("tcpdump: enet ioctl EIOCGETP error");
  150. exit(-1);
  151. }
  152. /* Set operating parameters. */
  153. #ifdef IBMRTPC
  154. ctl.en_rtout = 1 * ctl.en_hz;
  155. ctl.en_tr_etherhead = 1;
  156. ctl.en_tap_network = 1;
  157. ctl.en_multi_packet = 1;
  158. ctl.en_maxlen = BUFSPACE;
  159. #else /* !IBMRTPC */
  160. ctl.en_rtout = 64; /* randomly picked value for HZ */
  161. #endif /* IBMRTPC */
  162. if (ioctl(if_fd, EIOCSETP, &ctl) == -1) {
  163. perror("tcpdump: enet ioctl EIOCSETP error");
  164. exit(-1);
  165. }
  166. /* Flush the receive queue, since we've changed
  167. the operating parameters and we otherwise might
  168. receive data without headers. */
  169. if (ioctl(if_fd, EIOCFLUSH) == -1) {
  170. perror("tcpdump: enet ioctl EIOCFLUSH error");
  171. exit(-1);
  172. }
  173. /* Set the receive queue depth to its maximum. */
  174. maxwaiting = ctl.en_maxwaiting;
  175. if (ioctl(if_fd, EIOCSETW, &maxwaiting) == -1) {
  176. perror("tcpdump: enet ioctl EIOCSETW error");
  177. exit(-1);
  178. }
  179. #ifdef IBMRTPC
  180. /* Clear statistics. */
  181. if (ioctl(if_fd, EIOCLRSTAT, 0) == -1) {
  182. perror("tcpdump: enet ioctl EIOCLRSTAT error");
  183. exit(-1);
  184. }
  185. #endif /* IBMRTPC */
  186. /* Set the filter (accept all packets). */
  187. filter.enf_Priority = 3;
  188. filter.enf_FilterLen = 0;
  189. if (ioctl(if_fd, EIOCSETF, &filter) == -1) {
  190. perror("tcpdump: enet ioctl EIOCSETF error");
  191. exit(-1);
  192. }
  193. /*
  194. * "enetfilter" supports only ethernets.
  195. */
  196. *linktype = DLT_EN10MB;
  197. return(if_fd);
  198. }