1 /*
2 * Copyright (c) 1988, 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-nit.c,v 1.12 90/12/04 17:13:24 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/types.h>
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/nit.h>
38
39 #include <net/if.h>
40 #include <netinet/in.h>
41 #include <netinet/in_systm.h>
42 #include <netinet/ip.h>
43 #include <netinet/if_ether.h>
44 #include <netinet/ip_var.h>
45 #include <netinet/udp.h>
46 #include <netinet/udp_var.h>
47 #include <netinet/tcp.h>
48 #include <netinet/tcpip.h>
49 #include <net/bpf.h>
50
51 #include "interface.h"
52
53 /*
54 * The chunk size for NIT. This is the amount of buffering
55 * done for read calls.
56 */
57 #define CHUNKSIZE (2*1024)
58
59 /*
60 * The total buffer space used by NIT.
61 */
62 #define BUFSPACE (4*CHUNKSIZE)
63
64 void
readloop(cnt,if_fd,fp,printit)65 readloop(cnt, if_fd, fp, printit)
66 int cnt;
67 int if_fd;
68 struct bpf_program *fp;
69 void (*printit)();
70 {
71 u_char buf[CHUNKSIZE];
72 struct bpf_insn *fcode;
73 int cc, i;
74
75 fcode = fp->bf_insns;
76 i = 0;
77
78 while ((cc = read(if_fd, (char *)buf, sizeof(buf))) > 0) {
79 register u_char *bp, *bstop;
80 register u_char *sp;
81 register struct nit_hdr *nh;
82 register int datalen = 0;
83 int caplen;
84
85 /*
86 * Loop through each packet. The increment expression
87 * rounds up to the next int boundary past the end of
88 * the previous packet.
89 */
90 bstop = buf + cc;
91 for (bp = buf; bp < bstop;
92 bp += ((sizeof(struct nit_hdr)+datalen+sizeof(int)-1)
93 & ~(sizeof(int)-1))) {
94
95 nh = (struct nit_hdr *)bp;
96 sp = bp + sizeof(*nh);
97
98 switch (nh->nh_state) {
99 case NIT_CATCH:
100 datalen = nh->nh_datalen;
101 break;
102 case NIT_SEQNO:
103 case NIT_NOMBUF:
104 case NIT_NOCLUSTER:
105 case NIT_NOSPACE:
106 datalen = 0;
107 continue;
108 default:
109 (void)fprintf(stderr,
110 "bad nit state %d\n", nh->nh_state);
111 exit(1);
112 }
113 caplen = nh->nh_wirelen;
114 if (caplen > snaplen)
115 caplen = snaplen;
116 if (bpf_filter(fcode, sp, nh->nh_wirelen, caplen)) {
117 (*printit)(sp, &nh->nh_timestamp,
118 nh->nh_wirelen, caplen);
119 if (cflag && ++i >= cnt) {
120 wrapup(if_fd);
121 return;
122 }
123 }
124 }
125 }
126 perror("read");
127 exit(-1);
128 }
129
wrapup(fd)130 wrapup(fd)
131 int fd;
132 {
133 close(fd);
134 }
135
136 int
initdevice(device,pflag,linktype)137 initdevice(device, pflag, linktype)
138 char *device;
139 int pflag;
140 int *linktype;
141 {
142 struct sockaddr_nit snit;
143 struct nit_ioc nioc;
144 int if_fd;
145
146 if (snaplen < 96)
147 /*
148 * NIT requires a snapshot length of at least 96.
149 */
150 snaplen = 96;
151
152 if_fd = socket(AF_NIT, SOCK_RAW, NITPROTO_RAW);
153
154 if (if_fd < 0) {
155 perror("nit socket");
156 exit(-1);
157 }
158
159 snit.snit_family = AF_NIT;
160 (void)strncpy(snit.snit_ifname, device, NITIFSIZ);
161
162 if (bind(if_fd, (struct sockaddr *)&snit, sizeof(snit))) {
163 perror(snit.snit_ifname);
164 exit(1);
165 }
166
167 bzero((char *)&nioc, sizeof(nioc));
168 nioc.nioc_bufspace = BUFSPACE;
169 nioc.nioc_chunksize = CHUNKSIZE;
170 nioc.nioc_typetomatch = NT_ALLTYPES;
171 nioc.nioc_snaplen = snaplen;
172 nioc.nioc_bufalign = sizeof(int);
173 nioc.nioc_bufoffset = 0;
174 nioc.nioc_flags = pflag ? NF_TIMEOUT : NF_PROMISC|NF_TIMEOUT;
175 nioc.nioc_timeout.tv_sec = 1;
176 nioc.nioc_timeout.tv_usec = 0;
177
178 if (ioctl(if_fd, SIOCSNIT, &nioc) != 0) {
179 perror("nit ioctl");
180 exit(1);
181 }
182 /*
183 * NIT supports only ethernets.
184 */
185 *linktype = DLT_EN10MB;
186
187 return if_fd;
188 }
189